2010-11-20 10:37:14 +00:00
|
|
|
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
|
|
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
2008-08-14 18:46:52 +00:00
|
|
|
#include <new>
|
2010-05-29 07:25:38 +00:00
|
|
|
#include "player.h"
|
2008-08-14 18:46:52 +00:00
|
|
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
MACRO_ALLOC_POOL_ID_IMPL(CPlayer, MAX_CLIENTS)
|
2008-08-14 18:46:52 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
IServer *CPlayer::Server() const { return m_pGameServer->Server(); }
|
|
|
|
|
|
|
|
CPlayer::CPlayer(CGameContext *pGameServer, int CID, int Team)
|
2008-08-14 18:46:52 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
m_pGameServer = pGameServer;
|
|
|
|
m_RespawnTick = Server()->Tick();
|
|
|
|
m_DieTick = Server()->Tick();
|
2010-05-31 20:35:47 +00:00
|
|
|
m_ScoreStartTick = Server()->Tick();
|
2010-05-29 07:25:38 +00:00
|
|
|
Character = 0;
|
|
|
|
this->m_ClientID = CID;
|
|
|
|
m_Team = GameServer()->m_pController->ClampTeam(Team);
|
2010-10-09 17:14:42 +00:00
|
|
|
m_LastActionTick = Server()->Tick();
|
2008-08-14 18:46:52 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
CPlayer::~CPlayer()
|
2008-09-24 09:03:49 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
delete Character;
|
|
|
|
Character = 0;
|
2008-09-24 09:03:49 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CPlayer::Tick()
|
2008-08-14 18:46:52 +00:00
|
|
|
{
|
2010-09-21 23:00:33 +00:00
|
|
|
if(!Server()->ClientIngame(m_ClientID))
|
|
|
|
return;
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
Server()->SetClientScore(m_ClientID, m_Score);
|
2008-08-14 18:46:52 +00:00
|
|
|
|
|
|
|
// do latency stuff
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
IServer::CClientInfo Info;
|
|
|
|
if(Server()->GetClientInfo(m_ClientID, &Info))
|
2008-08-14 18:46:52 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
m_Latency.m_Accum += Info.m_Latency;
|
|
|
|
m_Latency.m_AccumMax = max(m_Latency.m_AccumMax, Info.m_Latency);
|
|
|
|
m_Latency.m_AccumMin = min(m_Latency.m_AccumMin, Info.m_Latency);
|
2008-08-14 18:46:52 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
// each second
|
|
|
|
if(Server()->Tick()%Server()->TickSpeed() == 0)
|
2008-08-14 18:46:52 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
m_Latency.m_Avg = m_Latency.m_Accum/Server()->TickSpeed();
|
|
|
|
m_Latency.m_Max = m_Latency.m_AccumMax;
|
|
|
|
m_Latency.m_Min = m_Latency.m_AccumMin;
|
|
|
|
m_Latency.m_Accum = 0;
|
|
|
|
m_Latency.m_AccumMin = 1000;
|
|
|
|
m_Latency.m_AccumMax = 0;
|
2008-08-14 18:46:52 +00:00
|
|
|
}
|
|
|
|
}
|
2008-11-16 14:28:44 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(!Character && m_DieTick+Server()->TickSpeed()*3 <= Server()->Tick())
|
|
|
|
m_Spawning = true;
|
2008-09-24 14:54:51 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(Character)
|
2008-09-24 14:54:51 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(Character->IsAlive())
|
2008-09-24 14:54:51 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
m_ViewPos = Character->m_Pos;
|
2008-09-24 14:54:51 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
delete Character;
|
|
|
|
Character = 0;
|
2008-09-24 14:54:51 +00:00
|
|
|
}
|
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
else if(m_Spawning && m_RespawnTick <= Server()->Tick())
|
|
|
|
TryRespawn();
|
2008-08-14 18:46:52 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CPlayer::Snap(int SnappingClient)
|
2008-08-14 18:46:52 +00:00
|
|
|
{
|
2010-09-21 23:00:33 +00:00
|
|
|
if(!Server()->ClientIngame(m_ClientID))
|
|
|
|
return;
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
CNetObj_ClientInfo *ClientInfo = static_cast<CNetObj_ClientInfo *>(Server()->SnapNewItem(NETOBJTYPE_CLIENTINFO, m_ClientID, sizeof(CNetObj_ClientInfo)));
|
|
|
|
StrToInts(&ClientInfo->m_Name0, 6, Server()->ClientName(m_ClientID));
|
|
|
|
StrToInts(&ClientInfo->m_Skin0, 6, m_TeeInfos.m_SkinName);
|
|
|
|
ClientInfo->m_UseCustomColor = m_TeeInfos.m_UseCustomColor;
|
|
|
|
ClientInfo->m_ColorBody = m_TeeInfos.m_ColorBody;
|
|
|
|
ClientInfo->m_ColorFeet = m_TeeInfos.m_ColorFeet;
|
|
|
|
|
|
|
|
CNetObj_PlayerInfo *Info = static_cast<CNetObj_PlayerInfo *>(Server()->SnapNewItem(NETOBJTYPE_PLAYERINFO, m_ClientID, sizeof(CNetObj_PlayerInfo)));
|
|
|
|
|
|
|
|
Info->m_Latency = m_Latency.m_Min;
|
|
|
|
Info->m_LatencyFlux = m_Latency.m_Max-m_Latency.m_Min;
|
|
|
|
Info->m_Local = 0;
|
|
|
|
Info->m_ClientId = m_ClientID;
|
|
|
|
Info->m_Score = m_Score;
|
|
|
|
Info->m_Team = m_Team;
|
|
|
|
|
|
|
|
if(m_ClientID == SnappingClient)
|
|
|
|
Info->m_Local = 1;
|
2008-08-14 18:46:52 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CPlayer::OnDisconnect()
|
2008-08-14 18:46:52 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
KillCharacter();
|
|
|
|
|
|
|
|
if(Server()->ClientIngame(m_ClientID))
|
|
|
|
{
|
2010-08-17 22:06:00 +00:00
|
|
|
char aBuf[512];
|
2010-09-12 11:34:30 +00:00
|
|
|
str_format(aBuf, sizeof(aBuf), "'%s' has left the game", Server()->ClientName(m_ClientID));
|
2010-08-17 22:06:00 +00:00
|
|
|
GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf);
|
2008-08-14 18:46:52 +00:00
|
|
|
|
2010-08-17 22:06:00 +00:00
|
|
|
str_format(aBuf, sizeof(aBuf), "leave player='%d:%s'", m_ClientID, Server()->ClientName(m_ClientID));
|
|
|
|
GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "game", aBuf);
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
2008-08-14 18:46:52 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CPlayer::OnPredictedInput(CNetObj_PlayerInput *NewInput)
|
2008-08-14 18:46:52 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(Character)
|
|
|
|
Character->OnPredictedInput(NewInput);
|
2008-08-14 18:46:52 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CPlayer::OnDirectInput(CNetObj_PlayerInput *NewInput)
|
2008-08-14 18:46:52 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(Character)
|
|
|
|
Character->OnDirectInput(NewInput);
|
2008-08-14 18:46:52 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(!Character && m_Team >= 0 && (NewInput->m_Fire&1))
|
|
|
|
m_Spawning = true;
|
2008-09-09 15:50:41 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(!Character && m_Team == -1)
|
|
|
|
m_ViewPos = vec2(NewInput->m_TargetX, NewInput->m_TargetY);
|
2010-10-09 17:14:42 +00:00
|
|
|
|
|
|
|
// check for activity
|
|
|
|
if(NewInput->m_Direction || m_LatestActivity.m_TargetX != NewInput->m_TargetX ||
|
|
|
|
m_LatestActivity.m_TargetY != NewInput->m_TargetY || NewInput->m_Jump ||
|
|
|
|
NewInput->m_Fire&1 || NewInput->m_Hook)
|
|
|
|
{
|
|
|
|
m_LatestActivity.m_TargetX = NewInput->m_TargetX;
|
|
|
|
m_LatestActivity.m_TargetY = NewInput->m_TargetY;
|
|
|
|
m_LastActionTick = Server()->Tick();
|
|
|
|
}
|
2008-08-14 18:46:52 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
CCharacter *CPlayer::GetCharacter()
|
2008-08-14 18:46:52 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(Character && Character->IsAlive())
|
|
|
|
return Character;
|
2008-08-14 18:46:52 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CPlayer::KillCharacter(int Weapon)
|
2008-08-14 18:46:52 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(Character)
|
2008-09-23 18:08:19 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
Character->Die(m_ClientID, Weapon);
|
|
|
|
delete Character;
|
|
|
|
Character = 0;
|
2008-09-23 18:08:19 +00:00
|
|
|
}
|
2008-08-14 18:46:52 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CPlayer::Respawn()
|
2008-08-14 18:46:52 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(m_Team > -1)
|
|
|
|
m_Spawning = true;
|
2008-08-14 18:46:52 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CPlayer::SetTeam(int Team)
|
2008-08-14 18:46:52 +00:00
|
|
|
{
|
|
|
|
// clamp the team
|
2010-05-29 07:25:38 +00:00
|
|
|
Team = GameServer()->m_pController->ClampTeam(Team);
|
|
|
|
if(m_Team == Team)
|
2008-08-14 18:46:52 +00:00
|
|
|
return;
|
|
|
|
|
2010-08-17 22:06:00 +00:00
|
|
|
char aBuf[512];
|
2010-09-12 11:34:30 +00:00
|
|
|
str_format(aBuf, sizeof(aBuf), "'%s' joined the %s", Server()->ClientName(m_ClientID), GameServer()->m_pController->GetTeamName(Team));
|
2010-08-17 22:06:00 +00:00
|
|
|
GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf);
|
2008-08-14 18:46:52 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
KillCharacter();
|
2010-06-03 14:35:18 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
m_Team = Team;
|
2010-10-09 17:14:42 +00:00
|
|
|
m_LastActionTick = Server()->Tick();
|
2010-05-29 07:25:38 +00:00
|
|
|
// we got to wait 0.5 secs before respawning
|
|
|
|
m_RespawnTick = Server()->Tick()+Server()->TickSpeed()/2;
|
2010-08-17 22:06:00 +00:00
|
|
|
str_format(aBuf, sizeof(aBuf), "team_join player='%d:%s' m_Team=%d", m_ClientID, Server()->ClientName(m_ClientID), m_Team);
|
|
|
|
GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf);
|
2008-08-14 18:46:52 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
GameServer()->m_pController->OnPlayerInfoChange(GameServer()->m_apPlayers[m_ClientID]);
|
2008-08-14 18:46:52 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CPlayer::TryRespawn()
|
2008-08-14 18:46:52 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
vec2 SpawnPos = vec2(100.0f, -60.0f);
|
2008-08-14 18:46:52 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(!GameServer()->m_pController->CanSpawn(this, &SpawnPos))
|
2008-08-27 15:48:50 +00:00
|
|
|
return;
|
2008-08-14 18:46:52 +00:00
|
|
|
|
|
|
|
// check if the position is occupado
|
2010-05-29 07:25:38 +00:00
|
|
|
CEntity *apEnts[2] = {0};
|
|
|
|
int NumEnts = GameServer()->m_World.FindEntities(SpawnPos, 64, apEnts, 2, NETOBJTYPE_CHARACTER);
|
2008-08-14 18:46:52 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(NumEnts == 0)
|
2008-08-14 18:46:52 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
m_Spawning = false;
|
|
|
|
Character = new(m_ClientID) CCharacter(&GameServer()->m_World);
|
|
|
|
Character->Spawn(this, SpawnPos);
|
|
|
|
GameServer()->CreatePlayerSpawn(SpawnPos);
|
2008-08-14 18:46:52 +00:00
|
|
|
}
|
|
|
|
}
|