added spectator mode for dead players in survival

This commit is contained in:
oy 2012-02-15 01:40:24 +01:00
parent 6b8287f7c7
commit ad33841deb
10 changed files with 136 additions and 41 deletions

View file

@ -129,7 +129,7 @@ void CItems::RenderPickup(const CNetObj_Pickup *pPrev, const CNetObj_Pickup *pCu
case PICKUP_LASER: case PICKUP_LASER:
Size = g_pData->m_Weapons.m_aId[WEAPON_LASER].m_VisualSize; Size = g_pData->m_Weapons.m_aId[WEAPON_LASER].m_VisualSize;
break; break;
case SPRITE_PICKUP_NINJA: case PICKUP_NINJA:
m_pClient->m_pEffects->PowerupShine(Pos, vec2(96,18)); m_pClient->m_pEffects->PowerupShine(Pos, vec2(96,18));
Size *= 2.0f; Size *= 2.0f;
Pos.x -= 10.0f; Pos.x -= 10.0f;

View file

@ -414,8 +414,8 @@ bool CScoreboard::Active()
if(m_pClient->m_Snap.m_pLocalInfo && m_pClient->m_Snap.m_pLocalInfo->m_Team != TEAM_SPECTATORS) 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 // 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_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_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; return true;
} }

View file

@ -195,6 +195,8 @@ void CSpectator::OnRender()
float LineHeight = 60.0f; float LineHeight = 60.0f;
bool Selected = false; bool Selected = false;
if(m_pClient->m_Snap.m_pLocalInfo->m_Team == TEAM_SPECTATORS)
{
if(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SPEC_FREEVIEW) if(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SPEC_FREEVIEW)
{ {
Graphics()->TextureSet(-1); Graphics()->TextureSet(-1);
@ -212,11 +214,14 @@ void CSpectator::OnRender()
} }
TextRender()->TextColor(1.0f, 1.0f, 1.0f, Selected?1.0f:0.5f); 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()->Text(0, Width/2.0f-240.0f, Height/2.0f-265.0f, FontSize, Localize("Free-View"), -1);
}
float x = -270.0f, y = StartY; float x = -270.0f, y = StartY;
for(int i = 0, Count = 0; i < MAX_CLIENTS; ++i) 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; continue;
if(++Count%9 == 0) if(++Count%9 == 0)

View file

@ -777,7 +777,7 @@ void CGameClient::OnNewSnapshot()
{ {
m_Snap.m_pSpectatorInfo = (const CNetObj_SpectatorInfo *)pData; 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_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; m_Snap.m_SpecInfo.m_SpectatorID = m_Snap.m_pSpectatorInfo->m_SpectatorID;
} }
else if(Item.m_Type == NETOBJTYPE_GAMEINFO) else if(Item.m_Type == NETOBJTYPE_GAMEINFO)

View file

@ -770,7 +770,8 @@ bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon)
int Mask = CmaskOne(From); int Mask = CmaskOne(From);
for(int i = 0; i < MAX_CLIENTS; i++) 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); Mask |= CmaskOne(i);
} }
GameServer()->CreateSound(GameServer()->m_apPlayers[From]->m_ViewPos, SOUND_HIT, Mask); 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; pCharacter->m_Direction = m_Input.m_Direction;
if(m_pPlayer->GetCID() == SnappingClient || SnappingClient == -1 || 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_Health = m_Health;
pCharacter->m_Armor = m_Armor; pCharacter->m_Armor = m_Armor;

View file

@ -573,13 +573,6 @@ void CGameContext::OnClientDrop(int ClientID, const char *pReason)
m_apPlayers[ClientID] = 0; m_apPlayers[ClientID] = 0;
m_VoteUpdate = true; 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) 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; CNetMsg_Cl_SetSpectatorMode *pMsg = (CNetMsg_Cl_SetSpectatorMode *)pRawMsg;
if(pPlayer->GetTeam() != TEAM_SPECTATORS || pPlayer->m_SpectatorID == pMsg->m_SpectatorID || ClientID == pMsg->m_SpectatorID || if(g_Config.m_SvSpamprotection && pPlayer->m_LastSetSpectatorMode && pPlayer->m_LastSetSpectatorMode+Server()->TickSpeed()*3 > Server()->Tick())
(g_Config.m_SvSpamprotection && pPlayer->m_LastSetSpectatorMode && pPlayer->m_LastSetSpectatorMode+Server()->TickSpeed()*3 > Server()->Tick()))
return; return;
pPlayer->m_LastSetSpectatorMode = Server()->Tick(); 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"); SendChatTarget(ClientID, "Invalid spectator id used");
else
pPlayer->m_SpectatorID = pMsg->m_SpectatorID;
} }
else if (MsgID == NETMSGTYPE_CL_STARTINFO) else if (MsgID == NETMSGTYPE_CL_STARTINFO)
{ {

View file

@ -226,6 +226,16 @@ int IGameController::OnCharacterDeath(class CCharacter *pVictim, class CPlayer *
} }
if(Weapon == WEAPON_SELF) if(Weapon == WEAPON_SELF)
pVictim->GetPlayer()->m_RespawnTick = Server()->Tick()+Server()->TickSpeed()*3.0f; 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; return 0;
} }

View file

@ -254,7 +254,8 @@ void CGameControllerCTF::Tick()
if(!pPlayer) if(!pPlayer)
continue; 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); GameServer()->CreateSoundGlobal(SOUND_CTF_GRAB_EN, c);
else if(pPlayer->GetTeam() == fi) else if(pPlayer->GetTeam() == fi)
GameServer()->CreateSoundGlobal(SOUND_CTF_GRAB_EN, c); GameServer()->CreateSoundGlobal(SOUND_CTF_GRAB_EN, c);

View file

@ -27,6 +27,8 @@ CPlayer::CPlayer(CGameContext *pGameServer, int ClientID, bool Dummy)
m_IsReadyToPlay = GameServer()->m_pController->GetGameState() != IGameController::GS_WARMUP && m_IsReadyToPlay = GameServer()->m_pController->GetGameState() != IGameController::GS_WARMUP &&
GameServer()->m_pController->GetGameState() != IGameController::GS_PAUSED; GameServer()->m_pController->GetGameState() != IGameController::GS_PAUSED;
m_RespawnDisabled = GameServer()->m_pController->GetStartRespawnState(); m_RespawnDisabled = GameServer()->m_pController->GetStartRespawnState();
m_DeadSpecMode = false;
m_Spawning = 0;
} }
CPlayer::~CPlayer() CPlayer::~CPlayer()
@ -74,7 +76,7 @@ void CPlayer::Tick()
if(!m_pCharacter && m_Team == TEAM_SPECTATORS && m_SpectatorID == SPEC_FREEVIEW) 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)); 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(); Respawn();
if(m_pCharacter) if(m_pCharacter)
@ -107,8 +109,8 @@ void CPlayer::PostTick()
} }
} }
// update view pos for spectators // update view pos for spectators and dead players
if(m_Team == TEAM_SPECTATORS && m_SpectatorID != SPEC_FREEVIEW && GameServer()->m_apPlayers[m_SpectatorID]) 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; m_ViewPos = GameServer()->m_apPlayers[m_SpectatorID]->m_ViewPos;
} }
@ -147,7 +149,7 @@ void CPlayer::Snap(int SnappingClient)
if(m_ClientID == SnappingClient) if(m_ClientID == SnappingClient)
pPlayerInfo->m_Local = 1; 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))); CNetObj_SpectatorInfo *pSpectatorInfo = static_cast<CNetObj_SpectatorInfo *>(Server()->SnapNewItem(NETOBJTYPE_SPECTATORINFO, m_ClientID, sizeof(CNetObj_SpectatorInfo)));
if(!pSpectatorInfo) if(!pSpectatorInfo)
@ -162,6 +164,21 @@ void CPlayer::Snap(int SnappingClient)
void CPlayer::OnDisconnect() void CPlayer::OnDisconnect()
{ {
KillCharacter(); 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) void CPlayer::OnPredictedInput(CNetObj_PlayerInput *NewInput)
@ -236,20 +253,79 @@ void CPlayer::Respawn()
{ {
if(m_RespawnDisabled) if(m_RespawnDisabled)
{ {
// todo: enable spectate mode // enable spectate mode for dead players
m_DeadSpecMode = true;
UpdateDeadSpecMode();
return; return;
} }
m_DeadSpecMode = false;
if(m_Team != TEAM_SPECTATORS) if(m_Team != TEAM_SPECTATORS)
m_Spawning = true; 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) void CPlayer::SetTeam(int Team, bool DoChatMsg)
{ {
KillCharacter(); KillCharacter();
m_Team = Team; m_Team = Team;
m_LastActionTick = Server()->Tick(); m_LastActionTick = Server()->Tick();
m_SpectatorID = SPEC_FREEVIEW;
m_DeadSpecMode = false;
// we got to wait 0.5 secs before respawning // we got to wait 0.5 secs before respawning
m_RespawnTick = Server()->Tick()+Server()->TickSpeed()/2; m_RespawnTick = Server()->Tick()+Server()->TickSpeed()/2;
@ -260,10 +336,15 @@ void CPlayer::SetTeam(int Team, bool DoChatMsg)
for(int i = 0; i < MAX_CLIENTS; ++i) 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] && 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; GameServer()->m_apPlayers[i]->m_SpectatorID = SPEC_FREEVIEW;
} }
} }
} }
}
void CPlayer::TryRespawn() void CPlayer::TryRespawn()
{ {

View file

@ -53,7 +53,11 @@ public:
int m_aActLatency[MAX_CLIENTS]; int m_aActLatency[MAX_CLIENTS];
// used for spectator mode // 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_IsReadyToEnter;
bool m_IsReadyToPlay; bool m_IsReadyToPlay;
@ -118,6 +122,9 @@ private:
int m_ClientID; int m_ClientID;
int m_Team; int m_Team;
bool m_Dummy; bool m_Dummy;
// used for spectator mode
int m_SpectatorID;
}; };
#endif #endif