UFO: Alien Invasion
Loading...
Searching...
No Matches
g_round.cpp
Go to the documentation of this file.
1
4
5/*
6Copyright (C) 2002-2025 UFO: Alien Invasion.
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17See the GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23*/
24
25#include "g_local.h"
26#include "g_actor.h"
27#include "g_ai.h"
28#include "g_client.h"
29#include "g_edicts.h"
30#include "g_health.h"
31#include "g_match.h"
32#include "g_reaction.h"
33#include "g_utils.h"
34#include "g_vis.h"
35
40{
41 /* check for roundlimits in multiplayer only */
42 if (!sv_roundtimelimit->integer || G_IsSinglePlayer())
43 return;
44
45 if (!G_MatchIsRunning())
46 return;
47
48 if (level.time != ceil(level.time))
49 return;
50
51 const int diff = level.roundstartTime + sv_roundtimelimit->integer - level.time;
52 switch (diff) {
53 case 240:
54 gi.BroadcastPrintf(PRINT_HUD, _("4 minutes left until forced turn end."));
55 return;
56 case 180:
57 gi.BroadcastPrintf(PRINT_HUD, _("3 minutes left until forced turn end."));
58 return;
59 case 120:
60 gi.BroadcastPrintf(PRINT_HUD, _("2 minutes left until forced turn end."));
61 return;
62 case 60:
63 gi.BroadcastPrintf(PRINT_HUD, _("1 minute left until forced turn end."));
64 return;
65 case 30:
66 gi.BroadcastPrintf(PRINT_HUD, _("30 seconds left until forced turn end."));
67 return;
68 case 15:
69 gi.BroadcastPrintf(PRINT_HUD, _("15 seconds left until forced turn end."));
70 return;
71 }
72
73 /* active team still has time left */
74 if (level.time < level.roundstartTime + sv_roundtimelimit->integer)
75 return;
76
77 gi.BroadcastPrintf(PRINT_HUD, _("Current active team hit the max round time."));
78
79 /* store this in a local variable, as the global variable is changed in G_ClientEndRound */
80 const int activeTeam = level.activeTeam;
81 /* set all team members to ready (only human players) */
82 Player* p = nullptr;
83 while ((p = G_PlayerGetNextActiveHuman(p))) {
84 if (p->getTeam() == activeTeam) {
86 level.nextEndRound = level.framenum;
87 }
88 }
89
90 level.roundstartTime = level.time;
91}
92
96static int G_PlayerSoldiersCount (const Player& player)
97{
98 int cnt = 0;
99 Actor* actor = nullptr;
100
101 while ((actor = G_EdictsGetNextLivingActor(actor))) {
102 if (actor->getPlayerNum() == player.getNum())
103 cnt++;
104 }
105
106 return cnt;
107}
108
117static void G_UpdateStunState (int team)
118{
119 const int regen = 1;
120
121 Actor* actor = nullptr;
122 while ((actor = G_EdictsGetNextLivingActorOfTeam(actor, team))) {
123 const int stun = actor->getStun();
124 if (stun > 0) {
125 if (regen > stun)
126 actor->setStun(0);
127 else
128 actor->addStun(-regen);
129
131 }
132 }
133}
134
139static void G_UpdateCarriedWeight (int team)
140{
141 Actor* actor = nullptr;
142
143 while ((actor = G_EdictsGetNextLivingActorOfTeam(actor, team))) {
144 if (actor->chr.scoreMission) {
145 actor->chr.scoreMission->carriedWeight += actor->chr.inv.getWeight();
146 }
147 }
148}
149
150static void G_RoundTouchTriggers (int team)
151{
152 Actor* actor = nullptr;
153
154 while ((actor = G_EdictsGetNextLivingActorOfTeam(actor, team))) {
155 G_TouchTriggers(actor);
156 }
157}
158
162static void G_GetNextActiveTeam (void)
163{
164 const int lastTeam = G_GetActiveTeam();
165
166 Com_DPrintf(DEBUG_GAME, "round end from team %i\n", lastTeam);
167 level.activeTeam = TEAM_NO_ACTIVE;
168
169 /* search next team */
170 for (int i = 1; i < MAX_TEAMS; i++) {
171 const int team = (lastTeam + i) % MAX_TEAMS;
172 if (level.num_alive[team]) {
173 /* found next player */
174 level.activeTeam = team;
175 Com_DPrintf(DEBUG_GAME, "round start for team %i\n", team);
176 break;
177 }
178 }
179}
180
184void G_ClientEndRound (Player& player)
185{
186 const int lastTeamIndex = (G_GetActiveTeam() + level.teamOfs) % MAX_TEAMS;
187
188 if (!G_IsAIPlayer(&player)) {
189 /* inactive players can't end their inactive turn :) */
190 if (level.activeTeam != player.getTeam())
191 return;
192
193 /* check for "team oszillation" */
194 if (level.framenum < level.nextEndRound)
195 return;
196
197 level.nextEndRound = level.framenum + 20;
198 }
199
200 /* only use this for teamplay matches like coopX or fight2on2 and above
201 * also skip this for ai players, this is only called when all ai actors
202 * have finished their 'thinking' */
203 if (!G_IsAIPlayer(&player) && sv_teamplay->integer) {
204 /* check if all team members are ready */
205 if (!player.roundDone) {
206 player.roundDone = true;
208 G_EventEnd();
209 }
210 Player* p = nullptr;
211 while ((p = G_PlayerGetNextActiveHuman(p)))
212 if (p->getTeam() == level.activeTeam && !p->roundDone && G_PlayerSoldiersCount(*p) > 0)
213 return;
214 p = nullptr;
215 while ((p = G_PlayerGetNextActiveAI(p)))
216 if (p->getTeam() == level.activeTeam && !p->roundDone && G_PlayerSoldiersCount(*p) > 0)
217 return;
218 } else {
219 player.roundDone = true;
220 }
221
222 /* clear any remaining reaction fire */
224
225 if (!G_IsAIPlayer(&player)) {
226 if (g_lastseen->integer > 0) {
227 Actor* actor = nullptr;
228 while ((actor = G_EdictsGetNextActor(actor))) {
229 if (G_IsAI(actor) && G_IsVisibleForTeam(actor, level.activeTeam)) {
230 player.lastSeen = level.actualRound;
231 break;
232 }
233 }
234 if (level.actualRound - player.lastSeen > g_lastseen->integer) {
235 Com_Printf("round end triggered by g_lastseen (player %i (team %i) last seen in round %i of %i rounds)\n",
236 player.getNum(), level.activeTeam, player.lastSeen, level.actualRound);
237 G_MatchEndTrigger(-1, 0);
238 }
239 }
240 }
241
242 /* Wounded team members bleed now */
243 G_BleedWounds(level.activeTeam);
244
245 /* let all the invisible players perish now */
246 G_CheckVisTeamAll(level.activeTeam, VIS_APPEAR, nullptr);
247
249
251
252 /* no other team left? */
253 if (!G_MatchIsRunning())
254 return;
255
256 if (lastTeamIndex > (level.activeTeam + level.teamOfs) % MAX_TEAMS)
257 level.actualRound++;
258
259 /* communicate next player in row to clients */
261
262 /* store the round start time to be able to abort the round after a give time */
263 level.roundstartTime = level.time;
264
265 G_RoundTouchTriggers(level.activeTeam);
266
267 /* Update the state of stuned team-members. The actual statistics are sent below! */
268 G_UpdateStunState(level.activeTeam);
269
270 /* Give the actors of the now active team their TUs. */
271 G_GiveTimeUnits(level.activeTeam);
272
273 G_UpdateCarriedWeight(level.activeTeam);
274
275 /* apply morale behaviour, reset reaction fire */
276 G_ReactionFireReset(level.activeTeam);
277 if (mor_panic->integer)
278 G_MoraleBehaviour(level.activeTeam);
279
280 /* start ai - there is only one player for ai teams, and the last pointer must only
281 * be updated for ai players */
282 Player* p = G_GetPlayerForTeam(level.activeTeam);
283 if (p == nullptr)
284 gi.Error("Could not find player for team %i", level.activeTeam);
285
286 /* finish off events */
287 G_EventEnd();
288
289 /* reset ready flag for every player on the current team (even ai players) */
290 p = nullptr;
291 while ((p = G_PlayerGetNextActiveHuman(p))) {
292 if (p->getTeam() == level.activeTeam) {
293 p->roundDone = false;
294 }
295 }
296
297 p = nullptr;
298 while ((p = G_PlayerGetNextActiveAI(p))) {
299 if (p->getTeam() == level.activeTeam) {
300 p->roundDone = false;
301 }
302 }
303}
#define _(String)
Definition cl_shared.h:44
An Edict of type Actor.
Definition g_edict.h:348
int getPlayerNum() const
Definition g_edict.h:234
character_t chr
Definition g_edict.h:116
void addStun(int stu)
Definition g_edict.h:305
void setStun(int stu)
Definition g_edict.h:302
int getStun() const
Definition g_edict.h:308
int getWeight() const
Get the weight of the items in the given inventory (excluding those in temp containers).
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition common.cpp:440
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
#define PRINT_HUD
Definition defines.h:107
#define MAX_TEAMS
Definition defines.h:98
#define DEBUG_GAME
Definition defines.h:61
void G_ActorCheckRevitalise(Actor *actor)
Definition g_actor.cpp:386
void AI_CheckRespawn(int team)
If the cvar g_endlessaliens is set we will endlessly respawn aliens.
Definition g_ai.cpp:1908
Artificial Intelligence functions.
Player * G_PlayerGetNextActiveHuman(Player *lastPlayer)
Iterate through the list of players.
Definition g_client.cpp:110
Player * G_PlayerGetNextActiveAI(Player *lastPlayer)
Iterate through the list of players.
Definition g_client.cpp:126
void G_GiveTimeUnits(int team)
Network function to update the time units (TUs) for each team-member.
Definition g_client.cpp:224
int G_GetActiveTeam(void)
Returns the current active team to the server.
Definition g_client.cpp:327
Interface for g_client.cpp.
Actor * G_EdictsGetNextLivingActorOfTeam(Actor *lastEnt, const int team)
Iterate through the living actor entities of the given team.
Definition g_edicts.cpp:216
Actor * G_EdictsGetNextActor(Actor *lastEnt)
Iterate through the actor entities (even the dead!).
Definition g_edicts.cpp:231
Actor * G_EdictsGetNextLivingActor(Actor *lastEnt)
Iterate through the living actor entities.
Definition g_edicts.cpp:196
functions to handle the storage and lifecycle of all edicts in the game module.
void G_EventEnd(void)
Definition g_events.cpp:711
void G_EventEndRoundAnnounce(const Player &player)
Definition g_events.cpp:654
void G_EventEndRound(void)
End of turn event for the current active team.
Definition g_events.cpp:414
void G_BleedWounds(const int team)
Deal damage to each wounded team member.
Definition g_health.cpp:130
Local definitions for game module.
cvar_t * g_lastseen
Definition g_main.cpp:120
level_locals_t level
Definition g_main.cpp:38
cvar_t * mor_panic
Definition g_main.cpp:103
cvar_t * sv_teamplay
Definition g_main.cpp:61
#define G_IsAI(ent)
Definition g_local.h:141
#define G_IsVisibleForTeam(ent, team)
Definition g_local.h:144
game_import_t gi
Definition g_main.cpp:39
#define G_IsAIPlayer(player)
Definition g_local.h:142
void G_MoraleBehaviour(int team)
Applies morale behaviour on actors.
Definition g_morale.cpp:156
#define G_IsSinglePlayer()
Definition g_local.h:146
cvar_t * sv_roundtimelimit
Definition g_main.cpp:56
void G_MatchEndTrigger(int team, int timeGap)
Triggers the end of the game. Will be executed in the next server (or game) frame.
Definition g_match.cpp:125
bool G_MatchIsRunning(void)
Checks whether the game is running (active team and no intermission time).
Definition g_match.cpp:320
Match related functions.
void G_ReactionFireOnEndTurn(void)
Called at the end of turn, all outstanding reaction fire is resolved.
void G_ReactionFireReset(int team)
Guess! Reset all "shaken" states on end of turn?
Reaction fire system.
static void G_GetNextActiveTeam(void)
Get the next active team.
Definition g_round.cpp:162
static void G_UpdateStunState(int team)
Regenerate the "STUN" value of each (partly) stunned team member.
Definition g_round.cpp:117
static void G_RoundTouchTriggers(int team)
Definition g_round.cpp:150
void G_ClientEndRound(Player &player)
Definition g_round.cpp:184
static void G_UpdateCarriedWeight(int team)
Updates the weight carried for each team member.
Definition g_round.cpp:139
static int G_PlayerSoldiersCount(const Player &player)
Counts the still living actors for a player.
Definition g_round.cpp:96
void G_CheckForceEndRound(void)
Check whether a forced turn end should be executed.
Definition g_round.cpp:39
int G_TouchTriggers(Edict *ent, const entity_type_t type)
Check the world against triggers for the current entity.
Definition g_utils.cpp:547
Player * G_GetPlayerForTeam(int team)
Gets player for given team.
Definition g_utils.cpp:188
Misc utility functions for game module.
int G_CheckVisTeamAll(const int team, const vischeckflags_t visFlags, const Edict *ent)
Do G_CheckVisTeam for all entities ent is the one that is looking at the others.
Definition g_vis.cpp:376
#define VIS_APPEAR
Definition g_vis.h:36
#define TEAM_ALIEN
Definition q_shared.h:63
#define TEAM_NO_ACTIVE
Definition q_shared.h:60
QGL_EXTERN GLint i
Definition r_gl.h:113
chrScoreMission_t * scoreMission
Definition chr_shared.h:407
Inventory inv
Definition chr_shared.h:411