From: LegendaryGuard Date: Wed, 5 Jan 2022 18:18:09 +0000 (+0100) Subject: Merge branch 'master' into LegendaryGuard/cyber X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=ea7a3b717331f01a459bf8e19a6ae259987a8fe2;p=xonotic%2Fxonotic-data.pk3dir.git Merge branch 'master' into LegendaryGuard/cyber --- ea7a3b717331f01a459bf8e19a6ae259987a8fe2 diff --cc qcsrc/client/hud/panel/timer.qc index a48776602,035d21b60..906e942ad --- a/qcsrc/client/hud/panel/timer.qc +++ b/qcsrc/client/hud/panel/timer.qc @@@ -38,23 -36,14 +38,23 @@@ void HUD_Timer( mySize -= '2 2 0' * panel_bg_padding; } - string timer; - float timelimit, timeleft, minutesLeft; + string timer_sub = ""; + float timelimit, timeleft, minutesLeft, overtimes, timeout_last; timelimit = STAT(TIMELIMIT); + overtimes = STAT(OVERTIMESADDED); + timeout_last = STAT(TIMEOUT_LAST); - timeleft = max(0, timelimit * 60 + STAT(GAMESTARTTIME) - time); + timeleft = bound(0, timelimit * 60 + STAT(GAMESTARTTIME) - time, timelimit * 60); timeleft = ceil(timeleft); + // countdown sound + if(autocvar_hud_panel_timer_count && timeleft > 0 && timeleft != last_timeleft && timeleft <= 10) + { + sound(NULL, CH_INFO, SND_ENDCOUNT, VOL_BASE, ATTN_NONE); + last_timeleft = timeleft; + } + minutesLeft = floor(timeleft / 60); float warmup_timeleft = 0; diff --cc qcsrc/common/gamemodes/gamemode/clanarena/sv_clanarena.qc index 446995d4f,866a00419..087d9b1bf --- a/qcsrc/common/gamemodes/gamemode/clanarena/sv_clanarena.qc +++ b/qcsrc/common/gamemodes/gamemode/clanarena/sv_clanarena.qc @@@ -42,49 -40,8 +47,24 @@@ void CA_count_alive_players( }); } - int CA_GetWinnerTeam() - { - int winner_team = 0; - if (Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(1)) >= 1) - { - winner_team = NUM_TEAM_1; - } - for (int i = 2; i <= NUM_TEAMS; ++i) - { - if (Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(i)) >= 1) - { - if (winner_team != 0) - { - return 0; - } - winner_team = Team_IndexToTeam(i); - } - } - if (winner_team) - { - return winner_team; - } - return -1; // no player left - } - void nades_Clear(entity player); +entity ca_LastPlayer(float tm) +{ + entity last_pl = NULL; + FOREACH_CLIENT(IS_PLAYER(it) && it.team == tm, { + if (!IS_DEAD(it)) + { + if (!last_pl) + last_pl = it; + else + return NULL; + } + }); + return last_pl; +} + + float CA_CheckWinner() { if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0) @@@ -102,30 -57,15 +82,28 @@@ } CA_count_alive_players(); - if (Team_GetNumberOfAliveTeams() > 1) - { + int winner_team = Team_GetWinnerAliveTeam(); + if (!winner_team) return 0; - } -- - int winner_team = CA_GetWinnerTeam(); ++ + bool perfect = false; if(winner_team > 0) { + entity tm = Team_GetTeam(winner_team); + entity last_pl = ca_LastPlayer(winner_team); + + if(last_pl && Team_GetNumberOfPlayers(tm) >= 3) { + Give_Medal(last_pl, DEFENSE); + } + Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN)); Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN)); + if(fragsleft > 1) Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, APP_TEAM_NUM(winner_team, ANNCE_ROUND_TEAM_WIN)); TeamScore_AddToTeam(winner_team, ST_CA_ROUNDS, +1); + + if (Team_GetNumberOfPlayers(tm) >= 3 && + Team_GetNumberOfAlivePlayers(tm) == Team_GetNumberOfPlayers(tm)) + perfect = true; } else if(winner_team == -1) { diff --cc qcsrc/common/gamemodes/gamemode/freezetag/sv_freezetag.qc index 93e291b24,58fd90c89..fbf6cd451 --- a/qcsrc/common/gamemodes/gamemode/freezetag/sv_freezetag.qc +++ b/qcsrc/common/gamemodes/gamemode/freezetag/sv_freezetag.qc @@@ -140,23 -102,15 +120,21 @@@ bool freezetag_CheckWinner( return true; } - if (Team_GetNumberOfAliveTeams() > 1) - { + int winner_team = Team_GetWinnerAliveTeam(); + if (!winner_team) return false; - } - int winner_team = freezetag_getWinnerTeam(); if(winner_team > 0) { - Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN)); - Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN)); + entity last_pl = freezetag_LastPlayer(winner_team); + if(last_pl) { + Give_Medal(last_pl, DEFENSE); + } + + Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_SCORES)); + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_SCORES)); TeamScore_AddToTeam(winner_team, ST_FT_ROUNDS, +1); + if(fragsleft > 1) AnnounceScores(winner_team); } else if(winner_team == -1) { diff --cc qcsrc/server/chat.qc index 82da61ff2,a73de2a1f..33a2e406f --- a/qcsrc/server/chat.qc +++ b/qcsrc/server/chat.qc @@@ -323,12 -315,10 +323,12 @@@ int Say(entity source, int teamsay, ent { sprint(source, sourcemsgstr); dedicated_print(msgstr); // send to server console too - FOREACH_CLIENT(!(IS_PLAYER(it) || it.caplayer) && IS_REAL_CLIENT(it) && it != source && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), { + FOREACH_CLIENT(!(IS_PLAYER(it) || INGAME(it)) && IS_REAL_CLIENT(it) && it != source && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), { sprint(it, msgstr); }); - event_log_msg = sprintf(":chat_spec:%d:%s", source.playerid, strreplace("\n", " ", msgin)); + + if(!play_chatsound(source, msgin)) + event_log_msg = sprintf(":chat_spec:%d:%s", source.playerid, strreplace("\n", " ", msgin)); } else { diff --cc qcsrc/server/command/cmd.qc index 961059738,c9ceb31b6..17e237114 --- a/qcsrc/server/command/cmd.qc +++ b/qcsrc/server/command/cmd.qc @@@ -372,31 -372,17 +372,17 @@@ void ClientCommand_ready(entity caller { case CMD_REQUEST_COMMAND: { - if (IS_CLIENT(caller)) + if (IS_CLIENT(caller) && caller.last_ready < time - 3) // anti-spam { - if (warmup_stage || autocvar_sv_ready_restart || g_race_qualifying == 2) + if (warmup_stage || g_race_qualifying == 2) { - if (!readyrestart_happened || autocvar_sv_ready_restart_repeatable) + if (time < game_starttime) // game is already restarting + return; + if (caller.ready) // toggle { - if (time < game_starttime) // game is already restarting - return; - if (caller.ready) // toggle - { - caller.ready = false; - if(IS_PLAYER(caller) || caller.caplayer == 1) - bprint("\{1}", playername(caller.netname, caller.team, false), "^2 is ^1NOT^2 ready\n"); - } - else - { - caller.ready = true; - if(IS_PLAYER(caller) || caller.caplayer == 1) - bprint("\{1}", playername(caller.netname, caller.team, false), "^2 is ready\n"); - } - - caller.last_ready = time; - - // cannot reset the game while a timeout is active! - if (!timeout_status) ReadyCount(); + caller.ready = false; + if (IS_PLAYER(caller) || INGAME_JOINED(caller)) + bprint(playername(caller.netname, caller.team, false), "^2 is ^1NOT^2 ready\n"); } else { diff --cc qcsrc/server/command/sv_cmd.qc index 9b72f7a3f,ca6b268e2..d2a143bad --- a/qcsrc/server/command/sv_cmd.qc +++ b/qcsrc/server/command/sv_cmd.qc @@@ -1708,11 -1651,8 +1739,11 @@@ void GameCommand_(int request // ================================== // Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;) +SERVER_COMMAND(setflag, "Set client flag") { GameCommand_setflag(request, arguments); } +SERVER_COMMAND(teamname, "Set team name") { GameCommand_teamname(request, arguments); } + SERVER_COMMAND(adminmsg, "Send an admin message to a client directly") { GameCommand_adminmsg(request, arguments); } - SERVER_COMMAND(allready, "Restart the server and reset the players") { GameCommand_allready(request); } + SERVER_COMMAND(allready, "Ends warmup and starts the match") { GameCommand_allready(request); } SERVER_COMMAND(allspec, "Force all players to spectate") { GameCommand_allspec(request, arguments); } SERVER_COMMAND(anticheat, "Create an anticheat report for a client") { GameCommand_anticheat(request, arguments); } SERVER_COMMAND(animbench, "Benchmark model animation (LAGS)") { GameCommand_animbench(request, arguments); } diff --cc qcsrc/server/command/vote.qc index a179438ce,6b39ab7b6..b5b97b00b --- a/qcsrc/server/command/vote.qc +++ b/qcsrc/server/command/vote.qc @@@ -420,10 -414,8 +418,9 @@@ void reset_map(bool dorespawn, bool is_ // Restarts the map after the countdown is over (and cvar sv_ready_restart_after_countdown is set) void ReadyRestart_think(entity this) { - restart_mapalreadyrestarted = true; - reset_map(true); + reset_map(true, false); Score_ClearAll(); + Inventory_ClearAll(); delete(this); } @@@ -449,22 -443,14 +448,17 @@@ void ReadyRestart_force(bool is_fake_ro FOREACH_CLIENT(IS_PLAYER(it), { it.alivetime = 0; CS(it).killcount = 0; - float val = PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_ALIVETIME, 0); - PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_ALIVETIME, -val); }); - restart_mapalreadyrestarted = false; // reset this var, needed when cvar sv_ready_restart_repeatable is in use - - // disable the warmup global for the server - if(warmup_stage) + // if we're ending the warmup stage call the corresponding hook + if(!is_fake_round_start && !warmup_stage) localcmd("\nsv_hook_warmupend\n"); - warmup_stage = 0; // once the game is restarted the game is in match stage // reset the .ready status of all players (also spectators) - FOREACH_CLIENT(IS_REAL_CLIENT(it), { it.ready = false; }); + FOREACH_CLIENT(IS_REAL_CLIENT(it), { + it.ready = false; + Kill_Notification(NOTIF_ONE_ONLY, it, MSG_CENTER, CPID_MISSING_READY); + }); readycount = 0; Nagger_ReadyCounted(); // NOTE: this causes a resend of that entity, and will also turn off warmup state on the client diff --cc qcsrc/server/command/vote.qh index 156021b8f,63c9e8e45..355f241ef --- a/qcsrc/server/command/vote.qh +++ b/qcsrc/server/command/vote.qh @@@ -70,10 -63,7 +70,8 @@@ void VoteCommand(int request, entity ca const float RESTART_COUNTDOWN = 10; entity nagger; float readycount; // amount of players who are ready - float readyrestart_happened; // keeps track of whether a restart has already happened - float restart_mapalreadyrestarted; // bool, indicates whether reset_map() was already executed .float ready; // flag for if a player is ready +.float last_ready; // z411 time of the last readyup for anti-spam .int team_saved; // team number to restore upon map reset .void(entity this) reset; // if set, an entity is reset using this .void(entity this) reset2; // if set, an entity is reset using this (after calling ALL the reset functions for other entities) diff --cc qcsrc/server/teamplay.qc index d27be8ad8,0bc7e7cbb..d21a33b0c --- a/qcsrc/server/teamplay.qc +++ b/qcsrc/server/teamplay.qc @@@ -103,16 -92,21 +103,31 @@@ void Team_SetNumberOfAlivePlayers(entit team_ent.m_num_players_alive = number; } +int Team_GetNumberOfPlayers(entity team_ent) +{ + return team_ent.m_num_players; +} + +void Team_SetNumberOfPlayers(entity team_ent, int number) +{ + team_ent.m_num_players = number; +} + + int Team_GetWinnerAliveTeam() + { + int winner = 0; + for (int i = 0; i < NUM_TEAMS; ++i) + { + if (g_team_entities[i].m_num_players_alive > 0) + { + if (winner) + return 0; + winner = Team_IndexToTeam(i + 1); + } + } + return (winner ? winner : -1); + } + int Team_GetNumberOfAliveTeams() { int result = 0; diff --cc qcsrc/server/teamplay.qh index c8e6a5d18,a94b247a8..8c67bb84f --- a/qcsrc/server/teamplay.qh +++ b/qcsrc/server/teamplay.qh @@@ -51,8 -50,11 +51,12 @@@ int Team_GetNumberOfPlayers(entity team /// \param[in,out] team_ent Team entity. /// \param[in] number Number of players to set. void Team_SetNumberOfAlivePlayers(entity team_ent, int number); +void Team_SetNumberOfPlayers(entity team_ent, int number); + /// \brief Returns the winner team. + /// \return Winner team or 0 if 2 or more teams have alive players or -1 if no team has any alive players. + int Team_GetWinnerAliveTeam(); + /// \brief Returns the number of alive teams. /// \return Number of alive teams. int Team_GetNumberOfAliveTeams(); diff --cc qcsrc/server/weapons/accuracy.qc index 4482fc9fd,337ae54a9..800550617 --- a/qcsrc/server/weapons/accuracy.qc +++ b/qcsrc/server/weapons/accuracy.qc @@@ -71,9 -53,23 +71,24 @@@ void accuracy_init(entity e void accuracy_free(entity e) { delete(CS(e).accuracy); + delete(e.roundaccuracy); } + void accuracy_reset(entity e) + { + entity a = CS(e).accuracy; + if (!a) return; + + for (int i = 0; i < REGISTRY_MAX(Weapons); i++) + { + a.accuracy_frags[i] = 0; + a.accuracy_hit[i] = 0; + a.accuracy_fired[i] = 0; + a.accuracy_cnt_hit[i] = 0; + a.accuracy_cnt_fired[i] = 0; + } + } + // force a resend of a player's accuracy stats void accuracy_resend(entity e) { diff --cc qcsrc/server/world.qc index 8a93d4169,a438e633f..65ee2b1a6 --- a/qcsrc/server/world.qc +++ b/qcsrc/server/world.qc @@@ -1448,52 -1405,10 +1456,52 @@@ void AddWinners(.float field, float val // clear the .winning flags void ClearWinners() { - FOREACH_CLIENT(IS_PLAYER(it), { it.winning = 0; }); + FOREACH_CLIENT(IS_PLAYER(it) || INGAME(it), { it.winning = 0; }); } -int fragsleft_last; +void AnnounceNewLeader() +{ + if(teamplay) { + if (WinningConditionHelper_equality) + Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_TEAM_LEADS_TIED); + else + FOREACH_CLIENT(IS_PLAYER(it), { + if(it.team == WinningConditionHelper_winnerteam) + Send_Notification(NOTIF_ONE_ONLY, it, MSG_ANNCE, ANNCE_TEAM_LEADS_TEAM); + else + Send_Notification(NOTIF_ONE_ONLY, it, MSG_ANNCE, ANNCE_TEAM_LEADS_ENEMY); + }); + Send_Notification(NOTIF_ALL_SPEC, NULL, MSG_ANNCE, APP_TEAM_NUM(WinningConditionHelper_winnerteam, ANNCE_TEAM_LEADS)); + } else { + if (WinningConditionHelper_equality) + { + Send_Notification(NOTIF_ONE, WinningConditionHelper_equality_one, MSG_ANNCE, ANNCE_LEAD_TIED); + Send_Notification(NOTIF_ONE, WinningConditionHelper_equality_two, MSG_ANNCE, ANNCE_LEAD_TIED); + } + else + { + Send_Notification(NOTIF_ONE, WinningConditionHelper_winner, MSG_ANNCE, ANNCE_LEAD_GAINED); + Send_Notification(NOTIF_ONE, WinningConditionHelper_second, MSG_ANNCE, ANNCE_LEAD_LOST); + } + } +} + +void AnnounceScores(float tm) +{ + WinningConditionHelper(NULL); + if (Score_NewLeader()) { + AnnounceNewLeader(); + } else { + FOREACH_CLIENT(IS_PLAYER(it), { + if(it.team == tm) + Send_Notification(NOTIF_ONE_ONLY, it, MSG_ANNCE, ANNCE_TEAM_SCORES_TEAM); + else + Send_Notification(NOTIF_ONE_ONLY, it, MSG_ANNCE, ANNCE_TEAM_SCORES_ENEMY); + }); + Send_Notification(NOTIF_ALL_SPEC, NULL, MSG_ANNCE, APP_TEAM_NUM(tm, ANNCE_TEAM_SCORES)); + } +} + float WinningCondition_Scores(float limit, float leadlimit) { // TODO make everything use THIS winning condition (except LMS)