X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fmutators%2Fgamemode_freezetag.qc;h=f2e624c56325826affe75d0f4420d4ef43b71c48;hb=9ff7ce8cc439211d86751ba7ff30a7a1bb9dbe23;hp=6e40375082fc4e3642646422554fcceb8ffc3dff;hpb=7be96bf3d445539ab94b6f2bfe97d253de3f63cc;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/mutators/gamemode_freezetag.qc b/qcsrc/server/mutators/gamemode_freezetag.qc index 6e4037508..f2e624c56 100644 --- a/qcsrc/server/mutators/gamemode_freezetag.qc +++ b/qcsrc/server/mutators/gamemode_freezetag.qc @@ -1,9 +1,13 @@ +float freezetag_teams; +float freezetag_CheckTeams(); +float freezetag_CheckWinner(); void freezetag_Initialize() { precache_model("models/ice/ice.md3"); - warmup = max(time, game_starttime) + autocvar_g_freezetag_warmup; ScoreRules_freezetag(); + round_handler_Spawn(freezetag_CheckTeams, freezetag_CheckWinner, 5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit); + addstat(STAT_REDALIVE, AS_INT, redalive_stat); addstat(STAT_BLUEALIVE, AS_INT, bluealive_stat); addstat(STAT_YELLOWALIVE, AS_INT, yellowalive_stat); @@ -13,53 +17,132 @@ void freezetag_Initialize() addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, freezetag_revive_progress); } -void freezetag_CheckWinner() +void freezetag_count_alive_players() { - if(time <= game_starttime || inWarmupStage) - return; - - if(next_round || (time > warmup - autocvar_g_freezetag_warmup && time < warmup)) - return; // already waiting for next round to start - - if((redalive >= 1 && bluealive >= 1) - || (redalive >= 1 && yellowalive >= 1) - || (redalive >= 1 && pinkalive >= 1) - || (bluealive >= 1 && yellowalive >= 1) - || (bluealive >= 1 && pinkalive >= 1) - || (yellowalive >= 1 && pinkalive >= 1)) - return; // we still have active players on two or more teams, nobody won yet - - entity e, winner; - string teamname; - winner = world; + entity e; + total_players = redalive = bluealive = yellowalive = pinkalive = 0; + FOR_EACH_PLAYER(e) { + if(e.team == COLOR_TEAM1 && e.health >= 1) + { + ++total_players; + if (!e.freezetag_frozen) ++redalive; + } + else if(e.team == COLOR_TEAM2 && e.health >= 1) + { + ++total_players; + if (!e.freezetag_frozen) ++bluealive; + } + else if(e.team == COLOR_TEAM3 && e.health >= 1) + { + ++total_players; + if (!e.freezetag_frozen) ++yellowalive; + } + else if(e.team == COLOR_TEAM4 && e.health >= 1) + { + ++total_players; + if (!e.freezetag_frozen) ++pinkalive; + } + } + FOR_EACH_REALCLIENT(e) { + e.redalive_stat = redalive; + e.bluealive_stat = bluealive; + e.yellowalive_stat = yellowalive; + e.pinkalive_stat = pinkalive; + } +} +#define FREEZETAG_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0)) +#define FREEZETAG_ALIVE_TEAMS_OK() (FREEZETAG_ALIVE_TEAMS() == freezetag_teams) - FOR_EACH_PLAYER(e) +float prev_total_players; +float freezetag_CheckTeams() +{ + entity e; + if(FREEZETAG_ALIVE_TEAMS_OK()) { - if(e.freezetag_frozen == 0 && e.health >= 1) // here's one player from the winning team... good + if(prev_total_players != -1) { - winner = e; - break; // break, we found the winner + FOR_EACH_REALCLIENT(e) + Send_CSQC_Centerprint_Generic_Expire(e, CPID_WAITING_PLAYERS); } + prev_total_players = -1; + return 1; } + if(prev_total_players != total_players) + { + string teams_missing; + if(!redalive) teams_missing = strcat(teams_missing, ColoredTeamName(COLOR_TEAM1), ", "); + if(!bluealive) teams_missing = strcat(teams_missing, ColoredTeamName(COLOR_TEAM2), ", "); + if(freezetag_teams >= 3) + if(!yellowalive) teams_missing = strcat(teams_missing, ColoredTeamName(COLOR_TEAM3), ", "); + if(freezetag_teams == 4) + if(!pinkalive) teams_missing = strcat(teams_missing, ColoredTeamName(COLOR_TEAM4), ", "); + teams_missing = substring(teams_missing, 0, strlen(teams_missing)-2); + + FOR_EACH_REALCLIENT(e) + Send_CSQC_Centerprint_Generic(e, CPID_WAITING_PLAYERS, strcat("Waiting for players to join...\n\nNeed active players for: ", teams_missing), -1, 0); + prev_total_players = total_players; + } + return 0; +} - if(winner != world) // just in case a winner wasn't found +float freezetag_getWinnerTeam() +{ + float winner_team; + if(redalive >= 1) + winner_team = COLOR_TEAM1; + if(bluealive >= 1) { - if(winner.team == COLOR_TEAM1) - teamname = "^1Red Team"; - else if(winner.team == COLOR_TEAM2) - teamname = "^4Blue Team"; - else if(winner.team == COLOR_TEAM3) - teamname = "^3Yellow Team"; - else - teamname = "^6Pink Team"; - FOR_EACH_PLAYER(e) { - centerprint(e, strcat(teamname, "^5 wins the round, all other teams were frozen.\n")); - } + if(winner_team) return 0; + winner_team = COLOR_TEAM2; + } + if(yellowalive >= 1) + { + if(winner_team) return 0; + winner_team = COLOR_TEAM3; + } + if(pinkalive >= 1) + { + if(winner_team) return 0; + winner_team = COLOR_TEAM4; + } + if(winner_team) + return winner_team; + return -1; // no player left +} + +float freezetag_CheckWinner() +{ + entity e; + if(round_handler_GetTimeLeft() <= 0) + { + FOR_EACH_REALCLIENT(e) + centerprint(e, "Round over, there's no winner"); + bprint("Round over, there's no winner.\n"); + return 1; + } + + if(FREEZETAG_ALIVE_TEAMS() > 1) + return 0; + + float winner_team; + string teamname; + winner_team = freezetag_getWinnerTeam(); + if(winner_team > 0) + { + teamname = ColoredTeamName(winner_team); + FOR_EACH_REALCLIENT(e) + centerprint(e, strcat(teamname, "^5 wins the round, all other teams were frozen.")); bprint(teamname, "^5 wins the round since all the other teams were frozen.\n"); - TeamScore_AddToTeam(winner.team, ST_SCORE, +1); + TeamScore_AddToTeam(winner_team, ST_SCORE, +1); + } + else if(winner_team == -1) + { + FOR_EACH_REALCLIENT(e) + centerprint(e, "^5Round tied! All teams were frozen."); + bprint("^5Round tied! All teams were frozen.\n"); } - next_round = time + 5; + return 1; } // this is needed to allow the player to turn his view around (fixangle can't @@ -71,33 +154,22 @@ void freezetag_Ice_Think() self.nextthink = time; } -void freezetag_update_alive_stats() +void freezetag_Add_Score(entity attacker) { - entity e; - FOR_EACH_REALCLIENT(e) { - e.redalive_stat = redalive; - e.bluealive_stat = bluealive; - e.yellowalive_stat = yellowalive; - e.pinkalive_stat = pinkalive; + if(attacker == self) + { + // you froze your own dumb self + // counted as "suicide" already + PlayerScore_Add(self, SP_SCORE, -1); } -} - -void freezetag_add_alive() -{ - if(self.team == COLOR_TEAM1) ++redalive; - else if(self.team == COLOR_TEAM2) ++bluealive; - else if(self.team == COLOR_TEAM3) ++yellowalive; - else if(self.team == COLOR_TEAM4) ++pinkalive; - freezetag_update_alive_stats(); -} - -void freezetag_remove_alive() -{ - if(self.team == COLOR_TEAM1) --redalive; - else if(self.team == COLOR_TEAM2) --bluealive; - else if(self.team == COLOR_TEAM3) --yellowalive; - else if(self.team == COLOR_TEAM4) --pinkalive; - freezetag_update_alive_stats(); + else if(attacker.classname == "player") + { + // got frozen by an enemy + // counted as "kill" and "death" already + PlayerScore_Add(self, SP_SCORE, -1); + PlayerScore_Add(attacker, SP_SCORE, +1); + } + // else nothing - got frozen by the game type rules themselves } void freezetag_Freeze(entity attacker) @@ -107,8 +179,10 @@ void freezetag_Freeze(entity attacker) self.freezetag_frozen = 1; self.freezetag_revive_progress = 0; self.health = 1; - if(inWarmupStage) - self.freezetag_frozen_timeout = time + 5; + // if(inWarmupStage) + // self.freezetag_frozen_timeout = time + 5; + + freezetag_count_alive_players(); entity ice; ice = spawn(); @@ -130,23 +204,7 @@ void freezetag_Freeze(entity attacker) // add waypoint WaypointSprite_Spawn("freezetag_frozen", 0, 0, self, '0 0 64', world, self.team, self, waypointsprite_attached, TRUE, RADARICON_WAYPOINT, '0.25 0.90 1'); - if(attacker == self) - { - // you froze your own dumb self - // counted as "suicide" already - PlayerScore_Add(self, SP_SCORE, -1); - } - else if(attacker.classname == "player") - { - // got frozen by an enemy - // counted as "kill" and "death" already - PlayerScore_Add(self, SP_SCORE, -1); - PlayerScore_Add(attacker, SP_SCORE, +1); - } - else - { - // nothing - got frozen by the game type rules themselves - } + freezetag_Add_Score(attacker); } void freezetag_Unfreeze(entity attacker) @@ -154,7 +212,6 @@ void freezetag_Unfreeze(entity attacker) self.freezetag_frozen = 0; self.freezetag_frozen_timeout = 0; self.freezetag_revive_progress = 0; - self.health = autocvar_g_balance_health_start; // remove the ice block entity ice; @@ -280,38 +337,44 @@ void havocbot_role_ft_freeing() MUTATOR_HOOKFUNCTION(freezetag_RemovePlayer) { - if(self.freezetag_frozen == 0 && self.health >= 1) - freezetag_remove_alive(); - + self.health = 0; // neccessary to update correctly alive stats freezetag_Unfreeze(world); - - if(total_players > 2) // only check for winners if we had more than two players (one of them left, don't let the other player win just because of that) - freezetag_CheckWinner(); - + freezetag_count_alive_players(); return 1; } MUTATOR_HOOKFUNCTION(freezetag_PlayerDies) { - if(frag_deathtype == DEATH_HURTTRIGGER) + if(round_handler_IsActive()) + if(round_handler_CountdownRunning()) { + if(self.freezetag_frozen) + freezetag_Unfreeze(world); + freezetag_count_alive_players(); + return 1; // let the player die so that he can respawn whenever he wants + } + + // Cases DEATH_TEAMCHANGE and DEATH_AUTOTEAMCHANGE are needed to fix a bug whe + // you succeed changing team through the menu: you both really die (gibbing) and get frozen + if(ITEM_DAMAGE_NEEDKILL(frag_deathtype) + || frag_deathtype == DEATH_TEAMCHANGE || frag_deathtype == DEATH_AUTOTEAMCHANGE) + { + // let the player die, he will be automatically frozen when he respawns if(!self.freezetag_frozen) { - freezetag_remove_alive(); - freezetag_Freeze(world); - freezetag_CheckWinner(); + freezetag_Add_Score(frag_attacker); + freezetag_count_alive_players(); } - PutClientInServer(); // respawn the player - self.health = 1; - self.armorvalue = 0; - return 0; + else + freezetag_Unfreeze(world); // remove ice + self.freezetag_frozen_timeout = -2; // freeze on respawn + return 1; } - if(self.freezetag_frozen == 0) - { - freezetag_Freeze(frag_attacker); - freezetag_remove_alive(); - } + if(self.freezetag_frozen) + return 1; + + freezetag_Freeze(frag_attacker); if(frag_attacker == frag_target || frag_attacker == world) { @@ -330,55 +393,43 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerDies) frag_target.health = 1; // "respawn" the player :P - freezetag_CheckWinner(); - - return 0; + return 1; } MUTATOR_HOOKFUNCTION(freezetag_PlayerSpawn) { - if(self.freezetag_frozen) // stay frozen if respawning after death (DEATH_HURTTRIGGER) - return 1; - - freezetag_add_alive(); + if(self.freezetag_frozen_timeout == -1) // if PlayerSpawn is called by reset_map_players + return 1; // do nothing, round is starting right now - if(time <= game_starttime || inWarmupStage || total_players == 0) - return 1; - - if(total_players == 1) // only one player active on server, start a new match immediately - if(!next_round && warmup && (time < warmup - autocvar_g_freezetag_warmup || time > warmup)) // not awaiting next round + if(self.freezetag_frozen_timeout == -2) // player was dead { - next_round = time; + freezetag_Freeze(world); return 1; } - if(warmup && time > warmup) // spawn too late, freeze player + freezetag_count_alive_players(); + + if(round_handler_IsActive()) + if(round_handler_IsRoundStarted()) { centerprint(self, "^1Round already started, you spawn as frozen."); freezetag_Freeze(world); - freezetag_remove_alive(); } return 1; } -MUTATOR_HOOKFUNCTION(freezetag_reset_map_global) -{ - redalive = bluealive = yellowalive = pinkalive = 0; - warmup = max(time, game_starttime); - if(autocvar_g_freezetag_warmup > 0) - warmup += autocvar_g_freezetag_warmup; - return 1; -} - MUTATOR_HOOKFUNCTION(freezetag_reset_map_players) { FOR_EACH_PLAYER(self) { if (self.freezetag_frozen) freezetag_Unfreeze(world); + self.freezetag_frozen_timeout = -1; PutClientInServer(); + self.freezetag_frozen_timeout = 0; } + freezetag_count_alive_players(); return 1; } @@ -395,16 +446,24 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerPreThink) if(gameover) return 1; - if(self.freezetag_frozen && !self.freezetag_revive_progress) - self.health = 1; - if(self.freezetag_frozen_timeout && time >= self.freezetag_frozen_timeout) + + if(self.freezetag_frozen) { - freezetag_Unfreeze(world); - freezetag_add_alive(); - return 1; + // keep health = 1 + self.pauseregen_finished = time + autocvar_g_balance_pause_health_regen; + + if(self.freezetag_frozen_timeout > 0 && time >= self.freezetag_frozen_timeout) + { + self.health = autocvar_g_balance_health_start; + freezetag_Unfreeze(world); + freezetag_count_alive_players(); + return 1; + } } - if(next_round || (time > warmup - autocvar_g_freezetag_warmup && time < warmup)) - return 1; // already waiting for next round to start + + if(round_handler_IsActive()) + if(!round_handler_IsRoundStarted()) + return 1; revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size; @@ -435,7 +494,7 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerPreThink) if(self.freezetag_revive_progress >= 1) { freezetag_Unfreeze(self); - freezetag_add_alive(); + freezetag_count_alive_players(); // EVERY team mate nearby gets a point (even if multiple!) FOR_EACH_PLAYER(other) if(self != other) @@ -530,20 +589,38 @@ MUTATOR_HOOKFUNCTION(freezetag_BotRoles) return TRUE; } +MUTATOR_HOOKFUNCTION(freezetag_SpectateCopy) +{ + self.freezetag_frozen = other.freezetag_frozen; + self.freezetag_revive_progress = other.freezetag_revive_progress; + return 0; +} + +MUTATOR_HOOKFUNCTION(freezetag_GetTeamCount) +{ + freezetag_teams = autocvar_g_freezetag_teams_override; + if(freezetag_teams < 2) + freezetag_teams = autocvar_g_freezetag_teams; + freezetag_teams = bound(2, freezetag_teams, 4); + ret_float = freezetag_teams; + return 0; +} + MUTATOR_DEFINITION(gamemode_freezetag) { MUTATOR_HOOK(MakePlayerObserver, freezetag_RemovePlayer, CBC_ORDER_ANY); MUTATOR_HOOK(ClientDisconnect, freezetag_RemovePlayer, CBC_ORDER_ANY); MUTATOR_HOOK(PlayerDies, freezetag_PlayerDies, CBC_ORDER_ANY); MUTATOR_HOOK(PlayerSpawn, freezetag_PlayerSpawn, CBC_ORDER_ANY); - MUTATOR_HOOK(reset_map_global, freezetag_reset_map_global, CBC_ORDER_ANY); MUTATOR_HOOK(reset_map_players, freezetag_reset_map_players, CBC_ORDER_ANY); MUTATOR_HOOK(GiveFragsForKill, freezetag_GiveFragsForKill, CBC_ORDER_FIRST); MUTATOR_HOOK(PlayerPreThink, freezetag_PlayerPreThink, CBC_ORDER_FIRST); MUTATOR_HOOK(PlayerPhysics, freezetag_PlayerPhysics, CBC_ORDER_FIRST); MUTATOR_HOOK(PlayerDamage_Calculate, freezetag_PlayerDamage_Calculate, CBC_ORDER_ANY); - MUTATOR_HOOK(ForbidThrowCurrentWeapon, freezetag_ForbidThrowCurrentWeapon, CBC_ORDER_FIRST); //first, last or any? dunno. + MUTATOR_HOOK(ForbidThrowCurrentWeapon, freezetag_ForbidThrowCurrentWeapon, CBC_ORDER_ANY); MUTATOR_HOOK(HavocBot_ChooseRule, freezetag_BotRoles, CBC_ORDER_ANY); + MUTATOR_HOOK(SpectateCopy, freezetag_SpectateCopy, CBC_ORDER_ANY); + MUTATOR_HOOK(GetTeamCount, freezetag_GetTeamCount, CBC_ORDER_EXCLUSIVE); MUTATOR_ONADD {