Add rescuemodes

May `/rescuemode` be case-insensitive

clang-tidy

conflicts

clang-tidy

`CMDFLAG_PRACTICE`
This commit is contained in:
Vlad 2024-02-28 20:56:43 +03:00 committed by gerdoe-jr
parent 3887eea18d
commit 4532a64b2b
10 changed files with 139 additions and 46 deletions

View file

@ -1652,8 +1652,76 @@ void CGameContext::ConRescue(IConsole::IResult *pResult, void *pUserData)
return; return;
} }
pChr->Rescue(); bool GoRescue = true;
pChr->UnFreeze();
if(pPlayer->m_RescueMode == RESCUEMODE_MANUAL)
{
// if character can't set his rescue state then we should rescue him instead
GoRescue = !pChr->TrySetRescue(RESCUEMODE_MANUAL);
}
if(GoRescue)
{
pChr->Rescue();
pChr->UnFreeze();
}
}
void CGameContext::ConRescueMode(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)
return;
CGameTeams &Teams = pSelf->m_pController->Teams();
int Team = pSelf->GetDDRaceTeam(pResult->m_ClientId);
if(!g_Config.m_SvRescue && !Teams.IsPractice(Team))
{
pSelf->SendChatTarget(pPlayer->GetCid(), "Rescue is not enabled on this server and you're not in a team with /practice turned on. Note that you can't earn a rank with practice enabled.");
return;
}
if(str_comp_nocase(pResult->GetString(0), "auto") == 0)
{
if(pPlayer->m_RescueMode != RESCUEMODE_AUTO)
{
pPlayer->m_RescueMode = RESCUEMODE_AUTO;
pSelf->SendChatTarget(pPlayer->GetCid(), "Rescue mode changed to auto.");
}
return;
}
if(str_comp_nocase(pResult->GetString(0), "manual") == 0)
{
if(pPlayer->m_RescueMode != RESCUEMODE_MANUAL)
{
pPlayer->m_RescueMode = RESCUEMODE_MANUAL;
pSelf->SendChatTarget(pPlayer->GetCid(), "Rescue mode changed to manual.");
}
return;
}
if(str_comp_nocase(pResult->GetString(0), "list") == 0)
{
pSelf->SendChatTarget(pPlayer->GetCid(), "Available rescue modes: auto, manual");
}
else if(str_comp_nocase(pResult->GetString(0), "") == 0)
{
char aBuf[64];
str_format(aBuf, sizeof(aBuf), "Current rescue mode: %s.", pPlayer->m_RescueMode == RESCUEMODE_MANUAL ? "manual" : "auto");
pSelf->SendChatTarget(pPlayer->GetCid(), aBuf);
}
else
{
pSelf->SendChatTarget(pPlayer->GetCid(), "Unknown argument. Check '/rescuemode list'");
}
} }
void CGameContext::ConTeleTo(IConsole::IResult *pResult, void *pUserData) void CGameContext::ConTeleTo(IConsole::IResult *pResult, void *pUserData)

View file

@ -99,6 +99,7 @@ bool CCharacter::Spawn(CPlayer *pPlayer, vec2 Pos)
SendZoneMsgs(); // we want a entermessage also on spawn SendZoneMsgs(); // we want a entermessage also on spawn
GameServer()->SendTuningParams(m_pPlayer->GetCid(), m_TuneZone); GameServer()->SendTuningParams(m_pPlayer->GetCid(), m_TuneZone);
TrySetRescue(RESCUEMODE_MANUAL);
Server()->StartRecord(m_pPlayer->GetCid()); Server()->StartRecord(m_pPlayer->GetCid());
return true; return true;
@ -2010,10 +2011,46 @@ void CCharacter::SetTeams(CGameTeams *pTeams)
m_Core.SetTeamsCore(&m_pTeams->m_Core); m_Core.SetTeamsCore(&m_pTeams->m_Core);
} }
void CCharacter::SetRescue() bool CCharacter::TrySetRescue(int RescueMode)
{ {
m_RescueTee.Save(this); bool Set = false;
m_SetSavePos = true; if(g_Config.m_SvRescue || ((g_Config.m_SvTeam == SV_TEAM_FORCED_SOLO || Team() > TEAM_FLOCK) && Team() >= TEAM_FLOCK && Team() < TEAM_SUPER))
{
// check for nearby health pickups (also freeze)
bool InHealthPickup = false;
if(!m_Core.m_IsInFreeze)
{
CEntity *apEnts[9];
int Num = GameWorld()->FindEntities(m_Pos, GetProximityRadius() + CPickup::ms_CollisionExtraSize, apEnts, std::size(apEnts), CGameWorld::ENTTYPE_PICKUP);
for(int i = 0; i < Num; ++i)
{
CPickup *pPickup = static_cast<CPickup *>(apEnts[i]);
if(pPickup->Type() == POWERUP_HEALTH)
{
// This uses a separate variable InHealthPickup instead of setting m_Core.m_IsInFreeze
// as the latter causes freezebars to flicker when standing in the freeze range of a
// health pickup. When the same code for client prediction is added, the freezebars
// still flicker, but only when standing at the edge of the health pickup's freeze range.
InHealthPickup = true;
break;
}
}
}
if(!m_Core.m_IsInFreeze && IsGrounded() && !m_Core.m_DeepFrozen && !InHealthPickup)
{
ForceSetRescue(RescueMode);
Set = true;
}
}
return Set;
}
void CCharacter::ForceSetRescue(int RescueMode)
{
m_RescueTee[RescueMode].Save(this);
m_SetSavePos[RescueMode] = true;
} }
void CCharacter::DDRaceTick() void CCharacter::DDRaceTick()
@ -2061,35 +2098,9 @@ void CCharacter::DDRaceTick()
} }
} }
// check for nearby health pickups (also freeze)
bool InHealthPickup = false;
if(!m_Core.m_IsInFreeze)
{
CEntity *apEnts[9];
int Num = GameWorld()->FindEntities(m_Pos, GetProximityRadius() + CPickup::ms_CollisionExtraSize, apEnts, std::size(apEnts), CGameWorld::ENTTYPE_PICKUP);
for(int i = 0; i < Num; ++i)
{
CPickup *pPickup = static_cast<CPickup *>(apEnts[i]);
if(pPickup->Type() == POWERUP_HEALTH)
{
// This uses a separate variable InHealthPickup instead of setting m_Core.m_IsInFreeze
// as the latter causes freezebars to flicker when standing in the freeze range of a
// health pickup. When the same code for client prediction is added, the freezebars
// still flicker, but only when standing at the edge of the health pickup's freeze range.
InHealthPickup = true;
break;
}
}
}
// look for save position for rescue feature // look for save position for rescue feature
if(g_Config.m_SvRescue || ((g_Config.m_SvTeam == SV_TEAM_FORCED_SOLO || Team() > TEAM_FLOCK) && Team() >= TEAM_FLOCK && Team() < TEAM_SUPER)) // always update auto rescue
{ TrySetRescue(RESCUEMODE_AUTO);
if(!m_Core.m_IsInFreeze && IsGrounded() && !m_Core.m_DeepFrozen && !InHealthPickup)
{
SetRescue();
}
}
m_Core.m_Id = GetPlayer()->GetCid(); m_Core.m_Id = GetPlayer()->GetCid();
} }
@ -2298,7 +2309,8 @@ void CCharacter::DDRaceInit()
m_Paused = false; m_Paused = false;
m_DDRaceState = DDRACE_NONE; m_DDRaceState = DDRACE_NONE;
m_PrevPos = m_Pos; m_PrevPos = m_Pos;
m_SetSavePos = false; for(bool &Set : m_SetSavePos)
Set = false;
m_LastBroadcast = 0; m_LastBroadcast = 0;
m_TeamBeforeSuper = 0; m_TeamBeforeSuper = 0;
m_Core.m_Id = GetPlayer()->GetCid(); m_Core.m_Id = GetPlayer()->GetCid();
@ -2348,7 +2360,7 @@ void CCharacter::DDRaceInit()
void CCharacter::Rescue() void CCharacter::Rescue()
{ {
if(m_SetSavePos && !m_Core.m_Super) if(m_SetSavePos[GetPlayer()->m_RescueMode] && !m_Core.m_Super)
{ {
if(m_LastRescue + (int64_t)g_Config.m_SvRescueDelay * Server()->TickSpeed() > Server()->Tick()) if(m_LastRescue + (int64_t)g_Config.m_SvRescueDelay * Server()->TickSpeed() > Server()->Tick())
{ {
@ -2359,7 +2371,7 @@ void CCharacter::Rescue()
} }
float StartTime = m_StartTime; float StartTime = m_StartTime;
m_RescueTee.Load(this, Team()); m_RescueTee[GetPlayer()->m_RescueMode].Load(this, Team());
// Don't load these from saved tee: // Don't load these from saved tee:
m_Core.m_Vel = vec2(0, 0); m_Core.m_Vel = vec2(0, 0);
m_Core.m_HookState = HOOK_IDLE; m_Core.m_HookState = HOOK_IDLE;

View file

@ -166,7 +166,7 @@ private:
int m_LastBroadcast; int m_LastBroadcast;
void DDRaceInit(); void DDRaceInit();
void HandleSkippableTiles(int Index); void HandleSkippableTiles(int Index);
void SetRescue(); void ForceSetRescue(int RescueMode);
void DDRaceTick(); void DDRaceTick();
void DDRacePostCoreTick(); void DDRacePostCoreTick();
void HandleBroadcast(); void HandleBroadcast();
@ -174,12 +174,13 @@ private:
void SendZoneMsgs(); void SendZoneMsgs();
IAntibot *Antibot(); IAntibot *Antibot();
bool m_SetSavePos; bool m_SetSavePos[NUM_RESCUEMODES];
CSaveTee m_RescueTee; CSaveTee m_RescueTee[NUM_RESCUEMODES];
public: public:
CGameTeams *Teams() { return m_pTeams; } CGameTeams *Teams() { return m_pTeams; }
void SetTeams(CGameTeams *pTeams); void SetTeams(CGameTeams *pTeams);
bool TrySetRescue(int RescueMode);
void FillAntibot(CAntibotCharacterData *pData); void FillAntibot(CAntibotCharacterData *pData);
void Pause(bool Pause); void Pause(bool Pause);
@ -259,7 +260,7 @@ public:
bool IsSuper() { return m_Core.m_Super; } bool IsSuper() { return m_Core.m_Super; }
CSaveTee &GetRescueTeeRef() { return m_RescueTee; } CSaveTee &GetLastRescueTeeRef(int Mode = RESCUEMODE_AUTO) { return m_RescueTee[Mode]; }
}; };
enum enum

View file

@ -3689,9 +3689,9 @@ void CGameContext::RegisterChatCommands()
Console()->Register("saytimeall", "", CFGFLAG_CHAT | CFGFLAG_SERVER | CFGFLAG_NONTEEHISTORIC, ConSayTimeAll, this, "Publicly messages everyone your current time in this current running race"); Console()->Register("saytimeall", "", CFGFLAG_CHAT | CFGFLAG_SERVER | CFGFLAG_NONTEEHISTORIC, ConSayTimeAll, this, "Publicly messages everyone your current time in this current running race");
Console()->Register("time", "", CFGFLAG_CHAT | CFGFLAG_SERVER, ConTime, this, "Privately shows you your current time in this current running race in the broadcast message"); Console()->Register("time", "", CFGFLAG_CHAT | CFGFLAG_SERVER, ConTime, this, "Privately shows you your current time in this current running race in the broadcast message");
Console()->Register("timer", "?s['gametimer'|'broadcast'|'both'|'none'|'cycle']", CFGFLAG_CHAT | CFGFLAG_SERVER, ConSetTimerType, this, "Personal Setting of showing time in either broadcast or game/round timer, timer s, where s = broadcast for broadcast, gametimer for game/round timer, cycle for cycle, both for both, none for no timer and nothing to show current status"); Console()->Register("timer", "?s['gametimer'|'broadcast'|'both'|'none'|'cycle']", CFGFLAG_CHAT | CFGFLAG_SERVER, ConSetTimerType, this, "Personal Setting of showing time in either broadcast or game/round timer, timer s, where s = broadcast for broadcast, gametimer for game/round timer, cycle for cycle, both for both, none for no timer and nothing to show current status");
Console()->Register("r", "", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConRescue, this, "Teleport yourself out of freeze if auto rescue mode is enabled, otherwise it will set position for rescuing if grounded and teleport you out of freeze if not (use sv_rescue 1 to enable this feature)");
Console()->Register("r", "", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConRescue, this, "Teleport yourself out of freeze (use sv_rescue 1 to enable this feature)"); Console()->Register("rescue", "", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConRescue, this, "Teleport yourself out of freeze if auto rescue mode is enabled, otherwise it will set position for rescuing if grounded and teleport you out of freeze if not (use sv_rescue 1 to enable this feature)");
Console()->Register("rescue", "", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConRescue, this, "Teleport yourself out of freeze (use sv_rescue 1 to enable this feature)"); Console()->Register("rescuemode", "?r['auto'|'manual']", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConRescueMode, this, "Sets one of the two rescue modes (auto or manual). Prints current mode if no arguments provided");
Console()->Register("tp", "?r[player name]", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConTeleTo, this, "Depending on the number of supplied arguments, teleport yourself to; (0.) where you are spectating or aiming; (1.) the specified player name"); Console()->Register("tp", "?r[player name]", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConTeleTo, this, "Depending on the number of supplied arguments, teleport yourself to; (0.) where you are spectating or aiming; (1.) the specified player name");
Console()->Register("teleport", "?r[player name]", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConTeleTo, this, "Depending on the number of supplied arguments, teleport yourself to; (0.) where you are spectating or aiming; (1.) the specified player name"); Console()->Register("teleport", "?r[player name]", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConTeleTo, this, "Depending on the number of supplied arguments, teleport yourself to; (0.) where you are spectating or aiming; (1.) the specified player name");
Console()->Register("tpxy", "f[x] f[y]", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConTeleXY, this, "Teleport yourself to the specified coordinates. A tilde (~) can be used to denote your current position, e.g. '/tpxy ~1 ~' to teleport one tile to the right"); Console()->Register("tpxy", "f[x] f[y]", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConTeleXY, this, "Teleport yourself to the specified coordinates. A tilde (~) can be used to denote your current position, e.g. '/tpxy ~1 ~' to teleport one tile to the right");
@ -3718,7 +3718,6 @@ void CGameContext::RegisterChatCommands()
Console()->Register("unweapons", "", CFGFLAG_CHAT | CMDFLAG_PRACTICE, ConPracticeUnWeapons, this, "Removes all weapons from you"); Console()->Register("unweapons", "", CFGFLAG_CHAT | CMDFLAG_PRACTICE, ConPracticeUnWeapons, this, "Removes all weapons from you");
Console()->Register("ninja", "", CFGFLAG_CHAT | CMDFLAG_PRACTICE, ConPracticeNinja, this, "Makes you a ninja"); Console()->Register("ninja", "", CFGFLAG_CHAT | CMDFLAG_PRACTICE, ConPracticeNinja, this, "Makes you a ninja");
Console()->Register("unninja", "", CFGFLAG_CHAT | CMDFLAG_PRACTICE, ConPracticeUnNinja, this, "Removes ninja from you"); Console()->Register("unninja", "", CFGFLAG_CHAT | CMDFLAG_PRACTICE, ConPracticeUnNinja, this, "Removes ninja from you");
Console()->Register("kill", "", CFGFLAG_CHAT | CFGFLAG_SERVER, ConProtectedKill, this, "Kill yourself when kill-protected during a long game (use f1, kill for regular kill)"); Console()->Register("kill", "", CFGFLAG_CHAT | CFGFLAG_SERVER, ConProtectedKill, this, "Kill yourself when kill-protected during a long game (use f1, kill for regular kill)");
} }

View file

@ -457,6 +457,7 @@ private:
static void ConTime(IConsole::IResult *pResult, void *pUserData); static void ConTime(IConsole::IResult *pResult, void *pUserData);
static void ConSetTimerType(IConsole::IResult *pResult, void *pUserData); static void ConSetTimerType(IConsole::IResult *pResult, void *pUserData);
static void ConRescue(IConsole::IResult *pResult, void *pUserData); static void ConRescue(IConsole::IResult *pResult, void *pUserData);
static void ConRescueMode(IConsole::IResult *pResult, void *pUserData);
static void ConTeleTo(IConsole::IResult *pResult, void *pUserData); static void ConTeleTo(IConsole::IResult *pResult, void *pUserData);
static void ConTeleXY(IConsole::IResult *pResult, void *pUserData); static void ConTeleXY(IConsole::IResult *pResult, void *pUserData);
static void ConTeleCursor(IConsole::IResult *pResult, void *pUserData); static void ConTeleCursor(IConsole::IResult *pResult, void *pUserData);

View file

@ -143,6 +143,7 @@ void CPlayer::Reset()
m_VotedForPractice = false; m_VotedForPractice = false;
m_SwapTargetsClientId = -1; m_SwapTargetsClientId = -1;
m_BirthdayAnnounced = false; m_BirthdayAnnounced = false;
m_RescueMode = RESCUEMODE_AUTO;
} }
static int PlayerFlags_SixToSeven(int Flags) static int PlayerFlags_SixToSeven(int Flags)

View file

@ -225,6 +225,8 @@ public:
int m_SwapTargetsClientId; //Client ID of the swap target for the given player int m_SwapTargetsClientId; //Client ID of the swap target for the given player
bool m_BirthdayAnnounced; bool m_BirthdayAnnounced;
int m_RescueMode;
CSaveTee m_LastTeleTee; CSaveTee m_LastTeleTee;
}; };

View file

@ -236,7 +236,8 @@ void CSaveTee::Load(CCharacter *pChr, int Team, bool IsSwap)
{ {
// Always create a rescue tee at the exact location we loaded from so that // Always create a rescue tee at the exact location we loaded from so that
// the old one gets overwritten. // the old one gets overwritten.
pChr->SetRescue(); pChr->ForceSetRescue(RESCUEMODE_AUTO);
pChr->ForceSetRescue(RESCUEMODE_MANUAL);
} }
} }

View file

@ -12,6 +12,13 @@ class CGameWorld;
class CCharacter; class CCharacter;
class CSaveTeam; class CSaveTeam;
enum
{
RESCUEMODE_AUTO = 0,
RESCUEMODE_MANUAL,
NUM_RESCUEMODES
};
class CSaveTee class CSaveTee
{ {
public: public:

View file

@ -951,7 +951,8 @@ void CGameTeams::SwapTeamCharacters(CPlayer *pPrimaryPlayer, CPlayer *pTargetPla
} }
std::swap(m_aTeeStarted[pPrimaryPlayer->GetCid()], m_aTeeStarted[pTargetPlayer->GetCid()]); std::swap(m_aTeeStarted[pPrimaryPlayer->GetCid()], m_aTeeStarted[pTargetPlayer->GetCid()]);
std::swap(m_aTeeFinished[pPrimaryPlayer->GetCid()], m_aTeeFinished[pTargetPlayer->GetCid()]); std::swap(m_aTeeFinished[pPrimaryPlayer->GetCid()], m_aTeeFinished[pTargetPlayer->GetCid()]);
std::swap(pPrimaryPlayer->GetCharacter()->GetRescueTeeRef(), pTargetPlayer->GetCharacter()->GetRescueTeeRef()); std::swap(pPrimaryPlayer->GetCharacter()->GetLastRescueTeeRef(RESCUEMODE_AUTO), pTargetPlayer->GetCharacter()->GetLastRescueTeeRef(RESCUEMODE_AUTO));
std::swap(pPrimaryPlayer->GetCharacter()->GetLastRescueTeeRef(RESCUEMODE_MANUAL), pTargetPlayer->GetCharacter()->GetLastRescueTeeRef(RESCUEMODE_MANUAL));
GameServer()->m_World.SwapClients(pPrimaryPlayer->GetCid(), pTargetPlayer->GetCid()); GameServer()->m_World.SwapClients(pPrimaryPlayer->GetCid(), pTargetPlayer->GetCid());