From: terencehill Date: Sun, 19 Oct 2014 16:14:04 +0000 (+0200) Subject: Merge branch 'master' into terencehill/ca_fixes X-Git-Tag: xonotic-v0.8.0~126^2~8 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=commitdiff_plain;h=49e5f5d2c7423c3c4536a57e6740d79d9b8eec94;hp=14f88293289444c9a39357a88c1980c019733eff Merge branch 'master' into terencehill/ca_fixes --- diff --git a/gamemodes.cfg b/gamemodes.cfg index dfc240536e..c5cfa05291 100644 --- a/gamemodes.cfg +++ b/gamemodes.cfg @@ -203,10 +203,10 @@ set g_assault 0 "Assault: attack the enemy base as fast as you can, then defend // ============ // clan arena // ============ -set g_ca 0 "Clan Arena: Played in rounds, once you're dead you're out! The team with survivors wins the round." -set g_ca_point_limit 10 "point limit 10 is standard for clan arena" -set g_ca_point_leadlimit 0 -set g_ca_spectate_enemies 0 "Allow spectating enemy player by dead player during clan arena games." +set g_ca 0 "Clan Arena: Played in rounds, once you're dead you're out! The team with survivors wins the round" +seta g_ca_point_limit -1 "Clan Arena point limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)" +seta g_ca_point_leadlimit -1 "Clan Arena point lead limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)" +set g_ca_spectate_enemies 0 "Allow spectating enemy player by dead player during clan arena games" set g_ca_warmup 10 "how long the players will have time to run around the map before the round starts" set g_ca_damage2score_multiplier 0.01 set g_ca_round_timelimit 180 "round time limit in seconds" diff --git a/qcsrc/common/mapinfo.qh b/qcsrc/common/mapinfo.qh index 3c0afec982..e381513ca5 100644 --- a/qcsrc/common/mapinfo.qh +++ b/qcsrc/common/mapinfo.qh @@ -51,7 +51,7 @@ REGISTER_GAMETYPE(_("Team Deathmatch"),tdm,g_tdm,TEAM_DEATHMATCH,"timelimit=20 p REGISTER_GAMETYPE(_("Capture the Flag"),ctf,g_ctf,CTF,"timelimit=20 caplimit=10 leadlimit=0"); #define g_ctf IS_GAMETYPE(CTF) -REGISTER_GAMETYPE(_("Clan Arena"),ca,g_ca,CA,"timelimit=20 pointlimit=10 leadlimit=0"); +REGISTER_GAMETYPE(_("Clan Arena"),ca,g_ca,CA,"timelimit=20 pointlimit=10 teams=2 leadlimit=0"); #define g_ca IS_GAMETYPE(CA) REGISTER_GAMETYPE(_("Domination"),dom,g_domination,DOMINATION,"timelimit=20 pointlimit=200 teams=2 leadlimit=0"); diff --git a/qcsrc/common/notifications.qh b/qcsrc/common/notifications.qh index 117965f7bb..d05c6babda 100644 --- a/qcsrc/common/notifications.qh +++ b/qcsrc/common/notifications.qh @@ -429,6 +429,8 @@ void Send_Notification_WOCOVA( MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VH_WAKI_ROCKET, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 couldn't find shelter from a Racer rocket%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VOID, 2, 1, "s1 s2loc spree_lost", "s1", "notify_void", _("^BG%s^K1 was in the wrong place%s%s"), "") \ MULTITEAM_INFO(1, INFO_DEATH_TEAMKILL_, 4, 3, 1, "s1 s2 s3loc spree_end", "s2 s1", "notify_teamkill_%s", _("^BG%s^K1 was betrayed by ^BG%s^K1%s%s"), "") \ + MSG_INFO_NOTIF(1, INFO_CA_JOIN_LATE, 0, 0, "", "", "", _("^F1Round already started, you will join the game in the next round"), "") \ + MSG_INFO_NOTIF(1, INFO_CA_LEAVE, 0, 0, "", "", "", _("^F2You will spectate in the next round"), "") \ MSG_INFO_NOTIF(1, INFO_FREEZETAG_FREEZE, 2, 0, "s1 s2", "", "", _("^BG%s^K1 was frozen by ^BG%s"), "") \ MSG_INFO_NOTIF(1, INFO_FREEZETAG_REVIVED, 2, 0, "s1 s2", "", "", _("^BG%s^K3 was revived by ^BG%s"), "") \ MSG_INFO_NOTIF(1, INFO_FREEZETAG_REVIVED_FALL, 1, 0, "s1", "", "", _("^BG%s^K3 was revived by falling"), "") \ @@ -545,6 +547,7 @@ void Send_Notification_WOCOVA( MULTITEAM_CENTER##teams(default,prefix,strnum,flnum,args,cpid,durcnt,normal,gentle) #define MSG_CENTER_NOTIFICATIONS \ + MSG_CENTER_NOTIF(1, CENTER_ALONE, 0, 0, "", NO_CPID, "0 0", _("^F4You are now alone!"), "") \ MSG_CENTER_NOTIF(1, CENTER_ASSAULT_ATTACKING, 0, 0, "", CPID_ASSAULT_ROLE, "0 0", _("^BGYou are attacking!"), "") \ MSG_CENTER_NOTIF(1, CENTER_ASSAULT_DEFENDING, 0, 0, "", CPID_ASSAULT_ROLE, "0 0", _("^BGYou are defending!"), "") \ MSG_CENTER_NOTIF(1, CENTER_COUNTDOWN_BEGIN, 0, 0, "", CPID_ROUND, "2 0", _("^F4Begin!"), "") \ @@ -645,8 +648,8 @@ void Send_Notification_WOCOVA( MSG_CENTER_NOTIF(1, CENTER_KEYHUNT_ROUNDSTART, 0, 1, "", CPID_KEYHUNT_OTHER, "1 f1", _("^F4Round will start in ^COUNT"), "") \ MSG_CENTER_NOTIF(1, CENTER_KEYHUNT_SCAN, 0, 1, "", CPID_KEYHUNT_OTHER, "f1 0", _("^BGScanning frequency range..."), "") \ MULTITEAM_CENTER(1, CENTER_KEYHUNT_START_, 4, 0, 0, "", CPID_KEYHUNT, "0 0", _("^BGYou are starting with the ^TC^TT Key"), "") \ - MSG_CENTER_NOTIF(1, CENTER_KEYHUNT_WAIT, 0, 4, "missing_teams", CPID_KEYHUNT_OTHER, "0 0", _("^BGWaiting for players to join...\nNeed active players for: %s"), "") \ - MSG_CENTER_NOTIF(1, CENTER_MISSING_TEAMS, 0, 4, "missing_teams", CPID_MISSING_TEAMS, "-1 0", _("^BGWaiting for players to join...\nNeed active players for: %s"), "") \ + MSG_CENTER_NOTIF(1, CENTER_KEYHUNT_WAIT, 0, 1, "missing_teams", CPID_KEYHUNT_OTHER, "0 0", _("^BGWaiting for players to join...\nNeed active players for: %s"), "") \ + MSG_CENTER_NOTIF(1, CENTER_MISSING_TEAMS, 0, 1, "missing_teams", CPID_MISSING_TEAMS, "-1 0", _("^BGWaiting for players to join...\nNeed active players for: %s"), "") \ MSG_CENTER_NOTIF(1, CENTER_MISSING_PLAYERS, 0, 1, "f1", CPID_MISSING_PLAYERS, "-1 0", _("^BGWaiting for %s player(s) to join..."), "") \ MSG_CENTER_NOTIF(1, CENTER_MINSTA_FINDAMMO, 0, 0, "", CPID_MINSTA_FINDAMMO, "1 9", _("^F4^COUNT^BG left to find some ammo!"), "") \ MSG_CENTER_NOTIF(1, CENTER_MINSTA_FINDAMMO_FIRST, 0, 0, "", CPID_MINSTA_FINDAMMO, "1 10", _("^BGGet some ammo or you'll be dead in ^F4^COUNT^BG!"), _("^BGGet some ammo! ^F4^COUNT^BG left!")) \ @@ -976,7 +979,7 @@ string arg_slot[NOTIF_MAX_ARGS]; ARG_CASE(ARG_CS_SV_HA, "f3race_time", mmssss(f3)) \ ARG_CASE(ARG_CS_SV, "race_col", CCR(((f1 == 1) ? "^F1" : "^F2"))) \ ARG_CASE(ARG_CS_SV, "race_diff", ((f2 > f3) ? sprintf(CCR("^1[+%s]"), mmssss(f2 - f3)) : sprintf(CCR("^2[-%s]"), mmssss(f3 - f2)))) \ - ARG_CASE(ARG_CS, "missing_teams", notif_arg_missing_teams(f1, f2, f3, f4)) \ + ARG_CASE(ARG_CS, "missing_teams", notif_arg_missing_teams(f1)) \ ARG_CASE(ARG_CS, "pass_key", ((((tmp_s = getcommandkey("pass", "+use")) != "pass") && !(strstrofs(tmp_s, "not bound", 0) >= 0)) ? sprintf(CCR(_(" ^F1(Press %s)")), tmp_s) : "")) \ ARG_CASE(ARG_CS, "frag_ping", notif_arg_frag_ping(TRUE, f2)) \ ARG_CASE(ARG_CS, "frag_stats", notif_arg_frag_stats(f2, f3, f4)) \ @@ -1020,26 +1023,26 @@ string notif_arg_frag_stats(float fhealth, float farmor, float fping) return sprintf(CCR(_("\n(^F4Dead^BG)%s")), notif_arg_frag_ping(FALSE, fping)); } -string notif_arg_missing_teams(float f1, float f2, float f3, float f4) +string notif_arg_missing_teams(float f1) { return sprintf("%s%s%s%s", - (f1 ? - sprintf("%s%s", Team_ColoredFullName(f1 - 1), ((f2 + f3 + f4) ? ", " : "")) + ((f1 & 1) ? + sprintf("%s%s", Team_ColoredFullName(NUM_TEAM_1), ((f1 & (2 + 4 + 8)) ? ", " : "")) : "" ), - (f2 ? - sprintf("%s%s", Team_ColoredFullName(f2 - 1), ((f3 + f4) ? ", " : "")) + ((f1 & 2) ? + sprintf("%s%s", Team_ColoredFullName(NUM_TEAM_2), ((f1 & (4 + 8)) ? ", " : "")) : "" ), - (f3 ? - sprintf("%s%s", Team_ColoredFullName(f3 - 1), (f4 ? ", " : "")) + ((f1 & 4) ? + sprintf("%s%s", Team_ColoredFullName(NUM_TEAM_3), ((f1 & 8) ? ", " : "")) : "" ), - (f4 ? - Team_ColoredFullName(f4 - 1) + ((f1 & 8) ? + Team_ColoredFullName(NUM_TEAM_4) : "" ) diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index 4ab1836e8c..718518231f 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -265,6 +265,7 @@ void PutObserverInServer (void) self.punchvector = '0 0 0'; self.oldvelocity = self.velocity; self.fire_endtime = -1; + self.event_damage = func_null; } .float model_randomizer; @@ -786,8 +787,8 @@ void ClientKill_Now() if(self.killindicator_teamchange) ClientKill_Now_TeamChange(); - // in any case: - Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0'); + if(IS_PLAYER(self)) + Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0'); // now I am sure the player IS dead } @@ -1991,7 +1992,7 @@ float nJoinAllowed(entity ignore) { float currentlyPlaying = 0; FOR_EACH_REALCLIENT(e) - if(IS_PLAYER(e) || e.caplayer == 1) + if(IS_PLAYER(e) || e.caplayer) currentlyPlaying += 1; if(currentlyPlaying < autocvar_g_maxplayers) @@ -2005,7 +2006,10 @@ float nJoinAllowed(entity ignore) { * g_maxplayers_spectator_blocktime seconds */ void checkSpectatorBlock() { - if(IS_SPEC(self) || IS_OBSERVER(self)) { + if(IS_SPEC(self) || IS_OBSERVER(self)) + if(!self.caplayer) + if(IS_REAL_CLIENT(self)) + { if( time > (self.spectatortime + autocvar_g_maxplayers_spectator_blocktime) ) { Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_QUIT_KICK_SPECTATING); dropclient(self); diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc index 0fe71f1448..8c61d6f568 100644 --- a/qcsrc/server/cl_player.qc +++ b/qcsrc/server/cl_player.qc @@ -336,6 +336,9 @@ void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float void calculate_player_respawn_time() { + if(g_ca) + return; + float gametype_setting_tmp; float sdelay_max = GAMETYPE_DEFAULTED_SETTING(respawn_delay_max); float sdelay_small = GAMETYPE_DEFAULTED_SETTING(respawn_delay_small); @@ -708,6 +711,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht self.flags &= ~FL_ONGROUND; // dying animation self.deadflag = DEAD_DYING; + // when to allow respawn calculate_player_respawn_time(); diff --git a/qcsrc/server/command/cmd.qc b/qcsrc/server/command/cmd.qc index 78424484aa..cb6884b0f5 100644 --- a/qcsrc/server/command/cmd.qc +++ b/qcsrc/server/command/cmd.qc @@ -152,6 +152,8 @@ void ClientCommand_join(float request) { if(!IS_PLAYER(self) && !lockteams) { + if(self.caplayer) + return; if(nJoinAllowed(self)) { if(autocvar_g_campaign) { campaign_bots_may_start = 1; } @@ -580,15 +582,11 @@ void ClientCommand_spectate(float request) } } - if(IS_PLAYER(self) && autocvar_sv_spectate == 1) - ClientKill_TeamChange(-2); // observe - - // in CA, allow a dead player to move to spectators (without that, caplayer!=0 will be moved back to the player list) - // note: if arena game mode is ever done properly, this needs to be removed. - if(self.caplayer && (IS_SPEC(self) || IS_OBSERVER(self))) + if((IS_PLAYER(self) || self.caplayer) && autocvar_sv_spectate == 1) { - sprint(self, "WARNING: you will spectate in the next round.\n"); - self.caplayer = 0; + if(self.caplayer && (IS_SPEC(self) || IS_OBSERVER(self))) + Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_CA_LEAVE); + ClientKill_TeamChange(-2); // observe } } return; // never fall through to usage diff --git a/qcsrc/server/command/sv_cmd.qc b/qcsrc/server/command/sv_cmd.qc index c0da029c51..edeb571c0d 100644 --- a/qcsrc/server/command/sv_cmd.qc +++ b/qcsrc/server/command/sv_cmd.qc @@ -213,6 +213,8 @@ void GameCommand_allspec(float request, float argc) FOR_EACH_REALPLAYER(client) { self = client; + if(self.caplayer) + self.caplayer = 0; PutObserverInServer(); ++i; } @@ -1045,6 +1047,8 @@ void GameCommand_moveplayer(float request, float argc) if(!IS_SPEC(client) && !IS_OBSERVER(client)) { self = client; + if(self.caplayer) + self.caplayer = 0; PutObserverInServer(); successful = strcat(successful, (successful ? ", " : ""), client.netname); @@ -1150,9 +1154,10 @@ void GameCommand_nospectators(float request) { blockSpectators = 1; entity plr; - FOR_EACH_CLIENT(plr) //give every spectator seconds time to become a player + FOR_EACH_REALCLIENT(plr) //give every spectator seconds time to become a player { if(IS_SPEC(plr) || IS_OBSERVER(plr)) + if(!plr.caplayer) { plr.spectatortime = time; Send_Notification(NOTIF_ONE_ONLY, plr, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime); diff --git a/qcsrc/server/mutators/gamemode_ca.qc b/qcsrc/server/mutators/gamemode_ca.qc index 8a6315c423..76419d8387 100644 --- a/qcsrc/server/mutators/gamemode_ca.qc +++ b/qcsrc/server/mutators/gamemode_ca.qc @@ -106,29 +106,32 @@ void CA_RoundStart() allowed_to_spawn = FALSE; } -float prev_total_players; +float prev_missing_teams_mask; float CA_CheckTeams() { allowed_to_spawn = TRUE; CA_count_alive_players(); if(CA_ALIVE_TEAMS_OK()) { - if(prev_total_players > 0) + if(prev_missing_teams_mask > 0) Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_MISSING_TEAMS); - prev_total_players = -1; + prev_missing_teams_mask = -1; return 1; } - if(prev_total_players != total_players) + if(total_players == 0) { - float p1 = 0, p2 = 0, p3 = 0, p4 = 0; - if(!redalive) p1 = NUM_TEAM_1; - if(!bluealive) p2 = NUM_TEAM_2; - if(ca_teams >= 3) - if(!yellowalive) p3 = NUM_TEAM_3; - if(ca_teams >= 4) - if(!pinkalive) p4 = NUM_TEAM_4; - Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_MISSING_TEAMS, p1, p2, p3, p4); - prev_total_players = total_players; + if(prev_missing_teams_mask > 0) + Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_MISSING_TEAMS); + prev_missing_teams_mask = -1; + return 0; + } + float missing_teams_mask = (!redalive) + (!bluealive) * 2; + if(ca_teams >= 3) missing_teams_mask += (!yellowalive) * 4; + if(ca_teams >= 4) missing_teams_mask += (!pinkalive) * 8; + if(prev_missing_teams_mask != missing_teams_mask) + { + Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask); + prev_missing_teams_mask = missing_teams_mask; } return 0; } @@ -142,6 +145,7 @@ MUTATOR_HOOKFUNCTION(ca_PlayerSpawn) MUTATOR_HOOKFUNCTION(ca_PutClientInServer) { if(!allowed_to_spawn) + if(IS_PLAYER(self)) // this is true even when player is trying to join { self.classname = "observer"; if(self.jointime != time) //not when connecting @@ -149,7 +153,7 @@ MUTATOR_HOOKFUNCTION(ca_PutClientInServer) { self.caplayer = 0.5; if(IS_REAL_CLIENT(self)) - sprint(self, "You will join the game in the next round.\n"); + Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_CA_JOIN_LATE); } } return 1; @@ -160,6 +164,11 @@ MUTATOR_HOOKFUNCTION(ca_reset_map_players) FOR_EACH_CLIENT(self) { self.killcount = 0; + if(!self.caplayer && IS_BOT_CLIENT(self)) + { + self.team = -1; + self.caplayer = 1; + } if(self.caplayer) { self.classname = "player"; @@ -188,13 +197,48 @@ MUTATOR_HOOKFUNCTION(ca_GetTeamCount) return 0; } +entity ca_LastPlayerForTeam() +{ + entity pl, last_pl = world; + FOR_EACH_PLAYER(pl) + { + if(pl.health >= 1) + if(pl != self) + if(pl.team == self.team) + if(!last_pl) + last_pl = pl; + else + return world; + } + return last_pl; +} + +void ca_LastPlayerForTeam_Notify() +{ + if(round_handler_IsActive()) + if(round_handler_IsRoundStarted()) + { + entity pl = ca_LastPlayerForTeam(); + if(pl) + Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_ALONE); + } +} + MUTATOR_HOOKFUNCTION(ca_PlayerDies) { + ca_LastPlayerForTeam_Notify(); if(!allowed_to_spawn) self.respawn_flags = RESPAWN_SILENT; return 1; } +MUTATOR_HOOKFUNCTION(ca_ClientDisconnect) +{ + if(self.caplayer == 1) + ca_LastPlayerForTeam_Notify(); + return 1; +} + MUTATOR_HOOKFUNCTION(ca_ForbidPlayerScore_Clear) { return 1; @@ -202,6 +246,8 @@ MUTATOR_HOOKFUNCTION(ca_ForbidPlayerScore_Clear) MUTATOR_HOOKFUNCTION(ca_MakePlayerObserver) { + if(self.caplayer == 1) + ca_LastPlayerForTeam_Notify(); if(self.killindicator_teamchange == -2) self.caplayer = 0; if(self.caplayer) @@ -304,6 +350,7 @@ MUTATOR_DEFINITION(gamemode_ca) MUTATOR_HOOK(reset_map_players, ca_reset_map_players, CBC_ORDER_ANY); MUTATOR_HOOK(GetTeamCount, ca_GetTeamCount, CBC_ORDER_EXCLUSIVE); MUTATOR_HOOK(PlayerDies, ca_PlayerDies, CBC_ORDER_ANY); + MUTATOR_HOOK(ClientDisconnect, ca_ClientDisconnect, CBC_ORDER_ANY); MUTATOR_HOOK(ForbidPlayerScore_Clear, ca_ForbidPlayerScore_Clear, CBC_ORDER_ANY); MUTATOR_HOOK(ForbidThrowCurrentWeapon, ca_ForbidThrowCurrentWeapon, CBC_ORDER_ANY); MUTATOR_HOOK(GiveFragsForKill, ca_GiveFragsForKill, CBC_ORDER_FIRST); diff --git a/qcsrc/server/mutators/gamemode_freezetag.qc b/qcsrc/server/mutators/gamemode_freezetag.qc index 26e19910ad..5280e559bb 100644 --- a/qcsrc/server/mutators/gamemode_freezetag.qc +++ b/qcsrc/server/mutators/gamemode_freezetag.qc @@ -42,27 +42,30 @@ void freezetag_count_alive_players() #define FREEZETAG_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0)) #define FREEZETAG_ALIVE_TEAMS_OK() (FREEZETAG_ALIVE_TEAMS() == freezetag_teams) -float prev_total_players; +float prev_missing_teams_mask; float freezetag_CheckTeams() { if(FREEZETAG_ALIVE_TEAMS_OK()) { - if(prev_total_players > 0) + if(prev_missing_teams_mask > 0) Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_MISSING_TEAMS); - prev_total_players = -1; + prev_missing_teams_mask = -1; return 1; } - if(prev_total_players != total_players) + if(total_players == 0) { - float p1 = 0, p2 = 0, p3 = 0, p4 = 0; - if(!redalive) p1 = NUM_TEAM_1; - if(!bluealive) p2 = NUM_TEAM_2; - if(freezetag_teams >= 3) - if(!yellowalive) p3 = NUM_TEAM_3; - if(freezetag_teams >= 4) - if(!pinkalive) p4 = NUM_TEAM_4; - Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_MISSING_TEAMS, p1, p2, p3, p4); - prev_total_players = total_players; + if(prev_missing_teams_mask > 0) + Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_MISSING_TEAMS); + prev_missing_teams_mask = -1; + return 0; + } + float missing_teams_mask = (!redalive) + (!bluealive) * 2; + if(freezetag_teams >= 3) missing_teams_mask += (!yellowalive) * 4; + if(freezetag_teams >= 4) missing_teams_mask += (!pinkalive) * 8; + if(prev_missing_teams_mask != missing_teams_mask) + { + Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask); + prev_missing_teams_mask = missing_teams_mask; } return 0; } @@ -134,6 +137,34 @@ float freezetag_CheckWinner() return 1; } +entity freezetag_LastPlayerForTeam() +{ + entity pl, last_pl = world; + FOR_EACH_PLAYER(pl) + { + if(pl.health >= 1) + if(!pl.freezetag_frozen) + if(pl != self) + if(pl.team == self.team) + if(!last_pl) + last_pl = pl; + else + return world; + } + return last_pl; +} + +void freezetag_LastPlayerForTeam_Notify() +{ + if(round_handler_IsActive()) + if(round_handler_IsRoundStarted()) + { + entity pl = freezetag_LastPlayerForTeam(); + if(pl) + Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_ALONE); + } +} + // this is needed to allow the player to turn his view around (fixangle can't // be used to freeze his view, as that also changes the angles), while not // turning that ice object with the player @@ -322,6 +353,8 @@ void havocbot_role_ft_freeing() MUTATOR_HOOKFUNCTION(freezetag_RemovePlayer) { self.health = 0; // neccessary to update correctly alive stats + if(!self.freezetag_frozen) + freezetag_LastPlayerForTeam_Notify(); freezetag_Unfreeze(world); freezetag_count_alive_players(); return 1; @@ -348,6 +381,7 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerDies) { freezetag_Add_Score(frag_attacker); freezetag_count_alive_players(); + freezetag_LastPlayerForTeam_Notify(); } else freezetag_Unfreeze(world); // remove ice @@ -359,6 +393,7 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerDies) return 1; freezetag_Freeze(frag_attacker); + freezetag_LastPlayerForTeam_Notify(); if(frag_attacker == frag_target || frag_attacker == world) { diff --git a/qcsrc/server/mutators/gamemode_invasion.qc b/qcsrc/server/mutators/gamemode_invasion.qc index 8448a215e9..364cb7fe3b 100644 --- a/qcsrc/server/mutators/gamemode_invasion.qc +++ b/qcsrc/server/mutators/gamemode_invasion.qc @@ -416,8 +416,6 @@ void invasion_DelayedInit() // Do this check with a delay so we can wait for tea round_handler_Spawn(Invasion_CheckPlayers, Invasion_CheckWinner, Invasion_RoundStart); round_handler_Init(5, autocvar_g_invasion_warmup, autocvar_g_invasion_round_timelimit); - allowed_to_spawn = TRUE; - inv_roundcnt = 0; inv_maxrounds = 15; // 15? }