mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-19 22:48:18 +00:00
added spectator mode for dead players in survival
This commit is contained in:
parent
6b8287f7c7
commit
ad33841deb
|
@ -129,7 +129,7 @@ void CItems::RenderPickup(const CNetObj_Pickup *pPrev, const CNetObj_Pickup *pCu
|
|||
case PICKUP_LASER:
|
||||
Size = g_pData->m_Weapons.m_aId[WEAPON_LASER].m_VisualSize;
|
||||
break;
|
||||
case SPRITE_PICKUP_NINJA:
|
||||
case PICKUP_NINJA:
|
||||
m_pClient->m_pEffects->PowerupShine(Pos, vec2(96,18));
|
||||
Size *= 2.0f;
|
||||
Pos.x -= 10.0f;
|
||||
|
|
|
@ -414,8 +414,8 @@ bool CScoreboard::Active()
|
|||
|
||||
if(m_pClient->m_Snap.m_pLocalInfo && m_pClient->m_Snap.m_pLocalInfo->m_Team != TEAM_SPECTATORS)
|
||||
{
|
||||
// we are not a spectator, check if we are dead and the game isn't paused
|
||||
if(!m_pClient->m_Snap.m_pLocalCharacter && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED))
|
||||
// we are not a spectator, check if we are dead, don't follow a player and the game isn't paused
|
||||
if(!m_pClient->m_Snap.m_pLocalCharacter && !m_pClient->m_Snap.m_SpecInfo.m_Active && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -195,28 +195,33 @@ void CSpectator::OnRender()
|
|||
float LineHeight = 60.0f;
|
||||
bool Selected = false;
|
||||
|
||||
if(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SPEC_FREEVIEW)
|
||||
if(m_pClient->m_Snap.m_pLocalInfo->m_Team == TEAM_SPECTATORS)
|
||||
{
|
||||
Graphics()->TextureSet(-1);
|
||||
Graphics()->QuadsBegin();
|
||||
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.25f);
|
||||
RenderTools()->DrawRoundRect(Width/2.0f-280.0f, Height/2.0f-280.0f, 270.0f, 60.0f, 20.0f);
|
||||
Graphics()->QuadsEnd();
|
||||
}
|
||||
if(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SPEC_FREEVIEW)
|
||||
{
|
||||
Graphics()->TextureSet(-1);
|
||||
Graphics()->QuadsBegin();
|
||||
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.25f);
|
||||
RenderTools()->DrawRoundRect(Width/2.0f-280.0f, Height/2.0f-280.0f, 270.0f, 60.0f, 20.0f);
|
||||
Graphics()->QuadsEnd();
|
||||
}
|
||||
|
||||
if(m_SelectorMouse.x >= -280.0f && m_SelectorMouse.x <= -10.0f &&
|
||||
m_SelectorMouse.y >= -280.0f && m_SelectorMouse.y <= -220.0f)
|
||||
{
|
||||
m_SelectedSpectatorID = SPEC_FREEVIEW;
|
||||
Selected = true;
|
||||
if(m_SelectorMouse.x >= -280.0f && m_SelectorMouse.x <= -10.0f &&
|
||||
m_SelectorMouse.y >= -280.0f && m_SelectorMouse.y <= -220.0f)
|
||||
{
|
||||
m_SelectedSpectatorID = SPEC_FREEVIEW;
|
||||
Selected = true;
|
||||
}
|
||||
TextRender()->TextColor(1.0f, 1.0f, 1.0f, Selected?1.0f:0.5f);
|
||||
TextRender()->Text(0, Width/2.0f-240.0f, Height/2.0f-265.0f, FontSize, Localize("Free-View"), -1);
|
||||
}
|
||||
TextRender()->TextColor(1.0f, 1.0f, 1.0f, Selected?1.0f:0.5f);
|
||||
TextRender()->Text(0, Width/2.0f-240.0f, Height/2.0f-265.0f, FontSize, Localize("Free-View"), -1);
|
||||
|
||||
float x = -270.0f, y = StartY;
|
||||
for(int i = 0, Count = 0; i < MAX_CLIENTS; ++i)
|
||||
{
|
||||
if(!m_pClient->m_Snap.m_paPlayerInfos[i] || m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team == TEAM_SPECTATORS)
|
||||
if(!m_pClient->m_Snap.m_paPlayerInfos[i] || m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team == TEAM_SPECTATORS ||
|
||||
(m_pClient->m_Snap.m_pLocalInfo->m_Team != TEAM_SPECTATORS && (m_pClient->m_Snap.m_paPlayerInfos[i]->m_PlayerFlags&PLAYERFLAG_DEAD ||
|
||||
m_pClient->m_Snap.m_pLocalInfo->m_Team != m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team || i == m_pClient->m_Snap.m_LocalClientID)))
|
||||
continue;
|
||||
|
||||
if(++Count%9 == 0)
|
||||
|
|
|
@ -777,7 +777,7 @@ void CGameClient::OnNewSnapshot()
|
|||
{
|
||||
m_Snap.m_pSpectatorInfo = (const CNetObj_SpectatorInfo *)pData;
|
||||
m_Snap.m_pPrevSpectatorInfo = (const CNetObj_SpectatorInfo *)Client()->SnapFindItem(IClient::SNAP_PREV, NETOBJTYPE_SPECTATORINFO, Item.m_ID);
|
||||
|
||||
m_Snap.m_SpecInfo.m_Active = true;
|
||||
m_Snap.m_SpecInfo.m_SpectatorID = m_Snap.m_pSpectatorInfo->m_SpectatorID;
|
||||
}
|
||||
else if(Item.m_Type == NETOBJTYPE_GAMEINFO)
|
||||
|
|
|
@ -770,7 +770,8 @@ bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon)
|
|||
int Mask = CmaskOne(From);
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() == TEAM_SPECTATORS && GameServer()->m_apPlayers[i]->m_SpectatorID == From)
|
||||
if(GameServer()->m_apPlayers[i] && (GameServer()->m_apPlayers[i]->GetTeam() == TEAM_SPECTATORS || GameServer()->m_apPlayers[i]->m_DeadSpecMode) &&
|
||||
GameServer()->m_apPlayers[i]->GetSpectatorID() == From)
|
||||
Mask |= CmaskOne(i);
|
||||
}
|
||||
GameServer()->CreateSound(GameServer()->m_apPlayers[From]->m_ViewPos, SOUND_HIT, Mask);
|
||||
|
@ -848,7 +849,7 @@ void CCharacter::Snap(int SnappingClient)
|
|||
pCharacter->m_Direction = m_Input.m_Direction;
|
||||
|
||||
if(m_pPlayer->GetCID() == SnappingClient || SnappingClient == -1 ||
|
||||
(!g_Config.m_SvStrictSpectateMode && m_pPlayer->GetCID() == GameServer()->m_apPlayers[SnappingClient]->m_SpectatorID))
|
||||
(!g_Config.m_SvStrictSpectateMode && m_pPlayer->GetCID() == GameServer()->m_apPlayers[SnappingClient]->GetSpectatorID()))
|
||||
{
|
||||
pCharacter->m_Health = m_Health;
|
||||
pCharacter->m_Armor = m_Armor;
|
||||
|
|
|
@ -573,13 +573,6 @@ void CGameContext::OnClientDrop(int ClientID, const char *pReason)
|
|||
m_apPlayers[ClientID] = 0;
|
||||
|
||||
m_VoteUpdate = true;
|
||||
|
||||
// update spectator modes
|
||||
for(int i = 0; i < MAX_CLIENTS; ++i)
|
||||
{
|
||||
if(m_apPlayers[i] && m_apPlayers[i]->m_SpectatorID == ClientID)
|
||||
m_apPlayers[i]->m_SpectatorID = SPEC_FREEVIEW;
|
||||
}
|
||||
}
|
||||
|
||||
void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
|
||||
|
@ -832,15 +825,12 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
|
|||
{
|
||||
CNetMsg_Cl_SetSpectatorMode *pMsg = (CNetMsg_Cl_SetSpectatorMode *)pRawMsg;
|
||||
|
||||
if(pPlayer->GetTeam() != TEAM_SPECTATORS || pPlayer->m_SpectatorID == pMsg->m_SpectatorID || ClientID == pMsg->m_SpectatorID ||
|
||||
(g_Config.m_SvSpamprotection && pPlayer->m_LastSetSpectatorMode && pPlayer->m_LastSetSpectatorMode+Server()->TickSpeed()*3 > Server()->Tick()))
|
||||
if(g_Config.m_SvSpamprotection && pPlayer->m_LastSetSpectatorMode && pPlayer->m_LastSetSpectatorMode+Server()->TickSpeed()*3 > Server()->Tick())
|
||||
return;
|
||||
|
||||
pPlayer->m_LastSetSpectatorMode = Server()->Tick();
|
||||
if(pMsg->m_SpectatorID != SPEC_FREEVIEW && (!m_apPlayers[pMsg->m_SpectatorID] || m_apPlayers[pMsg->m_SpectatorID]->GetTeam() == TEAM_SPECTATORS))
|
||||
if(!pPlayer->SetSpectatorID(pMsg->m_SpectatorID))
|
||||
SendChatTarget(ClientID, "Invalid spectator id used");
|
||||
else
|
||||
pPlayer->m_SpectatorID = pMsg->m_SpectatorID;
|
||||
}
|
||||
else if (MsgID == NETMSGTYPE_CL_STARTINFO)
|
||||
{
|
||||
|
|
|
@ -226,6 +226,16 @@ int IGameController::OnCharacterDeath(class CCharacter *pVictim, class CPlayer *
|
|||
}
|
||||
if(Weapon == WEAPON_SELF)
|
||||
pVictim->GetPlayer()->m_RespawnTick = Server()->Tick()+Server()->TickSpeed()*3.0f;
|
||||
|
||||
|
||||
// update spectator modes for dead players in survival
|
||||
if(m_GameFlags&GAMEFLAG_SURVIVAL)
|
||||
{
|
||||
for(int i = 0; i < MAX_CLIENTS; ++i)
|
||||
if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->m_DeadSpecMode)
|
||||
GameServer()->m_apPlayers[i]->UpdateDeadSpecMode();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -254,7 +254,8 @@ void CGameControllerCTF::Tick()
|
|||
if(!pPlayer)
|
||||
continue;
|
||||
|
||||
if(pPlayer->GetTeam() == TEAM_SPECTATORS && pPlayer->m_SpectatorID != SPEC_FREEVIEW && GameServer()->m_apPlayers[pPlayer->m_SpectatorID] && GameServer()->m_apPlayers[pPlayer->m_SpectatorID]->GetTeam() == fi)
|
||||
if((pPlayer->GetTeam() == TEAM_SPECTATORS || pPlayer->m_DeadSpecMode) && pPlayer->GetSpectatorID() != SPEC_FREEVIEW &&
|
||||
GameServer()->m_apPlayers[pPlayer->GetSpectatorID()] && GameServer()->m_apPlayers[pPlayer->GetSpectatorID()]->GetTeam() == fi)
|
||||
GameServer()->CreateSoundGlobal(SOUND_CTF_GRAB_EN, c);
|
||||
else if(pPlayer->GetTeam() == fi)
|
||||
GameServer()->CreateSoundGlobal(SOUND_CTF_GRAB_EN, c);
|
||||
|
|
|
@ -27,6 +27,8 @@ CPlayer::CPlayer(CGameContext *pGameServer, int ClientID, bool Dummy)
|
|||
m_IsReadyToPlay = GameServer()->m_pController->GetGameState() != IGameController::GS_WARMUP &&
|
||||
GameServer()->m_pController->GetGameState() != IGameController::GS_PAUSED;
|
||||
m_RespawnDisabled = GameServer()->m_pController->GetStartRespawnState();
|
||||
m_DeadSpecMode = false;
|
||||
m_Spawning = 0;
|
||||
}
|
||||
|
||||
CPlayer::~CPlayer()
|
||||
|
@ -74,7 +76,7 @@ void CPlayer::Tick()
|
|||
if(!m_pCharacter && m_Team == TEAM_SPECTATORS && m_SpectatorID == SPEC_FREEVIEW)
|
||||
m_ViewPos -= vec2(clamp(m_ViewPos.x-m_LatestActivity.m_TargetX, -500.0f, 500.0f), clamp(m_ViewPos.y-m_LatestActivity.m_TargetY, -400.0f, 400.0f));
|
||||
|
||||
if(!m_pCharacter && m_DieTick+Server()->TickSpeed()*3 <= Server()->Tick())
|
||||
if(!m_pCharacter && m_DieTick+Server()->TickSpeed()*3 <= Server()->Tick() && !m_DeadSpecMode)
|
||||
Respawn();
|
||||
|
||||
if(m_pCharacter)
|
||||
|
@ -107,8 +109,8 @@ void CPlayer::PostTick()
|
|||
}
|
||||
}
|
||||
|
||||
// update view pos for spectators
|
||||
if(m_Team == TEAM_SPECTATORS && m_SpectatorID != SPEC_FREEVIEW && GameServer()->m_apPlayers[m_SpectatorID])
|
||||
// update view pos for spectators and dead players
|
||||
if((m_Team == TEAM_SPECTATORS || m_DeadSpecMode) && m_SpectatorID != SPEC_FREEVIEW && GameServer()->m_apPlayers[m_SpectatorID])
|
||||
m_ViewPos = GameServer()->m_apPlayers[m_SpectatorID]->m_ViewPos;
|
||||
}
|
||||
|
||||
|
@ -147,7 +149,7 @@ void CPlayer::Snap(int SnappingClient)
|
|||
if(m_ClientID == SnappingClient)
|
||||
pPlayerInfo->m_Local = 1;
|
||||
|
||||
if(m_ClientID == SnappingClient && m_Team == TEAM_SPECTATORS)
|
||||
if(m_ClientID == SnappingClient && (m_Team == TEAM_SPECTATORS || m_DeadSpecMode))
|
||||
{
|
||||
CNetObj_SpectatorInfo *pSpectatorInfo = static_cast<CNetObj_SpectatorInfo *>(Server()->SnapNewItem(NETOBJTYPE_SPECTATORINFO, m_ClientID, sizeof(CNetObj_SpectatorInfo)));
|
||||
if(!pSpectatorInfo)
|
||||
|
@ -162,6 +164,21 @@ void CPlayer::Snap(int SnappingClient)
|
|||
void CPlayer::OnDisconnect()
|
||||
{
|
||||
KillCharacter();
|
||||
|
||||
if(m_Team != TEAM_SPECTATORS)
|
||||
{
|
||||
// update spectator modes
|
||||
for(int i = 0; i < MAX_CLIENTS; ++i)
|
||||
{
|
||||
if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->m_SpectatorID == m_ClientID)
|
||||
{
|
||||
if(GameServer()->m_apPlayers[i]->m_DeadSpecMode)
|
||||
GameServer()->m_apPlayers[i]->UpdateDeadSpecMode();
|
||||
else
|
||||
GameServer()->m_apPlayers[i]->m_SpectatorID = SPEC_FREEVIEW;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CPlayer::OnPredictedInput(CNetObj_PlayerInput *NewInput)
|
||||
|
@ -236,20 +253,79 @@ void CPlayer::Respawn()
|
|||
{
|
||||
if(m_RespawnDisabled)
|
||||
{
|
||||
// todo: enable spectate mode
|
||||
// enable spectate mode for dead players
|
||||
m_DeadSpecMode = true;
|
||||
UpdateDeadSpecMode();
|
||||
return;
|
||||
}
|
||||
|
||||
m_DeadSpecMode = false;
|
||||
|
||||
if(m_Team != TEAM_SPECTATORS)
|
||||
m_Spawning = true;
|
||||
}
|
||||
|
||||
bool CPlayer::SetSpectatorID(int SpectatorID)
|
||||
{
|
||||
if(m_SpectatorID == SpectatorID || m_ClientID == SpectatorID)
|
||||
return false;
|
||||
|
||||
if(m_Team == TEAM_SPECTATORS)
|
||||
{
|
||||
// check for freeview or if wanted player is playing
|
||||
if(SpectatorID == SPEC_FREEVIEW || (GameServer()->m_apPlayers[SpectatorID] && GameServer()->m_apPlayers[SpectatorID]->GetTeam() != TEAM_SPECTATORS))
|
||||
{
|
||||
m_SpectatorID = SpectatorID;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if(m_DeadSpecMode)
|
||||
{
|
||||
// check if wanted player can be followed
|
||||
if(GameServer()->m_apPlayers[SpectatorID] && DeadCanFollow(GameServer()->m_apPlayers[SpectatorID]))
|
||||
{
|
||||
m_SpectatorID = SpectatorID;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CPlayer::DeadCanFollow(CPlayer *pPlayer) const
|
||||
{
|
||||
// check if wanted player is in the same team and alive
|
||||
return (!pPlayer->m_RespawnDisabled || (pPlayer->GetCharacter() && pPlayer->GetCharacter()->IsAlive())) && pPlayer->GetTeam() == m_Team;
|
||||
}
|
||||
|
||||
void CPlayer::UpdateDeadSpecMode()
|
||||
{
|
||||
// check if actual spectator id is valid
|
||||
if(m_SpectatorID != SPEC_FREEVIEW && GameServer()->m_apPlayers[m_SpectatorID] && DeadCanFollow(GameServer()->m_apPlayers[m_SpectatorID]))
|
||||
return;
|
||||
|
||||
// find player to follow
|
||||
for(int i = 0; i < MAX_CLIENTS; ++i)
|
||||
{
|
||||
if(GameServer()->m_apPlayers[i] && DeadCanFollow(GameServer()->m_apPlayers[i]))
|
||||
{
|
||||
m_SpectatorID = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// no one available to follow -> turn spectator mode off
|
||||
m_DeadSpecMode = false;
|
||||
}
|
||||
|
||||
void CPlayer::SetTeam(int Team, bool DoChatMsg)
|
||||
{
|
||||
KillCharacter();
|
||||
|
||||
m_Team = Team;
|
||||
m_LastActionTick = Server()->Tick();
|
||||
m_SpectatorID = SPEC_FREEVIEW;
|
||||
m_DeadSpecMode = false;
|
||||
|
||||
// we got to wait 0.5 secs before respawning
|
||||
m_RespawnTick = Server()->Tick()+Server()->TickSpeed()/2;
|
||||
|
@ -260,7 +336,12 @@ void CPlayer::SetTeam(int Team, bool DoChatMsg)
|
|||
for(int i = 0; i < MAX_CLIENTS; ++i)
|
||||
{
|
||||
if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->m_SpectatorID == m_ClientID)
|
||||
GameServer()->m_apPlayers[i]->m_SpectatorID = SPEC_FREEVIEW;
|
||||
{
|
||||
if(GameServer()->m_apPlayers[i]->m_DeadSpecMode)
|
||||
GameServer()->m_apPlayers[i]->UpdateDeadSpecMode();
|
||||
else
|
||||
GameServer()->m_apPlayers[i]->m_SpectatorID = SPEC_FREEVIEW;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,11 @@ public:
|
|||
int m_aActLatency[MAX_CLIENTS];
|
||||
|
||||
// used for spectator mode
|
||||
int m_SpectatorID;
|
||||
int GetSpectatorID() const { return m_SpectatorID; }
|
||||
bool SetSpectatorID(int SpectatorID);
|
||||
bool m_DeadSpecMode;
|
||||
bool DeadCanFollow(CPlayer *pPlayer) const;
|
||||
void UpdateDeadSpecMode();
|
||||
|
||||
bool m_IsReadyToEnter;
|
||||
bool m_IsReadyToPlay;
|
||||
|
@ -118,6 +122,9 @@ private:
|
|||
int m_ClientID;
|
||||
int m_Team;
|
||||
bool m_Dummy;
|
||||
|
||||
// used for spectator mode
|
||||
int m_SpectatorID;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue