Xonotic
sv_assault.qc
Go to the documentation of this file.
1 #include "sv_assault.qh"
2 
3 #include <server/command/vote.qh>
7 #include <server/damage.qh>
8 #include <server/world.qh>
9 #include <server/spawnpoints.qh>
10 
11 .entity sprite;
12 #define AS_ROUND_DELAY 5
13 
14 // random functions
15 void assault_objective_use(entity this, entity actor, entity trigger)
16 {
17  // activate objective
18  SetResourceExplicit(this, RES_HEALTH, 100);
19  //print("^2Activated objective ", this.targetname, "=", etos(this), "\n");
20  //print("Activator is ", actor.classname, "\n");
21 
22  IL_EACH(g_assault_objectivedecreasers, it.target == this.targetname,
23  {
24  target_objective_decrease_activate(it);
25  });
26 }
27 
29 {
30  float hlth = GetResource(this, RES_HEALTH);
31  if (hlth < 0 || hlth >= ASSAULT_VALUE_INACTIVE)
32  return '-1 0 0';
33  return current;
34 }
35 
36 // reset this objective. Used when spawning an objective
37 // and when a new round starts
39 {
41 }
42 
43 // decrease the health of targeted objectives
45 {
46  if(actor.team != assault_attacker_team)
47  {
48  // wrong team triggered decrease
49  return;
50  }
51 
52  if(trigger.assault_sprite)
53  {
54  WaypointSprite_Disown(trigger.assault_sprite, waypointsprite_deadlifetime);
55  if(trigger.classname == "func_assault_destructible")
56  trigger.sprite = NULL; // TODO: just unsetting it?!
57  }
58  else
59  return; // already activated! cannot activate again!
60 
61  float hlth = GetResource(this.enemy, RES_HEALTH);
62  if (hlth < ASSAULT_VALUE_INACTIVE)
63  {
64  if (hlth - this.dmg > 0.5)
65  {
66  GameRules_scoring_add_team(actor, SCORE, this.dmg);
67  TakeResource(this.enemy, RES_HEALTH, this.dmg);
68  }
69  else
70  {
71  GameRules_scoring_add_team(actor, SCORE, hlth);
72  GameRules_scoring_add_team(actor, ASSAULT_OBJECTIVES, 1);
74 
75  if(this.enemy.message)
76  FOREACH_CLIENT(IS_PLAYER(it), { centerprint(it, this.enemy.message); });
77 
78  SUB_UseTargets(this.enemy, this, trigger);
79  }
80  }
81 }
82 
84 {
85  IL_EACH(g_assault_objectives, it.targetname == this.target,
86  {
87  if(this.enemy == NULL)
88  this.enemy = it;
89  else
90  objerror(this, "more than one objective as target - fix the map!");
91  break;
92  });
93 
94  if(this.enemy == NULL)
95  objerror(this, "no objective as target - fix the map!");
96 }
97 
99 {
101  return false;
102 
103  return true;
104 }
105 
107 {
108  entity spr;
109  this.owner = NULL;
111  {
112  if(it.assault_sprite != NULL)
113  {
114  WaypointSprite_Disown(it.assault_sprite, waypointsprite_deadlifetime);
115  if(it.classname == "func_assault_destructible")
116  it.sprite = NULL; // TODO: just unsetting it?!
117  }
118 
119  spr = WaypointSprite_SpawnFixed(WP_AssaultDefend, 0.5 * (it.absmin + it.absmax), it, assault_sprite, RADARICON_OBJECTIVE);
120  spr.assault_decreaser = this;
121  spr.waypointsprite_visible_for_player = assault_decreaser_sprite_visible;
122  WaypointSprite_UpdateRule(spr, assault_attacker_team, SPRITERULE_TEAMPLAY);
123  if(it.classname == "func_assault_destructible")
124  {
125  WaypointSprite_UpdateSprites(spr, WP_AssaultDefend, WP_AssaultDestroy, WP_AssaultDestroy);
126  WaypointSprite_UpdateMaxHealth(spr, it.max_health);
127  WaypointSprite_UpdateHealth(spr, GetResource(it, RES_HEALTH));
128  it.sprite = spr;
129  }
130  else
131  WaypointSprite_UpdateSprites(spr, WP_AssaultDefend, WP_AssaultPush, WP_AssaultPush);
132  });
133 }
134 
136 {
138 }
139 
141 {
142  //print("round end reset\n");
143  ++this.cnt; // up round counter
144  this.winning = false; // up round
145 }
146 
148 {
149  this.winning = 1; // round has been won by attackers
150 }
151 
152 void assault_roundstart_use(entity this, entity actor, entity trigger)
153 {
154  SUB_UseTargets(this, this, trigger);
155 
156  //(Re)spawn all turrets
157  IL_EACH(g_turrets, true,
158  {
159  // Swap turret teams
160  if(it.team == NUM_TEAM_1)
161  it.team = NUM_TEAM_2;
162  else
163  it.team = NUM_TEAM_1;
164 
165  // Doubles as teamchange
166  turret_respawn(it);
167  });
168 }
170 {
172 }
173 
175 {
176  if(GetResource(this.enemy, RES_HEALTH) < 0)
177  {
178  this.model = "";
179  this.solid = SOLID_NOT;
180  }
181  else
182  {
183  this.model = this.mdl;
184  this.solid = SOLID_BSP;
185  }
186 
187  this.nextthink = time + 0.2;
188 }
189 
190 // trigger new round
191 // reset objectives, toggle spawnpoints, reset triggers, ...
193 {
194  // up round counter
195  this.winning = this.winning + 1;
196 
197  // swap attacker/defender roles
200  else
202 
204  {
205  if(it.team_saved == NUM_TEAM_1)
206  it.team_saved = NUM_TEAM_2;
207  else if(it.team_saved == NUM_TEAM_2)
208  it.team_saved = NUM_TEAM_1;
209  });
210 
211  // reset the level with a countdown
212  cvar_set("timelimit", ftos(ceil(time - AS_ROUND_DELAY - game_starttime) / 60));
213  bprint("Starting second round...\n");
214  ReadyRestart_force(true); // sets game_starttime
215 }
216 
218 .entity ent_winning;
220 {
221  game_stopped = false;
222  assault_new_round(as_round.ent_winning);
223  delete(as_round);
224  as_round = NULL;
225 }
226 
227 // Assault winning condition: If the attackers triggered a round end (by fulfilling all objectives)
228 // they win. Otherwise the defending team wins once the timelimit passes.
230 {
231  if(as_round)
232  return WINNING_NO;
233 
234  WinningConditionHelper(NULL); // set worldstatus
235 
236  int status = WINNING_NO;
237  // as the timelimit has not yet passed just assume the defending team will win
239  {
241  }
242  else
243  {
245  }
246 
247  entity ent;
248  ent = find(NULL, classname, "target_assault_roundend");
249  if(ent)
250  {
251  if(ent.winning) // round end has been triggered by attacking team
252  {
253  bprint(Team_ColoredFullName(assault_attacker_team), " destroyed the objective in ", process_time(2, ceil(time - game_starttime)), "\n");
255 
257 
258  if(ent.cnt == 1 || autocvar_g_campaign) // this was the second round
259  {
260  status = WINNING_YES;
261  }
262  else
263  {
264  Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ASSAULT_OBJ_DESTROYED, ceil(time - game_starttime));
265  as_round = new(as_round);
266  as_round.think = as_round_think;
267  as_round.ent_winning = ent;
268  as_round.nextthink = time + AS_ROUND_DELAY;
269  game_stopped = true;
270 
271  // make sure timelimit isn't hit while the game is blocked
272  if(autocvar_timelimit > 0)
273  if(time + AS_ROUND_DELAY >= game_starttime + autocvar_timelimit * 60)
274  cvar_set("timelimit", ftos(autocvar_timelimit + AS_ROUND_DELAY / 60));
275  }
276  }
277  }
278 
279  return status;
280 }
281 
282 // spawnfuncs
283 spawnfunc(info_player_attacker)
284 {
285  if (!g_assault) { delete(this); return; }
286 
287  this.team = NUM_TEAM_1; // red, gets swapped every round
288  spawnfunc_info_player_deathmatch(this);
289 }
290 
291 spawnfunc(info_player_defender)
292 {
293  if (!g_assault) { delete(this); return; }
294 
295  this.team = NUM_TEAM_2; // blue, gets swapped every round
296  spawnfunc_info_player_deathmatch(this);
297 }
298 
299 spawnfunc(target_objective)
300 {
301  if (!g_assault) { delete(this); return; }
302 
304  this.use = assault_objective_use;
305  this.reset = assault_objective_reset;
306  this.reset(this);
308 }
309 
310 spawnfunc(target_objective_decrease)
311 {
312  if (!g_assault) { delete(this); return; }
313 
315 
316  if(!this.dmg)
317  this.dmg = 101;
318 
322  this.enemy = NULL;
323 
324  InitializeEntity(this, target_objective_decrease_findtarget, INITPRIO_FINDTARGET);
325 }
326 
327 // destructible walls that can be used to trigger target_objective_decrease
328 bool destructible_heal(entity targ, entity inflictor, float amount, float limit)
329 {
330  float true_limit = ((limit != RES_LIMIT_NONE) ? limit : targ.max_health);
331  float hlth = GetResource(targ, RES_HEALTH);
332  if (hlth <= 0 || hlth >= true_limit)
333  return false;
334 
335  GiveResourceWithLimit(targ, RES_HEALTH, amount, true_limit);
336  if(targ.sprite)
337  {
338  WaypointSprite_UpdateHealth(targ.sprite, GetResource(targ, RES_HEALTH));
339  }
340  func_breakable_colormod(targ);
341  return true;
342 }
343 
344 spawnfunc(func_assault_destructible)
345 {
346  if (!g_assault) { delete(this); return; }
347 
348  this.spawnflags = 3;
349  this.event_heal = destructible_heal;
351 
353  this.team = NUM_TEAM_2;
354  else
355  this.team = NUM_TEAM_1;
356 
357  func_breakable_setup(this);
358 }
359 
360 spawnfunc(func_assault_wall)
361 {
362  if (!g_assault) { delete(this); return; }
363 
364  this.mdl = this.model;
365  _setmodel(this, this.mdl);
366  this.solid = SOLID_BSP;
368  this.nextthink = time;
369  InitializeEntity(this, assault_setenemytoobjective, INITPRIO_FINDTARGET);
370 }
371 
372 spawnfunc(target_assault_roundend)
373 {
374  if (!g_assault) { delete(this); return; }
375 
376  this.winning = 0; // round not yet won by attackers
378  this.cnt = 0; // first round
379  this.reset = target_assault_roundend_reset;
380 }
381 
382 spawnfunc(target_assault_roundstart)
383 {
384  if (!g_assault) { delete(this); return; }
385 
388  this.reset2 = assault_roundstart_use_this;
389  InitializeEntity(this, assault_roundstart_use_this, INITPRIO_FINDTARGET);
390 }
391 
392 // legacy bot code
393 void havocbot_goalrating_ast_targets(entity this, float ratingscale)
394 {
395  IL_EACH(g_assault_destructibles, it.bot_attack,
396  {
397  if (it.target == "")
398  continue;
399 
400  bool found = false;
401  entity destr = it;
402  IL_EACH(g_assault_objectivedecreasers, it.targetname == destr.target,
403  {
404  float hlth = GetResource(it.enemy, RES_HEALTH);
405  if (hlth > 0 && hlth < ASSAULT_VALUE_INACTIVE)
406  {
407  found = true;
408  break;
409  }
410  });
411 
412  if(!found)
413  continue;
414 
415  vector p = 0.5 * (it.absmin + it.absmax);
416 
417  // Find and rate waypoints around it
418  found = false;
419  entity best = NULL;
420  float bestvalue = FLOAT_MAX;
421  entity des = it;
422  for (float radius = 500; radius <= 1500 && !found; radius += 500)
423  {
424  FOREACH_ENTITY_RADIUS(p, radius, it.classname == "waypoint" && !(it.wpflags & WAYPOINTFLAG_GENERATED),
425  {
426  if(checkpvs(it.origin, des))
427  {
428  found = true;
429  if(it.cnt < bestvalue)
430  {
431  best = it;
432  bestvalue = it.cnt;
433  }
434  }
435  });
436  }
437 
438  if(best)
439  {
441  // te_lightning2(NULL, '0 0 0', best.origin);
442  // te_knightspike(best.origin);
443 
444  navigation_routerating(this, best, ratingscale, 4000);
445  best.cnt += 1;
446 
447  this.havocbot_attack_time = 0;
448 
449  if(checkpvs(this.origin + this.view_ofs, it))
450  if(checkpvs(this.origin + this.view_ofs, best))
451  {
452  // dprint("increasing attack time for this target\n");
453  this.havocbot_attack_time = time + 2;
454  }
455  }
456  });
457 }
458 
460 {
461  if(IS_DEAD(this))
462  {
463  this.havocbot_attack_time = 0;
465  return;
466  }
467 
468  // Set the role timeout if necessary
469  if (!this.havocbot_role_timeout)
470  this.havocbot_role_timeout = time + 120;
471 
472  if (time > this.havocbot_role_timeout)
473  {
475  return;
476  }
477 
478  if(this.havocbot_attack_time>time)
479  return;
480 
482  {
483  // role: offense
485  havocbot_goalrating_enemyplayers(this, 10000, this.origin, 650);
486  havocbot_goalrating_ast_targets(this, 20000);
487  havocbot_goalrating_items(this, 30000, this.origin, 10000);
489 
491  }
492 }
493 
495 {
496  if(IS_DEAD(this))
497  {
498  this.havocbot_attack_time = 0;
500  return;
501  }
502 
503  // Set the role timeout if necessary
504  if (!this.havocbot_role_timeout)
505  this.havocbot_role_timeout = time + 120;
506 
507  if (time > this.havocbot_role_timeout)
508  {
510  return;
511  }
512 
513  if(this.havocbot_attack_time>time)
514  return;
515 
517  {
518  // role: defense
520  havocbot_goalrating_enemyplayers(this, 10000, this.origin, 3000);
521  havocbot_goalrating_ast_targets(this, 20000);
522  havocbot_goalrating_items(this, 30000, this.origin, 10000);
524 
526  }
527 }
528 
529 void havocbot_role_ast_setrole(entity this, float role)
530 {
531  switch(role)
532  {
534  this.havocbot_role = havocbot_role_ast_defense;
535  this.havocbot_role_timeout = 0;
536  break;
538  this.havocbot_role = havocbot_role_ast_offense;
539  this.havocbot_role_timeout = 0;
540  break;
541  }
542 }
543 
545 {
546  if(IS_DEAD(this))
547  return;
548 
549  if(this.team == assault_attacker_team)
551  else
553 }
554 
555 // mutator hooks
556 MUTATOR_HOOKFUNCTION(as, PlayerSpawn)
557 {
558  entity player = M_ARGV(0, entity);
559 
560  if(player.team == assault_attacker_team)
561  Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_ASSAULT_ATTACKING);
562  else
563  Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_ASSAULT_DEFENDING);
564 }
565 
566 MUTATOR_HOOKFUNCTION(as, TurretSpawn)
567 {
568  entity turret = M_ARGV(0, entity);
569 
570  if(!turret.team || turret.team == FLOAT_MAX)
571  turret.team = assault_attacker_team; // this gets reversed when match starts (assault_roundstart_use)
572 }
573 
574 MUTATOR_HOOKFUNCTION(as, VehicleInit)
575 {
576  entity veh = M_ARGV(0, entity);
577 
578  veh.nextthink = time + 0.5;
579 }
580 
581 MUTATOR_HOOKFUNCTION(as, HavocBot_ChooseRole)
582 {
583  entity bot = M_ARGV(0, entity);
584 
586  return true;
587 }
588 
589 MUTATOR_HOOKFUNCTION(as, PlayHitsound)
590 {
591  entity frag_victim = M_ARGV(0, entity);
592 
593  return (frag_victim.classname == "func_assault_destructible");
594 }
595 
597 {
598  // assault always has 2 teams
599  M_ARGV(0, float) = BIT(0) | BIT(1);
600  return true;
601 }
602 
604 {
605  M_ARGV(0, float) = WinningCondition_Assault();
606  return true;
607 }
608 
609 MUTATOR_HOOKFUNCTION(as, ReadLevelCvars)
610 {
611  // incompatible
612  warmup_stage = 0;
614 }
615 
616 MUTATOR_HOOKFUNCTION(as, OnEntityPreSpawn)
617 {
618  entity ent = M_ARGV(0, entity);
619 
620  switch(ent.classname)
621  {
622  case "info_player_team1":
623  case "info_player_team2":
624  case "info_player_team3":
625  case "info_player_team4":
626  return true;
627  }
628 }
629 
630 MUTATOR_HOOKFUNCTION(as, ReadyRestart_Deny)
631 {
632  // readyrestart not supported (yet)
633  return true;
634 }
const float SOLID_NOT
Definition: csprogsdefs.qc:244
#define IL_EACH(this, cond, body)
float havocbot_role_timeout
Definition: api.qh:46
void navigation_goalrating_start(entity this)
Definition: navigation.qc:1830
void target_assault_roundend_use(entity this, entity actor, entity trigger)
Definition: sv_assault.qc:147
entity sprite
Definition: sv_assault.qc:11
const int NUM_TEAM_2
Definition: teams.qh:19
void turret_respawn(entity this)
void havocbot_goalrating_items(entity this, float ratingscale, vector org, float sradius)
Definition: roles.qc:106
void ReadyRestart_force(bool is_fake_round_start)
Definition: vote.qc:426
vector view_ofs
Definition: progsdefs.qc:151
bool SetResourceExplicit(entity e, Resource res_type, float amount)
Sets the resource amount of an entity without calling any hooks.
Definition: cl_resources.qc:15
void navigation_goalrating_end(entity this)
Definition: navigation.qc:1845
void havocbot_goalrating_ast_targets(entity this, float ratingscale)
Definition: sv_assault.qc:393
#define IS_CLIENT(v)
Definition: utils.qh:13
void havocbot_role_ast_offense(entity this)
Definition: sv_assault.qc:459
int team
Definition: main.qh:157
void SetWinners(.float field, float value)
Definition: world.qc:1407
float TeamScore_AddToTeam(int t, float scorefield, float score)
Adds a score to the given team.
Definition: scores.qc:108
spawn_evalfunc_t spawn_evalfunc
Definition: spawnpoints.qh:28
void assault_roundstart_use(entity this, entity actor, entity trigger)
Definition: sv_assault.qc:152
const int ASSAULT_VALUE_INACTIVE
Definition: sv_assault.qh:6
entity() spawn
void assault_objective_decrease_use(entity this, entity actor, entity trigger)
Definition: sv_assault.qc:44
const int ST_ASSAULT_OBJECTIVES
Definition: sv_assault.qh:8
#define FOREACH_CLIENT(cond, body)
Definition: utils.qh:49
float radius
Definition: impulse.qh:11
entity ent_winning
Definition: sv_assault.qc:218
float checkpvs(vector viewpos, entity viewee)
void SUB_UseTargets(entity this, entity actor, entity trigger)
Definition: triggers.qc:366
bool warmup_stage
Definition: main.qh:103
#define AS_ROUND_DELAY
Definition: sv_assault.qc:12
float dmg
Definition: platforms.qh:6
ERASEABLE string process_time(float outputtype, int seconds)
Definition: counting.qh:120
entity as_round
Definition: sv_assault.qc:217
bool assault_decreaser_sprite_visible(entity this, entity player, entity view)
Definition: sv_assault.qc:98
spawnfunc(info_player_attacker)
Definition: sv_assault.qc:283
origin
Definition: ent_cs.qc:114
string classname
Definition: csprogsdefs.qc:107
void CheckRules_World()
Definition: world.qc:1593
void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org, float sradius)
Definition: roles.qc:176
float spawnflags
Definition: progsdefs.qc:191
entity owner
Definition: main.qh:73
string model
Definition: csprogsdefs.qc:108
IntrusiveList g_assault_objectives
Definition: sv_assault.qh:12
void target_objective_decrease_findtarget(entity this)
Definition: sv_assault.qc:135
void navigation_routerating(entity this, entity e, float f, float rangebias)
Definition: navigation.qc:1220
float havocbot_attack_time
Definition: sv_assault.qh:41
entity assault_decreaser
Definition: sv_assault.qh:33
const int WINNING_YES
Definition: world.qh:136
void TakeResource(entity receiver, Resource res_type, float amount)
Takes an entity some resource.
Definition: cl_resources.qc:31
IntrusiveList g_turrets
Definition: sv_turrets.qh:114
#define FOREACH_ENTITY_STRING(fld, match, body)
Definition: iter.qh:184
bool destructible_heal(entity targ, entity inflictor, float amount, float limit)
Definition: sv_assault.qc:328
void as_round_think()
Definition: sv_assault.qc:219
const int SPRITERULE_TEAMPLAY
RES_HEALTH
Definition: ent_cs.qc:126
const int HAVOCBOT_AST_ROLE_DEFENSE
Definition: sv_assault.qh:38
#define BIT(n)
Only ever assign into the first 24 bits in QC (so max is BIT(23)).
Definition: bits.qh:8
void assault_new_round(entity this)
Definition: sv_assault.qc:192
entity enemy
Definition: sv_ctf.qh:143
void assault_roundstart_use_this(entity this)
Definition: sv_assault.qc:169
float cnt
Definition: powerups.qc:24
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
void GiveResourceWithLimit(entity receiver, Resource res_type, float amount, float limit)
Gives an entity some resource but not more than a limit.
bool navigation_goalrating_timeout(entity this)
Definition: navigation.qc:43
vector target_objective_spawn_evalfunc(entity this, entity player, entity spot, vector current)
Definition: sv_assault.qc:28
const int RES_LIMIT_NONE
Definition: resources.qh:46
#define GameRules_scoring_add_team(client, fld, value)
Definition: sv_rules.qh:80
#define g_assault
Definition: assault.qh:27
void assault_objective_use(entity this, entity actor, entity trigger)
Definition: sv_assault.qc:15
void target_assault_roundend_reset(entity this)
Definition: sv_assault.qc:140
MUTATOR_HOOKFUNCTION(as, PlayerSpawn)
Definition: sv_assault.qc:556
void havocbot_ast_reset_role(entity this)
Definition: sv_assault.qc:544
#define NULL
Definition: post.qh:17
const int HAVOCBOT_AST_ROLE_OFFENSE
Definition: sv_assault.qh:39
entity assault_sprite
Definition: sv_assault.qh:34
float max_health
void havocbot_role_ast_setrole(entity this, float role)
Definition: sv_assault.qc:529
void assault_setenemytoobjective(entity this)
Definition: sv_assault.qc:83
#define M_ARGV(x, type)
Definition: events.qh:17
#define IS_DEAD(s)
Definition: utils.qh:26
float nextthink
Definition: csprogsdefs.qc:121
void navigation_goalrating_timeout_set(entity this)
Definition: navigation.qc:19
vector(float skel, float bonenum) _skel_get_boneabs_hidden
void assault_objective_reset(entity this)
Definition: sv_assault.qc:38
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
Definition: cl_resources.qc:10
const float SOLID_BSP
Definition: csprogsdefs.qc:248
void InitializeEntity(entity e, void(entity this) func, int order)
Definition: world.qc:2146
bool sv_ready_restart_after_countdown
Definition: world.qh:119
int WinningCondition_Assault()
Definition: sv_assault.qc:229
const int WINNING_NO
Definition: world.qh:135
string targetname
Definition: progsdefs.qc:194
IntrusiveList g_saved_team
Definition: vote.qh:77
const int WAYPOINTFLAG_GENERATED
Definition: api.qh:11
#define setthink(e, f)
IntrusiveList g_assault_destructibles
Definition: sv_assault.qh:10
const int NUM_TEAM_1
Definition: teams.qh:18
bool autocvar_g_campaign
Definition: campaign.qh:6
#define use
Definition: csprogsdefs.qh:50
best
Definition: all.qh:77
entity TeamBalance_CheckAllowedTeams(entity for_whom)
Checks whether the player can join teams according to global configuration and mutator settings...
Definition: teamplay.qc:487
string target
Definition: progsdefs.qc:193
void target_objective_decrease_activate(entity this)
Definition: sv_assault.qc:106
float time
Definition: csprogsdefs.qc:16
void assault_wall_think(entity this)
Definition: sv_assault.qc:174
#define Team_ColoredFullName(teamid)
Definition: teams.qh:230
void havocbot_role_ast_defense(entity this)
Definition: sv_assault.qc:494
float winning
Definition: world.qh:134
#define IS_PLAYER(v)
Definition: utils.qh:9
float assault_attacker_team
Definition: sv_assault.qh:52
IntrusiveList g_assault_objectivedecreasers
Definition: sv_assault.qh:11
const float FLOAT_MAX
Definition: float.qh:3
void WinningConditionHelper(entity this)
Sets the following results for the current scores entities.
Definition: scores.qc:415
float solid
Definition: csprogsdefs.qc:99