1 // ================================================================
2 // Official capture the flag game mode coding, reworked by Samual
3 // Last updated: March 27th, 2011
4 // ================================================================
7 #define FLAG_MIN (PL_MIN + '0 0 -13')
8 #define FLAG_MAX (PL_MAX + '0 0 -13')
9 #define FLAG_CARRY_POS '-15 0 7'
11 .entity bot_basewaypoint; // Flag waypointsprite
13 .entity wps_flagcarrier;
14 .entity wps_flagdropped;
16 entity ctf_worldflaglist; // CTF flags in the map
17 .entity ctf_worldflagnext;
19 .float ctf_dropperid; // Don't allow spam of dropping the flag
21 .float ctf_status; // status of the flag (FLAG_BASE, FLAG_DROPPED, FLAG_CARRY declared globally)
23 // Delay between when the person can pick up a flag // replace with .wait?
24 .float next_take_time;
26 // Record time for capturing the flag
27 float flagcaptimerecord;
28 .float flagpickuptime;
30 // CaptureShield: If the player is too bad to be allowed to capture, shield them from taking the flag.
31 .float ctf_captureshielded; // set to 1 if the player is too bad to be allowed to capture
32 float captureshield_min_negscore; // punish at -20 points
33 float captureshield_max_ratio; // punish at most 30% of each team
34 float captureshield_force; // push force of the shield
37 // declare functions so they can be used in any order in the file
38 void ctf_FlagTouch(void);
39 void ctf_FlagThink(void);
40 void ctf_SetupFlag(float, entity);
41 void ctf_RespawnFlag(entity);
42 float ctf_CaptureShield_CheckStatus(entity);
43 void ctf_CaptureShield_Update(entity, float);
44 float ctf_CaptureShield_Customize(void);
45 void ctf_CaptureShield_Touch(void);
46 void ctf_CaptureShield_Spawn(entity);
53 float ctf_ReadScore(string parameter) // make this obsolete
55 if(g_ctf_win_mode != 2)
56 return cvar(strcat("g_ctf_personal", parameter));
58 return cvar(strcat("g_ctf_flag", parameter));
61 void ctf_FakeTimeLimit(entity e, float t)
64 WriteByte(MSG_ONE, 3); // svc_updatestat
65 WriteByte(MSG_ONE, 236); // STAT_TIMELIMIT
67 WriteCoord(MSG_ONE, autocvar_timelimit);
69 WriteCoord(MSG_ONE, (t + 1) / 60);
72 void ctf_EventLog(string mode, float flagteam, entity actor)
75 if(!autocvar_sv_eventlog)
77 s = strcat(":ctf:", mode);
78 s = strcat(s, ":", ftos(flagteam));
80 s = strcat(s, ":", ftos(actor.playerid));
84 void ctf_CaptureShockwave(vector org)
86 shockwave_spawn("models/ctf/shockwavetransring.md3", org - '0 0 15', -0.8, 0, 1);
89 void ctf_CreateBaseWaypoints(entity flag, float teamnumber)
92 waypoint_spawnforitem_force(flag, flag.origin);
93 flag.nearestwaypointtimeout = 0; // activate waypointing again
94 flag.bot_basewaypoint = flag.nearestwaypoint;
97 WaypointSprite_SpawnFixed(((teamnumber) ? "redbase" : "bluebase"), flag.origin + '0 0 61', flag, wps_flagbase);
98 WaypointSprite_UpdateTeamRadar(flag.wps_flagbase, RADARICON_FLAG, colormapPaletteColor(((teamnumber) ? COLOR_TEAM1 : COLOR_TEAM2) - 1, FALSE));
101 void ctf_SetStatus_ForType(entity flag, float type)
103 if(flag.cnt == FLAG_CARRY)
105 if(flag.owner == self)
106 self.items |= type * 3; // carrying: self is currently carrying the flag
108 self.items |= type * 1; // taken: someone on self's team is carrying the flag
110 else if(flag.cnt == FLAG_DROPPED)
111 self.items |= type * 2; // lost: the flag is dropped somewhere on the map
114 void ctf_SetStatus() // re-write this in some less shitty way
117 float redflags, blueflags;
120 // initially clear items so they can be set as necessary later.
121 self.items &~= (IT_RED_FLAG_TAKEN | IT_RED_FLAG_LOST | IT_BLUE_FLAG_TAKEN | IT_BLUE_FLAG_LOST | IT_CTF_SHIELDED);
123 // item for stopping players from capturing the flag too often
124 if(self.ctf_captureshielded)
125 self.items |= IT_CTF_SHIELDED;
127 // figure out what flags we already own
128 for (flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext) if(flag.cnt != FLAG_BASE)
130 if(flag.items & IT_KEY2) // blue
132 else if(flag.items & IT_KEY1) // red
136 // blinking magic: if there is more than one flag, show one of these in a clever way // wtf?
138 redflags = mod(floor(time * redflags * 0.75), redflags);
141 blueflags = mod(floor(time * blueflags * 0.75), blueflags);
143 for (flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext) if(flag.cnt != FLAG_BASE)
145 if(flag.items & IT_KEY2) // blue
147 if(--redflags == -1) // happens exactly once (redflags is in 0..count-1, and will --'ed count times) // WHAT THE FUCK DOES THIS MEAN? whoever wrote this is shitty at explaining things.
148 ctf_SetStatus_ForType(flag, IT_RED_FLAG_TAKEN);
150 else if(flag.items & IT_KEY1) // red
152 if(--blueflags == -1) // happens exactly once
153 ctf_SetStatus_ForType(flag, IT_BLUE_FLAG_TAKEN);
160 ctf_Handle_Drop(self);
162 ctf_RespawnFlag(self);
170 void ctf_Handle_Drop(entity player) // make sure this works
172 entity flag = player.flagcarried;
174 if(!flag) { return; }
175 if(flag.speedrunning) { ctf_RespawnFlag(flag); return; }
178 setattachment(flag, world, "");
179 flag.owner.flagcarried = world;
181 flag.ctf_status = FLAG_DROPPED;
182 flag.movetype = MOVETYPE_TOSS;
183 flag.solid = SOLID_TRIGGER;
184 flag.takedamage = DAMAGE_YES;
185 flag.flags = FL_ITEM; // does this need set? same as above.
186 setorigin(flag, player.origin - '0 0 24' + '0 0 37'); // eh wtf is with these weird values?
187 flag.velocity = ('0 0 200' + ('0 100 0' * crandom()) + ('100 0 0' * crandom()));
188 flag.pain_finished = time + autocvar_g_ctf_flag_returntime;
190 flag.ctf_droptime = time;
191 flag.ctf_dropperid = player.playerid;
193 // messages and sounds
194 Send_KillNotification(player.netname, flag.netname, "", INFO_LOSTFLAG, MSG_INFO);
195 sound(flag, CHAN_TRIGGER, flag.noise4, VOL_BASE, ATTN_NONE);
196 ctf_EventLog("dropped", player.team, player);
199 PlayerScore_Add(player, SP_CTF_DROPS, 1);
200 UpdateFrags(player, -ctf_ReadScore("penalty_drop"));
203 WaypointSprite_Spawn("flagdropped", 0, 0, flag, '0 0 64', world, (COLOR_TEAM1 + COLOR_TEAM2 - flag.team), flag, wps_flagcarrier, FALSE);
204 WaypointSprite_Ping(player.wps_flagcarrier);
205 WaypointSprite_Kill(player.wps_flagcarrier);
207 ctf_CaptureShield_Update(player, 0); // shield only
210 trace_startsolid = FALSE;
211 tracebox(flag.origin, flag.mins, flag.maxs, flag.origin, TRUE, flag);
213 dprint("FLAG FALLTHROUGH will happen SOON\n");
218 void ctf_Handle_Capture(entity flag, entity player)
223 void ctf_Handle_Return(entity flag, entity player)
228 void ctf_Handle_Pickup_Base(entity flag, entity player)
233 void ctf_Handle_Pickup_Dropped(entity flag, entity player)
239 // ===================
240 // Main Flag Functions
241 // ===================
243 void ctf_SetupFlag(float teamnumber, entity flag) // called when spawning a flag entity on the map as a spawnfunc
246 teamnumber = fabs(teamnumber - bound(0, g_ctf_reverse, 1)); // if we were originally 1, this will become 0. If we were originally 0, this will become 1.
249 flag.ctf_worldflagnext = ctf_worldflaglist; // link flag into ctf_worldflaglist // todo: find out if this can be simplified
250 ctf_worldflaglist = flag;
252 setattachment(flag, world, "");
254 flag.netname = ((teamnumber) ? "^1RED^7 flag" : "^4BLUE^7 flag");
255 flag.team = ((teamnumber) ? COLOR_TEAM1 : COLOR_TEAM2); // COLOR_TEAM1: color 4 team (red) - COLOR_TEAM2: color 13 team (blue)
256 flag.items = ((teamnumber) ? IT_KEY2 : IT_KEY1); // IT_KEY2: gold key (redish enough) - IT_KEY1: silver key (bluish enough)
257 flag.classname = "item_flag_team";
258 flag.target = "###item###"; // wut?
259 flag.flags = FL_ITEM;
260 flag.solid = SOLID_TRIGGER;
261 flag.velocity = '0 0 0';
262 flag.ctf_status = FLAG_BASE;
263 flag.mangle = flag.angles;
264 flag.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
266 if(flag.spawnflags & 1) // I don't understand what all this is about.
269 flag.dropped_origin = flag.origin;
270 flag.movetype = MOVETYPE_NONE;
274 flag.noalign = FALSE;
276 flag.movetype = MOVETYPE_TOSS;
279 flag.reset = ctf_Reset;
280 flag.touch = ctf_FlagTouch;
281 flag.think = ctf_RespawnFlag;
282 flag.nextthink = time + 0.2; // start after doors etc // Samual: 0.2 though? Why?
285 if(!flag.model) { flag.model = ((teamnumber) ? autocvar_g_ctf_flag_red_model : autocvar_g_ctf_flag_blue_model); }
286 setmodel (flag, flag.model); // precision set below
287 setsize(flag, FLAG_MIN, FLAG_MAX);
288 setorigin(flag, flag.origin + '0 0 37');
289 flag.origin_z = flag.origin_z + 6; // why 6?
290 if(!flag.scale) { flag.scale = 0.6; }
292 flag.skin = ((teamnumber) ? autocvar_g_ctf_flag_red_skin : autocvar_g_ctf_flag_blue_skin);
294 if(autocvar_g_ctf_flag_glowtrails)
296 flag.glow_color = ((teamnumber) ? 251 : 210); // 251: red - 210: blue
301 flag.effects |= EF_LOWPRECISION;
302 if(autocvar_g_ctf_fullbrightflags) { flag.effects |= EF_FULLBRIGHT; }
303 if(autocvar_g_ctf_dynamiclights) { flag.effects |= ((teamnumber) ? EF_RED : EF_BLUE); }
306 if(!flag.noise) { flag.noise = ((teamnumber) ? "ctf/red_taken.wav" : "ctf/blue_taken.wav"); }
307 if(!flag.noise1) { flag.noise1 = ((teamnumber) ? "ctf/red_returned.wav" : "ctf/blue_returned.wav"); }
308 if(!flag.noise2) { flag.noise2 = ((teamnumber) ? "ctf/red_capture.wav" : "ctf/blue_capture.wav"); } // blue team scores by capturing the red flag
309 if(!flag.noise3) { flag.noise3 = "ctf/flag_respawn.wav"; } // if there is ever a team-based sound for this, update the code to match.
310 if(!flag.noise4) { flag.noise4 = ((teamnumber) ? "ctf/red_dropped.wav" : "ctf/blue_dropped.wav"); }
313 precache_sound(flag.noise);
314 precache_sound(flag.noise1);
315 precache_sound(flag.noise2);
316 precache_sound(flag.noise3);
317 precache_sound(flag.noise4);
318 precache_model(flag.model);
319 precache_model("models/ctf/shield.md3");
320 precache_model("models/ctf/shockwavetransring.md3");
322 // other initialization stuff
323 ctf_CreateBaseWaypoints(flag, teamnumber);
324 ctf_CaptureShield_Spawn(flag);
325 //InitializeEntity(self, ctf_CaptureShield_Spawn, INITPRIO_SETLOCATION);
328 void ctf_RespawnFlag(entity flag) // re-write this
330 if(flag.classname != "item_flag_team") { backtrace("ctf_RespawnFlag was called incorrectly."); return; }
333 if(flag.owner.flagcarried == flag)
335 WaypointSprite_DetachCarrier(flag.owner);
336 flag.owner.flagcarried = world;
338 if(flag.speedrunning)
339 ctf_FakeTimeLimit(flag.owner, -1);
343 if(flag.waypointsprite_attachedforcarrier)
344 WaypointSprite_DetachCarrier(flag);
346 setattachment(flag, world, "");
347 flag.damageforcescale = 0;
348 flag.takedamage = DAMAGE_NO;
349 flag.movetype = MOVETYPE_NONE;
351 flag.movetype = MOVETYPE_TOSS;
352 flag.velocity = '0 0 0';
353 flag.solid = SOLID_TRIGGER;
354 // TODO: play a sound here
355 setorigin(flag, flag.dropped_origin);
356 flag.angles = flag.mangle;
357 flag.ctf_status = FLAG_BASE;
359 flag.flags = FL_ITEM; // clear FL_ONGROUND and any other junk // there shouldn't be any "junk" set on this... look into it and make sure it's kept clean.
362 void ctf_FlagThink() // re-write this
366 self.nextthink = time + 0.1;
368 // sorry, we have to reset the flag size if it got squished by something
369 if(self.mins != FLAG_MIN || self.maxs != FLAG_MAX)
371 // if we can grow back, grow back
372 tracebox(self.origin, FLAG_MIN, FLAG_MAX, self.origin, MOVE_NOMONSTERS, self);
373 if(!trace_startsolid)
374 setsize(self, FLAG_MIN, FLAG_MAX);
377 if(self == ctf_worldflaglist) // only for the first flag
380 ctf_CaptureShield_Update(e, 1); // release shield only
383 if(self.speedrunning)
384 if(self.cnt == FLAG_CARRY)
387 if(flagcaptimerecord)
388 if(time >= self.flagpickuptime + flagcaptimerecord)
390 bprint("The ", self.netname, " became impatient after ", ftos_decimals(flagcaptimerecord, 2), " seconds and returned itself\n");
392 sound (self, CHAN_TRIGGER, self.noise3, VOL_BASE, ATTN_NONE);
393 self.owner.impulse = 141; // returning!
404 if(self.cnt == FLAG_BASE)
407 if(self.cnt == FLAG_DROPPED)
409 // flag fallthrough? FIXME remove this if bug is really fixed now
410 if(self.origin_z < -131072)
412 dprint("FLAG FALLTHROUGH just happened\n");
413 self.pain_finished = 0;
415 setattachment(self, world, "");
416 if(time > self.pain_finished)
418 bprint("The ", self.netname, " has returned to base\n");
419 sound (self, CHAN_TRIGGER, self.noise3, VOL_BASE, ATTN_NONE);
420 ctf_EventLog("returned", self.team, world);
421 ctf_RespawnFlag(self);
427 if(e.classname != "player" || (e.deadflag) || (e.flagcarried != self))
429 dprint("CANNOT HAPPEN - player dead and STILL had a flag!\n");
434 if(autocvar_g_ctf_allow_drop)
436 ctf_Handle_Drop(self);
441 if(gameover) { return; }
442 if(!self) { return; }
443 if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
444 { // The ball fell off the map, respawn it since players can't get to it
445 ctf_RespawnFlag(self);
448 if(other.deadflag != DEAD_NO) { return; }
449 if(other.classname != "player")
450 { // the flag just touched an object, most likely the world
451 pointparticles(particleeffectnum("kaball_sparks"), self.origin, '0 0 0', 1);
452 sound(self, CHAN_AUTO, "keepaway/touch.wav", VOL_BASE, ATTN_NORM);
455 else if(self.wait > time) { return; }
457 switch(self.ctf_status)
460 if((other.team == self.team) && (other.flagcarried) && (other.flagcarried.team != self.team))
461 ctf_Handle_Capture(self, other); // other just captured the enemies flag to his base
462 else if((other.team != self.team) && (!other.flagcarried) && (!other.ctf_captureshielded))
463 ctf_Handle_Pickup_Base(self, other); // other just stole the enemies flag
467 if(other.team == self.team)
468 ctf_Handle_Return(self, other); // other just returned his own flag
469 else if((!other.flagcarried) && ((other.playerid != self.ctf_dropperid) || (time > self.ctf_droptime + autocvar_g_balance_ctf_delay_collect)))
470 ctf_Handle_Pickup_Dropped(self, other); // other just picked up a dropped enemy flag
475 dprint("Someone touched a flag even though it was being carried? wtf?\n");
476 break; // this should never happen
481 // =======================
482 // CaptureShield Functions
483 // =======================
485 float ctf_CaptureShield_CheckStatus(entity p) // check to see
489 float players_worseeq, players_total;
491 if(captureshield_max_ratio <= 0)
494 s = PlayerScore_Add(p, SP_SCORE, 0);
495 if(s >= -captureshield_min_negscore)
498 players_total = players_worseeq = 0;
503 se = PlayerScore_Add(e, SP_SCORE, 0);
509 // player is in the worse half, if >= half the players are better than him, or consequently, if < half of the players are worse
510 // use this rule here
512 if(players_worseeq >= players_total * captureshield_max_ratio)
518 void ctf_CaptureShield_Update(entity p, float dir)
521 if(dir == p.ctf_captureshielded) // 0: shield only, 1: unshield only
523 should = ctf_CaptureShield_CheckStatus(p);
526 if(should) // TODO csqc notifier for this
527 centerprint_atprio(p, CENTERPRIO_SHIELDING, "^3You are now ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Make some defensive scores before trying again.");
529 centerprint_atprio(p, CENTERPRIO_SHIELDING, "^3You are now free.\n\n^3Feel free to ^1try to capture^3 the flag again\n^3if you think you will succeed.");
531 p.ctf_captureshielded = should;
536 float ctf_CaptureShield_Customize()
538 if not(other.ctf_captureshielded)
540 if(self.team == other.team)
545 void ctf_CaptureShield_Touch()
547 if not(other.ctf_captureshielded)
549 if(self.team == other.team)
553 mymid = (self.absmin + self.absmax) * 0.5;
554 othermid = (other.absmin + other.absmax) * 0.5;
555 Damage(other, self, self, 0, DEATH_HURTTRIGGER, mymid, normalize(othermid - mymid) * captureshield_force);
556 centerprint_atprio(other, CENTERPRIO_SHIELDING, "^3You are ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Get some defensive scores before trying again.");
559 void ctf_CaptureShield_Spawn(entity flag)
565 e.touch = ctf_CaptureShield_Touch;
566 e.customizeentityforclient = ctf_CaptureShield_Customize;
567 e.classname = "ctf_captureshield";
568 e.effects = EF_ADDITIVE;
569 e.movetype = MOVETYPE_NOCLIP;
570 e.solid = SOLID_TRIGGER;
571 e.avelocity = '7 0 11';
572 setorigin(e, self.origin);
573 setmodel(e, "models/ctf/shield.md3");
575 setsize(e, e.scale * e.mins, e.scale * e.maxs);
583 MUTATOR_HOOKFUNCTION(ctf_RemovePlayer)
585 if(self.flagcarried) { ctf_Handle_Drop(self); } // figure this out
595 /*QUAKED spawnfunc_info_player_team1 (1 0 0) (-16 -16 -24) (16 16 24)
596 CTF Starting point for a player in team one (Red).
597 Keys: "angle" viewing angle when spawning. */
598 void spawnfunc_info_player_team1()
600 if(g_assault) { remove(self); return; }
602 self.team = COLOR_TEAM1; // red
603 spawnfunc_info_player_deathmatch();
607 /*QUAKED spawnfunc_info_player_team2 (1 0 0) (-16 -16 -24) (16 16 24)
608 CTF Starting point for a player in team two (Blue).
609 Keys: "angle" viewing angle when spawning. */
610 void spawnfunc_info_player_team2()
612 if(g_assault) { remove(self); return; }
614 self.team = COLOR_TEAM2; // blue
615 spawnfunc_info_player_deathmatch();
618 /*QUAKED spawnfunc_info_player_team3 (1 0 0) (-16 -16 -24) (16 16 24)
619 CTF Starting point for a player in team three (Yellow).
620 Keys: "angle" viewing angle when spawning. */
621 void spawnfunc_info_player_team3()
623 if(g_assault) { remove(self); return; }
625 self.team = COLOR_TEAM3; // yellow
626 spawnfunc_info_player_deathmatch();
630 /*QUAKED spawnfunc_info_player_team4 (1 0 0) (-16 -16 -24) (16 16 24)
631 CTF Starting point for a player in team four (Purple).
632 Keys: "angle" viewing angle when spawning. */
633 void spawnfunc_info_player_team4()
635 if(g_assault) { remove(self); return; }
637 self.team = COLOR_TEAM4; // purple
638 spawnfunc_info_player_deathmatch();
641 /*QUAKED spawnfunc_item_flag_team1 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
642 CTF flag for team one (Red). Multiple flags are allowed.
644 "angle" Angle the flag will point (minus 90 degrees)...
645 "model" model to use, note this needs red and blue as skins 0 and 1 (default models/ctf/flag.md3)...
646 "noise" sound played when flag is picked up (default ctf/take.wav)...
647 "noise1" sound played when flag is returned by a teammate (default ctf/return.wav)...
648 "noise2" sound played when flag is captured (default ctf/redcapture.wav)...
649 "noise3" sound played when flag is lost in the field and respawns itself (default ctf/respawn.wav)... */
650 void spawnfunc_item_flag_team1()
652 if(!g_ctf) { remove(self); return; }
654 ctf_SetupFlag(1, self);
657 /*QUAKED spawnfunc_item_flag_team2 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
658 CTF flag for team two (Blue). Multiple flags are allowed.
660 "angle" Angle the flag will point (minus 90 degrees)...
661 "model" model to use, note this needs red and blue as skins 0 and 1 (default models/ctf/flag.md3)...
662 "noise" sound played when flag is picked up (default ctf/take.wav)...
663 "noise1" sound played when flag is returned by a teammate (default ctf/return.wav)...
664 "noise2" sound played when flag is captured (default ctf/redcapture.wav)...
665 "noise3" sound played when flag is lost in the field and respawns itself (default ctf/respawn.wav)... */
666 void spawnfunc_item_flag_team2()
668 if(!g_ctf) { remove(self); return; }
670 ctf_SetupFlag(0, self);
673 /*QUAKED spawnfunc_ctf_team (0 .5 .8) (-16 -16 -24) (16 16 32)
674 Team declaration for CTF gameplay, this allows you to decide what team names and control point models are used in your map.
675 Note: If you use spawnfunc_ctf_team entities you must define at least 2! However, unlike domination, you don't need to make a blank one too.
677 "netname" Name of the team (for example Red, Blue, Green, Yellow, Life, Death, Offense, Defense, etc)...
678 "cnt" Scoreboard color of the team (for example 4 is red and 13 is blue)... */
679 void spawnfunc_ctf_team()
681 if(!g_ctf) { remove(self); return; }
683 self.classname = "ctf_team";
684 self.team = self.cnt + 1;
692 // code from here on is just to support maps that don't have flag and team entities
693 void ctf_SpawnTeam (string teamname, float teamcolor)
695 local entity oldself;
698 self.classname = "ctf_team";
699 self.netname = teamname;
700 self.cnt = teamcolor;
702 spawnfunc_ctf_team();
707 void ctf_DelayedInit()
709 // if no teams are found, spawn defaults
710 if(find(world, classname, "ctf_team") == world)
712 ctf_SpawnTeam("Red", COLOR_TEAM1 - 1);
713 ctf_SpawnTeam("Blue", COLOR_TEAM2 - 1);
717 void ctf_Initialize()
719 flagcaptimerecord = stof(db_get(ServerProgsDB, strcat(GetMapname(), "/captimerecord/time")));
721 captureshield_min_negscore = autocvar_g_ctf_shield_min_negscore;
722 captureshield_max_ratio = autocvar_g_ctf_shield_max_ratio;
723 captureshield_force = autocvar_g_ctf_shield_force;
725 g_ctf_win_mode = cvar("g_ctf_win_mode");
729 InitializeEntity(world, ctf_DelayedInit, INITPRIO_GAMETYPE);
733 MUTATOR_DEFINITION(gamemode_ctf)
735 MUTATOR_HOOK(MakePlayerObserver, ctf_RemovePlayer, CBC_ORDER_ANY);
736 MUTATOR_HOOK(ClientDisconnect, ctf_RemovePlayer, CBC_ORDER_ANY);
737 MUTATOR_HOOK(PlayerDies, ctf_RemovePlayer, CBC_ORDER_ANY);
738 //MUTATOR_HOOK(GiveFragsForKill, ctf_GiveFragsForKill, CBC_ORDER_ANY);
739 //MUTATOR_HOOK(PlayerPreThink, ctf_PlayerPreThink, CBC_ORDER_ANY);
740 //MUTATOR_HOOK(PlayerDamage_Calculate, ctf_PlayerDamage, CBC_ORDER_ANY);
741 //MUTATOR_HOOK(PlayerPowerups, ctf_PlayerPowerups, CBC_ORDER_ANY);
745 if(time > 1) // game loads at time 1
746 error("This is a game type and it cannot be added at runtime.");
754 error("This is a game type and it cannot be removed at runtime.");