From: z411 Date: Wed, 5 Jan 2022 18:49:38 +0000 (-0300) Subject: Merge branch 'master' into z411/bai-server X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=d33e9e7e33962631c0c13aa679682327a8f72e9b;p=xonotic%2Fxonotic-data.pk3dir.git Merge branch 'master' into z411/bai-server --- d33e9e7e33962631c0c13aa679682327a8f72e9b diff --cc qcsrc/client/hud/panel/timer.qc index a9512a42f,035d21b60..095e44307 --- a/qcsrc/client/hud/panel/timer.qc +++ b/qcsrc/client/hud/panel/timer.qc @@@ -38,33 -36,14 +38,32 @@@ 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 = min(timeleft, timelimit * 60); + timeleft = bound(0, timelimit * 60 + STAT(GAMESTARTTIME) - time, timelimit * 60); timeleft = ceil(timeleft); + // countdown sound + // if 3 use server dictated option, otherwise the client's + int countdown_type; + if(autocvar_cl_timer_countdown == 3) + countdown_type = sv_timer_countdown; + else + countdown_type = autocvar_cl_timer_countdown; + + if(countdown_type && !warmup_stage && timeleft > 0 && timeleft != last_timeleft && timeleft <= 10) + { + if(countdown_type == 1 || (countdown_type == 2 && spectatee_status)) + 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 7ee4b4a55,866a00419..34e039654 --- a/qcsrc/common/gamemodes/gamemode/clanarena/sv_clanarena.qc +++ b/qcsrc/common/gamemodes/gamemode/clanarena/sv_clanarena.qc @@@ -51,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) @@@ -111,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 73933c23f,58fd90c89..4b01743c2 --- a/qcsrc/common/gamemodes/gamemode/freezetag/sv_freezetag.qc +++ b/qcsrc/common/gamemodes/gamemode/freezetag/sv_freezetag.qc @@@ -149,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..d1ae3c927 --- a/qcsrc/server/command/cmd.qc +++ b/qcsrc/server/command/cmd.qc @@@ -372,36 -372,27 +372,27 @@@ 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"); ++ bprint("\{1}", playername(caller.netname, caller.team, false), "^2 is ^1NOT^2 ready\n"); } else { - sprint(caller, "^1Game has already been restarted\n"); + caller.ready = true; + if (IS_PLAYER(caller) || INGAME_JOINED(caller)) - bprint(playername(caller.netname, caller.team, false), "^2 is ready\n"); ++ bprint("\{1}", playername(caller.netname, caller.team, false), "^2 is ready\n"); } + + // cannot reset the game while a timeout is active! + if (!timeout_status) ReadyCount(); } } return; // never fall through to usage diff --cc qcsrc/server/command/sv_cmd.qc index a0770cab7,ca6b268e2..2112d2f44 --- a/qcsrc/server/command/sv_cmd.qc +++ b/qcsrc/server/command/sv_cmd.qc @@@ -1809,12 -1675,10 +1804,12 @@@ SERVER_COMMAND(nospectators, "Automatic SERVER_COMMAND(printstats, "Dump eventlog player stats and other score information") { GameCommand_printstats(request); } SERVER_COMMAND(radarmap, "Generate a radar image of the map") { GameCommand_radarmap(request, arguments); } SERVER_COMMAND(reducematchtime, "Decrease the timelimit value incrementally") { GameCommand_reducematchtime(request); } - SERVER_COMMAND(reset, "Soft restart the server and reset the players") { GameCommand_reset(request); } + SERVER_COMMAND(resetmatch, "Soft restart the game without changing teams; goes back to warmup if enabled") { GameCommand_resetmatch(request); } SERVER_COMMAND(setbots, "Adjust how many bots are in the match") { GameCommand_setbots(request, arguments); } +SERVER_COMMAND(setflag, "Set client flag") { GameCommand_setflag(request, arguments); } SERVER_COMMAND(shuffleteams, "Randomly move players to different teams") { GameCommand_shuffleteams(request); } SERVER_COMMAND(stuffto, "Send a command to be executed on a client") { GameCommand_stuffto(request, arguments); } +SERVER_COMMAND(teamname, "Set team name") { GameCommand_teamname(request, arguments); } SERVER_COMMAND(trace, "Various debugging tools with tracing") { GameCommand_trace(request, arguments); } SERVER_COMMAND(unlockteams, "Enable the ability for players to switch or enter teams") { GameCommand_unlockteams(request); } SERVER_COMMAND(warp, "Choose different level in campaign") { GameCommand_warp(request, arguments); } diff --cc qcsrc/server/command/vote.qc index b98abd921,6b39ab7b6..4b9429842 --- a/qcsrc/server/command/vote.qc +++ b/qcsrc/server/command/vote.qc @@@ -430,10 -414,8 +424,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); } @@@ -809,18 -760,24 +796,37 @@@ int VoteCommand_parse(entity caller, st break; } - case "restart": - case "reset": + case "gg": + case "shuffleteams": - case "allready": + case "endmatch": + { + // add a delay so that vote result can be seen and announcer can be heard + // if the vote is accepted + vote_parsed_command = strcat("defer 2 ", vote_command); + vote_parsed_display = strzone(strcat("^1", vote_command)); ++ ++ break; ++ } ++ ++ case "reset": + case "restart": + case "resetmatch": // re-direct all match restarting to resetmatch + { - vote_parsed_command = "resetmatch"; ++ vote_parsed_command = "defer 2 resetmatch"; + vote_parsed_display = strzone("^1resetmatch"); + + break; + } + + case "allready": + { + if(!warmup_stage) { + print_to(caller, "Game already started. Use the resetmatch command to restart the match."); + return -1; + } - vote_parsed_command = vote_command; ++ vote_parsed_command = strcat("defer 2 ", vote_command); + vote_parsed_display = strzone(strcat("^1", vote_command)); break; } 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/world.qc index 2e87471f8,a438e633f..b39b36489 --- a/qcsrc/server/world.qc +++ b/qcsrc/server/world.qc @@@ -1491,52 -1405,10 +1498,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)