X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fmutators%2Fgamemode_ctf.qc;h=b82e26345063eb9d9369a9b5bbb33bd7a807fde0;hb=d957e789b57a046f8456b5e88ed4abfa5a34f6f1;hp=6eae4cb3efbffc629ede169550c8e97ae7d2c41a;hpb=c23da7be41c07c75530c713b6a4d7268cb5fcf69;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/mutators/gamemode_ctf.qc b/qcsrc/server/mutators/gamemode_ctf.qc index 6eae4cb3e..b82e26345 100644 --- a/qcsrc/server/mutators/gamemode_ctf.qc +++ b/qcsrc/server/mutators/gamemode_ctf.qc @@ -226,15 +226,18 @@ void ctf_Handle_Retrieve(entity flag, entity player) flag.ctf_status = FLAG_CARRY; // messages and sounds - sound(player, CH_TRIGGER, "keepaway/respawn.wav", VOL_BASE, ATTN_NORM); + sound(player, CH_TRIGGER, "keepaway/respawn.wav", VOL_BASE, ATTN_NORM); // FIXCTF ctf_EventLog("recieve", flag.team, player); + FOR_EACH_REALPLAYER(tmp_player) + { if(tmp_player == sender) centerprint(tmp_player, strcat("You passed the ", flag.netname, " to ", player.netname)); else if(tmp_player == player) centerprint(tmp_player, strcat("You recieved the ", flag.netname, " from ", sender.netname)); else if(!IsDifferentTeam(tmp_player, sender)) centerprint(tmp_player, strcat(sender.netname, " passed the ", flag.netname, " to ", player.netname)); + } // create new waypoint ctf_FlagcarrierWaypoints(player); @@ -333,10 +336,10 @@ void ctf_Handle_Throw(entity player, entity reciever, float droptype) WaypointSprite_Kill(player.wps_flagcarrier); if(player.wps_enemyflagcarrier) - WaypointSprite_Kill(player.wps_enemyflagcarrier); + WaypointSprite_Kill(player.wps_enemyflagcarrier); // captureshield - //ctf_CaptureShield_Update(player, 0); // shield only + ctf_CaptureShield_Update(player, 0); // shield player from picking up flag } @@ -389,7 +392,7 @@ void ctf_Handle_Return(entity flag, entity player) { // messages and sounds //centerprint(player, strcat("You returned the ", flag.netname)); - Send_KillNotification (player.netname, flag.netname, "", INFO_RETURNFLAG, MSG_INFO); + Send_KillNotification(player.netname, flag.netname, "", INFO_RETURNFLAG, MSG_INFO); sound(player, CH_TRIGGER, flag.snd_flag_returned, VOL_BASE, ATTN_NONE); ctf_EventLog("return", flag.team, player); @@ -401,12 +404,9 @@ void ctf_Handle_Return(entity flag, entity player) if(flag.ctf_dropper) { - // punish the player who dropped the flag - PlayerScore_Add(flag.ctf_dropper, SP_SCORE, -ctf_ReadScore("penalty_returned")); - ctf_CaptureShield_Update(flag.ctf_dropper, 0); // shield only - - // set next take time - flag.ctf_dropper.next_take_time = time + autocvar_g_ctf_flag_collect_delay; + PlayerScore_Add(flag.ctf_dropper, SP_SCORE, -ctf_ReadScore("penalty_returned")); // punish the player who dropped the flag + ctf_CaptureShield_Update(flag.ctf_dropper, 0); // shield player from picking up flag + flag.ctf_dropper.next_take_time = time + autocvar_g_ctf_flag_collect_delay; // set next take time } // reset the flag @@ -447,13 +447,15 @@ void ctf_Handle_Pickup(entity flag, entity player, float pickuptype) verbosename = ((autocvar_g_ctf_flag_pickup_verbosename) ? strcat(Team_ColorCode(player.team), "(^7", player.netname, Team_ColorCode(player.team), ") ") : ""); FOR_EACH_REALPLAYER(tmp_player) + { if(tmp_player == player) centerprint(tmp_player, strcat("You got the ", flag.netname, "!")); else if(!IsDifferentTeam(tmp_player, player)) centerprint(tmp_player, strcat("Your ", Team_ColorCode(player.team), "team mate ", verbosename, "^7got the flag! Protect them!")); else if(!IsDifferentTeam(tmp_player, flag)) centerprint(tmp_player, strcat("The ", Team_ColorCode(player.team), "enemy ", verbosename, "^7got your flag! Retrieve it!")); - + } + switch(pickuptype) { case PICKUP_BASE: ctf_EventLog("steal", flag.team, player); break; @@ -506,34 +508,88 @@ void ctf_Handle_Pickup(entity flag, entity player, float pickuptype) // Main Flag Functions // =================== -void ctf_CheckFlagReturn(entity flag) +void ctf_CheckFlagReturn(entity flag, float returntype) { if(flag.wps_flagdropped) { WaypointSprite_UpdateHealth(flag.wps_flagdropped, flag.health); } if((flag.health <= 0) || (time >= flag.ctf_droptime + autocvar_g_ctf_flag_return_time)) { - bprint("The ", flag.netname, " has returned to base\n"); + switch(returntype) + { + case RETURN_DROPPED: bprint("The ", flag.netname, " was dropped in the base and returned itself\n"); break; + case RETURN_DAMAGE: bprint("The ", flag.netname, " was destroyed and returned to base\n"); break; + case RETURN_SPEEDRUN: bprint("The ", flag.netname, " became impatient after ", ftos_decimals(ctf_captimerecord, 2), " seconds and returned itself\n"); break; + case RETURN_NEEDKILL: bprint("The ", flag.netname, " fell somewhere it couldn't be reached and returned to base\n"); break; + + default: + case RETURN_TIMEOUT: + { bprint("The ", flag.netname, " has returned to base\n"); break; } + } sound(flag, CH_TRIGGER, flag.snd_flag_respawn, VOL_BASE, ATTN_NONE); ctf_EventLog("returned", flag.team, world); ctf_RespawnFlag(flag); } } +void ctf_CheckStalemate(void) +{ + // declarations + float stale_red_flags, stale_blue_flags; + entity tmp_entity; + + // build list of stale flags + for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext) + { + if(autocvar_g_ctf_flagcarrier_waypointforenemy_stalemate) + if(time >= tmp_entity.ctf_pickuptime + autocvar_g_ctf_flagcarrier_waypointforenemy_stalemate) + { + tmp_entity.ctf_staleflagnext = ctf_staleflaglist; // link flag into staleflaglist + ctf_staleflaglist = tmp_entity; + + switch(tmp_entity.team) + { + case COLOR_TEAM1: ++stale_red_flags; break; + case COLOR_TEAM2: ++stale_blue_flags; break; + } + } + } + + // if sufficient stalemate, then set up the waypointsprite and announce the stalemate if necessary + if(stale_red_flags && stale_blue_flags) + { + for(tmp_entity = ctf_staleflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_staleflagnext) + { + if not(tmp_entity.owner.wps_enemyflagcarrier) + WaypointSprite_Spawn("enemyflagcarrier", 0, 0, tmp_entity.owner, FLAG_WAYPOINT_OFFSET, world, tmp_entity.team, tmp_entity.owner, wps_enemyflagcarrier, TRUE, RADARICON_FLAG, WPCOLOR_ENEMYFC(tmp_entity.owner.team)); + } + + if not(wpforenemy_announced) + { + FOR_EACH_REALPLAYER(tmp_entity) + if(tmp_entity.flagcarried) + centerprint(tmp_entity, "Stalemate! Enemies can now see you on radar!"); + else + centerprint(tmp_entity, "Stalemate! Flag carriers can now be seen by enemies on radar!"); + + wpforenemy_announced = TRUE; + } + } +} + void ctf_FlagDamage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) { if(ITEM_DAMAGE_NEEDKILL(deathtype)) { // automatically kill the flag and return it self.health = 0; - ctf_CheckFlagReturn(self); + ctf_CheckFlagReturn(self, RETURN_NEEDKILL); return; } - if(autocvar_g_ctf_flag_return_damage) { // reduce health and check if it should be returned self.health = self.health - damage; - ctf_CheckFlagReturn(self); + ctf_CheckFlagReturn(self, RETURN_DAMAGE); return; } } @@ -556,6 +612,18 @@ void ctf_FlagThink() tracebox(self.origin, FLAG_MIN, FLAG_MAX, self.origin, MOVE_NOMONSTERS, self); if(!trace_startsolid) // can we resize it without getting stuck? setsize(self, FLAG_MIN, FLAG_MAX); } + + switch(self.ctf_status) // reset flag angles in case warpzones adjust it + { + case FLAG_DROPPED: + case FLAG_PASSING: + { + self.angles = '0 0 0'; + break; + } + + default: break; + } // main think method switch(self.ctf_status) @@ -574,19 +642,22 @@ void ctf_FlagThink() case FLAG_DROPPED: { + if(autocvar_g_ctf_flag_dropped_floatinwater && (self.flags & FL_INWATER)) + self.velocity_z = autocvar_g_ctf_flag_dropped_floatinwater; + if(autocvar_g_ctf_flag_return_dropped) { if((vlen(self.origin - self.ctf_spawnorigin) <= autocvar_g_ctf_flag_return_dropped) || (autocvar_g_ctf_flag_return_dropped == -1)) { self.health = 0; - ctf_CheckFlagReturn(self); + ctf_CheckFlagReturn(self, RETURN_DROPPED); return; } } if(autocvar_g_ctf_flag_return_time) { self.health -= ((self.max_flag_health / autocvar_g_ctf_flag_return_time) * FLAG_THINKRATE); - ctf_CheckFlagReturn(self); + ctf_CheckFlagReturn(self, RETURN_TIMEOUT); return; } return; @@ -596,10 +667,8 @@ void ctf_FlagThink() { if(self.speedrunning && ctf_captimerecord && (time >= self.ctf_pickuptime + ctf_captimerecord)) { - bprint("The ", self.netname, " became impatient after ", ftos_decimals(ctf_captimerecord, 2), " seconds and returned itself\n"); - sound(self, CH_TRIGGER, self.snd_flag_respawn, VOL_BASE, ATTN_NONE); - ctf_EventLog("returned", self.team, world); - ctf_RespawnFlag(tmp_entity); + self.health = 0; + ctf_CheckFlagReturn(self, RETURN_SPEEDRUN); tmp_entity = self; self = self.owner; @@ -607,33 +676,20 @@ void ctf_FlagThink() ImpulseCommands(); self = tmp_entity; } - - if(autocvar_g_ctf_flagcarrier_waypointforenemy_time) - if((time >= self.ctf_pickuptime + autocvar_g_ctf_flagcarrier_waypointforenemy_time) && !self.owner.wps_enemyflagcarrier) + if(autocvar_g_ctf_flagcarrier_waypointforenemy_stalemate) { - WaypointSprite_Spawn("enemyflagcarrier", 0, 0, self.owner, FLAG_WAYPOINT_OFFSET, world, self.team, self.owner, wps_enemyflagcarrier, TRUE, RADARICON_FLAG, WPCOLOR_ENEMYFC(self.owner.team)); - - if(!self.wpforenemy_announced) + if(time >= wpforenemy_nextthink) { - FOR_EACH_REALPLAYER(tmp_entity) - if(tmp_entity == self.owner) - centerprint(tmp_entity, strcat("Enemies can now see you on radar! (held ", self.netname, " for ", ftos(autocvar_g_ctf_flagcarrier_waypointforenemy_time), " seconds)")); - else if(!IsDifferentTeam(tmp_entity, self.owner)) - centerprint(tmp_entity, strcat("Enemies can now see your flag carrier on radar! (held ", self.netname, " for ", ftos(autocvar_g_ctf_flagcarrier_waypointforenemy_time), " seconds)")); - else if(!IsDifferentTeam(tmp_entity, self)) - centerprint(tmp_entity, strcat("You can now see the enemy flag carrier on radar! (held ", self.netname, " for ", ftos(autocvar_g_ctf_flagcarrier_waypointforenemy_time), " seconds)")); - - self.wpforenemy_announced = TRUE; + ctf_CheckStalemate(); + wpforenemy_nextthink = time + WPFE_THINKRATE; // waypoint for enemy think rate (to reduce unnecessary spam of this check) } } - return; } case FLAG_PASSING: // todo make work with warpzones { vector targ_origin = ((self.pass_target.absmin + self.pass_target.absmax) * 0.5); - traceline(self.origin, targ_origin, MOVE_NOMONSTERS, self); if((self.pass_target.deadflag != DEAD_NO) @@ -664,16 +720,26 @@ void ctf_FlagThink() void ctf_FlagTouch() { if(gameover) { return; } - if(!self) { return; } - if(other.deadflag != DEAD_NO) { return; } + + entity toucher = other; + + // automatically kill the flag and return it if it touched lava/slime/nodrop surfaces if(ITEM_TOUCH_NEEDKILL()) { - // automatically kill the flag and return it self.health = 0; - ctf_CheckFlagReturn(self); + ctf_CheckFlagReturn(self, RETURN_NEEDKILL); return; } - if(other.classname != "player") // The flag just touched an object, most likely the world + + // special touch behaviors + if(toucher.vehicle_flags & VHF_ISVEHICLE) + { + if(autocvar_g_ctf_allow_vehicle_touch) + toucher = toucher.owner; // the player is actually the vehicle owner, not other + else + return; // do nothing + } + else if(toucher.classname != "player") // The flag just touched an object, most likely the world { if(time > self.wait) // if we haven't in a while, play a sound/effect { @@ -683,24 +749,25 @@ void ctf_FlagTouch() } return; } + else if(toucher.deadflag != DEAD_NO) { return; } switch(self.ctf_status) { case FLAG_BASE: { - if(!IsDifferentTeam(other, self) && (other.flagcarried) && IsDifferentTeam(other.flagcarried, self)) - ctf_Handle_Capture(self, other, CAPTURE_NORMAL); // other just captured the enemies flag to his base - else if(IsDifferentTeam(other, self) && (!other.flagcarried) && (!other.ctf_captureshielded) && (time > other.next_take_time)) - ctf_Handle_Pickup(self, other, PICKUP_BASE); // other just stole the enemies flag + if(!IsDifferentTeam(toucher, self) && (toucher.flagcarried) && IsDifferentTeam(toucher.flagcarried, self)) + ctf_Handle_Capture(self, toucher, CAPTURE_NORMAL); // toucher just captured the enemies flag to his base + else if(IsDifferentTeam(toucher, self) && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time)) + ctf_Handle_Pickup(self, toucher, PICKUP_BASE); // toucher just stole the enemies flag break; } case FLAG_DROPPED: { - if(!IsDifferentTeam(other, self)) - ctf_Handle_Return(self, other); // other just returned his own flag - else if((!other.flagcarried) && ((other != self.ctf_dropper) || (time > self.ctf_droptime + autocvar_g_ctf_flag_collect_delay))) - ctf_Handle_Pickup(self, other, PICKUP_DROPPED); // other just picked up a dropped enemy flag + if(!IsDifferentTeam(toucher, self)) + ctf_Handle_Return(self, toucher); // toucher just returned his own flag + else if((!toucher.flagcarried) && ((toucher != self.ctf_dropper) || (time > self.ctf_droptime + autocvar_g_ctf_flag_collect_delay))) + ctf_Handle_Pickup(self, toucher, PICKUP_DROPPED); // toucher just picked up a dropped enemy flag break; } @@ -712,21 +779,15 @@ void ctf_FlagTouch() case FLAG_PASSING: { - if((other.classname == "player") && (other.deadflag == DEAD_NO) && (other != self.pass_sender)) + if((toucher.classname == "player") && (toucher.deadflag == DEAD_NO) && (toucher != self.pass_sender)) { - if(IsDifferentTeam(other, self.pass_sender)) - ctf_Handle_Return(self, other); + if(IsDifferentTeam(toucher, self.pass_sender)) + ctf_Handle_Return(self, toucher); else - ctf_Handle_Retrieve(self, other); + ctf_Handle_Retrieve(self, toucher); } break; } - - default: // this should never happen - { - dprint("Touch: Flag exists with no status?\n"); - break; - } } } @@ -769,7 +830,8 @@ void ctf_RespawnFlag(entity flag) flag.ctf_dropper = world; flag.ctf_pickuptime = 0; flag.ctf_droptime = 0; - flag.wpforenemy_announced = FALSE; + + wpforenemy_announced = FALSE; } void ctf_Reset() @@ -821,6 +883,7 @@ void ctf_FlagSetup(float teamnumber, entity flag) // called when spawning a flag flag.health = flag.max_flag_health; flag.event_damage = ctf_FlagDamage; flag.pushable = TRUE; + flag.teleportable = TELEPORT_NORMAL; flag.damagedbytriggers = autocvar_g_ctf_flag_return_when_unreachable; flag.damagedbycontents = autocvar_g_ctf_flag_return_when_unreachable; flag.velocity = '0 0 0'; @@ -893,23 +956,6 @@ void ctf_FlagSetup(float teamnumber, entity flag) // called when spawning a flag // Hook Functions // ============== -MUTATOR_HOOKFUNCTION(ctf_RemovePlayer) -{ - if(self.flagcarried) - { ctf_Handle_Throw(self, world, DROP_NORMAL); } - - return 0; -} - -MUTATOR_HOOKFUNCTION(ctf_PortalTeleport) -{ - if(self.flagcarried) - if(!autocvar_g_ctf_portalteleport) - { ctf_Handle_Throw(self, world, DROP_NORMAL); } - - return 0; -} - MUTATOR_HOOKFUNCTION(ctf_PlayerPreThink) { entity flag; @@ -921,13 +967,22 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerPreThink) // scan through all the flags and notify the client about them for(flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext) { - if(flag.ctf_status == FLAG_CARRY) - if(flag.owner == self) - self.items |= ((flag.items & IT_KEY2) ? IT_RED_FLAG_CARRYING : IT_BLUE_FLAG_CARRYING); // carrying: self is currently carrying the flag - else - self.items |= ((flag.items & IT_KEY2) ? IT_RED_FLAG_TAKEN : IT_BLUE_FLAG_TAKEN); // taken: someone on self's team is carrying the flag - else if(flag.ctf_status == FLAG_DROPPED) - self.items |= ((flag.items & IT_KEY2) ? IT_RED_FLAG_LOST : IT_BLUE_FLAG_LOST); // lost: the flag is dropped somewhere on the map + switch(flag.ctf_status) + { + case FLAG_CARRY: + { + if(flag.owner == self) + self.items |= ((flag.items & IT_KEY2) ? IT_RED_FLAG_CARRYING : IT_BLUE_FLAG_CARRYING); // carrying: self is currently carrying the flag + else + self.items |= ((flag.items & IT_KEY2) ? IT_RED_FLAG_TAKEN : IT_BLUE_FLAG_TAKEN); // taken: someone on self's team is carrying the flag + break; + } + case FLAG_DROPPED: + { + self.items |= ((flag.items & IT_KEY2) ? IT_RED_FLAG_LOST : IT_BLUE_FLAG_LOST); // lost: the flag is dropped somewhere on the map + break; + } + } } // item for stopping players from capturing the flag too often @@ -950,12 +1005,31 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerDamage) // for changing damage and force values t frag_damage *= autocvar_g_ctf_flagcarrier_selfdamagefactor; frag_force *= autocvar_g_ctf_flagcarrier_selfforcefactor; } - else // damage done everyone else + else // damage done to everyone else { frag_damage *= autocvar_g_ctf_flagcarrier_damagefactor; frag_force *= autocvar_g_ctf_flagcarrier_forcefactor; } } + else if(frag_target.flagcarried && (frag_target.deadflag == DEAD_NO) && IsDifferentTeam(frag_target, frag_attacker)) // if the target is a flagcarrier + { + if(autocvar_g_ctf_flagcarrier_auto_helpme_when_damaged > frag_target.health) + WaypointSprite_HelpMePing(frag_target.wps_flagcarrier); // TODO: only do this if there is a significant loss of health? + } + return 0; +} + +MUTATOR_HOOKFUNCTION(ctf_PlayerDies) +{ + if((frag_attacker != frag_target) && (frag_attacker.classname == "player") && (frag_target.flagcarried)) + { + PlayerTeamScore_AddScore(frag_attacker, ctf_ReadScore("score_kill")); + PlayerScore_Add(frag_attacker, SP_CTF_FCKILLS, 1); + } + + if(frag_target.flagcarried) + { ctf_Handle_Throw(frag_target, world, DROP_NORMAL); } + return 0; } @@ -965,11 +1039,28 @@ MUTATOR_HOOKFUNCTION(ctf_GiveFragsForKill) return (autocvar_g_ctf_ignore_frags); // no frags counted in ctf if this is true } +MUTATOR_HOOKFUNCTION(ctf_RemovePlayer) +{ + if(self.flagcarried) + { ctf_Handle_Throw(self, world, DROP_NORMAL); } + + return 0; +} + +MUTATOR_HOOKFUNCTION(ctf_PortalTeleport) +{ + if(self.flagcarried) + if(!autocvar_g_ctf_portalteleport) + { ctf_Handle_Throw(self, world, DROP_NORMAL); } + + return 0; +} + MUTATOR_HOOKFUNCTION(ctf_PlayerUseKey) { entity player = self; - if(time > player.throw_antispam) + if((time > player.throw_antispam) && !player.speedrunning && (!player.vehicle || autocvar_g_ctf_allow_vehicle_touch)) { // pass the flag to a team mate if(autocvar_g_ctf_pass) @@ -981,7 +1072,7 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerUseKey) { if(head.classname == "player" && head.deadflag == DEAD_NO) if(head != player && !IsDifferentTeam(head, player)) - if(!player.speedrunning && !head.speedrunning) + if(!head.speedrunning && (!head.vehicle || autocvar_g_ctf_allow_vehicle_touch)) { traceline(player.origin, head.origin, MOVE_NOMONSTERS, player); if not((trace_fraction < 1) && (trace_ent != head)) @@ -1015,13 +1106,107 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerUseKey) } // throw the flag in front of you - if(autocvar_g_ctf_drop && player.flagcarried && !player.speedrunning) + if(autocvar_g_ctf_drop && player.flagcarried) { ctf_Handle_Throw(player, world, DROP_THROW); } } return 0; } +MUTATOR_HOOKFUNCTION(ctf_HelpMePing) +{ + if(self.wps_flagcarrier) // update the flagcarrier waypointsprite with "NEEDING HELP" notification + { + WaypointSprite_HelpMePing(self.wps_flagcarrier); + } + else // create a normal help me waypointsprite + { + WaypointSprite_Spawn("helpme", waypointsprite_deployed_lifetime, waypointsprite_limitedrange, self, FLAG_WAYPOINT_OFFSET, world, self.team, self, wps_helpme, FALSE, RADARICON_HELPME, '1 0.5 0'); + WaypointSprite_Ping(self.wps_helpme); + } + + return 1; +} + +MUTATOR_HOOKFUNCTION(ctf_VehicleEnter) +{ + if(other.flagcarried) + { + if(!autocvar_g_ctf_flagcarrier_allow_vehicle_carry) + { + ctf_Handle_Throw(self, world, DROP_NORMAL); + } + else + { + setattachment(other.flagcarried, self, ""); + setorigin(other, VEHICLE_FLAG_OFFSET); + other.flagcarried.scale = VEHICLE_FLAG_SCALE; + //other.flagcarried.angles = '0 0 0'; + } + } + + return 0; +} + +MUTATOR_HOOKFUNCTION(ctf_VehicleExit) +{ + if(self.owner.flagcarried) + { + setattachment(self.owner.flagcarried, self.owner, ""); + setorigin(self.owner.flagcarried, FLAG_CARRY_OFFSET); + self.owner.flagcarried.scale = FLAG_SCALE; + self.owner.flagcarried.angles = '0 0 0'; + } + + return 0; +} + +MUTATOR_HOOKFUNCTION(ctf_AbortSpeedrun) +{ + if(self.flagcarried) + { + bprint("The ", self.flagcarried.netname, " was returned to base by its carrier\n"); + ctf_RespawnFlag(self); + } + + return 0; +} + +MUTATOR_HOOKFUNCTION(ctf_MatchEnd) +{ + entity flag; // temporary entity for the search method + + for(flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext) + { + switch(flag.ctf_status) + { + case FLAG_DROPPED: + case FLAG_PASSING: + { + // lock the flag, game is over + flag.movetype = MOVETYPE_NONE; + flag.takedamage = DAMAGE_NO; + flag.solid = SOLID_NOT; + flag.nextthink = 0; // stop thinking + + print("stopping the ", flag.netname, " from moving.\n"); + break; + } + + default: + case FLAG_BASE: + case FLAG_CARRY: + { + // do nothing for these flags + break; + } + } + } + + return 0; +} + + // ========== // Spawnfuncs // ========== @@ -1171,13 +1356,18 @@ MUTATOR_DEFINITION(gamemode_ctf) { MUTATOR_HOOK(MakePlayerObserver, ctf_RemovePlayer, CBC_ORDER_ANY); MUTATOR_HOOK(ClientDisconnect, ctf_RemovePlayer, CBC_ORDER_ANY); - MUTATOR_HOOK(PlayerDies, ctf_RemovePlayer, CBC_ORDER_ANY); + MUTATOR_HOOK(PlayerDies, ctf_PlayerDies, CBC_ORDER_ANY); + MUTATOR_HOOK(MatchEnd, ctf_MatchEnd, CBC_ORDER_ANY); MUTATOR_HOOK(PortalTeleport, ctf_PortalTeleport, CBC_ORDER_ANY); MUTATOR_HOOK(GiveFragsForKill, ctf_GiveFragsForKill, CBC_ORDER_ANY); MUTATOR_HOOK(PlayerPreThink, ctf_PlayerPreThink, CBC_ORDER_ANY); MUTATOR_HOOK(PlayerDamage_Calculate, ctf_PlayerDamage, CBC_ORDER_ANY); MUTATOR_HOOK(PlayerUseKey, ctf_PlayerUseKey, CBC_ORDER_ANY); - + MUTATOR_HOOK(HelpMePing, ctf_HelpMePing, CBC_ORDER_ANY); + MUTATOR_HOOK(VehicleEnter, ctf_VehicleEnter, CBC_ORDER_ANY); + MUTATOR_HOOK(VehicleExit, ctf_VehicleExit, CBC_ORDER_ANY); + MUTATOR_HOOK(AbortSpeedrun, ctf_AbortSpeedrun, CBC_ORDER_ANY); + MUTATOR_ONADD { if(time > 1) // game loads at time 1