ddnet/src/game/server/ddracecommands.cpp
Robert Müller 34ef28c6b6 Fix empty chat message being sent when using moderate
When activating `moderate` on a server that already has another active moderator, `aBuf` contained undefined values and the empty or undefined message was sent to the clients.

Clients ignore empty chat messages and don't display or log them, but the empty message can be seen in the server console.

Now no buffer is used anymore, so no empty message can be sent.
2023-01-28 16:36:03 +01:00

872 lines
26 KiB
C++

/* (c) Shereef Marzouk. See "licence DDRace.txt" and the readme.txt in the root of the distribution for more information. */
#include "gamecontext.h"
#include <engine/antibot.h>
#include <engine/shared/config.h>
#include <game/server/entities/character.h>
#include <game/server/gamemodes/DDRace.h>
#include <game/server/player.h>
#include <game/server/save.h>
#include <game/server/teams.h>
bool CheckClientID(int ClientID);
void CGameContext::ConGoLeft(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
pSelf->MoveCharacter(pResult->m_ClientID, -1, 0);
}
void CGameContext::ConGoRight(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
pSelf->MoveCharacter(pResult->m_ClientID, 1, 0);
}
void CGameContext::ConGoDown(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
pSelf->MoveCharacter(pResult->m_ClientID, 0, 1);
}
void CGameContext::ConGoUp(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
pSelf->MoveCharacter(pResult->m_ClientID, 0, -1);
}
void CGameContext::ConMove(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
pSelf->MoveCharacter(pResult->m_ClientID, pResult->GetInteger(0),
pResult->GetInteger(1));
}
void CGameContext::ConMoveRaw(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
pSelf->MoveCharacter(pResult->m_ClientID, pResult->GetInteger(0),
pResult->GetInteger(1), true);
}
void CGameContext::MoveCharacter(int ClientID, int X, int Y, bool Raw)
{
CCharacter *pChr = GetPlayerChar(ClientID);
if(!pChr)
return;
pChr->Core()->m_Pos.x += ((Raw) ? 1 : 32) * X;
pChr->Core()->m_Pos.y += ((Raw) ? 1 : 32) * Y;
pChr->m_DDRaceState = DDRACE_CHEAT;
}
void CGameContext::ConKillPlayer(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
int Victim = pResult->GetVictim();
if(pSelf->m_apPlayers[Victim])
{
pSelf->m_apPlayers[Victim]->KillCharacter(WEAPON_GAME);
char aBuf[512];
str_format(aBuf, sizeof(aBuf), "%s was killed by %s",
pSelf->Server()->ClientName(Victim),
pSelf->Server()->ClientName(pResult->m_ClientID));
pSelf->SendChat(-1, CGameContext::CHAT_ALL, aBuf);
}
}
void CGameContext::ConNinja(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, WEAPON_NINJA, false);
}
void CGameContext::ConEndlessHook(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
{
pChr->SetEndlessHook(true);
}
}
void CGameContext::ConUnEndlessHook(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
{
pChr->SetEndlessHook(false);
}
}
void CGameContext::ConSuper(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr && !pChr->IsSuper())
{
pChr->SetSuper(true);
pChr->UnFreeze();
}
}
void CGameContext::ConUnSuper(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr && pChr->IsSuper())
{
pChr->SetSuper(false);
}
}
void CGameContext::ConUnSolo(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
pChr->SetSolo(false);
}
void CGameContext::ConUnDeep(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
pChr->SetDeepFrozen(false);
}
void CGameContext::ConLiveFreeze(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
pChr->SetLiveFrozen(true);
}
void CGameContext::ConUnLiveFreeze(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
pChr->SetLiveFrozen(false);
}
void CGameContext::ConShotgun(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, WEAPON_SHOTGUN, false);
}
void CGameContext::ConGrenade(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, WEAPON_GRENADE, false);
}
void CGameContext::ConLaser(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, WEAPON_LASER, false);
}
void CGameContext::ConJetpack(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
pChr->SetJetpack(true);
}
void CGameContext::ConWeapons(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, -1, false);
}
void CGameContext::ConUnShotgun(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, WEAPON_SHOTGUN, true);
}
void CGameContext::ConUnGrenade(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, WEAPON_GRENADE, true);
}
void CGameContext::ConUnLaser(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, WEAPON_LASER, true);
}
void CGameContext::ConUnJetpack(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
pChr->SetJetpack(false);
}
void CGameContext::ConUnWeapons(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, -1, true);
}
void CGameContext::ConAddWeapon(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, pResult->GetInteger(0), false);
}
void CGameContext::ConRemoveWeapon(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, pResult->GetInteger(0), true);
}
void CGameContext::ModifyWeapons(IConsole::IResult *pResult, void *pUserData,
int Weapon, bool Remove)
{
CGameContext *pSelf = (CGameContext *)pUserData;
CCharacter *pChr = GetPlayerChar(pResult->m_ClientID);
if(!pChr)
return;
if(clamp(Weapon, -1, NUM_WEAPONS - 1) != Weapon)
{
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "info",
"invalid weapon id");
return;
}
if(Weapon == -1)
{
pChr->GiveWeapon(WEAPON_SHOTGUN, Remove);
pChr->GiveWeapon(WEAPON_GRENADE, Remove);
pChr->GiveWeapon(WEAPON_LASER, Remove);
}
else
{
pChr->GiveWeapon(Weapon, Remove);
}
pChr->m_DDRaceState = DDRACE_CHEAT;
}
void CGameContext::Teleport(CCharacter *pChr, vec2 Pos)
{
pChr->Core()->m_Pos = Pos;
pChr->m_Pos = Pos;
pChr->m_PrevPos = Pos;
pChr->m_DDRaceState = DDRACE_CHEAT;
}
void CGameContext::ConToTeleporter(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
unsigned int TeleTo = pResult->GetInteger(0);
CGameControllerDDRace *pGameControllerDDRace = (CGameControllerDDRace *)pSelf->m_pController;
if(!pGameControllerDDRace->m_TeleOuts[TeleTo - 1].empty())
{
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
{
int TeleOut = pSelf->m_World.m_Core.RandomOr0(pGameControllerDDRace->m_TeleOuts[TeleTo - 1].size());
pSelf->Teleport(pChr, pGameControllerDDRace->m_TeleOuts[TeleTo - 1][TeleOut]);
}
}
}
void CGameContext::ConToCheckTeleporter(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
unsigned int TeleTo = pResult->GetInteger(0);
CGameControllerDDRace *pGameControllerDDRace = (CGameControllerDDRace *)pSelf->m_pController;
if(!pGameControllerDDRace->m_TeleCheckOuts[TeleTo - 1].empty())
{
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
{
int TeleOut = pSelf->m_World.m_Core.RandomOr0(pGameControllerDDRace->m_TeleCheckOuts[TeleTo - 1].size());
pSelf->Teleport(pChr, pGameControllerDDRace->m_TeleCheckOuts[TeleTo - 1][TeleOut]);
pChr->m_TeleCheckpoint = TeleTo;
}
}
}
void CGameContext::ConTeleport(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int Tele = pResult->NumArguments() == 2 ? pResult->GetInteger(0) : pResult->m_ClientID;
int TeleTo = pResult->NumArguments() ? pResult->GetInteger(pResult->NumArguments() - 1) : pResult->m_ClientID;
int AuthLevel = pSelf->Server()->GetAuthedState(pResult->m_ClientID);
if(Tele != pResult->m_ClientID && AuthLevel < g_Config.m_SvTeleOthersAuthLevel)
{
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "tele", "you aren't allowed to tele others");
return;
}
CCharacter *pChr = pSelf->GetPlayerChar(Tele);
if(pChr && pSelf->GetPlayerChar(TeleTo))
{
pSelf->Teleport(pChr, pSelf->m_apPlayers[TeleTo]->m_ViewPos);
}
}
void CGameContext::ConKill(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientID];
if(!pPlayer || (pPlayer->m_LastKill && pPlayer->m_LastKill + pSelf->Server()->TickSpeed() * g_Config.m_SvKillDelay > pSelf->Server()->Tick()))
return;
pPlayer->m_LastKill = pSelf->Server()->Tick();
pPlayer->KillCharacter(WEAPON_SELF);
//pPlayer->m_RespawnTick = pSelf->Server()->Tick() + pSelf->Server()->TickSpeed() * g_Config.m_SvSuicidePenalty;
}
void CGameContext::ConForcePause(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int Victim = pResult->GetVictim();
int Seconds = 0;
if(pResult->NumArguments() > 1)
Seconds = clamp(pResult->GetInteger(1), 0, 360);
CPlayer *pPlayer = pSelf->m_apPlayers[Victim];
if(!pPlayer)
return;
pPlayer->ForcePause(Seconds);
}
bool CGameContext::TryVoteMute(const NETADDR *pAddr, int Secs, const char *pReason)
{
// find a matching vote mute for this ip, update expiration time if found
for(int i = 0; i < m_NumVoteMutes; i++)
{
if(net_addr_comp_noport(&m_aVoteMutes[i].m_Addr, pAddr) == 0)
{
m_aVoteMutes[i].m_Expire = Server()->Tick() + Secs * Server()->TickSpeed();
str_copy(m_aVoteMutes[i].m_aReason, pReason, sizeof(m_aVoteMutes[i].m_aReason));
return true;
}
}
// nothing to update create new one
if(m_NumVoteMutes < MAX_VOTE_MUTES)
{
m_aVoteMutes[m_NumVoteMutes].m_Addr = *pAddr;
m_aVoteMutes[m_NumVoteMutes].m_Expire = Server()->Tick() + Secs * Server()->TickSpeed();
str_copy(m_aVoteMutes[m_NumVoteMutes].m_aReason, pReason, sizeof(m_aVoteMutes[m_NumVoteMutes].m_aReason));
m_NumVoteMutes++;
return true;
}
// no free slot found
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "votemute", "vote mute array is full");
return false;
}
void CGameContext::VoteMute(const NETADDR *pAddr, int Secs, const char *pReason, const char *pDisplayName, int AuthedID)
{
if(!TryVoteMute(pAddr, Secs, pReason))
return;
if(!pDisplayName)
return;
char aBuf[128];
if(pReason[0])
str_format(aBuf, sizeof aBuf, "'%s' banned '%s' for %d seconds from voting (%s)",
Server()->ClientName(AuthedID), pDisplayName, Secs, pReason);
else
str_format(aBuf, sizeof aBuf, "'%s' banned '%s' for %d seconds from voting",
Server()->ClientName(AuthedID), pDisplayName, Secs);
SendChat(-1, CHAT_ALL, aBuf);
}
bool CGameContext::VoteUnmute(const NETADDR *pAddr, const char *pDisplayName, int AuthedID)
{
for(int i = 0; i < m_NumVoteMutes; i++)
{
if(net_addr_comp_noport(&m_aVoteMutes[i].m_Addr, pAddr) == 0)
{
m_NumVoteMutes--;
m_aVoteMutes[i] = m_aVoteMutes[m_NumVoteMutes];
if(pDisplayName)
{
char aBuf[128];
str_format(aBuf, sizeof aBuf, "'%s' unbanned '%s' from voting.",
Server()->ClientName(AuthedID), pDisplayName);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "voteunmute", aBuf);
}
return true;
}
}
return false;
}
bool CGameContext::TryMute(const NETADDR *pAddr, int Secs, const char *pReason, bool InitialChatDelay)
{
// find a matching mute for this ip, update expiration time if found
for(int i = 0; i < m_NumMutes; i++)
{
if(net_addr_comp_noport(&m_aMutes[i].m_Addr, pAddr) == 0)
{
const int NewExpire = Server()->Tick() + Secs * Server()->TickSpeed();
if(NewExpire > m_aMutes[i].m_Expire)
{
m_aMutes[i].m_Expire = NewExpire;
str_copy(m_aMutes[i].m_aReason, pReason, sizeof(m_aMutes[i].m_aReason));
m_aMutes[i].m_InitialChatDelay = InitialChatDelay;
}
return true;
}
}
// nothing to update create new one
if(m_NumMutes < MAX_MUTES)
{
m_aMutes[m_NumMutes].m_Addr = *pAddr;
m_aMutes[m_NumMutes].m_Expire = Server()->Tick() + Secs * Server()->TickSpeed();
str_copy(m_aMutes[m_NumMutes].m_aReason, pReason, sizeof(m_aMutes[m_NumMutes].m_aReason));
m_aMutes[m_NumMutes].m_InitialChatDelay = InitialChatDelay;
m_NumMutes++;
return true;
}
// no free slot found
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "mutes", "mute array is full");
return false;
}
void CGameContext::Mute(const NETADDR *pAddr, int Secs, const char *pDisplayName, const char *pReason, bool InitialChatDelay)
{
if(Secs <= 0)
return;
if(!TryMute(pAddr, Secs, pReason, InitialChatDelay))
return;
if(InitialChatDelay)
return;
if(!pDisplayName)
return;
char aBuf[128];
if(pReason[0])
str_format(aBuf, sizeof aBuf, "'%s' has been muted for %d seconds (%s)", pDisplayName, Secs, pReason);
else
str_format(aBuf, sizeof aBuf, "'%s' has been muted for %d seconds", pDisplayName, Secs);
SendChat(-1, CHAT_ALL, aBuf);
}
void CGameContext::ConVoteMute(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int Victim = pResult->GetVictim();
if(Victim < 0 || Victim > MAX_CLIENTS || !pSelf->m_apPlayers[Victim])
{
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "votemute", "Client ID not found");
return;
}
NETADDR Addr;
pSelf->Server()->GetClientAddr(Victim, &Addr);
int Seconds = clamp(pResult->GetInteger(1), 1, 86400);
const char *pReason = pResult->NumArguments() > 2 ? pResult->GetString(2) : "";
pSelf->VoteMute(&Addr, Seconds, pReason, pSelf->Server()->ClientName(Victim), pResult->m_ClientID);
}
void CGameContext::ConVoteUnmute(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int Victim = pResult->GetVictim();
if(Victim < 0 || Victim > MAX_CLIENTS || !pSelf->m_apPlayers[Victim])
{
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "voteunmute", "Client ID not found");
return;
}
NETADDR Addr;
pSelf->Server()->GetClientAddr(Victim, &Addr);
bool Found = pSelf->VoteUnmute(&Addr, pSelf->Server()->ClientName(Victim), pResult->m_ClientID);
if(Found)
{
char aBuf[128];
str_format(aBuf, sizeof aBuf, "'%s' unbanned '%s' from voting.",
pSelf->Server()->ClientName(pResult->m_ClientID), pSelf->Server()->ClientName(Victim));
pSelf->SendChat(-1, 0, aBuf);
}
}
void CGameContext::ConVoteMutes(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(pSelf->m_NumVoteMutes <= 0)
{
// Just to make sure.
pSelf->m_NumVoteMutes = 0;
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "votemutes",
"There are no active vote mutes.");
return;
}
char aIpBuf[64];
char aBuf[128];
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "votemutes",
"Active vote mutes:");
for(int i = 0; i < pSelf->m_NumVoteMutes; i++)
{
net_addr_str(&pSelf->m_aVoteMutes[i].m_Addr, aIpBuf, sizeof(aIpBuf), false);
str_format(aBuf, sizeof aBuf, "%d: \"%s\", %d seconds left (%s)", i,
aIpBuf, (pSelf->m_aVoteMutes[i].m_Expire - pSelf->Server()->Tick()) / pSelf->Server()->TickSpeed(), pSelf->m_aVoteMutes[i].m_aReason);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "votemutes", aBuf);
}
}
void CGameContext::ConMute(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->Console()->Print(
IConsole::OUTPUT_LEVEL_STANDARD,
"mutes",
"Use either 'muteid <client_id> <seconds> <reason>' or 'muteip <ip> <seconds> <reason>'");
}
// mute through client id
void CGameContext::ConMuteID(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int Victim = pResult->GetVictim();
if(Victim < 0 || Victim > MAX_CLIENTS || !pSelf->m_apPlayers[Victim])
{
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "muteid", "Client id not found.");
return;
}
NETADDR Addr;
pSelf->Server()->GetClientAddr(Victim, &Addr);
const char *pReason = pResult->NumArguments() > 2 ? pResult->GetString(2) : "";
pSelf->Mute(&Addr, clamp(pResult->GetInteger(1), 1, 86400),
pSelf->Server()->ClientName(Victim), pReason);
}
// mute through ip, arguments reversed to workaround parsing
void CGameContext::ConMuteIP(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
NETADDR Addr;
if(net_addr_from_str(&Addr, pResult->GetString(0)))
{
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "mutes",
"Invalid network address to mute");
}
const char *pReason = pResult->NumArguments() > 2 ? pResult->GetString(2) : "";
pSelf->Mute(&Addr, clamp(pResult->GetInteger(1), 1, 86400), NULL, pReason);
}
// unmute by mute list index
void CGameContext::ConUnmute(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int Index = pResult->GetInteger(0);
if(Index < 0 || Index >= pSelf->m_NumMutes)
return;
char aIpBuf[64];
char aBuf[64];
net_addr_str(&pSelf->m_aMutes[Index].m_Addr, aIpBuf, sizeof(aIpBuf), false);
str_format(aBuf, sizeof(aBuf), "Unmuted %s", aIpBuf);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "mutes", aBuf);
pSelf->m_NumMutes--;
pSelf->m_aMutes[Index] = pSelf->m_aMutes[pSelf->m_NumMutes];
}
// unmute by player id
void CGameContext::ConUnmuteID(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int Victim = pResult->GetVictim();
if(Victim < 0 || Victim > MAX_CLIENTS || !pSelf->m_apPlayers[Victim])
return;
NETADDR Addr;
pSelf->Server()->GetClientAddr(Victim, &Addr);
for(int i = 0; i < pSelf->m_NumMutes; i++)
{
if(net_addr_comp_noport(&pSelf->m_aMutes[i].m_Addr, &Addr) == 0)
{
char aIpBuf[64];
char aBuf[64];
net_addr_str(&pSelf->m_aMutes[i].m_Addr, aIpBuf, sizeof(aIpBuf), false);
str_format(aBuf, sizeof(aBuf), "Unmuted %s", aIpBuf);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "mutes", aBuf);
pSelf->m_NumMutes--;
pSelf->m_aMutes[i] = pSelf->m_aMutes[pSelf->m_NumMutes];
return;
}
}
}
// list mutes
void CGameContext::ConMutes(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(pSelf->m_NumMutes <= 0)
{
// Just to make sure.
pSelf->m_NumMutes = 0;
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "mutes",
"There are no active mutes.");
return;
}
char aIpBuf[64];
char aBuf[128];
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "mutes",
"Active mutes:");
for(int i = 0; i < pSelf->m_NumMutes; i++)
{
net_addr_str(&pSelf->m_aMutes[i].m_Addr, aIpBuf, sizeof(aIpBuf), false);
str_format(aBuf, sizeof aBuf, "%d: \"%s\", %d seconds left (%s)", i, aIpBuf,
(pSelf->m_aMutes[i].m_Expire - pSelf->Server()->Tick()) / pSelf->Server()->TickSpeed(), pSelf->m_aMutes[i].m_aReason);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "mutes", aBuf);
}
}
void CGameContext::ConModerate(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
bool HadModerator = pSelf->PlayerModerating();
CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientID];
pPlayer->m_Moderating = !pPlayer->m_Moderating;
if(!HadModerator && pPlayer->m_Moderating)
pSelf->SendChat(-1, CHAT_ALL, "Server kick/spec votes will now be actively moderated.", 0);
if(!pSelf->PlayerModerating())
pSelf->SendChat(-1, CHAT_ALL, "Server kick/spec votes are no longer actively moderated.", 0);
if(pPlayer->m_Moderating)
pSelf->SendChatTarget(pResult->m_ClientID, "Active moderator mode enabled for you.");
else
pSelf->SendChatTarget(pResult->m_ClientID, "Active moderator mode disabled for you.");
}
void CGameContext::ConSetDDRTeam(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
CGameControllerDDRace *pController = (CGameControllerDDRace *)pSelf->m_pController;
if(g_Config.m_SvTeam == SV_TEAM_FORBIDDEN || g_Config.m_SvTeam == SV_TEAM_FORCED_SOLO)
{
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "join",
"Teams are disabled");
return;
}
int Target = pResult->GetVictim();
int Team = pResult->GetInteger(1);
if(Team < TEAM_FLOCK || Team >= TEAM_SUPER)
return;
CCharacter *pChr = pSelf->GetPlayerChar(Target);
if((pController->m_Teams.m_Core.Team(Target) && pController->m_Teams.GetDDRaceState(pSelf->m_apPlayers[Target]) == DDRACE_STARTED) || (pChr && pController->m_Teams.IsPractice(pChr->Team())))
pSelf->m_apPlayers[Target]->KillCharacter(WEAPON_GAME);
pController->m_Teams.SetForceCharacterTeam(Target, Team);
}
void CGameContext::ConUninvite(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
CGameControllerDDRace *pController = (CGameControllerDDRace *)pSelf->m_pController;
pController->m_Teams.SetClientInvited(pResult->GetInteger(1), pResult->GetVictim(), false);
}
void CGameContext::ConFreezeHammer(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int Victim = pResult->GetVictim();
CCharacter *pChr = pSelf->GetPlayerChar(Victim);
if(!pChr)
return;
char aBuf[128];
str_format(aBuf, sizeof aBuf, "'%s' got freeze hammer!",
pSelf->Server()->ClientName(Victim));
pSelf->SendChat(-1, CHAT_ALL, aBuf);
pChr->m_FreezeHammer = true;
}
void CGameContext::ConUnFreezeHammer(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int Victim = pResult->GetVictim();
CCharacter *pChr = pSelf->GetPlayerChar(Victim);
if(!pChr)
return;
char aBuf[128];
str_format(aBuf, sizeof aBuf, "'%s' lost freeze hammer!",
pSelf->Server()->ClientName(Victim));
pSelf->SendChat(-1, CHAT_ALL, aBuf);
pChr->m_FreezeHammer = false;
}
void CGameContext::ConVoteNo(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ForceVote(pResult->m_ClientID, false);
}
void CGameContext::ConDrySave(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientID];
if(!pPlayer || pSelf->Server()->GetAuthedState(pResult->m_ClientID) != AUTHED_ADMIN)
return;
CSaveTeam SavedTeam;
int Result = SavedTeam.Save(pSelf, pPlayer->GetTeam(), true);
if(CSaveTeam::HandleSaveError(Result, pResult->m_ClientID, pSelf))
return;
char aTimestamp[32];
str_timestamp(aTimestamp, sizeof(aTimestamp));
char aBuf[64];
str_format(aBuf, sizeof(aBuf), "%s_%s_%s.save", pSelf->Server()->GetMapName(), aTimestamp, pSelf->Server()->GetAuthName(pResult->m_ClientID));
IOHANDLE File = pSelf->Storage()->OpenFile(aBuf, IOFLAG_WRITE, IStorage::TYPE_ALL);
if(!File)
return;
int Len = str_length(SavedTeam.GetString());
io_write(File, SavedTeam.GetString(), Len);
io_close(File);
}
void CGameContext::ConDumpAntibot(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->Antibot()->Dump();
}
void CGameContext::ConDumpLog(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int LimitSecs = MAX_LOG_SECONDS;
if(pResult->NumArguments() > 0)
LimitSecs = pResult->GetInteger(0);
if(LimitSecs < 0)
return;
for(int i = pSelf->m_FirstLog; i != pSelf->m_LastLog; i = (i + 1) % pSelf->MAX_LOGS)
{
CLog *pEntry = &pSelf->m_aLogs[i];
if(!pEntry->m_Timestamp)
continue;
int Seconds = (time_get() - pEntry->m_Timestamp) / time_freq();
if(Seconds > LimitSecs)
continue;
char aBuf[256];
if(pEntry->m_FromServer)
str_format(aBuf, sizeof aBuf, "%s, %d seconds ago", pEntry->m_aDescription, Seconds);
else
str_format(aBuf, sizeof aBuf, "%s, %d seconds ago < addr=<{%s}> name='%s' client=%d",
pEntry->m_aDescription, Seconds, pEntry->m_aClientAddrStr, pEntry->m_aClientName, pEntry->m_ClientVersion);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "log", aBuf);
}
}
void CGameContext::LogEvent(const char *Description, int ClientID)
{
CLog *pNewEntry = &m_aLogs[m_LastLog];
m_LastLog = (m_LastLog + 1) % MAX_LOGS;
if(m_LastLog == m_FirstLog)
m_FirstLog++;
pNewEntry->m_Timestamp = time_get();
str_copy(pNewEntry->m_aDescription, Description);
pNewEntry->m_FromServer = ClientID < 0;
if(!pNewEntry->m_FromServer)
{
pNewEntry->m_ClientVersion = Server()->GetClientVersion(ClientID);
Server()->GetClientAddr(ClientID, pNewEntry->m_aClientAddrStr, sizeof(pNewEntry->m_aClientAddrStr));
str_copy(pNewEntry->m_aClientName, Server()->ClientName(ClientID));
}
}