ddnet/src/game/server/gamecontext.cpp

1200 lines
33 KiB
C++
Raw Normal View History

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-09-23 07:43:41 +00:00
#include <new>
2010-05-29 07:25:38 +00:00
#include <base/math.h>
#include <engine/shared/config.h>
#include <engine/map.h>
#include <engine/console.h>
#include "gamecontext.h"
#include <game/version.h>
#include <game/collision.h>
#include <game/gamecore.h>
#include "gamemodes/dm.h"
#include "gamemodes/tdm.h"
#include "gamemodes/ctf.h"
#include "gamemodes/mod.h"
2010-05-29 07:25:38 +00:00
enum
{
RESET,
NO_RESET
};
2010-05-29 07:25:38 +00:00
void CGameContext::Construct(int Resetting)
{
2010-05-29 07:25:38 +00:00
m_Resetting = 0;
m_pServer = 0;
2008-09-23 07:43:41 +00:00
for(int i = 0; i < MAX_CLIENTS; i++)
2010-05-29 07:25:38 +00:00
m_apPlayers[i] = 0;
2010-05-29 07:25:38 +00:00
m_pController = 0;
m_VoteCloseTime = 0;
m_pVoteOptionFirst = 0;
m_pVoteOptionLast = 0;
if(Resetting==NO_RESET)
m_pVoteOptionHeap = new CHeap();
}
CGameContext::CGameContext(int Resetting)
{
Construct(Resetting);
}
CGameContext::CGameContext()
{
Construct(NO_RESET);
2008-09-23 07:43:41 +00:00
}
2010-05-29 07:25:38 +00:00
CGameContext::~CGameContext()
2008-09-23 07:43:41 +00:00
{
for(int i = 0; i < MAX_CLIENTS; i++)
2010-05-29 07:25:38 +00:00
delete m_apPlayers[i];
if(!m_Resetting)
delete m_pVoteOptionHeap;
}
2010-05-29 07:25:38 +00:00
void CGameContext::Clear()
{
2010-05-29 07:25:38 +00:00
CHeap *pVoteOptionHeap = m_pVoteOptionHeap;
CVoteOption *pVoteOptionFirst = m_pVoteOptionFirst;
CVoteOption *pVoteOptionLast = m_pVoteOptionLast;
CTuningParams Tuning = m_Tuning;
m_Resetting = true;
this->~CGameContext();
2008-09-23 07:43:41 +00:00
mem_zero(this, sizeof(*this));
2010-05-29 07:25:38 +00:00
new (this) CGameContext(RESET);
m_pVoteOptionHeap = pVoteOptionHeap;
m_pVoteOptionFirst = pVoteOptionFirst;
m_pVoteOptionLast = pVoteOptionLast;
m_Tuning = Tuning;
}
class CCharacter *CGameContext::GetPlayerChar(int ClientID)
{
if(ClientID < 0 || ClientID >= MAX_CLIENTS || !m_apPlayers[ClientID])
return 0;
return m_apPlayers[ClientID]->GetCharacter();
}
void CGameContext::CreateDamageInd(vec2 Pos, float Angle, int Amount)
{
float a = 3 * 3.14159f / 2 + Angle;
//float a = get_angle(dir);
float s = a-pi/3;
float e = a+pi/3;
2010-05-29 07:25:38 +00:00
for(int i = 0; i < Amount; i++)
{
float f = mix(s, e, float(i+1)/float(Amount+2));
NETEVENT_DAMAGEIND *pEvent = (NETEVENT_DAMAGEIND *)m_Events.Create(NETEVENTTYPE_DAMAGEIND, sizeof(NETEVENT_DAMAGEIND));
if(pEvent)
{
pEvent->m_X = (int)Pos.x;
pEvent->m_Y = (int)Pos.y;
pEvent->m_Angle = (int)(f*256.0f);
}
}
}
void CGameContext::CreateHammerHit(vec2 Pos)
{
// create the event
NETEVENT_HAMMERHIT *pEvent = (NETEVENT_HAMMERHIT *)m_Events.Create(NETEVENTTYPE_HAMMERHIT, sizeof(NETEVENT_HAMMERHIT));
if(pEvent)
{
pEvent->m_X = (int)Pos.x;
pEvent->m_Y = (int)Pos.y;
}
}
void CGameContext::CreateExplosion(vec2 Pos, int Owner, int Weapon, bool NoDamage)
{
// create the event
NETEVENT_EXPLOSION *pEvent = (NETEVENT_EXPLOSION *)m_Events.Create(NETEVENTTYPE_EXPLOSION, sizeof(NETEVENT_EXPLOSION));
if(pEvent)
{
pEvent->m_X = (int)Pos.x;
pEvent->m_Y = (int)Pos.y;
}
2010-05-29 07:25:38 +00:00
if (!NoDamage)
{
// deal damage
CCharacter *apEnts[MAX_CLIENTS];
2010-05-29 07:25:38 +00:00
float Radius = 135.0f;
float InnerRadius = 48.0f;
int Num = m_World.FindEntities(Pos, Radius, (CEntity**)apEnts, MAX_CLIENTS, CGameWorld::ENTTYPE_CHARACTER);
2010-05-29 07:25:38 +00:00
for(int i = 0; i < Num; i++)
{
vec2 Diff = apEnts[i]->m_Pos - Pos;
2010-05-29 07:25:38 +00:00
vec2 ForceDir(0,1);
float l = length(Diff);
if(l)
2010-05-29 07:25:38 +00:00
ForceDir = normalize(Diff);
l = 1-clamp((l-InnerRadius)/(Radius-InnerRadius), 0.0f, 1.0f);
float Dmg = 6 * l;
if((int)Dmg)
apEnts[i]->TakeDamage(ForceDir*Dmg*2, (int)Dmg, Owner, Weapon);
}
}
}
/*
void create_smoke(vec2 Pos)
{
// create the event
EV_EXPLOSION *pEvent = (EV_EXPLOSION *)events.create(EVENT_SMOKE, sizeof(EV_EXPLOSION));
if(pEvent)
{
pEvent->x = (int)Pos.x;
pEvent->y = (int)Pos.y;
}
}*/
void CGameContext::CreatePlayerSpawn(vec2 Pos)
{
// create the event
2010-05-29 07:25:38 +00:00
NETEVENT_SPAWN *ev = (NETEVENT_SPAWN *)m_Events.Create(NETEVENTTYPE_SPAWN, sizeof(NETEVENT_SPAWN));
if(ev)
{
ev->m_X = (int)Pos.x;
ev->m_Y = (int)Pos.y;
}
}
void CGameContext::CreateDeath(vec2 Pos, int ClientID)
{
// create the event
NETEVENT_DEATH *pEvent = (NETEVENT_DEATH *)m_Events.Create(NETEVENTTYPE_DEATH, sizeof(NETEVENT_DEATH));
if(pEvent)
{
pEvent->m_X = (int)Pos.x;
pEvent->m_Y = (int)Pos.y;
pEvent->m_ClientID = ClientID;
}
}
2010-05-29 07:25:38 +00:00
void CGameContext::CreateSound(vec2 Pos, int Sound, int Mask)
{
2010-05-29 07:25:38 +00:00
if (Sound < 0)
return;
// create a sound
NETEVENT_SOUNDWORLD *pEvent = (NETEVENT_SOUNDWORLD *)m_Events.Create(NETEVENTTYPE_SOUNDWORLD, sizeof(NETEVENT_SOUNDWORLD), Mask);
if(pEvent)
{
pEvent->m_X = (int)Pos.x;
pEvent->m_Y = (int)Pos.y;
pEvent->m_SoundID = Sound;
}
}
2010-05-29 07:25:38 +00:00
void CGameContext::CreateSoundGlobal(int Sound, int Target)
{
2010-05-29 07:25:38 +00:00
if (Sound < 0)
return;
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_SoundGlobal Msg;
Msg.m_SoundID = Sound;
2010-05-29 07:25:38 +00:00
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, Target);
}
2010-05-29 07:25:38 +00:00
void CGameContext::SendChatTarget(int To, const char *pText)
{
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_Chat Msg;
Msg.m_Team = 0;
Msg.m_ClientID = -1;
2010-05-29 07:25:38 +00:00
Msg.m_pMessage = pText;
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, To);
}
void CGameContext::SendChat(int ChatterClientID, int Team, const char *pText)
{
char aBuf[256];
if(ChatterClientID >= 0 && ChatterClientID < MAX_CLIENTS)
str_format(aBuf, sizeof(aBuf), "%d:%d:%s: %s", ChatterClientID, Team, Server()->ClientName(ChatterClientID), pText);
else
str_format(aBuf, sizeof(aBuf), "*** %s", pText);
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "chat", aBuf);
2010-05-29 07:25:38 +00:00
if(Team == CHAT_ALL)
{
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_Chat Msg;
Msg.m_Team = 0;
Msg.m_ClientID = ChatterClientID;
2010-05-29 07:25:38 +00:00
Msg.m_pMessage = pText;
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, -1);
}
else
{
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_Chat Msg;
Msg.m_Team = 1;
Msg.m_ClientID = ChatterClientID;
2010-05-29 07:25:38 +00:00
Msg.m_pMessage = pText;
// pack one for the recording only
2010-05-29 07:25:38 +00:00
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL|MSGFLAG_NOSEND, -1);
// send to the clients
for(int i = 0; i < MAX_CLIENTS; i++)
{
2010-05-29 07:25:38 +00:00
if(m_apPlayers[i] && m_apPlayers[i]->GetTeam() == Team)
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL|MSGFLAG_NORECORD, i);
}
}
}
void CGameContext::SendEmoticon(int ClientID, int Emoticon)
{
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_Emoticon Msg;
Msg.m_ClientID = ClientID;
2010-05-29 07:25:38 +00:00
Msg.m_Emoticon = Emoticon;
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, -1);
}
void CGameContext::SendWeaponPickup(int ClientID, int Weapon)
{
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_WeaponPickup Msg;
Msg.m_Weapon = Weapon;
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, ClientID);
}
void CGameContext::SendBroadcast(const char *pText, int ClientID)
{
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_Broadcast Msg;
Msg.m_pMessage = pText;
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, ClientID);
}
2008-09-24 14:47:03 +00:00
//
2010-05-29 07:25:38 +00:00
void CGameContext::StartVote(const char *pDesc, const char *pCommand)
2008-09-24 14:47:03 +00:00
{
// check if a vote is already running
2010-05-29 07:25:38 +00:00
if(m_VoteCloseTime)
2008-09-24 14:47:03 +00:00
return;
// reset votes
2010-05-29 07:25:38 +00:00
m_VoteEnforce = VOTE_ENFORCE_UNKNOWN;
2008-09-24 14:47:03 +00:00
for(int i = 0; i < MAX_CLIENTS; i++)
{
2010-05-29 07:25:38 +00:00
if(m_apPlayers[i])
{
m_apPlayers[i]->m_Vote = 0;
m_apPlayers[i]->m_VotePos = 0;
}
2008-09-24 14:47:03 +00:00
}
// start vote
2010-05-29 07:25:38 +00:00
m_VoteCloseTime = time_get() + time_freq()*25;
str_copy(m_aVoteDescription, pDesc, sizeof(m_aVoteDescription));
str_copy(m_aVoteCommand, pCommand, sizeof(m_aVoteCommand));
SendVoteSet(-1);
m_VoteUpdate = true;
2008-09-24 14:47:03 +00:00
}
2008-09-25 12:41:37 +00:00
2010-05-29 07:25:38 +00:00
void CGameContext::EndVote()
2008-09-25 12:41:37 +00:00
{
2010-05-29 07:25:38 +00:00
m_VoteCloseTime = 0;
SendVoteSet(-1);
2008-09-25 12:41:37 +00:00
}
void CGameContext::SendVoteSet(int ClientID)
2008-09-24 14:47:03 +00:00
{
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_VoteSet Msg;
if(m_VoteCloseTime)
2008-09-24 14:47:03 +00:00
{
2010-05-29 07:25:38 +00:00
Msg.m_Timeout = (m_VoteCloseTime-time_get())/time_freq();
Msg.m_pDescription = m_aVoteDescription;
2008-09-24 14:47:03 +00:00
}
else
{
2010-05-29 07:25:38 +00:00
Msg.m_Timeout = 0;
Msg.m_pDescription = "";
2008-09-24 14:47:03 +00:00
}
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, ClientID);
2008-09-24 14:47:03 +00:00
}
void CGameContext::SendVoteStatus(int ClientID, int Total, int Yes, int No)
2008-09-24 14:47:03 +00:00
{
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_VoteStatus Msg = {0};
Msg.m_Total = Total;
Msg.m_Yes = Yes;
Msg.m_No = No;
Msg.m_Pass = Total - (Yes+No);
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, ClientID);
2010-05-29 07:25:38 +00:00
}
void CGameContext::AbortVoteKickOnDisconnect(int ClientID)
2010-05-29 07:25:38 +00:00
{
if(m_VoteCloseTime && !str_comp_num(m_aVoteCommand, "kick ", 5) && str_toint(&m_aVoteCommand[5]) == ClientID)
2010-05-29 07:25:38 +00:00
m_VoteCloseTime = -1;
}
void CGameContext::CheckPureTuning()
{
// might not be created yet during start up
if(!m_pController)
return;
if( str_comp(m_pController->m_pGameType, "DM")==0 ||
str_comp(m_pController->m_pGameType, "TDM")==0 ||
str_comp(m_pController->m_pGameType, "CTF")==0)
2008-09-24 14:47:03 +00:00
{
2010-05-29 07:25:38 +00:00
CTuningParams p;
if(mem_comp(&p, &m_Tuning, sizeof(p)) != 0)
2008-09-24 14:47:03 +00:00
{
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "resetting tuning due to pure server");
2010-05-29 07:25:38 +00:00
m_Tuning = p;
2008-09-24 14:47:03 +00:00
}
}
}
void CGameContext::SendTuningParams(int ClientID)
{
2010-05-29 07:25:38 +00:00
CheckPureTuning();
CMsgPacker Msg(NETMSGTYPE_SV_TUNEPARAMS);
int *pParams = (int *)&m_Tuning;
for(unsigned i = 0; i < sizeof(m_Tuning)/sizeof(int); i++)
Msg.AddInt(pParams[i]);
Server()->SendMsg(&Msg, MSGFLAG_VITAL, ClientID);
}
2010-05-29 07:25:38 +00:00
void CGameContext::OnTick()
{
2010-05-29 07:25:38 +00:00
// check tuning
CheckPureTuning();
// copy tuning
m_World.m_Core.m_Tuning = m_Tuning;
m_World.Tick();
//if(world.paused) // make sure that the game object always updates
2010-05-29 07:25:38 +00:00
m_pController->Tick();
for(int i = 0; i < MAX_CLIENTS; i++)
{
2010-05-29 07:25:38 +00:00
if(m_apPlayers[i])
{
2010-05-29 07:25:38 +00:00
m_apPlayers[i]->Tick();
m_apPlayers[i]->PostTick();
}
}
2008-09-24 14:47:03 +00:00
// update voting
2010-05-29 07:25:38 +00:00
if(m_VoteCloseTime)
2008-09-24 14:47:03 +00:00
{
// abort the kick-vote on player-leave
2010-05-29 07:25:38 +00:00
if(m_VoteCloseTime == -1)
2008-09-24 14:47:03 +00:00
{
2010-05-29 07:25:38 +00:00
SendChat(-1, CGameContext::CHAT_ALL, "Vote aborted");
EndVote();
}
else
{
2010-05-29 07:25:38 +00:00
int Total = 0, Yes = 0, No = 0;
if(m_VoteUpdate)
2008-09-24 14:47:03 +00:00
{
2010-05-29 07:25:38 +00:00
// count votes
char aaBuf[MAX_CLIENTS][64] = {{0}};
for(int i = 0; i < MAX_CLIENTS; i++)
if(m_apPlayers[i])
Server()->GetClientIP(i, aaBuf[i], 64);
bool aVoteChecked[MAX_CLIENTS] = {0};
for(int i = 0; i < MAX_CLIENTS; i++)
{
2011-01-03 11:50:38 +00:00
if(!m_apPlayers[i] || m_apPlayers[i]->GetTeam() == TEAM_SPECTATORS || aVoteChecked[i]) // don't count in votes by spectators
2010-05-29 07:25:38 +00:00
continue;
int ActVote = m_apPlayers[i]->m_Vote;
int ActVotePos = m_apPlayers[i]->m_VotePos;
// check for more players with the same ip (only use the vote of the one who voted first)
for(int j = i+1; j < MAX_CLIENTS; ++j)
{
if(!m_apPlayers[j] || aVoteChecked[j] || str_comp(aaBuf[j], aaBuf[i]))
continue;
aVoteChecked[j] = true;
if(m_apPlayers[j]->m_Vote && (!ActVote || ActVotePos > m_apPlayers[j]->m_VotePos))
{
ActVote = m_apPlayers[j]->m_Vote;
ActVotePos = m_apPlayers[j]->m_VotePos;
}
}
Total++;
if(ActVote > 0)
Yes++;
else if(ActVote < 0)
No++;
}
2010-05-29 07:25:38 +00:00
if(Yes >= Total/2+1)
m_VoteEnforce = VOTE_ENFORCE_YES;
2010-09-12 10:51:07 +00:00
else if(No >= (Total+1)/2)
2010-05-29 07:25:38 +00:00
m_VoteEnforce = VOTE_ENFORCE_NO;
2008-09-24 14:47:03 +00:00
}
2010-05-29 07:25:38 +00:00
if(m_VoteEnforce == VOTE_ENFORCE_YES)
{
Console()->ExecuteLine(m_aVoteCommand);
EndVote();
SendChat(-1, CGameContext::CHAT_ALL, "Vote passed");
if(m_apPlayers[m_VoteCreator])
m_apPlayers[m_VoteCreator]->m_LastVoteCall = 0;
2010-05-29 07:25:38 +00:00
}
else if(m_VoteEnforce == VOTE_ENFORCE_NO || time_get() > m_VoteCloseTime)
{
EndVote();
SendChat(-1, CGameContext::CHAT_ALL, "Vote failed");
}
else if(m_VoteUpdate)
{
m_VoteUpdate = false;
SendVoteStatus(-1, Total, Yes, No);
}
}
}
#ifdef CONF_DEBUG
if(g_Config.m_DbgDummies)
{
for(int i = 0; i < g_Config.m_DbgDummies ; i++)
{
CNetObj_PlayerInput Input = {0};
Input.m_Direction = (i&1)?-1:1;
m_apPlayers[MAX_CLIENTS-i-1]->OnPredictedInput(&Input);
}
}
#endif
}
// Server hooks
void CGameContext::OnClientDirectInput(int ClientID, void *pInput)
{
if(!m_World.m_Paused)
m_apPlayers[ClientID]->OnDirectInput((CNetObj_PlayerInput *)pInput);
}
void CGameContext::OnClientPredictedInput(int ClientID, void *pInput)
{
if(!m_World.m_Paused)
m_apPlayers[ClientID]->OnPredictedInput((CNetObj_PlayerInput *)pInput);
}
void CGameContext::OnClientEnter(int ClientID)
2010-05-29 07:25:38 +00:00
{
//world.insert_entity(&players[client_id]);
m_apPlayers[ClientID]->Respawn();
2010-05-29 07:25:38 +00:00
char aBuf[512];
str_format(aBuf, sizeof(aBuf), "'%s' entered and joined the %s", Server()->ClientName(ClientID), m_pController->GetTeamName(m_apPlayers[ClientID]->GetTeam()));
2010-05-29 07:25:38 +00:00
SendChat(-1, CGameContext::CHAT_ALL, aBuf);
str_format(aBuf, sizeof(aBuf), "team_join player='%d:%s' team=%d", ClientID, Server()->ClientName(ClientID), m_apPlayers[ClientID]->GetTeam());
Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf);
2010-05-29 07:25:38 +00:00
m_VoteUpdate = true;
}
void CGameContext::OnClientConnected(int ClientID)
2010-05-29 07:25:38 +00:00
{
// Check which team the player should be on
const int StartTeam = g_Config.m_SvTournamentMode ? TEAM_SPECTATORS : m_pController->GetAutoTeam(ClientID);
2010-05-29 07:25:38 +00:00
m_apPlayers[ClientID] = new(ClientID) CPlayer(this, ClientID, StartTeam);
2010-05-29 07:25:38 +00:00
//players[client_id].init(client_id);
//players[client_id].client_id = client_id;
(void)m_pController->CheckTeamBalance();
#ifdef CONF_DEBUG
if(g_Config.m_DbgDummies)
{
if(ClientID >= MAX_CLIENTS-g_Config.m_DbgDummies)
2010-05-29 07:25:38 +00:00
return;
}
#endif
// send active vote
if(m_VoteCloseTime)
SendVoteSet(ClientID);
2010-05-29 07:25:38 +00:00
// send motd
CNetMsg_Sv_Motd Msg;
Msg.m_pMessage = g_Config.m_SvMotd;
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, ClientID);
2010-05-29 07:25:38 +00:00
}
void CGameContext::OnClientDrop(int ClientID)
2010-05-29 07:25:38 +00:00
{
AbortVoteKickOnDisconnect(ClientID);
m_apPlayers[ClientID]->OnDisconnect();
delete m_apPlayers[ClientID];
m_apPlayers[ClientID] = 0;
2010-05-29 07:25:38 +00:00
(void)m_pController->CheckTeamBalance();
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;
}
2010-05-29 07:25:38 +00:00
}
void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
2010-05-29 07:25:38 +00:00
{
void *pRawMsg = m_NetObjHandler.SecureUnpackMsg(MsgID, pUnpacker);
CPlayer *pPlayer = m_apPlayers[ClientID];
2010-05-29 07:25:38 +00:00
if(!pRawMsg)
{
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "dropped weird message '%s' (%d), failed on '%s'", m_NetObjHandler.GetMsgName(MsgID), MsgID, m_NetObjHandler.FailedMsgOn());
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf);
2010-05-29 07:25:38 +00:00
return;
}
if(MsgID == NETMSGTYPE_CL_SAY)
2010-05-29 07:25:38 +00:00
{
CNetMsg_Cl_Say *pMsg = (CNetMsg_Cl_Say *)pRawMsg;
int Team = pMsg->m_Team;
if(Team)
Team = pPlayer->GetTeam();
2010-05-29 07:25:38 +00:00
else
Team = CGameContext::CHAT_ALL;
if(g_Config.m_SvSpamprotection && pPlayer->m_LastChat && pPlayer->m_LastChat+Server()->TickSpeed() > Server()->Tick())
2010-05-29 07:25:38 +00:00
return;
pPlayer->m_LastChat = Server()->Tick();
2010-05-29 07:25:38 +00:00
// check for invalid chars
unsigned char *pMessage = (unsigned char *)pMsg->m_pMessage;
while (*pMessage)
{
if(*pMessage < 32)
*pMessage = ' ';
pMessage++;
}
SendChat(ClientID, Team, pMsg->m_pMessage);
2010-05-29 07:25:38 +00:00
}
else if(MsgID == NETMSGTYPE_CL_CALLVOTE)
2010-05-29 07:25:38 +00:00
{
if(g_Config.m_SvSpamprotection && pPlayer->m_LastVoteTry && pPlayer->m_LastVoteTry+Server()->TickSpeed()*3 > Server()->Tick())
2010-05-29 07:25:38 +00:00
return;
int64 Now = Server()->Tick();
pPlayer->m_LastVoteTry = Now;
if(pPlayer->GetTeam() == TEAM_SPECTATORS)
2010-08-06 19:03:38 +00:00
{
SendChatTarget(ClientID, "Spectators aren't allowed to start a vote.");
2010-08-06 19:03:38 +00:00
return;
}
2010-05-29 07:25:38 +00:00
if(m_VoteCloseTime)
{
SendChatTarget(ClientID, "Wait for current vote to end before calling a new one.");
2010-05-29 07:25:38 +00:00
return;
}
2008-09-24 14:47:03 +00:00
int Timeleft = pPlayer->m_LastVoteCall + Server()->TickSpeed()*60 - Now;
if(pPlayer->m_LastVoteCall && Timeleft > 0)
2010-05-29 07:25:38 +00:00
{
char aChatmsg[512] = {0};
str_format(aChatmsg, sizeof(aChatmsg), "You must wait %d seconds before making another vote", (Timeleft/Server()->TickSpeed())+1);
SendChatTarget(ClientID, aChatmsg);
2010-05-29 07:25:38 +00:00
return;
}
char aChatmsg[512] = {0};
char aDesc[512] = {0};
char aCmd[512] = {0};
CNetMsg_Cl_CallVote *pMsg = (CNetMsg_Cl_CallVote *)pRawMsg;
if(str_comp_nocase(pMsg->m_Type, "option") == 0)
{
CVoteOption *pOption = m_pVoteOptionFirst;
while(pOption)
{
2011-03-25 08:49:21 +00:00
if(str_comp_nocase(pMsg->m_Value, pOption->m_aDescription) == 0)
2010-05-29 07:25:38 +00:00
{
2011-03-25 08:49:21 +00:00
str_format(aChatmsg, sizeof(aChatmsg), "'%s' called vote to change server option '%s'", Server()->ClientName(ClientID), pOption->m_aDescription);
2010-05-29 07:25:38 +00:00
str_format(aDesc, sizeof(aDesc), "%s", pOption->m_aCommand);
str_format(aCmd, sizeof(aCmd), "%s", pOption->m_aCommand);
break;
}
pOption = pOption->m_pNext;
}
2010-05-29 07:25:38 +00:00
if(!pOption)
{
str_format(aChatmsg, sizeof(aChatmsg), "'%s' isn't an option on this server", pMsg->m_Value);
SendChatTarget(ClientID, aChatmsg);
2010-05-29 07:25:38 +00:00
return;
}
2010-05-29 07:25:38 +00:00
}
else if(str_comp_nocase(pMsg->m_Type, "kick") == 0)
{
if(!g_Config.m_SvVoteKick)
{
SendChatTarget(ClientID, "Server does not allow voting to kick players");
2010-05-29 07:25:38 +00:00
return;
}
if(g_Config.m_SvVoteKickMin)
{
int PlayerNum = 0;
for(int i = 0; i < MAX_CLIENTS; ++i)
if(m_apPlayers[i] && m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS)
++PlayerNum;
if(PlayerNum < g_Config.m_SvVoteKickMin)
{
str_format(aChatmsg, sizeof(aChatmsg), "Kick voting requires %d players on the server", g_Config.m_SvVoteKickMin);
SendChatTarget(ClientID, aChatmsg);
return;
}
}
2010-05-29 07:25:38 +00:00
int KickID = str_toint(pMsg->m_Value);
if(KickID < 0 || KickID >= MAX_CLIENTS || !m_apPlayers[KickID])
2010-05-29 07:25:38 +00:00
{
SendChatTarget(ClientID, "Invalid client id to kick");
2010-05-29 07:25:38 +00:00
return;
}
if(KickID == ClientID)
{
SendChatTarget(ClientID, "You cant kick yourself");
return;
}
if(Server()->IsAuthed(KickID))
{
SendChatTarget(ClientID, "You cant kick admins");
char aBufKick[128];
str_format(aBufKick, sizeof(aBufKick), "'%s' called for vote to kick you", Server()->ClientName(ClientID));
SendChatTarget(KickID, aBufKick);
return;
}
2010-05-29 07:25:38 +00:00
const char *pReason = "No reason given";
for(const char *pStr = pMsg->m_Value; *pStr; ++pStr)
{
if(*pStr == ' ')
2010-10-10 23:06:44 +00:00
{
pReason = pStr+1;
2010-10-10 23:06:44 +00:00
break;
}
}
str_format(aChatmsg, sizeof(aChatmsg), "'%s' called for vote to kick '%s' (%s)", Server()->ClientName(ClientID), Server()->ClientName(KickID), pReason);
str_format(aDesc, sizeof(aDesc), "Kick '%s'", Server()->ClientName(KickID));
2010-05-29 07:25:38 +00:00
if (!g_Config.m_SvVoteKickBantime)
str_format(aCmd, sizeof(aCmd), "kick %d Kicked by vote", KickID);
2010-05-29 07:25:38 +00:00
else
{
char aBuf[64] = {0};
Server()->GetClientIP(KickID, aBuf, sizeof(aBuf));
str_format(aCmd, sizeof(aCmd), "ban %s %d Banned by vote", aBuf, g_Config.m_SvVoteKickBantime);
2010-05-29 07:25:38 +00:00
}
}
if(aCmd[0])
{
SendChat(-1, CGameContext::CHAT_ALL, aChatmsg);
StartVote(aDesc, aCmd);
pPlayer->m_Vote = 1;
pPlayer->m_VotePos = m_VotePos = 1;
m_VoteCreator = ClientID;
pPlayer->m_LastVoteCall = Now;
2010-05-29 07:25:38 +00:00
}
}
else if(MsgID == NETMSGTYPE_CL_VOTE)
2010-05-29 07:25:38 +00:00
{
if(!m_VoteCloseTime)
return;
if(pPlayer->m_Vote == 0)
2010-05-29 07:25:38 +00:00
{
CNetMsg_Cl_Vote *pMsg = (CNetMsg_Cl_Vote *)pRawMsg;
if(!pMsg->m_Vote)
return;
pPlayer->m_Vote = pMsg->m_Vote;
pPlayer->m_VotePos = ++m_VotePos;
2010-05-29 07:25:38 +00:00
m_VoteUpdate = true;
2008-09-25 12:23:44 +00:00
}
2008-09-24 14:47:03 +00:00
}
else if (MsgID == NETMSGTYPE_CL_SETTEAM && !m_World.m_Paused)
2010-05-29 07:25:38 +00:00
{
CNetMsg_Cl_SetTeam *pMsg = (CNetMsg_Cl_SetTeam *)pRawMsg;
if(pPlayer->GetTeam() == pMsg->m_Team || (g_Config.m_SvSpamprotection && pPlayer->m_LastSetTeam && pPlayer->m_LastSetTeam+Server()->TickSpeed()*3 > Server()->Tick()))
2010-05-29 07:25:38 +00:00
return;
// Switch team on given client and kill/respawn him
if(m_pController->CanJoinTeam(pMsg->m_Team, ClientID))
2010-05-29 07:25:38 +00:00
{
if(m_pController->CanChangeTeam(pPlayer, pMsg->m_Team))
2010-05-29 07:25:38 +00:00
{
pPlayer->m_LastSetTeam = Server()->Tick();
if(pPlayer->GetTeam() == TEAM_SPECTATORS || pMsg->m_Team == TEAM_SPECTATORS)
2010-05-29 07:25:38 +00:00
m_VoteUpdate = true;
pPlayer->SetTeam(pMsg->m_Team);
2010-05-29 07:25:38 +00:00
(void)m_pController->CheckTeamBalance();
}
else
SendBroadcast("Teams must be balanced, please join other team", ClientID);
2010-05-29 07:25:38 +00:00
}
else
{
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "Only %d active players are allowed", g_Config.m_SvMaxClients-g_Config.m_SvSpectatorSlots);
SendBroadcast(aBuf, ClientID);
2010-05-29 07:25:38 +00:00
}
}
else if (MsgID == NETMSGTYPE_CL_SETSPECTATORMODE && !m_World.m_Paused)
{
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()))
return;
pPlayer->m_LastSetSpectatorMode = Server()->Tick();
if(pMsg->m_SpectatorID != SPEC_FREEVIEW && !m_apPlayers[pMsg->m_SpectatorID])
SendChatTarget(ClientID, "Invalid spectator id used");
else
pPlayer->m_SpectatorID = pMsg->m_SpectatorID;
}
else if (MsgID == NETMSGTYPE_CL_STARTINFO)
{
if(pPlayer->m_IsReady)
2010-05-29 07:25:38 +00:00
return;
CNetMsg_Cl_StartInfo *pMsg = (CNetMsg_Cl_StartInfo *)pRawMsg;
pPlayer->m_LastChangeInfo = Server()->Tick();
2010-05-29 07:25:38 +00:00
// set start infos
Server()->SetClientName(ClientID, pMsg->m_pName);
Server()->SetClientClan(ClientID, pMsg->m_pClan);
Server()->SetClientCountry(ClientID, pMsg->m_Country);
str_copy(pPlayer->m_TeeInfos.m_SkinName, pMsg->m_pSkin, sizeof(pPlayer->m_TeeInfos.m_SkinName));
pPlayer->m_TeeInfos.m_UseCustomColor = pMsg->m_UseCustomColor;
pPlayer->m_TeeInfos.m_ColorBody = pMsg->m_ColorBody;
pPlayer->m_TeeInfos.m_ColorFeet = pMsg->m_ColorFeet;
m_pController->OnPlayerInfoChange(pPlayer);
2010-05-29 07:25:38 +00:00
// send vote options
CNetMsg_Sv_VoteClearOptions ClearMsg;
Server()->SendPackMsg(&ClearMsg, MSGFLAG_VITAL, ClientID);
CVoteOption *pCurrent = m_pVoteOptionFirst;
while(pCurrent)
{
CNetMsg_Sv_VoteOption OptionMsg;
2011-03-25 08:49:21 +00:00
OptionMsg.m_pDescription = pCurrent->m_aDescription;
Server()->SendPackMsg(&OptionMsg, MSGFLAG_VITAL, ClientID);
pCurrent = pCurrent->m_pNext;
}
// send tuning parameters to client
SendTuningParams(ClientID);
// client is ready to enter
pPlayer->m_IsReady = true;
CNetMsg_Sv_ReadyToEnter m;
Server()->SendPackMsg(&m, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID);
}
else if (MsgID == NETMSGTYPE_CL_CHANGEINFO)
{
if(g_Config.m_SvSpamprotection && pPlayer->m_LastChangeInfo && pPlayer->m_LastChangeInfo+Server()->TickSpeed()*5 > Server()->Tick())
return;
CNetMsg_Cl_ChangeInfo *pMsg = (CNetMsg_Cl_ChangeInfo *)pRawMsg;
pPlayer->m_LastChangeInfo = Server()->Tick();
2010-05-29 07:25:38 +00:00
// set infos
char aOldName[MAX_NAME_LENGTH];
str_copy(aOldName, Server()->ClientName(ClientID), sizeof(aOldName));
Server()->SetClientName(ClientID, pMsg->m_pName);
if(str_comp(aOldName, Server()->ClientName(ClientID)) != 0)
2010-05-29 07:25:38 +00:00
{
char aChatText[256];
str_format(aChatText, sizeof(aChatText), "'%s' changed name to '%s'", aOldName, Server()->ClientName(ClientID));
2010-05-29 07:25:38 +00:00
SendChat(-1, CGameContext::CHAT_ALL, aChatText);
}
Server()->SetClientClan(ClientID, pMsg->m_pClan);
Server()->SetClientCountry(ClientID, pMsg->m_Country);
str_copy(pPlayer->m_TeeInfos.m_SkinName, pMsg->m_pSkin, sizeof(pPlayer->m_TeeInfos.m_SkinName));
pPlayer->m_TeeInfos.m_UseCustomColor = pMsg->m_UseCustomColor;
pPlayer->m_TeeInfos.m_ColorBody = pMsg->m_ColorBody;
pPlayer->m_TeeInfos.m_ColorFeet = pMsg->m_ColorFeet;
m_pController->OnPlayerInfoChange(pPlayer);
2010-05-29 07:25:38 +00:00
}
else if (MsgID == NETMSGTYPE_CL_EMOTICON && !m_World.m_Paused)
2010-05-29 07:25:38 +00:00
{
CNetMsg_Cl_Emoticon *pMsg = (CNetMsg_Cl_Emoticon *)pRawMsg;
if(g_Config.m_SvSpamprotection && pPlayer->m_LastEmote && pPlayer->m_LastEmote+Server()->TickSpeed()*3 > Server()->Tick())
2010-05-29 07:25:38 +00:00
return;
pPlayer->m_LastEmote = Server()->Tick();
2010-05-29 07:25:38 +00:00
SendEmoticon(ClientID, pMsg->m_Emoticon);
2010-05-29 07:25:38 +00:00
}
else if (MsgID == NETMSGTYPE_CL_KILL && !m_World.m_Paused)
2010-05-29 07:25:38 +00:00
{
if(pPlayer->m_LastKill && pPlayer->m_LastKill+Server()->TickSpeed()*3 > Server()->Tick())
2010-05-29 07:25:38 +00:00
return;
pPlayer->m_LastKill = Server()->Tick();
pPlayer->KillCharacter(WEAPON_SELF);
pPlayer->m_RespawnTick = Server()->Tick()+Server()->TickSpeed()*3;
2010-05-29 07:25:38 +00:00
}
}
void CGameContext::ConTuneParam(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
const char *pParamName = pResult->GetString(0);
float NewValue = pResult->GetFloat(1);
if(pSelf->Tuning()->Set(pParamName, NewValue))
{
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "%s changed to %.2f", pParamName, NewValue);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "tuning", aBuf);
2010-05-29 07:25:38 +00:00
pSelf->SendTuningParams(-1);
}
else
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "tuning", "No such tuning parameter");
2010-05-29 07:25:38 +00:00
}
void CGameContext::ConTuneReset(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
CTuningParams TuningParams;
*pSelf->Tuning() = TuningParams;
2010-05-29 07:25:38 +00:00
pSelf->SendTuningParams(-1);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "tuning", "Tuning reset");
2010-05-29 07:25:38 +00:00
}
void CGameContext::ConTuneDump(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
char aBuf[256];
2010-05-29 07:25:38 +00:00
for(int i = 0; i < pSelf->Tuning()->Num(); i++)
{
float v;
pSelf->Tuning()->Get(i, &v);
str_format(aBuf, sizeof(aBuf), "%s %.2f", pSelf->Tuning()->m_apNames[i], v);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "tuning", aBuf);
2010-05-29 07:25:38 +00:00
}
}
void CGameContext::ConChangeMap(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->m_pController->ChangeMap(pResult->NumArguments() ? pResult->GetString(0) : "");
2010-05-29 07:25:38 +00:00
}
void CGameContext::ConRestart(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(pResult->NumArguments())
pSelf->m_pController->DoWarmup(pResult->GetInteger(0));
else
pSelf->m_pController->StartRound();
}
void CGameContext::ConBroadcast(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->SendBroadcast(pResult->GetString(0), -1);
}
void CGameContext::ConSay(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->SendChat(-1, CGameContext::CHAT_ALL, pResult->GetString(0));
}
void CGameContext::ConSetTeam(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int ClientID = clamp(pResult->GetInteger(0), 0, (int)MAX_CLIENTS-1);
2010-05-29 07:25:38 +00:00
int Team = clamp(pResult->GetInteger(1), -1, 1);
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "moved client %d to team %d", ClientID, Team);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
2010-05-29 07:25:38 +00:00
if(!pSelf->m_apPlayers[ClientID])
2010-05-29 07:25:38 +00:00
return;
pSelf->m_apPlayers[ClientID]->SetTeam(Team);
2010-05-29 07:25:38 +00:00
(void)pSelf->m_pController->CheckTeamBalance();
}
void CGameContext::ConSetTeamAll(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int Team = clamp(pResult->GetInteger(0), -1, 1);
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "moved all clients to team %d", Team);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
for(int i = 0; i < MAX_CLIENTS; ++i)
if(pSelf->m_apPlayers[i])
pSelf->m_apPlayers[i]->SetTeam(Team);
(void)pSelf->m_pController->CheckTeamBalance();
}
2010-05-29 07:25:38 +00:00
void CGameContext::ConAddVote(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
2011-03-25 08:49:21 +00:00
const char *pDescription = pResult->GetString(0);
const char *pCommand = pResult->GetString(1);
// check for valid option
2011-03-25 08:49:21 +00:00
if(!pSelf->Console()->LineIsValid(pCommand))
{
char aBuf[256];
2011-03-25 08:49:21 +00:00
str_format(aBuf, sizeof(aBuf), "skipped invalid option '%s'", pCommand);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
return;
}
2010-05-29 07:25:38 +00:00
2011-03-25 08:49:21 +00:00
// check for duplicate entry
CGameContext::CVoteOption *pOption = pSelf->m_pVoteOptionFirst;
while(pOption)
{
2011-03-25 08:49:21 +00:00
if(str_comp_nocase(pDescription, pOption->m_aCommand) == 0)
{
char aBuf[256];
2011-03-25 08:49:21 +00:00
str_format(aBuf, sizeof(aBuf), "option '%s' already exists", pDescription);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
return;
}
pOption = pOption->m_pNext;
}
2011-03-25 08:49:21 +00:00
// add the option
int Len = str_length(pCommand);
pOption = (CGameContext::CVoteOption *)pSelf->m_pVoteOptionHeap->Allocate(sizeof(CGameContext::CVoteOption) + Len);
2010-05-29 07:25:38 +00:00
pOption->m_pNext = 0;
pOption->m_pPrev = pSelf->m_pVoteOptionLast;
if(pOption->m_pPrev)
pOption->m_pPrev->m_pNext = pOption;
pSelf->m_pVoteOptionLast = pOption;
if(!pSelf->m_pVoteOptionFirst)
pSelf->m_pVoteOptionFirst = pOption;
2011-03-25 08:49:21 +00:00
str_copy(pOption->m_aDescription, pDescription, sizeof(pOption->m_aDescription));
mem_copy(pOption->m_aCommand, pCommand, Len+1);
char aBuf[256];
2011-03-25 08:49:21 +00:00
str_format(aBuf, sizeof(aBuf), "added option '%s' '%s'", pOption->m_aDescription, pOption->m_aCommand);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
2010-05-29 07:25:38 +00:00
2011-03-25 08:49:21 +00:00
// send added option to the clients
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_VoteOption OptionMsg;
2011-03-25 08:49:21 +00:00
OptionMsg.m_pDescription = pOption->m_aDescription;
2010-05-29 07:25:38 +00:00
pSelf->Server()->SendPackMsg(&OptionMsg, MSGFLAG_VITAL, -1);
}
void CGameContext::ConClearVotes(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "cleared votes");
CNetMsg_Sv_VoteClearOptions VoteClearOptionsMsg;
pSelf->Server()->SendPackMsg(&VoteClearOptionsMsg, MSGFLAG_VITAL, -1);
pSelf->m_pVoteOptionHeap->Reset();
pSelf->m_pVoteOptionFirst = 0;
pSelf->m_pVoteOptionLast = 0;
}
2010-05-29 07:25:38 +00:00
void CGameContext::ConVote(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(str_comp_nocase(pResult->GetString(0), "yes") == 0)
pSelf->m_VoteEnforce = CGameContext::VOTE_ENFORCE_YES;
else if(str_comp_nocase(pResult->GetString(0), "no") == 0)
pSelf->m_VoteEnforce = CGameContext::VOTE_ENFORCE_NO;
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "forcing vote %s", pResult->GetString(0));
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
2010-05-29 07:25:38 +00:00
}
void CGameContext::ConchainSpecialMotdupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
{
pfnCallback(pResult, pCallbackUserData);
if(pResult->NumArguments())
{
CNetMsg_Sv_Motd Msg;
Msg.m_pMessage = g_Config.m_SvMotd;
CGameContext *pSelf = (CGameContext *)pUserData;
for(int i = 0; i < MAX_CLIENTS; ++i)
if(pSelf->m_apPlayers[i])
pSelf->Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, i);
}
}
void CGameContext::OnConsoleInit()
{
m_pServer = Kernel()->RequestInterface<IServer>();
m_pConsole = Kernel()->RequestInterface<IConsole>();
Console()->Register("tune", "si", CFGFLAG_SERVER, ConTuneParam, this, "");
Console()->Register("tune_reset", "", CFGFLAG_SERVER, ConTuneReset, this, "");
Console()->Register("tune_dump", "", CFGFLAG_SERVER, ConTuneDump, this, "");
Console()->Register("change_map", "?r", CFGFLAG_SERVER|CFGFLAG_STORE, ConChangeMap, this, "");
Console()->Register("restart", "?i", CFGFLAG_SERVER|CFGFLAG_STORE, ConRestart, this, "");
2010-05-29 07:25:38 +00:00
Console()->Register("broadcast", "r", CFGFLAG_SERVER, ConBroadcast, this, "");
Console()->Register("say", "r", CFGFLAG_SERVER, ConSay, this, "");
Console()->Register("set_team", "ii", CFGFLAG_SERVER, ConSetTeam, this, "");
Console()->Register("set_team_all", "i", CFGFLAG_SERVER, ConSetTeamAll, this, "");
2010-05-29 07:25:38 +00:00
2011-03-25 08:49:21 +00:00
Console()->Register("add_vote", "sr", CFGFLAG_SERVER, ConAddVote, this, "");
Console()->Register("clear_votes", "", CFGFLAG_SERVER, ConClearVotes, this, "");
2010-05-29 07:25:38 +00:00
Console()->Register("vote", "r", CFGFLAG_SERVER, ConVote, this, "");
Console()->Chain("sv_motd", ConchainSpecialMotdupdate, this);
}
void CGameContext::OnInit(/*class IKernel *pKernel*/)
{
m_pServer = Kernel()->RequestInterface<IServer>();
m_pConsole = Kernel()->RequestInterface<IConsole>();
m_World.SetGameServer(this);
m_Events.SetGameServer(this);
//if(!data) // only load once
//data = load_data_from_memory(internal_data);
for(int i = 0; i < NUM_NETOBJTYPES; i++)
Server()->SnapSetStaticsize(i, m_NetObjHandler.GetObjSize(i));
m_Layers.Init(Kernel());
m_Collision.Init(&m_Layers);
// reset everything here
//world = new GAMEWORLD;
//players = new CPlayer[MAX_CLIENTS];
// select gametype
if(str_comp(g_Config.m_SvGametype, "mod") == 0)
m_pController = new CGameControllerMOD(this);
else if(str_comp(g_Config.m_SvGametype, "ctf") == 0)
m_pController = new CGameControllerCTF(this);
else if(str_comp(g_Config.m_SvGametype, "tdm") == 0)
m_pController = new CGameControllerTDM(this);
else
m_pController = new CGameControllerDM(this);
// setup core world
//for(int i = 0; i < MAX_CLIENTS; i++)
// game.players[i].core.world = &game.world.core;
// create all entities from the game layer
CMapItemLayerTilemap *pTileMap = m_Layers.GameLayer();
CTile *pTiles = (CTile *)Kernel()->RequestInterface<IMap>()->GetData(pTileMap->m_Data);
/*
num_spawn_points[0] = 0;
num_spawn_points[1] = 0;
num_spawn_points[2] = 0;
*/
for(int y = 0; y < pTileMap->m_Height; y++)
{
for(int x = 0; x < pTileMap->m_Width; x++)
{
int Index = pTiles[y*pTileMap->m_Width+x].m_Index;
if(Index >= ENTITY_OFFSET)
{
vec2 Pos(x*32.0f+16.0f, y*32.0f+16.0f);
m_pController->OnEntity(Index-ENTITY_OFFSET, Pos);
}
}
}
//game.world.insert_entity(game.Controller);
#ifdef CONF_DEBUG
if(g_Config.m_DbgDummies)
{
for(int i = 0; i < g_Config.m_DbgDummies ; i++)
{
OnClientConnected(MAX_CLIENTS-i-1);
}
}
#endif
}
void CGameContext::OnShutdown()
{
delete m_pController;
m_pController = 0;
Clear();
}
void CGameContext::OnSnap(int ClientID)
{
m_World.Snap(ClientID);
m_pController->Snap(ClientID);
m_Events.Snap(ClientID);
for(int i = 0; i < MAX_CLIENTS; i++)
{
2010-05-29 07:25:38 +00:00
if(m_apPlayers[i])
m_apPlayers[i]->Snap(ClientID);
}
}
2010-05-29 07:25:38 +00:00
void CGameContext::OnPreSnap() {}
void CGameContext::OnPostSnap()
{
m_Events.Clear();
}
bool CGameContext::IsClientReady(int ClientID)
{
return m_apPlayers[ClientID] && m_apPlayers[ClientID]->m_IsReady ? true : false;
}
bool CGameContext::IsClientPlayer(int ClientID)
{
return m_apPlayers[ClientID] && m_apPlayers[ClientID]->GetTeam() == TEAM_SPECTATORS ? false : true;
}
const char *CGameContext::GameType() { return m_pController && m_pController->m_pGameType ? m_pController->m_pGameType : ""; }
2010-05-29 07:25:38 +00:00
const char *CGameContext::Version() { return GAME_VERSION; }
const char *CGameContext::NetVersion() { return GAME_NETVERSION; }
2011-02-13 12:06:19 +00:00
IGameServer *CreateGameServer() { return new CGameContext; }