1 // ================================================================
2 // Official capture the flag game mode coding, reworked by Samual
3 // Last updated: March 28th, 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
36 // declare functions so they can be used in any order in the file
37 void ctf_FlagTouch(void);
38 void ctf_FlagThink(void);
39 void ctf_SetupFlag(float, entity);
40 void ctf_RespawnFlag(entity);
41 float ctf_CaptureShield_CheckStatus(entity);
42 void ctf_CaptureShield_Update(entity, float);
43 float ctf_CaptureShield_Customize(void);
44 void ctf_CaptureShield_Touch(void);
45 void ctf_CaptureShield_Spawn(entity);
52 float ctf_ReadScore(string parameter) // make this obsolete
54 if(g_ctf_win_mode != 2)
55 return cvar(strcat("g_ctf_personal", parameter));
57 return cvar(strcat("g_ctf_flag", parameter));
60 void ctf_FakeTimeLimit(entity e, float t)
63 WriteByte(MSG_ONE, 3); // svc_updatestat
64 WriteByte(MSG_ONE, 236); // STAT_TIMELIMIT
66 WriteCoord(MSG_ONE, autocvar_timelimit);
68 WriteCoord(MSG_ONE, (t + 1) / 60);
71 void ctf_EventLog(string mode, float flagteam, entity actor)
74 if(!autocvar_sv_eventlog)
76 s = strcat(":ctf:", mode);
77 s = strcat(s, ":", ftos(flagteam));
79 s = strcat(s, ":", ftos(actor.playerid));
83 void ctf_CaptureShockwave(vector org)
85 shockwave_spawn("models/ctf/shockwavetransring.md3", org - '0 0 15', -0.8, 0, 1);
88 void ctf_CreateBaseWaypoints(entity flag, float teamnumber)
91 waypoint_spawnforitem_force(flag, flag.origin);
92 flag.nearestwaypointtimeout = 0; // activate waypointing again
93 flag.bot_basewaypoint = flag.nearestwaypoint;
96 WaypointSprite_SpawnFixed(((teamnumber) ? "redbase" : "bluebase"), flag.origin + '0 0 61', flag, wps_flagbase);
97 WaypointSprite_UpdateTeamRadar(flag.wps_flagbase, RADARICON_FLAG, colormapPaletteColor(((teamnumber) ? COLOR_TEAM1 : COLOR_TEAM2) - 1, FALSE));
100 void ctf_SetStatus_ForType(entity flag, float type)
102 if(flag.cnt == FLAG_CARRY)
104 if(flag.owner == self)
105 self.items |= type * 3; // carrying: self is currently carrying the flag
107 self.items |= type * 1; // taken: someone on self's team is carrying the flag
109 else if(flag.cnt == FLAG_DROPPED)
110 self.items |= type * 2; // lost: the flag is dropped somewhere on the map
113 void ctf_SetStatus() // re-write this in some less shitty way
116 float redflags, blueflags;
119 // initially clear items so they can be set as necessary later.
120 self.items &~= (IT_RED_FLAG_TAKEN | IT_RED_FLAG_LOST | IT_BLUE_FLAG_TAKEN | IT_BLUE_FLAG_LOST | IT_CTF_SHIELDED);
122 // item for stopping players from capturing the flag too often
123 if(self.ctf_captureshielded)
124 self.items |= IT_CTF_SHIELDED;
126 // figure out what flags we already own
127 for (flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext) if(flag.cnt != FLAG_BASE)
129 if(flag.items & IT_KEY2) // blue
131 else if(flag.items & IT_KEY1) // red
135 // blinking magic: if there is more than one flag, show one of these in a clever way // wtf?
137 redflags = mod(floor(time * redflags * 0.75), redflags);
140 blueflags = mod(floor(time * blueflags * 0.75), blueflags);
142 for (flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext) if(flag.cnt != FLAG_BASE)
144 if(flag.items & IT_KEY2) // blue
146 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.
147 ctf_SetStatus_ForType(flag, IT_RED_FLAG_TAKEN);
149 else if(flag.items & IT_KEY1) // red
151 if(--blueflags == -1) // happens exactly once
152 ctf_SetStatus_ForType(flag, IT_BLUE_FLAG_TAKEN);
159 ctf_Handle_Drop(self);
160 ctf_RespawnFlag(self);
168 void ctf_Handle_Drop(entity player) // make sure this works
170 entity flag = player.flagcarried;
172 if(!flag) { return; }
173 if(flag.speedrunning) { ctf_RespawnFlag(flag); return; }
176 setattachment(flag, world, "");
177 flag.owner.flagcarried = world;
179 flag.ctf_status = FLAG_DROPPED;
180 flag.movetype = MOVETYPE_TOSS;
181 flag.solid = SOLID_TRIGGER;
182 flag.takedamage = DAMAGE_YES;
183 flag.flags = FL_ITEM; // does this need set? same as above.
184 setorigin(flag, player.origin - '0 0 24' + '0 0 37'); // eh wtf is with these weird values?
185 flag.velocity = ('0 0 200' + ('0 100 0' * crandom()) + ('100 0 0' * crandom()));
186 flag.pain_finished = time + autocvar_g_ctf_flag_returntime;
188 flag.ctf_droptime = time;
189 flag.ctf_dropperid = player.playerid;
191 // messages and sounds
192 Send_KillNotification(player.netname, flag.netname, "", INFO_LOSTFLAG, MSG_INFO);
193 sound(flag, CHAN_TRIGGER, flag.noise4, VOL_BASE, ATTN_NONE);
194 ctf_EventLog("dropped", player.team, player);
197 PlayerScore_Add(player, SP_CTF_DROPS, 1);
198 UpdateFrags(player, -ctf_ReadScore("penalty_drop"));
201 WaypointSprite_Spawn("flagdropped", 0, 0, flag, '0 0 64', world, (COLOR_TEAM1 + COLOR_TEAM2 - flag.team), flag, wps_flagcarrier, FALSE);
202 WaypointSprite_Ping(player.wps_flagcarrier);
203 WaypointSprite_Kill(player.wps_flagcarrier);
205 ctf_CaptureShield_Update(player, 0); // shield only
208 trace_startsolid = FALSE;
209 tracebox(flag.origin, flag.mins, flag.maxs, flag.origin, TRUE, flag);
211 dprint("FLAG FALLTHROUGH will happen SOON\n");
216 void ctf_Handle_Capture(entity flag, entity player)
221 void ctf_Handle_Return(entity flag, entity player)
226 void ctf_Handle_Pickup_Base(entity flag, entity player)
231 void ctf_Handle_Pickup_Dropped(entity flag, entity player)
237 // ===================
238 // Main Flag Functions
239 // ===================
241 void ctf_SetupFlag(float teamnumber, entity flag) // called when spawning a flag entity on the map as a spawnfunc
244 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.
247 flag.ctf_worldflagnext = ctf_worldflaglist; // link flag into ctf_worldflaglist // todo: find out if this can be simplified
248 ctf_worldflaglist = flag;
250 setattachment(flag, world, "");
252 flag.netname = ((teamnumber) ? "^1RED^7 flag" : "^4BLUE^7 flag");
253 flag.team = ((teamnumber) ? COLOR_TEAM1 : COLOR_TEAM2); // COLOR_TEAM1: color 4 team (red) - COLOR_TEAM2: color 13 team (blue)
254 flag.items = ((teamnumber) ? IT_KEY2 : IT_KEY1); // IT_KEY2: gold key (redish enough) - IT_KEY1: silver key (bluish enough)
255 flag.classname = "item_flag_team";
256 flag.target = "###item###"; // wut?
257 flag.flags = FL_ITEM;
258 flag.solid = SOLID_TRIGGER;
259 flag.velocity = '0 0 0';
260 flag.ctf_status = FLAG_BASE;
261 flag.mangle = flag.angles;
262 flag.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
264 if(flag.spawnflags & 1) // I don't understand what all this is about.
267 flag.dropped_origin = flag.origin;
268 flag.movetype = MOVETYPE_NONE;
272 flag.noalign = FALSE;
274 flag.movetype = MOVETYPE_TOSS;
277 flag.reset = ctf_Reset;
278 flag.touch = ctf_FlagTouch;
279 flag.think = ctf_RespawnFlag;
280 flag.nextthink = time + 0.2; // start after doors etc // Samual: 0.2 though? Why?
283 if(!flag.model) { flag.model = ((teamnumber) ? autocvar_g_ctf_flag_red_model : autocvar_g_ctf_flag_blue_model); }
284 setmodel (flag, flag.model); // precision set below
285 setsize(flag, FLAG_MIN, FLAG_MAX);
286 setorigin(flag, flag.origin + '0 0 37');
287 flag.origin_z = flag.origin_z + 6; // why 6?
288 if(!flag.scale) { flag.scale = 0.6; }
290 flag.skin = ((teamnumber) ? autocvar_g_ctf_flag_red_skin : autocvar_g_ctf_flag_blue_skin);
292 if(autocvar_g_ctf_flag_glowtrails)
294 flag.glow_color = ((teamnumber) ? 251 : 210); // 251: red - 210: blue
299 flag.effects |= EF_LOWPRECISION;
300 if(autocvar_g_ctf_fullbrightflags) { flag.effects |= EF_FULLBRIGHT; }
301 if(autocvar_g_ctf_dynamiclights) { flag.effects |= ((teamnumber) ? EF_RED : EF_BLUE); }
304 if(!flag.noise) { flag.noise = ((teamnumber) ? "ctf/red_taken.wav" : "ctf/blue_taken.wav"); }
305 if(!flag.noise1) { flag.noise1 = ((teamnumber) ? "ctf/red_returned.wav" : "ctf/blue_returned.wav"); }
306 if(!flag.noise2) { flag.noise2 = ((teamnumber) ? "ctf/red_capture.wav" : "ctf/blue_capture.wav"); } // blue team scores by capturing the red flag
307 if(!flag.noise3) { flag.noise3 = "ctf/flag_respawn.wav"; } // if there is ever a team-based sound for this, update the code to match.
308 if(!flag.noise4) { flag.noise4 = ((teamnumber) ? "ctf/red_dropped.wav" : "ctf/blue_dropped.wav"); }
311 precache_sound(flag.noise);
312 precache_sound(flag.noise1);
313 precache_sound(flag.noise2);
314 precache_sound(flag.noise3);
315 precache_sound(flag.noise4);
316 precache_model(flag.model);
317 precache_model("models/ctf/shield.md3");
318 precache_model("models/ctf/shockwavetransring.md3");
320 // other initialization stuff
321 ctf_CreateBaseWaypoints(flag, teamnumber);
322 ctf_CaptureShield_Spawn(flag);
323 //InitializeEntity(self, ctf_CaptureShield_Spawn, INITPRIO_SETLOCATION);
326 void ctf_RespawnFlag(entity flag) // re-write this
328 if(flag.classname != "item_flag_team") { backtrace("ctf_RespawnFlag was called incorrectly."); return; }
331 if(flag.owner.flagcarried == flag)
333 WaypointSprite_DetachCarrier(flag.owner);
334 flag.owner.flagcarried = world;
336 if(flag.speedrunning)
337 ctf_FakeTimeLimit(flag.owner, -1);
341 if(flag.waypointsprite_attachedforcarrier)
342 WaypointSprite_DetachCarrier(flag);
344 setattachment(flag, world, "");
345 flag.damageforcescale = 0;
346 flag.takedamage = DAMAGE_NO;
347 flag.movetype = MOVETYPE_NONE;
349 flag.movetype = MOVETYPE_TOSS;
350 flag.velocity = '0 0 0';
351 flag.solid = SOLID_TRIGGER;
352 // TODO: play a sound here
353 setorigin(flag, flag.dropped_origin);
354 flag.angles = flag.mangle;
355 flag.ctf_status = FLAG_BASE;
357 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.
360 void ctf_FlagThink() // re-write this
364 self.nextthink = time + 0.1;
366 // sorry, we have to reset the flag size if it got squished by something
367 if(self.mins != FLAG_MIN || self.maxs != FLAG_MAX)
369 // if we can grow back, grow back
370 tracebox(self.origin, FLAG_MIN, FLAG_MAX, self.origin, MOVE_NOMONSTERS, self);
371 if(!trace_startsolid)
372 setsize(self, FLAG_MIN, FLAG_MAX);
375 if(self == ctf_worldflaglist) // only for the first flag
378 ctf_CaptureShield_Update(e, 1); // release shield only
381 if(self.speedrunning)
382 if(self.cnt == FLAG_CARRY)
385 if(flagcaptimerecord)
386 if(time >= self.flagpickuptime + flagcaptimerecord)
388 bprint("The ", self.netname, " became impatient after ", ftos_decimals(flagcaptimerecord, 2), " seconds and returned itself\n");
390 sound (self, CHAN_TRIGGER, self.noise3, VOL_BASE, ATTN_NONE);
391 self.owner.impulse = 141; // returning!
402 if(self.cnt == FLAG_BASE)
405 if(self.cnt == FLAG_DROPPED)
407 // flag fallthrough? FIXME remove this if bug is really fixed now
408 if(self.origin_z < -131072)
410 dprint("FLAG FALLTHROUGH just happened\n");
411 self.pain_finished = 0;
413 setattachment(self, world, "");
414 if(time > self.pain_finished)
416 bprint("The ", self.netname, " has returned to base\n");
417 sound (self, CHAN_TRIGGER, self.noise3, VOL_BASE, ATTN_NONE);
418 ctf_EventLog("returned", self.team, world);
419 ctf_RespawnFlag(self);
425 if(e.classname != "player" || (e.deadflag) || (e.flagcarried != self))
427 dprint("CANNOT HAPPEN - player dead and STILL had a flag!\n");
432 if(autocvar_g_ctf_allow_drop)
434 ctf_Handle_Drop(self);
439 if(gameover) { return; }
440 if(!self) { return; }
441 if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
442 { // The flag fell off the map, respawn it since players can't get to it
443 ctf_RespawnFlag(self);
446 if(other.deadflag != DEAD_NO) { return; }
447 if(other.classname != "player")
448 { // The flag just touched an object, most likely the world
449 pointparticles(particleeffectnum("kaball_sparks"), self.origin, '0 0 0', 1);
450 sound(self, CHAN_AUTO, "keepaway/touch.wav", VOL_BASE, ATTN_NORM);
453 else if(self.wait > time) { return; }
455 switch(self.ctf_status)
458 if((other.team == self.team) && (other.flagcarried) && (other.flagcarried.team != self.team))
459 ctf_Handle_Capture(self, other); // other just captured the enemies flag to his base
460 else if((other.team != self.team) && (!other.flagcarried) && (!other.ctf_captureshielded))
461 ctf_Handle_Pickup_Base(self, other); // other just stole the enemies flag
465 if(other.team == self.team)
466 ctf_Handle_Return(self, other); // other just returned his own flag
467 else if((!other.flagcarried) && ((other.playerid != self.ctf_dropperid) || (time > self.ctf_droptime + autocvar_g_balance_ctf_delay_collect)))
468 ctf_Handle_Pickup_Dropped(self, other); // other just picked up a dropped enemy flag
473 dprint("Someone touched a flag even though it was being carried? wtf?\n");
474 break; // this should never happen
479 // =======================
480 // CaptureShield Functions
481 // =======================
483 float ctf_CaptureShield_CheckStatus(entity p) // check to see
487 float players_worseeq, players_total;
489 if(captureshield_max_ratio <= 0)
492 s = PlayerScore_Add(p, SP_SCORE, 0);
493 if(s >= -captureshield_min_negscore)
496 players_total = players_worseeq = 0;
501 se = PlayerScore_Add(e, SP_SCORE, 0);
507 // player is in the worse half, if >= half the players are better than him, or consequently, if < half of the players are worse
508 // use this rule here
510 if(players_worseeq >= players_total * captureshield_max_ratio)
516 void ctf_CaptureShield_Update(entity p, float dir)
519 if(dir == p.ctf_captureshielded) // 0: shield only, 1: unshield only
521 should = ctf_CaptureShield_CheckStatus(p);
524 if(should) // TODO csqc notifier for this
525 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.");
527 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.");
529 p.ctf_captureshielded = should;
534 float ctf_CaptureShield_Customize()
536 if not(other.ctf_captureshielded)
538 if(self.team == other.team)
543 void ctf_CaptureShield_Touch()
545 if not(other.ctf_captureshielded)
547 if(self.team == other.team)
551 mymid = (self.absmin + self.absmax) * 0.5;
552 othermid = (other.absmin + other.absmax) * 0.5;
553 Damage(other, self, self, 0, DEATH_HURTTRIGGER, mymid, normalize(othermid - mymid) * captureshield_force);
554 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.");
557 void ctf_CaptureShield_Spawn(entity flag)
563 e.touch = ctf_CaptureShield_Touch;
564 e.customizeentityforclient = ctf_CaptureShield_Customize;
565 e.classname = "ctf_captureshield";
566 e.effects = EF_ADDITIVE;
567 e.movetype = MOVETYPE_NOCLIP;
568 e.solid = SOLID_TRIGGER;
569 e.avelocity = '7 0 11';
570 setorigin(e, self.origin);
571 setmodel(e, "models/ctf/shield.md3");
573 setsize(e, e.scale * e.mins, e.scale * e.maxs);
581 MUTATOR_HOOKFUNCTION(ctf_RemovePlayer)
583 if(self.flagcarried) { ctf_Handle_Drop(self); } // figure this out
593 /*QUAKED spawnfunc_info_player_team1 (1 0 0) (-16 -16 -24) (16 16 24)
594 CTF Starting point for a player in team one (Red).
595 Keys: "angle" viewing angle when spawning. */
596 void spawnfunc_info_player_team1()
598 if(g_assault) { remove(self); return; }
600 self.team = COLOR_TEAM1; // red
601 spawnfunc_info_player_deathmatch();
605 /*QUAKED spawnfunc_info_player_team2 (1 0 0) (-16 -16 -24) (16 16 24)
606 CTF Starting point for a player in team two (Blue).
607 Keys: "angle" viewing angle when spawning. */
608 void spawnfunc_info_player_team2()
610 if(g_assault) { remove(self); return; }
612 self.team = COLOR_TEAM2; // blue
613 spawnfunc_info_player_deathmatch();
616 /*QUAKED spawnfunc_info_player_team3 (1 0 0) (-16 -16 -24) (16 16 24)
617 CTF Starting point for a player in team three (Yellow).
618 Keys: "angle" viewing angle when spawning. */
619 void spawnfunc_info_player_team3()
621 if(g_assault) { remove(self); return; }
623 self.team = COLOR_TEAM3; // yellow
624 spawnfunc_info_player_deathmatch();
628 /*QUAKED spawnfunc_info_player_team4 (1 0 0) (-16 -16 -24) (16 16 24)
629 CTF Starting point for a player in team four (Purple).
630 Keys: "angle" viewing angle when spawning. */
631 void spawnfunc_info_player_team4()
633 if(g_assault) { remove(self); return; }
635 self.team = COLOR_TEAM4; // purple
636 spawnfunc_info_player_deathmatch();
639 /*QUAKED spawnfunc_item_flag_team1 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
640 CTF flag for team one (Red). Multiple flags are allowed.
642 "angle" Angle the flag will point (minus 90 degrees)...
643 "model" model to use, note this needs red and blue as skins 0 and 1 (default models/ctf/flag.md3)...
644 "noise" sound played when flag is picked up (default ctf/take.wav)...
645 "noise1" sound played when flag is returned by a teammate (default ctf/return.wav)...
646 "noise2" sound played when flag is captured (default ctf/redcapture.wav)...
647 "noise3" sound played when flag is lost in the field and respawns itself (default ctf/respawn.wav)... */
648 void spawnfunc_item_flag_team1()
650 if(!g_ctf) { remove(self); return; }
652 ctf_SetupFlag(1, self);
655 /*QUAKED spawnfunc_item_flag_team2 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
656 CTF flag for team two (Blue). Multiple flags are allowed.
658 "angle" Angle the flag will point (minus 90 degrees)...
659 "model" model to use, note this needs red and blue as skins 0 and 1 (default models/ctf/flag.md3)...
660 "noise" sound played when flag is picked up (default ctf/take.wav)...
661 "noise1" sound played when flag is returned by a teammate (default ctf/return.wav)...
662 "noise2" sound played when flag is captured (default ctf/redcapture.wav)...
663 "noise3" sound played when flag is lost in the field and respawns itself (default ctf/respawn.wav)... */
664 void spawnfunc_item_flag_team2()
666 if(!g_ctf) { remove(self); return; }
668 ctf_SetupFlag(0, self);
671 /*QUAKED spawnfunc_ctf_team (0 .5 .8) (-16 -16 -24) (16 16 32)
672 Team declaration for CTF gameplay, this allows you to decide what team names and control point models are used in your map.
673 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.
675 "netname" Name of the team (for example Red, Blue, Green, Yellow, Life, Death, Offense, Defense, etc)...
676 "cnt" Scoreboard color of the team (for example 4 is red and 13 is blue)... */
677 void spawnfunc_ctf_team()
679 if(!g_ctf) { remove(self); return; }
681 self.classname = "ctf_team";
682 self.team = self.cnt + 1;
690 // code from here on is just to support maps that don't have flag and team entities
691 void ctf_SpawnTeam (string teamname, float teamcolor)
693 local entity oldself;
696 self.classname = "ctf_team";
697 self.netname = teamname;
698 self.cnt = teamcolor;
700 spawnfunc_ctf_team();
705 void ctf_DelayedInit()
707 // if no teams are found, spawn defaults
708 if(find(world, classname, "ctf_team") == world)
710 ctf_SpawnTeam("Red", COLOR_TEAM1 - 1);
711 ctf_SpawnTeam("Blue", COLOR_TEAM2 - 1);
715 void ctf_Initialize()
717 flagcaptimerecord = stof(db_get(ServerProgsDB, strcat(GetMapname(), "/captimerecord/time")));
719 captureshield_min_negscore = autocvar_g_ctf_shield_min_negscore;
720 captureshield_max_ratio = autocvar_g_ctf_shield_max_ratio;
721 captureshield_force = autocvar_g_ctf_shield_force;
723 g_ctf_win_mode = cvar("g_ctf_win_mode");
727 InitializeEntity(world, ctf_DelayedInit, INITPRIO_GAMETYPE);
731 MUTATOR_DEFINITION(gamemode_ctf)
733 MUTATOR_HOOK(MakePlayerObserver, ctf_RemovePlayer, CBC_ORDER_ANY);
734 MUTATOR_HOOK(ClientDisconnect, ctf_RemovePlayer, CBC_ORDER_ANY);
735 MUTATOR_HOOK(PlayerDies, ctf_RemovePlayer, CBC_ORDER_ANY);
736 //MUTATOR_HOOK(GiveFragsForKill, ctf_GiveFragsForKill, CBC_ORDER_ANY);
737 //MUTATOR_HOOK(PlayerPreThink, ctf_PlayerPreThink, CBC_ORDER_ANY);
738 //MUTATOR_HOOK(PlayerDamage_Calculate, ctf_PlayerDamage, CBC_ORDER_ANY);
739 //MUTATOR_HOOK(PlayerPowerups, ctf_PlayerPowerups, CBC_ORDER_ANY);
743 if(time > 1) // game loads at time 1
744 error("This is a game type and it cannot be added at runtime.");
752 error("This is a game type and it cannot be removed at runtime.");