Merge pull request #7521 from dobrykafe/pr-team-0-mode

Add `/mode` allowing teams to behave like team 0
This commit is contained in:
Dennis Felsing 2024-04-07 08:58:38 +00:00 committed by GitHub
commit ff991af6dd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 136 additions and 19 deletions

View file

@ -635,6 +635,15 @@ void CGameContext::ConPractice(IConsole::IResult *pResult, void *pUserData)
return;
}
if(Teams.TeamFlock(Team))
{
pSelf->Console()->Print(
IConsole::OUTPUT_LEVEL_STANDARD,
"chatresp",
"Practice mode can't be enabled in team 0 mode.");
return;
}
if(Teams.IsPractice(Team))
{
pSelf->Console()->Print(
@ -772,7 +781,7 @@ void CGameContext::ConSwap(IConsole::IResult *pResult, void *pUserData)
}
CPlayer *pSwapPlayer = pSelf->m_apPlayers[TargetClientId];
if(Team == TEAM_FLOCK && g_Config.m_SvTeam != 3)
if((Team == TEAM_FLOCK || Teams.TeamFlock(Team)) && g_Config.m_SvTeam != 3)
{
CCharacter *pChr = pPlayer->GetCharacter();
CCharacter *pSwapChr = pSwapPlayer->GetCharacter();
@ -782,7 +791,7 @@ void CGameContext::ConSwap(IConsole::IResult *pResult, void *pUserData)
return;
}
}
else if(!Teams.IsStarted(Team))
else if(!Teams.IsStarted(Team) && !Teams.TeamFlock(Team))
{
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "chatresp", "Need to have started the map to swap with a player.");
return;
@ -926,6 +935,9 @@ void CGameContext::ConLock(IConsole::IResult *pResult, void *pUserData)
{
pSelf->m_pController->Teams().SetTeamLock(Team, true);
if(pSelf->m_pController->Teams().TeamFlock(Team))
str_format(aBuf, sizeof(aBuf), "'%s' locked your team.", pSelf->Server()->ClientName(pResult->m_ClientId));
else
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));
pSelf->SendChatTeam(Team, aBuf);
}
@ -1015,7 +1027,7 @@ void CGameContext::AttemptJoinTeam(int ClientId, int Team)
"This team is locked using /lock. Only members of the team can unlock it using /lock." :
"This team is locked using /lock. Only members of the team can invite you or unlock it using /lock.");
}
else if(Team > 0 && Team < MAX_CLIENTS && m_pController->Teams().Count(Team) >= g_Config.m_SvMaxTeamSize)
else if(Team > 0 && Team < MAX_CLIENTS && m_pController->Teams().Count(Team) >= g_Config.m_SvMaxTeamSize && !m_pController->Teams().TeamFlock(Team))
{
char aBuf[512];
str_format(aBuf, sizeof(aBuf), "This team already has the maximum allowed size of %d players", g_Config.m_SvMaxTeamSize);
@ -1036,6 +1048,9 @@ void CGameContext::AttemptJoinTeam(int ClientId, int Team)
if(m_pController->Teams().IsPractice(Team))
SendChatTarget(pPlayer->GetCid(), "Practice mode enabled for your team, happy practicing!");
if(m_pController->Teams().TeamFlock(Team))
SendChatTarget(pPlayer->GetCid(), "Team 0 mode enabled for your team, happy team 0-ing!");
}
}
}
@ -1104,6 +1119,70 @@ void CGameContext::ConInvite(IConsole::IResult *pResult, void *pUserData)
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "chatresp", "Can't invite players to this team");
}
void CGameContext::ConFlock(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
auto *pController = pSelf->m_pController;
if(!CheckClientId(pResult->m_ClientId))
return;
if(g_Config.m_SvTeam == SV_TEAM_FORBIDDEN || g_Config.m_SvTeam == SV_TEAM_FORCED_SOLO || g_Config.m_SvTeam == SV_TEAM_MANDATORY)
{
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "chatresp",
"Team mode change disabled");
return;
}
int Team = pController->Teams().m_Core.Team(pResult->m_ClientId);
bool Mode = pController->Teams().TeamFlock(Team);
if(Team <= TEAM_FLOCK || Team >= TEAM_SUPER)
{
pSelf->Console()->Print(
IConsole::OUTPUT_LEVEL_STANDARD,
"chatresp",
"This team can't have the mode changed");
return;
}
if(pController->Teams().GetTeamState(Team) != CGameTeams::TEAMSTATE_OPEN)
{
pSelf->SendChatTarget(pResult->m_ClientId, "Team mode can't be changed while racing");
return;
}
if(pResult->NumArguments() > 0)
Mode = !pResult->GetInteger(0);
if(pSelf->ProcessSpamProtection(pResult->m_ClientId, false))
return;
char aBuf[512];
if(Mode)
{
if(pController->Teams().Count(Team) > g_Config.m_SvMaxTeamSize)
{
str_format(aBuf, sizeof(aBuf), "Can't disable team 0 mode. This team exceeds the maximum allowed size of %d players for regular team", g_Config.m_SvMaxTeamSize);
pSelf->SendChatTarget(pResult->m_ClientId, aBuf);
}
else
{
pController->Teams().SetTeamFlock(Team, false);
str_format(aBuf, sizeof(aBuf), "'%s' disabled team 0 mode.", pSelf->Server()->ClientName(pResult->m_ClientId));
pSelf->SendChatTeam(Team, aBuf);
}
}
else
{
pController->Teams().SetTeamFlock(Team, true);
str_format(aBuf, sizeof(aBuf), "'%s' enabled team 0 mode.", pSelf->Server()->ClientName(pResult->m_ClientId));
pSelf->SendChatTeam(Team, aBuf);
}
}
void CGameContext::ConTeam(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;

View file

@ -942,7 +942,7 @@ void CCharacter::Die(int Killer, int Weapon, bool SendKillMsg)
GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf);
// send the kill message
if(SendKillMsg && (Team() == TEAM_FLOCK || Teams()->Count(Team()) == 1 || Teams()->GetTeamState(Team()) == CGameTeams::TEAMSTATE_OPEN || Teams()->TeamLocked(Team()) == false))
if(SendKillMsg && (Team() == TEAM_FLOCK || Teams()->TeamFlock(Team()) || Teams()->Count(Team()) == 1 || Teams()->GetTeamState(Team()) == CGameTeams::TEAMSTATE_OPEN || !Teams()->TeamLocked(Team())))
{
CNetMsg_Sv_KillMsg Msg;
Msg.m_Killer = Killer;
@ -1773,7 +1773,7 @@ void CCharacter::HandleTiles(int Index)
m_StartTime -= (min * 60 + sec) * Server()->TickSpeed();
if((g_Config.m_SvTeam == SV_TEAM_FORCED_SOLO || Team != TEAM_FLOCK) && Team != TEAM_SUPER)
if((g_Config.m_SvTeam == SV_TEAM_FORCED_SOLO || (Team != TEAM_FLOCK && !Teams()->TeamFlock(Team))) && Team != TEAM_SUPER)
{
for(int i = 0; i < MAX_CLIENTS; i++)
{
@ -1799,7 +1799,7 @@ void CCharacter::HandleTiles(int Index)
if(m_StartTime > Server()->Tick())
m_StartTime = Server()->Tick();
if((g_Config.m_SvTeam == SV_TEAM_FORCED_SOLO || Team != TEAM_FLOCK) && Team != TEAM_SUPER)
if((g_Config.m_SvTeam == SV_TEAM_FORCED_SOLO || (Team != TEAM_FLOCK && !Teams()->TeamFlock(Team))) && Team != TEAM_SUPER)
{
for(int i = 0; i < MAX_CLIENTS; i++)
{

View file

@ -444,6 +444,8 @@ private:
static void ConUnlock(IConsole::IResult *pResult, void *pUserData);
static void ConInvite(IConsole::IResult *pResult, void *pUserData);
static void ConJoin(IConsole::IResult *pResult, void *pUserData);
static void ConMode(IConsole::IResult *pResult, void *pUserData);
static void ConFlock(IConsole::IResult *pResult, void *pUserData);
static void ConMe(IConsole::IResult *pResult, void *pUserData);
static void ConWhisper(IConsole::IResult *pResult, void *pUserData);
static void ConConverse(IConsole::IResult *pResult, void *pUserData);

View file

@ -67,7 +67,7 @@ void CGameControllerDDRace::HandleCharacterTiles(CCharacter *pChr, int MapIndex)
pChr->Die(ClientId, WEAPON_WORLD);
return;
}
if(g_Config.m_SvTeam != SV_TEAM_FORCED_SOLO && Team > TEAM_FLOCK && Team < TEAM_SUPER && Teams().Count(Team) < g_Config.m_SvMinTeamSize)
if(g_Config.m_SvTeam != SV_TEAM_FORCED_SOLO && Team > TEAM_FLOCK && Team < TEAM_SUPER && Teams().Count(Team) < g_Config.m_SvMinTeamSize && !Teams().TeamFlock(Team))
{
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "Your team has fewer than %d players, so your team rank won't count", g_Config.m_SvMinTeamSize);

View file

@ -481,6 +481,11 @@ int CSaveTeam::Save(CGameContext *pGameServer, int Team, bool Dry)
IGameController *pController = pGameServer->m_pController;
CGameTeams *pTeams = &pController->Teams();
if(pTeams->TeamFlock(Team))
{
return 5;
}
m_MembersCount = pTeams->Count(Team);
if(m_MembersCount <= 0)
{
@ -554,6 +559,9 @@ bool CSaveTeam::HandleSaveError(int Result, int ClientId, CGameContext *pGameCon
case 4:
pGameContext->SendChatTarget(ClientId, "Your team has not started yet");
break;
case 5:
pGameContext->SendChatTarget(ClientId, "Team can't be saved while in team 0 mode");
break;
default: // this state should never be reached
pGameContext->SendChatTarget(ClientId, "Unknown error while saving");
break;

View file

@ -345,6 +345,11 @@ void CScore::LoadTeam(const char *pCode, int ClientId)
GameServer()->SendChatTarget(ClientId, "Team can't be loaded while racing");
return;
}
if(pController->Teams().TeamFlock(Team))
{
GameServer()->SendChatTarget(ClientId, "Team can't be loaded while in team 0 mode");
return;
}
auto SaveResult = std::make_shared<CScoreSaveResult>(ClientId);
SaveResult->m_Status = CScoreSaveResult::LOAD_FAILED;
pController->Teams().SetSaving(Team, SaveResult);

View file

@ -32,6 +32,7 @@ void CGameTeams::Reset()
{
m_aTeamState[i] = TEAMSTATE_EMPTY;
m_aTeamLocked[i] = false;
m_aTeamFlock[i] = false;
m_apSaveTeamResult[i] = nullptr;
m_aTeamSentStartWarning[i] = false;
ResetRoundState(i);
@ -75,11 +76,14 @@ void CGameTeams::OnCharacterStart(int ClientId)
return;
if(g_Config.m_SvTeam == SV_TEAM_FORCED_SOLO && pStartingChar->m_DDRaceState == DDRACE_STARTED)
return;
if((g_Config.m_SvTeam == SV_TEAM_FORCED_SOLO || m_Core.Team(ClientId) != TEAM_FLOCK) && pStartingChar->m_DDRaceState == DDRACE_FINISHED)
if((g_Config.m_SvTeam == SV_TEAM_FORCED_SOLO || (m_Core.Team(ClientId) != TEAM_FLOCK && !m_aTeamFlock[m_Core.Team(ClientId)])) && pStartingChar->m_DDRaceState == DDRACE_FINISHED)
return;
if(g_Config.m_SvTeam != SV_TEAM_FORCED_SOLO &&
(m_Core.Team(ClientId) == TEAM_FLOCK || m_Core.Team(ClientId) == TEAM_SUPER))
(m_Core.Team(ClientId) == TEAM_FLOCK || TeamFlock(m_Core.Team(ClientId)) || m_Core.Team(ClientId) == TEAM_SUPER))
{
if(TeamFlock(m_Core.Team(ClientId)) && (m_aTeamState[m_Core.Team(ClientId)] < TEAMSTATE_STARTED))
ChangeTeamState(m_Core.Team(ClientId), TEAMSTATE_STARTED);
m_aTeeStarted[ClientId] = true;
pStartingChar->m_DDRaceState = DDRACE_STARTED;
pStartingChar->m_StartTime = Tick;
@ -184,7 +188,7 @@ void CGameTeams::OnCharacterStart(int ClientId)
void CGameTeams::OnCharacterFinish(int ClientId)
{
if((m_Core.Team(ClientId) == TEAM_FLOCK && g_Config.m_SvTeam != SV_TEAM_FORCED_SOLO) || m_Core.Team(ClientId) == TEAM_SUPER)
if(((m_Core.Team(ClientId) == TEAM_FLOCK || m_aTeamFlock[m_Core.Team(ClientId)]) && g_Config.m_SvTeam != SV_TEAM_FORCED_SOLO) || m_Core.Team(ClientId) == TEAM_SUPER)
{
CPlayer *pPlayer = GetPlayer(ClientId);
if(pPlayer && pPlayer->IsPlaying())
@ -250,7 +254,7 @@ void CGameTeams::Tick()
{
CCharacter *pChar = GameServer()->m_apPlayers[i] ? GameServer()->m_apPlayers[i]->GetCharacter() : nullptr;
int Team = m_Core.Team(i);
if(!pChar || m_aTeamState[Team] != TEAMSTATE_STARTED || m_aTeeStarted[i] || m_aPractice[m_Core.Team(i)])
if(!pChar || m_aTeamState[Team] != TEAMSTATE_STARTED || m_aTeamFlock[Team] || m_aTeeStarted[i] || m_aPractice[m_Core.Team(i)])
{
continue;
}
@ -372,7 +376,7 @@ const char *CGameTeams::SetCharacterTeam(int ClientId, int Team)
return "Invalid client ID";
if(Team < 0 || Team >= MAX_CLIENTS + 1)
return "Invalid team number";
if(Team != TEAM_SUPER && m_aTeamState[Team] > TEAMSTATE_OPEN && !m_aPractice[Team])
if(Team != TEAM_SUPER && m_aTeamState[Team] > TEAMSTATE_OPEN && !m_aPractice[Team] && !m_aTeamFlock[Team])
return "This team started already";
if(m_Core.Team(ClientId) == Team)
return "You are in this team already";
@ -412,6 +416,7 @@ void CGameTeams::SetForceCharacterTeam(int ClientId, int Team)
// unlock team when last player leaves
SetTeamLock(OldTeam, false);
SetTeamFlock(OldTeam, false);
ResetRoundState(OldTeam);
// do not reset SaveTeamResult, because it should be logged into teehistorian even if the team leaves
}
@ -433,7 +438,7 @@ void CGameTeams::SetForceCharacterTeam(int ClientId, int Team)
m_pGameContext->m_World.RemoveEntitiesFromPlayer(ClientId);
}
if(Team != TEAM_SUPER && (m_aTeamState[Team] == TEAMSTATE_EMPTY || m_aTeamLocked[Team]))
if(Team != TEAM_SUPER && (m_aTeamState[Team] == TEAMSTATE_EMPTY || (m_aTeamLocked[Team] && !m_aTeamFlock[Team])))
{
if(!m_aTeamLocked[Team])
ChangeTeamState(Team, TEAMSTATE_OPEN);
@ -931,7 +936,7 @@ void CGameTeams::SwapTeamCharacters(CPlayer *pPrimaryPlayer, CPlayer *pTargetPla
PrimarySavedTee.Load(pTargetPlayer->GetCharacter(), Team, true);
SecondarySavedTee.Load(pPrimaryPlayer->GetCharacter(), Team, true);
if(Team >= 1)
if(Team >= 1 && !m_aTeamFlock[Team])
{
for(const auto &pPlayer : GameServer()->m_apPlayers)
{
@ -1047,6 +1052,7 @@ void CGameTeams::OnCharacterSpawn(int ClientId)
SetForceCharacterTeam(ClientId, TEAM_FLOCK);
else
SetForceCharacterTeam(ClientId, ClientId); // initialize team
if(!m_aTeamFlock[Team])
CheckTeamFinished(Team);
}
}
@ -1083,7 +1089,7 @@ void CGameTeams::OnCharacterDeath(int ClientId, int Weapon)
{
SetForceCharacterTeam(ClientId, Team);
if(GetTeamState(Team) != TEAMSTATE_OPEN)
if(GetTeamState(Team) != TEAMSTATE_OPEN && !m_aTeamFlock[m_Core.Team(ClientId)])
{
ChangeTeamState(Team, CGameTeams::TEAMSTATE_OPEN);
@ -1102,7 +1108,7 @@ void CGameTeams::OnCharacterDeath(int ClientId, int Weapon)
}
else
{
if(m_aTeamState[m_Core.Team(ClientId)] == CGameTeams::TEAMSTATE_STARTED && !m_aTeeStarted[ClientId] && !m_aPractice[Team])
if(m_aTeamState[m_Core.Team(ClientId)] == CGameTeams::TEAMSTATE_STARTED && !m_aTeeStarted[ClientId] && !m_aTeamFlock[m_Core.Team(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));
@ -1113,6 +1119,7 @@ void CGameTeams::OnCharacterDeath(int ClientId, int Weapon)
ChangeTeamState(Team, CGameTeams::TEAMSTATE_STARTED_UNFINISHABLE);
}
SetForceCharacterTeam(ClientId, TEAM_FLOCK);
if(!m_aTeamFlock[m_Core.Team(ClientId)])
CheckTeamFinished(Team);
}
}
@ -1123,6 +1130,12 @@ void CGameTeams::SetTeamLock(int Team, bool Lock)
m_aTeamLocked[Team] = Lock;
}
void CGameTeams::SetTeamFlock(int Team, bool Mode)
{
if(Team > TEAM_FLOCK && Team < TEAM_SUPER)
m_aTeamFlock[Team] = Mode;
}
void CGameTeams::ResetInvited(int Team)
{
m_aInvited[Team].reset();

View file

@ -25,6 +25,7 @@ class CGameTeams
int m_aTeamState[NUM_TEAMS];
bool m_aTeamLocked[NUM_TEAMS];
bool m_aTeamFlock[NUM_TEAMS];
CClientMask m_aInvited[NUM_TEAMS];
bool m_aPractice[NUM_TEAMS];
std::shared_ptr<CScoreSaveResult> m_apSaveTeamResult[NUM_TEAMS];
@ -109,6 +110,7 @@ public:
void SendTeamsState(int ClientId);
void SetTeamLock(int Team, bool Lock);
void SetTeamFlock(int Team, bool Mode);
void ResetInvited(int Team);
void SetClientInvited(int Team, int ClientId, bool Invited);
@ -149,6 +151,14 @@ public:
return m_aTeamLocked[Team];
}
bool TeamFlock(int Team)
{
if(Team <= TEAM_FLOCK || Team >= TEAM_SUPER)
return false;
return m_aTeamFlock[Team];
}
bool IsInvited(int Team, int ClientId)
{
return m_aInvited[Team].test(ClientId);