From 726d1391cb31d02b76ca116237c67898631900aa Mon Sep 17 00:00:00 2001 From: TimePath Date: Tue, 16 Dec 2014 21:37:11 +1100 Subject: [PATCH] More infection cleanup --- gamemodes.cfg | 27 +- qcsrc/common/mapinfo.qh | 2 +- qcsrc/server/autocvars.qh | 1 - qcsrc/server/cl_client.qc | 2 +- qcsrc/server/cl_player.qc | 15 +- qcsrc/server/mutators/gamemode_infection.qc | 268 +++++++++++--------- 6 files changed, 175 insertions(+), 140 deletions(-) diff --git a/gamemodes.cfg b/gamemodes.cfg index 5c97c7cd05..338f6975ea 100644 --- a/gamemodes.cfg +++ b/gamemodes.cfg @@ -37,6 +37,7 @@ alias cl_hook_gamestart_nb alias cl_hook_gamestart_cts alias cl_hook_gamestart_ka alias cl_hook_gamestart_ft +alias cl_hook_gamestart_inf alias cl_hook_gamestart_inv alias cl_hook_gameend "rpn /cl_matchcount dup load 1 + =" // increase match count every time a game ends alias cl_hook_activeweapon @@ -58,6 +59,7 @@ alias sv_hook_gamestart_nb alias sv_hook_gamestart_cts alias sv_hook_gamestart_ka alias sv_hook_gamestart_ft +alias sv_hook_gamestart_inf alias sv_hook_gamestart_inv alias sv_hook_gamerestart alias sv_hook_gameend @@ -75,6 +77,7 @@ alias sv_vote_gametype_hook_cts alias sv_vote_gametype_hook_dm alias sv_vote_gametype_hook_dom alias sv_vote_gametype_hook_ft +alias sv_vote_gametype_hook_inf alias sv_vote_gametype_hook_inv alias sv_vote_gametype_hook_ka alias sv_vote_gametype_hook_kh @@ -208,6 +211,13 @@ set g_ft_respawn_delay_large_count 0 set g_ft_respawn_delay_max 0 set g_ft_respawn_waves 0 set g_ft_weapon_stay 0 +set g_inf_respawn_delay_small 0 +set g_inf_respawn_delay_small_count 0 +set g_inf_respawn_delay_large 0 +set g_inf_respawn_delay_large_count 0 +set g_inf_respawn_delay_max 0 +set g_inf_respawn_waves 0 +set g_inf_weapon_stay 0 set g_inv_respawn_delay_small 0 set g_inv_respawn_delay_small_count 0 set g_inv_respawn_delay_large 0 @@ -500,6 +510,16 @@ set g_race_qualifying_timelimit_override -1 set g_race_teams 0 "when 2, 3, or 4, the race is played as a team game (the team members can add up their laps)" +// =========== +// infection +// =========== +set g_infection 0 "Infection: Infect everyone with your color" +set g_infection_round_timelimit 180 "round time limit in seconds" +set g_infection_warmup 5 "Time players get to run around before the round starts" +set g_infection_teams 4 "Maximum number of teams (from 2 to 15 inclusive)" +set g_infection_conversions 1 "Enable stealing when killing an alpha" + + // ========== // invasion // ========== @@ -512,10 +532,3 @@ set g_invasion_spawn_delay 0.25 set g_invasion_spawnpoint_spawn_delay 0.5 set g_invasion_teams 0 "number of teams in invasion (note: use mapinfo to set this)" set g_invasion_team_spawns 1 "use team spawns in teamplay invasion mode" - - -// =========== -// infection -// =========== -set g_infection 0 "Infection: Infect everyone with your color to win!" -set g_infection_delay_round 5 "delay during which new colors can still be formed, after this a new player will join an existing team (and as such cannot win anymore)" diff --git a/qcsrc/common/mapinfo.qh b/qcsrc/common/mapinfo.qh index bd51473a45..659f9ce328 100644 --- a/qcsrc/common/mapinfo.qh +++ b/qcsrc/common/mapinfo.qh @@ -82,7 +82,7 @@ REGISTER_GAMETYPE(_("Keepaway"),ka,g_keepaway,KEEPAWAY,TRUE,"timelimit=20 pointl REGISTER_GAMETYPE(_("Invasion"),inv,g_invasion,INVASION,FALSE,"pointlimit=50 teams=0",_("Survive against waves of monsters")); #define g_invasion IS_GAMETYPE(INVASION) -REGISTER_GAMETYPE(_("Infection"),inf,g_infection,INFECTION,FALSE,"timelimit=20",_("Survive against the infection")) +REGISTER_GAMETYPE(_("Infection"),inf,g_infection,INFECTION,TRUE,"timelimit=20",_("Survive against the infection")) #define g_infection IS_GAMETYPE(INFECTION) const float MAPINFO_FEATURE_WEAPONS = 1; // not defined for instagib-only maps diff --git a/qcsrc/server/autocvars.qh b/qcsrc/server/autocvars.qh index 0d74b49c91..4b9468552d 100644 --- a/qcsrc/server/autocvars.qh +++ b/qcsrc/server/autocvars.qh @@ -837,7 +837,6 @@ float autocvar_g_campcheck_damage; float autocvar_g_campcheck_distance; float autocvar_g_campcheck_interval; float autocvar_g_jump_grunt; -float autocvar_g_infection_delay_round = 5; float autocvar_g_spawn_near_teammate_distance; float autocvar_g_spawn_near_teammate_ignore_spawnpoint; float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay; diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index c2a434a3e7..b1dccc7b5c 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -345,7 +345,7 @@ void FixPlayermodel() UpdatePlayerSounds(); // update skin sounds } - if(!(teamplay || g_infection)) + if(!teamplay) if(strlen(autocvar_sv_defaultplayercolors)) if(self.clientcolors != stof(autocvar_sv_defaultplayercolors)) setcolor(self, stof(autocvar_sv_defaultplayercolors)); diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc index 3e6817c2c9..fc94ccb9e1 100644 --- a/qcsrc/server/cl_player.qc +++ b/qcsrc/server/cl_player.qc @@ -299,7 +299,6 @@ void calculate_player_respawn_time() } void ClientKill_Now_TeamChange(); -void infection_CheckWinner(); void PlayerDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) { @@ -537,23 +536,13 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht // print an obituary message Obituary (attacker, inflictor, self, deathtype); - - if(g_infection) - { - if(deathtype == DEATH_HURTTRIGGER || deathtype == DEATH_KILL) - { - PutClientInServer(); // respawn with a random color - infection_CheckWinner(); - return; - } - } // increment frag counter for used weapon type float w; w = DEATH_WEAPONOF(deathtype); if(WEP_VALID(w)) - if(accuracy_isgooddamage(attacker, self)) - attacker.accuracy.(accuracy_frags[w-1]) += 1; + if(accuracy_isgooddamage(attacker, self)) + attacker.accuracy.(accuracy_frags[w-1]) += 1; frag_attacker = attacker; frag_inflictor = inflictor; diff --git a/qcsrc/server/mutators/gamemode_infection.qc b/qcsrc/server/mutators/gamemode_infection.qc index 94bc29c504..012e44213e 100644 --- a/qcsrc/server/mutators/gamemode_infection.qc +++ b/qcsrc/server/mutators/gamemode_infection.qc @@ -1,199 +1,224 @@ -float infection_players_count = 0; -float infection_coloridx; +float autocvar_g_infection_round_timelimit; +float autocvar_g_infection_warmup; +float autocvar_g_infection_teams; +float autocvar_g_infection_conversions; -float next_round; +float infection_players_count; -.float infection_jointime; .float infectioncolor; .float infectioncolor_original; -void infection_SetColor(entity e, float _color) -{ - setcolor(e, (_color << 4) | _color); -} +const float INFECTIONTEAM_NONE = -1; +const float INFECTIONTEAM_UNDEFINED = -2; -void infection_Initialize() +void infection_SetColor(entity _e, float _color) { - infection_coloridx = 0; - next_round = time + autocvar_g_infection_delay_round; + _e.infectioncolor = _color; + setcolor(_e, (_color << 4) | _color); } -void infection_CheckWinner() +string color_owner_green, color_owner_red; +// find whose color a player is carrying, TRUE if it's his own, otherwise set color_owner_* to the other owner +void infection_GetColorOwner(entity me) { - if (infection_players_count <= 1) return; // There can be no winner - - // Check if only one color remains - float previnfectioncolor = -1; - float we_have_a_winner = TRUE; // TRUE until below loop proves us wrong + if (me.infectioncolor == me.infectioncolor_original) + { + color_owner_green = "^2your own"; + color_owner_red = "^1their own"; + return; + } entity e; FOR_EACH_PLAYER(e) { - // All infection colors are the same if we have a winner - if (previnfectioncolor != -1 && previnfectioncolor != e.infectioncolor) + if (me.infectioncolor == e.infectioncolor_original) { - // In this case we still have more than one color alive - we_have_a_winner = FALSE; + color_owner_green = strcat(e.netname, "^2's"); + color_owner_red = strcat(e.netname, "^1's"); break; } - previnfectioncolor = e.infectioncolor; } +} - if (!we_have_a_winner) return; - - // Who is it? - entity winner = world; - FOR_EACH_PLAYER(e) +void infection_Assign(float _late) +{ + entity e; + if (_late == 0) { - if (e.infectioncolor == e.infectioncolor_original) + float infection_coloridx = 0; + FOR_EACH_PLAYER(e) { - winner = e; - break; + if (infection_coloridx < autocvar_g_infection_teams) // Limit alphas + e.infectioncolor_original = infection_coloridx; + infection_SetColor(e, infection_coloridx++ % bound(0, autocvar_g_infection_teams, 15)); } } - - if (winner.netname) + else { - UpdateFrags(winner, 1); - + // Spawn too late, give player a random color + float color = 15; + float skip = random() * (infection_players_count - 1); // Ignore self + skip = rint(skip); + entity e; FOR_EACH_PLAYER(e) { - centerprint(e, strcat(winner.netname, "^1 wins the round since their color survived.\n")); + if (e == self || IS_OBSERVER(e)) continue; + if (!skip --> 0) break; } - bprint(winner.netname, "^1 wins the round since their color survived.\n"); - } + dprint(strcat("[INFECTION] copying ", e.netname, "'s color\n")); + color = e.infectioncolor; + self.infectioncolor_original = INFECTIONTEAM_NONE; // Can't win if player didn't spawn during the round delay + infection_SetColor(self, color); + } +} - infection_Initialize(); +float infection_CheckTeams() +{ + return infection_players_count > 1; } -string color_owner_green, color_owner_red; -// find whose color your attacker is carrying, TRUE if it's his own, otherwise set color_owner_* to the other owner -float infection_GetColorOwner(entity me) +float infection_CheckWinner() { + if (infection_players_count <= 1) return FALSE; // There can be no winner + + if (0 < round_handler_GetEndTime() && round_handler_GetEndTime() <= time) // Round over + { + Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_OVER); + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_OVER); + round_handler_Init(5, autocvar_g_infection_warmup, autocvar_g_infection_round_timelimit); + return TRUE; + } + + // Check if only one color remains + float previnfectioncolor = -1; + float we_have_a_winner = TRUE; // TRUE until loop below proves us wrong entity e; FOR_EACH_PLAYER(e) { - if (e.infectioncolor_original == me.infectioncolor_original) - { - return TRUE; - } - else if (e.infectioncolor_original == me.infectioncolor) + // All infection colors are the same if we have a winner + if (previnfectioncolor != -1 && previnfectioncolor != e.infectioncolor) { - color_owner_green = strcat(e.netname, "^2's"); - color_owner_red = strcat(e.netname, "^1's"); + // In this case we still have more than one color alive + we_have_a_winner = FALSE; break; } + previnfectioncolor = e.infectioncolor; } - return FALSE; -} -MUTATOR_HOOKFUNCTION(infection_PlayerDies) -{ - // If this is the first time we die... (our infectioncolor remained unchanged) - if (frag_target.infectioncolor == frag_target.infectioncolor_original) + if (!we_have_a_winner) return FALSE; + + // Who is it? + FOR_EACH_PLAYER(e) { - infection_GetColorOwner(frag_attacker); - entity e; - FOR_EACH_PLAYER(e) // check other players... + if (e.infectioncolor == e.infectioncolor_original) { - if (e.infectioncolor == frag_target.infectioncolor) // And see if they have our original infection color - { - // If so, remove it, our infection color has now "died out" from this round and we can not win anymore. - // The attacker will "summon" all of our previously fragged targets, and also us. - centerprint(e, strcat("^1Your master ^7", frag_target.netname, "^1 was infected by ^7", frag_attacker.netname, " ^1with ^7", color_owner_red, " ^1color.\n")); - e.infectioncolor = frag_attacker.infectioncolor; - infection_SetColor(e, e.infectioncolor); - } + UpdateFrags(e, 10); // Bonus points + Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_PLAYER_WIN, e.netname); + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_PLAYER_WIN, e.netname); } } - else - { - frag_target.infectioncolor = frag_attacker.infectioncolor; - infection_SetColor(frag_target, frag_target.infectioncolor); - } - if (infection_GetColorOwner(frag_attacker)) - { - color_owner_green = "^2your own"; - color_owner_red = "^1their own"; - } - centerprint(frag_attacker, strcat("^2You infected ^7", frag_target.netname, " ^2with ^7", color_owner_green, " ^2color.\n")); - centerprint(frag_target, strcat("^1You were infected by ^7", frag_attacker.netname, " ^1with ^7", color_owner_red, " ^1color.\n")); + round_handler_Init(5, autocvar_g_infection_warmup, autocvar_g_infection_round_timelimit); + return TRUE; +} - bprint("^7", frag_target.netname, "^1 was infected by ^7", frag_attacker.netname, " ^1with ^7", color_owner_red, " ^1color.\n"); +void infection_RoundStart() +{ + infection_Assign(FALSE); + infection_CheckWinner(); +} - frag_target.health = cvar("g_balance_health_start"); // "respawn" the player +void infection_Initialize() +{ + infection_players_count = 0; + round_handler_Spawn(infection_CheckTeams, infection_CheckWinner, infection_RoundStart); + round_handler_Init(5, autocvar_g_infection_warmup, autocvar_g_infection_round_timelimit); +} +MUTATOR_HOOKFUNCTION(infection_PlayerDies) +{ infection_CheckWinner(); - return TRUE; } MUTATOR_HOOKFUNCTION(infection_RemovePlayer) { - if (!self.infection_jointime) - return FALSE; // nothing to remove + if (!IS_PLAYER(self)) return TRUE; // Wasn't playing infection_players_count--; - // if other players have our color, randomize their color - // ... but ONLY if next_round isn't set. We don't care about the colors if the round has already ended - if (!time < next_round) + self.infectioncolor_original = INFECTIONTEAM_UNDEFINED; + + // Grant alpha status to next of kin + entity e; + FOR_EACH_PLAYER(e) { - entity e; - FOR_EACH_PLAYER(e) // check other players... + if (e.infectioncolor == self.infectioncolor_original) { - if (e.infectioncolor == self.infectioncolor_original) // and see if they have our original infection color - { - e.infectioncolor_original = self.infectioncolor; - centerprint(frag_attacker, "^2You are now a master.\n"); - break; - } + e.infectioncolor_original = self.infectioncolor; + centerprint(e, "^2You are now an alpha.\n"); + break; } } - if (infection_players_count > 1 && time >= next_round) - infection_CheckWinner(); - + infection_CheckWinner(); return TRUE; } MUTATOR_HOOKFUNCTION(infection_PlayerSpawn) { - if (self.infection_jointime) return TRUE; // only add if we don't have a infection_jointime - self.infection_jointime = time; - if (++infection_players_count > 1 && time >= next_round) - next_round = time + autocvar_g_infection_delay_round; // start a new round immediately + if (self.infectioncolor_original != INFECTIONTEAM_UNDEFINED) return TRUE; // Wasn't observing + infection_players_count++; + + infection_Assign(TRUE); + + return TRUE; +} - if (time >= next_round) // spawn too late, give player a random color +MUTATOR_HOOKFUNCTION(infection_GiveFragsForKill) +{ + frag_score = 0; + infection_GetColorOwner(frag_attacker); + // If this is the first time we die... (our infectioncolor remained unchanged) + if (autocvar_g_infection_conversions && frag_target.infectioncolor == frag_target.infectioncolor_original) { - float skip = floor(random() * infection_players_count); entity e; - FOR_EACH_PLAYER(e) + FOR_EACH_PLAYER(e) // check other players... { - if (skip--) continue; - self.infectioncolor = e.infectioncolor; - self.infectioncolor_original = -1; // can't win if player didn't spawn during the round delay + if (e.infectioncolor == frag_target.infectioncolor) // And see if they have our original infection color + { + // If so, remove it, our infection color has now "died out" from this round and we can not win anymore. + // The attacker will "summon" all of our previously fragged targets, and also us. + centerprint(e, strcat("^1Your alpha ^7", frag_target.netname, "^1 was infected by ^7", frag_attacker.netname, " ^1with ^7", color_owner_red, " ^1color.\n")); + infection_SetColor(e, frag_attacker.infectioncolor); + frag_score++; + } } } - else // we are still in the delay period before the round starts + else { - self.infectioncolor = infection_coloridx++; - self.infectioncolor_original = self.infectioncolor; + infection_SetColor(frag_target, frag_attacker.infectioncolor); + frag_score++; } - infection_SetColor(self, self.infectioncolor); - return TRUE; -} + string target = frag_target.netname, attacker = frag_attacker.netname; + + centerprint(frag_attacker, strcat("^2You infected ^7", target, " ^2with ^7", color_owner_green, " ^2color.\n")); + centerprint(frag_target, strcat("^1You were infected by ^7", attacker, " ^1with ^7", color_owner_red, " ^1color.\n")); + + bprint("^7", frag_target.netname, "^1 was infected by ^7", attacker, " ^1with ^7", color_owner_red, " ^1color.\n"); -MUTATOR_HOOKFUNCTION(infection_GiveFragsForKill) -{ - frag_score = 0; // TODO: no frags counted in infection, maybe later return TRUE; } MUTATOR_HOOKFUNCTION(infection_PlayerPreThink) { - infection_SetColor(self, self.infectioncolor); // prevent cheating by changing player colors + if (IS_PLAYER(self)) + { + // Prevent cheating by changing player colors + infection_SetColor(self, round_handler_IsRoundStarted() + ? self.infectioncolor : 15 + ); + } return TRUE; } @@ -215,11 +240,20 @@ MUTATOR_HOOKFUNCTION(infection_PlayerDamage_Calculate) MUTATOR_HOOKFUNCTION(infection_BotShouldAttack) { - return checkentity.infectioncolor == self.infectioncolor; // FIXME: Has reverse meaning + return checkentity.infectioncolor == self.infectioncolor; +} + +MUTATOR_HOOKFUNCTION(infection_ClientConnect) +{ + self.infectioncolor_original = INFECTIONTEAM_UNDEFINED; + stuffcmd(self, "settemp cl_forceplayercolors 0\n"); + + return FALSE; } MUTATOR_DEFINITION(gamemode_infection) { + MUTATOR_HOOK(ClientConnect, infection_ClientConnect, CBC_ORDER_ANY); MUTATOR_HOOK(MakePlayerObserver, infection_RemovePlayer, CBC_ORDER_ANY); MUTATOR_HOOK(ClientDisconnect, infection_RemovePlayer, CBC_ORDER_ANY); MUTATOR_HOOK(PlayerDies, infection_PlayerDies, CBC_ORDER_ANY); -- 2.39.2