mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Merge #4148
4148: Kill unfinishable teams if they don't enter /practice within a minute r=Learath2 a=heinrich5991 This is to avoid players playing in unfinishable teams for a long time if they don't understand the system messages. Fixes #4088. ## Checklist - [x] Tested the change ingame - [ ] Provided screenshots if it is a visual change - [ ] Tested in combination with possibly related configuration options - [ ] Written a unit test if it works standalone, system.c especially - [ ] Considered possible null pointers and out of bounds array indexing - [ ] Changed no physics that affect existing maps - [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional) Co-authored-by: heinrich5991 <heinrich5991@gmail.com>
This commit is contained in:
commit
84ea62d769
|
@ -659,18 +659,12 @@ void CGameContext::ConPractice(IConsole::IResult *pResult, void *pUserData)
|
|||
|
||||
char aBuf[512];
|
||||
str_format(aBuf, sizeof(aBuf), "'%s' voted to %s /practice mode for your team, which means you can use /r, but you can't earn a rank. Type /practice to vote (%d/%d required votes)", pSelf->Server()->ClientName(pResult->m_ClientID), VotedForPractice ? "enable" : "disable", NumCurrentVotes, NumRequiredVotes);
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
if(Teams.m_Core.Team(i) == Team)
|
||||
pSelf->SendChatTarget(i, aBuf);
|
||||
pSelf->SendChatTeam(Team, aBuf);
|
||||
|
||||
if(NumCurrentVotes >= NumRequiredVotes)
|
||||
{
|
||||
Teams.EnablePractice(Team);
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
if(Teams.m_Core.Team(i) == Team)
|
||||
pSelf->SendChatTarget(i, "Practice mode enabled for your team, happy practicing!");
|
||||
pSelf->SendChatTeam(Team, "Practice mode enabled for your team, happy practicing!");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -879,10 +873,7 @@ void CGameContext::ConLockTeam(IConsole::IResult *pResult, void *pUserData)
|
|||
((CGameControllerDDRace *)pSelf->m_pController)->m_Teams.SetTeamLock(Team, true);
|
||||
|
||||
str_format(aBuf, sizeof(aBuf), "'%s' locked your team. After the race starts, killing will kill everyone in your team.", pSelf->Server()->ClientName(pResult->m_ClientID));
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
if(((CGameControllerDDRace *)pSelf->m_pController)->m_Teams.m_Core.Team(i) == Team)
|
||||
pSelf->SendChatTarget(i, aBuf);
|
||||
pSelf->SendChatTeam(Team, aBuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -916,10 +907,7 @@ void CGameContext::UnlockTeam(int ClientID, int Team)
|
|||
|
||||
char aBuf[512];
|
||||
str_format(aBuf, sizeof(aBuf), "'%s' unlocked your team.", Server()->ClientName(ClientID));
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
if(((CGameControllerDDRace *)m_pController)->m_Teams.m_Core.Team(i) == Team)
|
||||
SendChatTarget(i, aBuf);
|
||||
SendChatTeam(Team, aBuf);
|
||||
}
|
||||
|
||||
void CGameContext::ConInviteTeam(IConsole::IResult *pResult, void *pUserData)
|
||||
|
@ -980,10 +968,7 @@ void CGameContext::ConInviteTeam(IConsole::IResult *pResult, void *pUserData)
|
|||
pSelf->SendChatTarget(Target, aBuf);
|
||||
|
||||
str_format(aBuf, sizeof aBuf, "'%s' invited '%s' to your team.", pSelf->Server()->ClientName(pResult->m_ClientID), pSelf->Server()->ClientName(Target));
|
||||
;
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
if(((CGameControllerDDRace *)pSelf->m_pController)->m_Teams.m_Core.Team(i) == Team)
|
||||
pSelf->SendChatTarget(i, aBuf);
|
||||
pSelf->SendChatTeam(Team, aBuf);
|
||||
}
|
||||
else
|
||||
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "invite", "Can't invite players to this team");
|
||||
|
|
|
@ -103,10 +103,7 @@ void CGameControllerDDRace::HandleCharacterTiles(CCharacter *pChr, int MapIndex)
|
|||
else if(((m_TileIndex == TILE_UNLOCK_TEAM) || (m_TileFIndex == TILE_UNLOCK_TEAM)) && m_Teams.TeamLocked(GetPlayerTeam(ClientID)))
|
||||
{
|
||||
m_Teams.SetTeamLock(GetPlayerTeam(ClientID), false);
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
if(GetPlayerTeam(i) == GetPlayerTeam(ClientID))
|
||||
GameServer()->SendChatTarget(i, "Your team was unlocked by an unlock team tile");
|
||||
GameServer()->SendChatTeam(GetPlayerTeam(ClientID), "Your team was unlocked by an unlock team tile");
|
||||
}
|
||||
|
||||
// solo part
|
||||
|
|
|
@ -29,6 +29,7 @@ void CGameTeams::Reset()
|
|||
m_Practice[i] = false;
|
||||
m_LastSwap[i] = 0;
|
||||
m_TeamSentStartWarning[i] = false;
|
||||
m_TeamUnfinishableKillTick[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +39,8 @@ void CGameTeams::ResetRoundState(int Team)
|
|||
ResetSwitchers(Team);
|
||||
m_LastSwap[Team] = 0;
|
||||
|
||||
m_Practice[Team] = 0;
|
||||
m_Practice[Team] = false;
|
||||
m_TeamUnfinishableKillTick[Team] = -1;
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(m_Core.Team(i) == Team && GameServer()->m_apPlayers[i])
|
||||
|
@ -127,6 +129,7 @@ void CGameTeams::OnCharacterStart(int ClientID)
|
|||
{
|
||||
ChangeTeamState(m_Core.Team(ClientID), TEAMSTATE_STARTED);
|
||||
m_TeamSentStartWarning[m_Core.Team(ClientID)] = false;
|
||||
m_TeamUnfinishableKillTick[m_Core.Team(ClientID)] = -1;
|
||||
|
||||
int NumPlayers = Count(m_Core.Team(ClientID));
|
||||
|
||||
|
@ -205,6 +208,25 @@ void CGameTeams::OnCharacterFinish(int ClientID)
|
|||
void CGameTeams::Tick()
|
||||
{
|
||||
int Now = Server()->Tick();
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(m_TeamUnfinishableKillTick[i] == -1 || m_TeamState[i] != TEAMSTATE_STARTED_UNFINISHABLE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(Now >= m_TeamUnfinishableKillTick[i])
|
||||
{
|
||||
if(m_Practice[i])
|
||||
{
|
||||
m_TeamUnfinishableKillTick[i] = -1;
|
||||
continue;
|
||||
}
|
||||
KillTeam(i, -1);
|
||||
GameServer()->SendChatTeam(i, "Your team was killed because it couldn't finish anymore and hasn't entered /practice mode");
|
||||
}
|
||||
}
|
||||
|
||||
int Frequency = Server()->TickSpeed() * 60;
|
||||
int Remainder = Server()->TickSpeed() * 30;
|
||||
uint64_t TeamHasWantedStartTime = 0;
|
||||
|
@ -263,14 +285,7 @@ void CGameTeams::Tick()
|
|||
NumPlayersNotStarted,
|
||||
NumPlayersNotStarted == 1 ? "player that has" : "players that have",
|
||||
aPlayerNames);
|
||||
|
||||
for(int j = 0; j < MAX_CLIENTS; j++)
|
||||
{
|
||||
if(m_Core.Team(j) == i)
|
||||
{
|
||||
GameServer()->SendChatTarget(j, aBuf);
|
||||
}
|
||||
}
|
||||
GameServer()->SendChatTeam(i, aBuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,14 +327,7 @@ void CGameTeams::CheckTeamFinished(int Team)
|
|||
str_format(aBuf, sizeof(aBuf),
|
||||
"Your team would've finished in: %d minute(s) %5.2f second(s). Since you had practice mode enabled your rank doesn't count.",
|
||||
(int)Time / 60, Time - ((int)Time / 60 * 60));
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(m_Core.Team(i) == Team && GameServer()->m_apPlayers[i])
|
||||
{
|
||||
GameServer()->SendChatTarget(i, aBuf);
|
||||
}
|
||||
}
|
||||
GameServer()->SendChatTeam(Team, aBuf);
|
||||
|
||||
for(unsigned int i = 0; i < PlayersCount; ++i)
|
||||
{
|
||||
|
@ -434,6 +442,22 @@ void CGameTeams::ChangeTeamState(int Team, int State)
|
|||
m_TeamState[Team] = State;
|
||||
}
|
||||
|
||||
void CGameTeams::KillTeam(int Team, int NewStrongID)
|
||||
{
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(m_Core.Team(i) == Team && GameServer()->m_apPlayers[i])
|
||||
{
|
||||
GameServer()->m_apPlayers[i]->m_VotedForPractice = false;
|
||||
GameServer()->m_apPlayers[i]->KillCharacter(WEAPON_SELF);
|
||||
if(NewStrongID != -1 && i != NewStrongID)
|
||||
{
|
||||
GameServer()->m_apPlayers[i]->Respawn(true); // spawn the rest of team with weak hook on the killer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CGameTeams::TeamFinished(int Team)
|
||||
{
|
||||
if(m_TeamState[Team] != TEAMSTATE_STARTED)
|
||||
|
@ -982,20 +1006,11 @@ void CGameTeams::OnCharacterDeath(int ClientID, int Weapon)
|
|||
|
||||
m_Practice[Team] = false;
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
if(m_Core.Team(i) == Team && GameServer()->m_apPlayers[i])
|
||||
{
|
||||
GameServer()->m_apPlayers[i]->m_VotedForPractice = false;
|
||||
|
||||
if(i != ClientID)
|
||||
{
|
||||
GameServer()->m_apPlayers[i]->KillCharacter(WEAPON_SELF);
|
||||
if(Weapon == WEAPON_SELF)
|
||||
GameServer()->m_apPlayers[i]->Respawn(true); // spawn the rest of team with weak hook on the killer
|
||||
}
|
||||
if(Count(Team) > 1)
|
||||
GameServer()->SendChatTarget(i, aBuf);
|
||||
}
|
||||
KillTeam(Team, Weapon == WEAPON_SELF ? ClientID : -1);
|
||||
if(Count(Team) > 1)
|
||||
{
|
||||
GameServer()->SendChatTeam(Team, aBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1003,16 +1018,10 @@ void CGameTeams::OnCharacterDeath(int ClientID, int Weapon)
|
|||
if(m_TeamState[m_Core.Team(ClientID)] == CGameTeams::TEAMSTATE_STARTED && !m_TeeStarted[ClientID])
|
||||
{
|
||||
char aBuf[128];
|
||||
str_format(aBuf, sizeof(aBuf), "This team cannot finish anymore because '%s' left the team before hitting the start", Server()->ClientName(ClientID));
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(m_Core.Team(i) != Team || i == ClientID)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
GameServer()->SendChatTarget(i, aBuf);
|
||||
}
|
||||
str_format(aBuf, sizeof(aBuf), "This team cannot finish anymore because '%s' left the team before hitting the start, enter /practice mode to avoid being killed in 60 seconds", Server()->ClientName(ClientID));
|
||||
GameServer()->SendChatTeam(Team, aBuf);
|
||||
|
||||
m_TeamUnfinishableKillTick[Team] = Server()->Tick() + 60 * Server()->TickSpeed();
|
||||
ChangeTeamState(Team, CGameTeams::TEAMSTATE_STARTED_UNFINISHABLE);
|
||||
}
|
||||
SetForceCharacterTeam(ClientID, TEAM_FLOCK);
|
||||
|
@ -1044,14 +1053,7 @@ void CGameTeams::SetClientInvited(int Team, int ClientID, bool Invited)
|
|||
|
||||
void CGameTeams::KillSavedTeam(int ClientID, int Team)
|
||||
{
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(m_Core.Team(i) == Team && GameServer()->m_apPlayers[i])
|
||||
{
|
||||
GameServer()->m_apPlayers[i]->m_VotedForPractice = false;
|
||||
GameServer()->m_apPlayers[i]->KillCharacter(WEAPON_SELF);
|
||||
}
|
||||
}
|
||||
KillTeam(Team, -1);
|
||||
}
|
||||
|
||||
void CGameTeams::ResetSavedTeam(int ClientID, int Team)
|
||||
|
|
|
@ -27,9 +27,18 @@ class CGameTeams
|
|||
std::shared_ptr<CScoreSaveResult> m_pSaveTeamResult[MAX_CLIENTS];
|
||||
uint64_t m_LastSwap[MAX_CLIENTS];
|
||||
bool m_TeamSentStartWarning[MAX_CLIENTS];
|
||||
// `m_TeamUnfinishableKillTick` is -1 by default and gets set when a
|
||||
// team becomes unfinishable. If the team hasn't entered practice mode
|
||||
// by that time, it'll get killed to prevent people not understanding
|
||||
// the message from playing for a long time in an unfinishable team.
|
||||
int m_TeamUnfinishableKillTick[MAX_CLIENTS];
|
||||
|
||||
class CGameContext *m_pGameContext;
|
||||
|
||||
// Kill the whole team, making the player `NewStrongID` have strong
|
||||
// hook on everyone else. `NewStrongID` can be -1 to get the normal
|
||||
// spawning order.
|
||||
void KillTeam(int Team, int NewStrongID);
|
||||
bool TeamFinished(int Team);
|
||||
void OnTeamFinish(CPlayer **Players, unsigned int Size, float Time, const char *pTimestamp);
|
||||
void OnFinish(CPlayer *Player, float Time, const char *pTimestamp);
|
||||
|
|
Loading…
Reference in a new issue