ddnet/src/game/server/gamecontroller.cpp

865 lines
21 KiB
C++
Raw Normal View History

2010-05-29 07:25:38 +00:00
// copyright (c) 2007 magnus auvinen, see licence.txt for more info
#include <engine/shared/config.h>
#include <game/mapitems.h>
2010-05-29 07:25:38 +00:00
#include <game/generated/protocol.h>
2010-05-29 07:25:38 +00:00
#include "entities/pickup.h"
#include "gamecontroller.h"
#include "gamecontext.h"
#include "entities/light.h"
#include "entities/drager.h"
#include "entities/gun.h"
#include "entities/projectile.h"
#include "entities/plasma.h"
#include "entities/trigger.h"
#include "entities/door.h"
#include <game/layers.h>
2008-08-27 20:04:07 +00:00
2010-05-29 07:25:38 +00:00
IGameController::IGameController(class CGameContext *pGameServer)
2008-08-27 20:04:07 +00:00
{
2010-05-29 07:25:38 +00:00
m_pGameServer = pGameServer;
m_pServer = m_pGameServer->Server();
m_pGameType = "unknown";
2008-08-27 20:04:07 +00:00
//
2010-05-29 07:25:38 +00:00
DoWarmup(g_Config.m_SvWarmup);
m_GameOverTick = -1;
m_SuddenDeath = 0;
m_RoundStartTick = Server()->Tick();
m_RoundCount = 0;
m_GameFlags = 0;
//m_aTeamscore[0] = 0;
//m_aTeamscore[1] = 0;
2010-05-29 07:25:38 +00:00
m_aMapWish[0] = 0;
2010-05-29 07:25:38 +00:00
m_UnbalancedTick = -1;
m_ForceBalanced = false;
2010-05-29 07:25:38 +00:00
m_aNumSpawnPoints[0] = 0;
m_aNumSpawnPoints[1] = 0;
m_aNumSpawnPoints[2] = 0;
2008-08-27 20:04:07 +00:00
}
2010-05-29 07:25:38 +00:00
IGameController::~IGameController()
2008-10-02 14:44:35 +00:00
{
}
2010-05-29 07:25:38 +00:00
float IGameController::EvaluateSpawnPos(CSpawnEval *pEval, vec2 Pos)
{
2010-05-29 07:25:38 +00:00
float Score = 0.0f;
CCharacter *pC = static_cast<CCharacter *>(GameServer()->m_World.FindFirst(NETOBJTYPE_CHARACTER));
for(; pC; pC = (CCharacter *)pC->TypeNext())
{
// team mates are not as dangerous as enemies
2010-05-29 07:25:38 +00:00
float Scoremod = 1.0f;
if(pEval->m_FriendlyTeam != -1 && pC->GetPlayer()->GetTeam() == pEval->m_FriendlyTeam)
Scoremod = 0.5f;
2010-05-29 07:25:38 +00:00
float d = distance(Pos, pC->m_Pos);
if(d == 0)
2010-05-29 07:25:38 +00:00
Score += 1000000000.0f;
else
2010-05-29 07:25:38 +00:00
Score += 1.0f/d;
}
2010-05-29 07:25:38 +00:00
return Score;
}
2010-05-29 07:25:38 +00:00
void IGameController::EvaluateSpawnType(CSpawnEval *pEval, int T)
{
// get spawn point
2010-05-29 07:25:38 +00:00
for(int i = 0; i < m_aNumSpawnPoints[T]; i++)
{
2010-05-29 07:25:38 +00:00
vec2 P = m_aaSpawnPoints[T][i];
float S = EvaluateSpawnPos(pEval, P);
if(!pEval->m_Got || pEval->m_Score > S)
{
2010-05-29 07:25:38 +00:00
pEval->m_Got = true;
pEval->m_Score = S;
pEval->m_Pos = P;
}
}
}
2010-05-29 07:25:38 +00:00
bool IGameController::CanSpawn(CPlayer *pPlayer, vec2 *pOutPos)
{
2010-05-29 07:25:38 +00:00
CSpawnEval Eval;
2008-11-21 14:18:55 +00:00
// spectators can't spawn
2010-05-29 07:25:38 +00:00
if(pPlayer->GetTeam() == -1)
2008-11-21 14:18:55 +00:00
return false;
/*if(IsTeamplay())
{
2010-05-29 07:25:38 +00:00
Eval.m_FriendlyTeam = pPlayer->GetTeam();
// try first try own team spawn, then normal spawn and then enemy
2010-05-29 07:25:38 +00:00
EvaluateSpawnType(&Eval, 1+(pPlayer->GetTeam()&1));
if(!Eval.m_Got)
{
2010-05-29 07:25:38 +00:00
EvaluateSpawnType(&Eval, 0);
if(!Eval.m_Got)
EvaluateSpawnType(&Eval, 1+((pPlayer->GetTeam()+1)&1));
}
}
else
{*/
2010-05-29 07:25:38 +00:00
EvaluateSpawnType(&Eval, 0);
EvaluateSpawnType(&Eval, 1);
EvaluateSpawnType(&Eval, 2);
//}
2010-05-29 07:25:38 +00:00
*pOutPos = Eval.m_Pos;
return Eval.m_Got;
}
bool IGameController::OnEntity(int Index, vec2 Pos, bool Front)
2008-01-13 11:43:43 +00:00
{
//if (Index<0)
//return false;
dbg_msg("OnEntity","Index=%d, Pos=(%d,%d), Front=%d",Index,Pos.x,Pos.y,Front);//Remove*/
2010-05-29 07:25:38 +00:00
int Type = -1;
int SubType = 0;
int x,y;
x=(Pos.x-16.0f)/32.0f;
y=(Pos.y-16.0f)/32.0f;
/*dbg_msg("OnEntity","Pos(%d,%d)",x,y);//Remove*/
int sides[8];
sides[0]=GameServer()->Collision()->Entity(x,y+1, Front);
sides[1]=GameServer()->Collision()->Entity(x+1,y+1, Front);
sides[2]=GameServer()->Collision()->Entity(x+1,y, Front);
sides[3]=GameServer()->Collision()->Entity(x+1,y-1, Front);
sides[4]=GameServer()->Collision()->Entity(x,y-1, Front);
sides[5]=GameServer()->Collision()->Entity(x-1,y-1, Front);
sides[6]=GameServer()->Collision()->Entity(x-1,y, Front);
sides[7]=GameServer()->Collision()->Entity(x-1,y+1, Front);
2010-05-29 07:25:38 +00:00
if(Index == ENTITY_SPAWN)
m_aaSpawnPoints[0][m_aNumSpawnPoints[0]++] = Pos;
else if(Index == ENTITY_SPAWN_RED)
m_aaSpawnPoints[1][m_aNumSpawnPoints[1]++] = Pos;
else if(Index == ENTITY_SPAWN_BLUE)
m_aaSpawnPoints[2][m_aNumSpawnPoints[2]++] = Pos;
if(Index == ENTITY_DOOR)
{
for(int i=0; i<8;i++)
{
if (sides[i] >= ENTITY_LASER_SHORT && sides[i] <= ENTITY_LASER_LONG)
{
CDoor * door = new CDoor(&GameServer()->m_World, Pos, pi/4*i, 32*3 + 32*(sides[i] - ENTITY_LASER_SHORT)*3, false);
2010-08-12 18:07:35 +00:00
//for (int j = 0; j < 8; j++)
// if (j != i)
Connector(vec2(x, y), door, Front);
}
}
}
2010-08-14 10:46:54 +00:00
else if(Index >= ENTITY_CRAZY_SHOTGUN_U_EX && Index <= ENTITY_CRAZY_SHOTGUN_L_EX)
{
for (int i = 0; i < 4; i++)
{
if (Index - ENTITY_CRAZY_SHOTGUN_U_EX == i)
{
float Deg = i*(pi/2);
CProjectile *bullet = new CProjectile(&GameServer()->m_World,
2010-08-14 10:46:54 +00:00
WEAPON_SHOTGUN, //Type
-1, //Owner
Pos, //Pos
vec2(sin(Deg),cos(Deg)), //Dir
-2, //Span
true, //Freeze
true, //Explosive
0,
SOUND_GRENADE_EXPLODE,
2010-08-14 10:46:54 +00:00
WEAPON_SHOTGUN);
bullet->SetBouncing(2 - (i % 2));
}
}
}
else if(Index >= ENTITY_CRAZY_SHOTGUN_U && Index <= ENTITY_CRAZY_SHOTGUN_L)
{
for (int i = 0; i < 4; i++)
{
if (Index - ENTITY_CRAZY_SHOTGUN_U == i)
{
float Deg = i*(pi/2);
CProjectile *bullet = new CProjectile(&GameServer()->m_World,
2010-08-14 10:46:54 +00:00
WEAPON_SHOTGUN, //Type
-1, //Owner
Pos, //Pos
vec2(sin(Deg),cos(Deg)), //Dir
-2, //Span
true, //Freeze
false, //Explosive
0,
SOUND_GRENADE_EXPLODE,
2010-08-14 10:46:54 +00:00
WEAPON_SHOTGUN);
bullet->SetBouncing(2 - (i % 2));
}
}
}
if(Index == ENTITY_ARMOR_1)
Type = POWERUP_ARMOR;
else if(Index == ENTITY_HEALTH_1)
Type = POWERUP_HEALTH;
else if(Index == ENTITY_WEAPON_SHOTGUN)
{
Type = POWERUP_WEAPON;
SubType = WEAPON_SHOTGUN;
}
else if(Index == ENTITY_WEAPON_GRENADE)
{
Type = POWERUP_WEAPON;
SubType = WEAPON_GRENADE;
}
else if(Index == ENTITY_WEAPON_RIFLE)
{
Type = POWERUP_WEAPON;
SubType = WEAPON_RIFLE;
}
else if(Index == ENTITY_POWERUP_NINJA)
{
Type = POWERUP_NINJA;
SubType = WEAPON_NINJA;
}
else if(Index >= ENTITY_LASER_FAST_CW && Index <= ENTITY_LASER_FAST_CCW)
{
int sides2[8];
sides2[0]=GameServer()->Collision()->Entity(x,y+2, Front);
sides2[1]=GameServer()->Collision()->Entity(x+2,y+2, Front);
sides2[2]=GameServer()->Collision()->Entity(x+2,y, Front);
sides2[3]=GameServer()->Collision()->Entity(x+2,y-2, Front);
sides2[4]=GameServer()->Collision()->Entity(x,y-2, Front);
sides2[5]=GameServer()->Collision()->Entity(x-2,y-2, Front);
sides2[6]=GameServer()->Collision()->Entity(x-2,y, Front);
sides2[7]=GameServer()->Collision()->Entity(x-2,y+2, Front);
float ang_speed;
int ind=Index-ENTITY_LASER_STOP;
int m;
if (ind<0)
{
ind=-ind;
m=1;
}
else if(ind==0)
m=0;
else
m=-1;
if (ind==0)
ang_speed=0.0f;
else if (ind==1)
ang_speed=pi/360;
else if (ind==2)
ang_speed=pi/180;
else if (ind==3)
ang_speed=pi/90;
ang_speed*=m;
for(int i=0; i<8;i++)
{
if (sides[i] >= ENTITY_LASER_SHORT && sides[i] <= ENTITY_LASER_LONG)
{
CLight *lgt = new CLight(&GameServer()->m_World, Pos, pi/4*i,32*3 + 32*(sides[i] - ENTITY_LASER_SHORT)*3);
lgt->ang_speed=ang_speed;
if (sides2[i]>=ENTITY_LASER_C_SLOW && sides2[i]<=ENTITY_LASER_C_FAST)
{
lgt->speed=1+(sides2[i]-ENTITY_LASER_C_SLOW)*2;
lgt->cur_length=lgt->length;
}
else if(sides2[i]>=ENTITY_LASER_O_SLOW && sides2[i]<=ENTITY_LASER_O_FAST)
{
lgt->speed=1+(sides2[i]-ENTITY_LASER_O_SLOW)*2;
lgt->cur_length=0;
}
else
lgt->cur_length=lgt->length;
}
}
}
else if(Index>=ENTITY_DRAGGER_WEAK && Index <=ENTITY_DRAGGER_STRONG)
{
new CDrager(&GameServer()->m_World,Pos,Index-ENTITY_DRAGGER_WEAK+1);
}
else if(Index>=ENTITY_DRAGGER_WEAK_NW && Index <=ENTITY_DRAGGER_STRONG_NW)
{
new CDrager(&GameServer()->m_World, Pos,Index-ENTITY_DRAGGER_WEAK_NW+1,true);
}
else if(Index==ENTITY_PLASMA)
{
new CGun(&GameServer()->m_World, Pos);
}
if(Type != -1)
{
CPickup *pPickup = new CPickup(&GameServer()->m_World, Type, SubType);
pPickup->m_Pos = Pos;
return true;
}
return false;
}
vec2 GetSidePos(int side) {
switch(side)
{
case 0: return vec2(0, 1);
case 1: return vec2(1, 1);
case 2: return vec2(1, 0);
case 3: return vec2(1, -1);
case 4: return vec2(0, -1);
case 5: return vec2(-1, -1);
case 6: return vec2(-1, 0);
case 7: return vec2(-1, 1);
}
return vec2(0, 0);
}
void IGameController::Connector(vec2 Pos, CDoor* Door, bool Front) {
2010-08-12 18:07:35 +00:00
int sides[8];
sides[0] = GameServer()->Collision()->Entity(Pos.x, Pos.y + 1, Front);
sides[1] = GameServer()->Collision()->Entity(Pos.x + 1, Pos.y + 1, Front);
sides[2] = GameServer()->Collision()->Entity(Pos.x + 1, Pos.y, Front);
sides[3] = GameServer()->Collision()->Entity(Pos.x + 1, Pos.y - 1, Front);
sides[4] = GameServer()->Collision()->Entity(Pos.x, Pos.y - 1, Front);
sides[5] = GameServer()->Collision()->Entity(Pos.x - 1, Pos.y - 1, Front);
sides[6] = GameServer()->Collision()->Entity(Pos.x - 1, Pos.y, Front);
sides[7] = GameServer()->Collision()->Entity(Pos.x - 1, Pos.y + 1, Front);
2010-08-12 18:07:35 +00:00
for (int i=0;i<8;i++)
{
vec2 shift = GetSidePos(i);
if (sides[i]==ENTITY_CONNECTOR_D+(i+4) % 8)
Connector(Pos + shift, Door, Front);
2010-08-12 18:07:35 +00:00
else if(sides[i]==ENTITY_TRIGGER)
{
vec2 pos((Pos.x + shift.x)*32.0f + 16.0f, (Pos.y + shift.y)*32.0f + 16.0f);
new CTrigger(&GameServer()->m_World,pos, Door);
}
}
}
2010-05-29 07:25:38 +00:00
void IGameController::EndRound()
{
2010-05-29 07:25:38 +00:00
if(m_Warmup) // game can't end when we are running warmup
2007-10-06 17:36:24 +00:00
return;
2010-05-29 07:25:38 +00:00
GameServer()->m_World.m_Paused = true;
m_GameOverTick = Server()->Tick();
m_SuddenDeath = 0;
}
2010-05-29 07:25:38 +00:00
void IGameController::ResetGame()
{
2010-05-29 07:25:38 +00:00
GameServer()->m_World.m_ResetRequested = true;
}
2010-05-29 07:25:38 +00:00
const char *IGameController::GetTeamName(int Team)
{
2010-05-29 07:25:38 +00:00
if(Team == 0)
return "game";
return "spectators";
}
bool IsSeparator(char c) { return c == ';' || c == ' ' || c == ',' || c == '\t'; }
2010-05-29 07:25:38 +00:00
void IGameController::StartRound()
{
2010-05-29 07:25:38 +00:00
ResetGame();
2010-05-29 07:25:38 +00:00
m_RoundStartTick = Server()->Tick();
m_SuddenDeath = 0;
m_GameOverTick = -1;
GameServer()->m_World.m_Paused = false;
m_ForceBalanced = false;
dbg_msg("game","start round type='%s' teamplay='%d'", m_pGameType, m_GameFlags&GAMEFLAG_TEAMS);
}
2010-05-29 07:25:38 +00:00
void IGameController::ChangeMap(const char *pToMap)
{
2010-05-29 07:25:38 +00:00
str_copy(m_aMapWish, pToMap, sizeof(m_aMapWish));
EndRound();
}
/*
2010-05-29 07:25:38 +00:00
void IGameController::CycleMap()
{
2010-05-29 07:25:38 +00:00
if(m_aMapWish[0] != 0)
{
2010-05-29 07:25:38 +00:00
dbg_msg("game", "rotating map to %s", m_aMapWish);
str_copy(g_Config.m_SvMap, m_aMapWish, sizeof(g_Config.m_SvMap));
m_aMapWish[0] = 0;
m_RoundCount = 0;
return;
}
2010-05-29 07:25:38 +00:00
if(!str_length(g_Config.m_SvMaprotation))
return;
2010-05-29 07:25:38 +00:00
if(m_RoundCount < g_Config.m_SvRoundsPerMap-1)
return;
// handle maprotation
2010-05-29 07:25:38 +00:00
const char *pMapRotation = g_Config.m_SvMaprotation;
const char *pCurrentMap = g_Config.m_SvMap;
2010-05-29 07:25:38 +00:00
int CurrentMapLen = str_length(pCurrentMap);
const char *pNextMap = pMapRotation;
while(*pNextMap)
{
2010-05-29 07:25:38 +00:00
int WordLen = 0;
while(pNextMap[WordLen] && !IsSeparator(pNextMap[WordLen]))
WordLen++;
2010-05-29 07:25:38 +00:00
if(WordLen == CurrentMapLen && str_comp_num(pNextMap, pCurrentMap, CurrentMapLen) == 0)
{
// map found
2010-05-29 07:25:38 +00:00
pNextMap += CurrentMapLen;
while(*pNextMap && IsSeparator(*pNextMap))
pNextMap++;
break;
}
2010-05-29 07:25:38 +00:00
pNextMap++;
}
// restart rotation
2010-05-29 07:25:38 +00:00
if(pNextMap[0] == 0)
pNextMap = pMapRotation;
// cut out the next map
2010-05-29 07:25:38 +00:00
char Buf[512];
for(int i = 0; i < 512; i++)
{
2010-05-29 07:25:38 +00:00
Buf[i] = pNextMap[i];
if(IsSeparator(pNextMap[i]) || pNextMap[i] == 0)
{
2010-05-29 07:25:38 +00:00
Buf[i] = 0;
break;
}
}
// skip spaces
int i = 0;
2010-05-29 07:25:38 +00:00
while(IsSeparator(Buf[i]))
i++;
2010-05-29 07:25:38 +00:00
m_RoundCount = 0;
2010-05-29 07:25:38 +00:00
dbg_msg("game", "rotating map to %s", &Buf[i]);
str_copy(g_Config.m_SvMap, &Buf[i], sizeof(g_Config.m_SvMap));
}
*/
2010-05-29 07:25:38 +00:00
void IGameController::PostReset()
{
for(int i = 0; i < MAX_CLIENTS; i++)
{
2010-05-29 07:25:38 +00:00
if(GameServer()->m_apPlayers[i])
2008-10-25 08:36:55 +00:00
{
2010-05-29 07:25:38 +00:00
GameServer()->m_apPlayers[i]->Respawn();
//GameServer()->m_apPlayers[i]->m_Score = 0;
//GameServer()->m_apPlayers[i]->m_ScoreStartTick = Server()->Tick();
//GameServer()->m_apPlayers[i]->m_RespawnTick = Server()->Tick()+Server()->TickSpeed()/2;
2008-10-25 08:36:55 +00:00
}
}
}
/*
2010-05-29 07:25:38 +00:00
void IGameController::OnPlayerInfoChange(class CPlayer *pP)
{
2010-05-29 07:25:38 +00:00
const int aTeamColors[2] = {65387, 10223467};
if(IsTeamplay())
{
2010-05-29 07:25:38 +00:00
if(pP->GetTeam() >= 0 || pP->GetTeam() <= 1)
{
2010-05-29 07:25:38 +00:00
pP->m_TeeInfos.m_UseCustomColor = 1;
pP->m_TeeInfos.m_ColorBody = aTeamColors[pP->GetTeam()];
pP->m_TeeInfos.m_ColorFeet = aTeamColors[pP->GetTeam()];
}
}
}
*/
2010-05-29 07:25:38 +00:00
int IGameController::OnCharacterDeath(class CCharacter *pVictim, class CPlayer *pKiller, int Weapon)
{
/*
// do scoreing
if(!pKiller || Weapon == WEAPON_GAME)
return 0;
2010-05-29 07:25:38 +00:00
if(pKiller == pVictim->GetPlayer())
pVictim->GetPlayer()->m_Score--; // suicide
else
2007-12-11 21:19:52 +00:00
{
2010-05-29 07:25:38 +00:00
if(IsTeamplay() && pVictim->GetPlayer()->GetTeam() == pKiller->GetTeam())
pKiller->m_Score--; // teamkill
2007-12-11 21:19:52 +00:00
else
2010-05-29 07:25:38 +00:00
pKiller->m_Score++; // normal kill
}*/
return 0;
}
2010-05-29 07:25:38 +00:00
void IGameController::OnCharacterSpawn(class CCharacter *pChr)
2008-08-27 20:04:07 +00:00
{
// default health
2010-05-29 07:25:38 +00:00
pChr->IncreaseHealth(10);
2008-08-27 20:04:07 +00:00
// give default weapons
//pChr->GiveAllWeapons();
2010-05-29 07:25:38 +00:00
pChr->GiveWeapon(WEAPON_HAMMER, -1);
pChr->GiveWeapon(WEAPON_GUN, -1);
2008-08-27 20:04:07 +00:00
}
2010-05-29 07:25:38 +00:00
void IGameController::DoWarmup(int Seconds)
2007-10-06 17:36:24 +00:00
{
2010-05-29 07:25:38 +00:00
if(Seconds < 0)
m_Warmup = 0;
else
m_Warmup = Seconds*Server()->TickSpeed();
2007-10-06 17:36:24 +00:00
}
/*
2010-05-29 07:25:38 +00:00
bool IGameController::IsFriendlyFire(int Cid1, int Cid2)
2007-12-10 20:53:37 +00:00
{
2010-05-29 07:25:38 +00:00
if(Cid1 == Cid2)
2007-12-10 20:53:37 +00:00
return false;
2010-05-29 07:25:38 +00:00
if(IsTeamplay())
2007-12-10 20:53:37 +00:00
{
2010-05-29 07:25:38 +00:00
if(!GameServer()->m_apPlayers[Cid1] || !GameServer()->m_apPlayers[Cid2])
return false;
2010-05-29 07:25:38 +00:00
if(GameServer()->m_apPlayers[Cid1]->GetTeam() == GameServer()->m_apPlayers[Cid2]->GetTeam())
2007-12-10 20:53:37 +00:00
return true;
}
2007-12-10 20:53:37 +00:00
return false;
}
*/
2010-05-29 07:25:38 +00:00
bool IGameController::IsForceBalanced()
{
/*if(m_ForceBalanced)
{
2010-05-29 07:25:38 +00:00
m_ForceBalanced = false;
return true;
}
else*/
return false;
}
2010-05-29 07:25:38 +00:00
bool IGameController::CanBeMovedOnBalance(int Cid)
{
return true;
}
void IGameController::Tick()
{
2007-10-06 17:36:24 +00:00
// do warmup
2010-05-29 07:25:38 +00:00
if(m_Warmup)
2007-10-06 17:36:24 +00:00
{
2010-05-29 07:25:38 +00:00
m_Warmup--;
if(!m_Warmup)
StartRound();
2007-10-06 17:36:24 +00:00
}
2010-05-29 07:25:38 +00:00
if(m_GameOverTick != -1)
{
// game over.. wait for restart
2010-05-29 07:25:38 +00:00
if(Server()->Tick() > m_GameOverTick+Server()->TickSpeed()*10)
{
//CycleMap();
2010-05-29 07:25:38 +00:00
StartRound();
m_RoundCount++;
}
}
/*
2008-10-19 16:51:16 +00:00
// do team-balancing
2010-05-29 07:25:38 +00:00
if (IsTeamplay() && m_UnbalancedTick != -1 && Server()->Tick() > m_UnbalancedTick+g_Config.m_SvTeambalanceTime*Server()->TickSpeed()*60)
{
dbg_msg("game", "Balancing teams");
2010-05-29 07:25:38 +00:00
int aT[2] = {0,0};
float aTScore[2] = {0,0};
float aPScore[MAX_CLIENTS] = {0.0f};
for(int i = 0; i < MAX_CLIENTS; i++)
{
2010-05-29 07:25:38 +00:00
if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != -1)
{
2010-05-29 07:25:38 +00:00
aT[GameServer()->m_apPlayers[i]->GetTeam()]++;
aPScore[i] = GameServer()->m_apPlayers[i]->m_Score*Server()->TickSpeed()*60.0f/
(Server()->Tick()-GameServer()->m_apPlayers[i]->m_ScoreStartTick);
aTScore[GameServer()->m_apPlayers[i]->GetTeam()] += aPScore[i];
}
}
// are teams unbalanced?
2010-05-29 07:25:38 +00:00
if(absolute(aT[0]-aT[1]) >= 2)
{
2010-05-29 07:25:38 +00:00
int M = (aT[0] > aT[1]) ? 0 : 1;
int NumBalance = absolute(aT[0]-aT[1]) / 2;
do
{
2010-05-29 07:25:38 +00:00
CPlayer *pP = 0;
int PD = aTScore[M];
for(int i = 0; i < MAX_CLIENTS; i++)
{
if(!GameServer()->m_apPlayers[i] || !CanBeMovedOnBalance(i))
continue;
// remember the player who would cause lowest score-difference
if(GameServer()->m_apPlayers[i]->GetTeam() == M && (!pP || absolute((aTScore[M^1]+aPScore[i]) - (aTScore[M]-aPScore[i])) < PD))
{
2010-05-29 07:25:38 +00:00
pP = GameServer()->m_apPlayers[i];
PD = absolute((aTScore[M^1]+aPScore[i]) - (aTScore[M]-aPScore[i]));
}
}
2010-06-06 22:08:40 +00:00
// move the player to the other team
2010-05-29 07:25:38 +00:00
pP->SetTeam(M^1);
2010-05-29 07:25:38 +00:00
pP->Respawn();
pP->m_ForceBalanced = true;
} while (--NumBalance);
2010-05-29 07:25:38 +00:00
m_ForceBalanced = true;
}
2010-05-29 07:25:38 +00:00
m_UnbalancedTick = -1;
}
*/
// update browse info
2010-05-29 07:25:38 +00:00
int Prog = -1;
/*
2010-05-29 07:25:38 +00:00
if(g_Config.m_SvTimelimit > 0)
Prog = max(Prog, (Server()->Tick()-m_RoundStartTick) * 100 / (g_Config.m_SvTimelimit*Server()->TickSpeed()*60));
2010-05-29 07:25:38 +00:00
if(g_Config.m_SvScorelimit)
{
2010-05-29 07:25:38 +00:00
if(IsTeamplay())
{
2010-05-29 07:25:38 +00:00
Prog = max(Prog, (m_aTeamscore[0]*100)/g_Config.m_SvScorelimit);
Prog = max(Prog, (m_aTeamscore[1]*100)/g_Config.m_SvScorelimit);
}
else
{
for(int i = 0; i < MAX_CLIENTS; i++)
{
2010-05-29 07:25:38 +00:00
if(GameServer()->m_apPlayers[i])
Prog = max(Prog, (GameServer()->m_apPlayers[i]->m_Score*100)/g_Config.m_SvScorelimit);
}
}
}
2010-05-29 07:25:38 +00:00
if(m_Warmup)
Prog = -1;
*/
2010-05-29 07:25:38 +00:00
Server()->SetBrowseInfo(m_pGameType, Prog);
}
/*
2010-05-29 07:25:38 +00:00
bool IGameController::IsTeamplay() const
2008-08-31 14:37:35 +00:00
{
2010-05-29 07:25:38 +00:00
return m_GameFlags&GAMEFLAG_TEAMS;
2008-08-31 14:37:35 +00:00
}
*/
2010-05-29 07:25:38 +00:00
void IGameController::Snap(int SnappingClient)
{
2010-05-29 07:25:38 +00:00
CNetObj_Game *pGameObj = (CNetObj_Game *)Server()->SnapNewItem(NETOBJTYPE_GAME, 0, sizeof(CNetObj_Game));
pGameObj->m_Paused = GameServer()->m_World.m_Paused;
pGameObj->m_GameOver = m_GameOverTick==-1?0:1;
pGameObj->m_SuddenDeath = m_SuddenDeath;
//pGameObj->m_ScoreLimit = g_Config.m_SvScorelimit;
//pGameObj->m_TimeLimit = g_Config.m_SvTimelimit;
2010-05-29 07:25:38 +00:00
pGameObj->m_RoundStartTick = m_RoundStartTick;
pGameObj->m_Flags = m_GameFlags;
2010-05-29 07:25:38 +00:00
pGameObj->m_Warmup = m_Warmup;
pGameObj->m_RoundNum = /*(str_length(g_Config.m_SvMaprotation) && g_Config.m_SvRoundsPerMap) ? g_Config.m_SvRoundsPerMap :*/ 0;
2010-05-29 07:25:38 +00:00
pGameObj->m_RoundCurrent = m_RoundCount+1;
2010-05-29 07:25:38 +00:00
if(SnappingClient == -1)
{
// we are recording a demo, just set the scores
pGameObj->m_TeamscoreRed = 0;//m_aTeamscore[0];
pGameObj->m_TeamscoreBlue = 0;//m_aTeamscore[1];
}
else
{
// TODO: this little hack should be removed
pGameObj->m_TeamscoreRed = /*IsTeamplay() ? m_aTeamscore[0] : */GameServer()->m_apPlayers[SnappingClient]->m_Score;
pGameObj->m_TeamscoreBlue = 0;//m_aTeamscore[1];
}
}
2010-05-29 07:25:38 +00:00
int IGameController::GetAutoTeam(int Notthisid)
{
// this will force the auto balancer to work overtime aswell
2010-05-29 07:25:38 +00:00
if(g_Config.m_DbgStress)
return 0;
2010-05-29 07:25:38 +00:00
int aNumplayers[2] = {0,0};
for(int i = 0; i < MAX_CLIENTS; i++)
{
2010-05-29 07:25:38 +00:00
if(GameServer()->m_apPlayers[i] && i != Notthisid)
{
2010-05-29 07:25:38 +00:00
if(GameServer()->m_apPlayers[i]->GetTeam() == 0 || GameServer()->m_apPlayers[i]->GetTeam() == 1)
aNumplayers[GameServer()->m_apPlayers[i]->GetTeam()]++;
}
}
2010-05-29 07:25:38 +00:00
int Team = 0;
//if(IsTeamplay())
// Team = aNumplayers[0] > aNumplayers[1] ? 1 : 0;
2010-05-29 07:25:38 +00:00
if(CanJoinTeam(Team, Notthisid))
return Team;
2008-03-23 14:59:58 +00:00
return -1;
}
2010-05-29 07:25:38 +00:00
bool IGameController::CanJoinTeam(int Team, int Notthisid)
2008-03-23 14:59:58 +00:00
{
if(Team == -1 || (GameServer()->m_apPlayers[Notthisid] && GameServer()->m_apPlayers[Notthisid]->GetTeam() != -1))
2010-05-29 07:25:38 +00:00
return true;
int aNumplayers[2] = {0,0};
2008-03-23 14:59:58 +00:00
for(int i = 0; i < MAX_CLIENTS; i++)
{
2010-05-29 07:25:38 +00:00
if(GameServer()->m_apPlayers[i] && i != Notthisid)
2008-03-23 14:59:58 +00:00
{
2010-05-29 07:25:38 +00:00
if(GameServer()->m_apPlayers[i]->GetTeam() >= 0 || GameServer()->m_apPlayers[i]->GetTeam() == 1)
aNumplayers[GameServer()->m_apPlayers[i]->GetTeam()]++;
2008-03-23 14:59:58 +00:00
}
}
2010-05-29 07:25:38 +00:00
return (aNumplayers[0] + aNumplayers[1]) < g_Config.m_SvMaxClients-g_Config.m_SvSpectatorSlots;
}
/*
2010-05-29 07:25:38 +00:00
bool IGameController::CheckTeamBalance()
{
2010-05-29 07:25:38 +00:00
if(!IsTeamplay() || !g_Config.m_SvTeambalanceTime)
return true;
2010-05-29 07:25:38 +00:00
int aT[2] = {0, 0};
for(int i = 0; i < MAX_CLIENTS; i++)
{
2010-05-29 07:25:38 +00:00
CPlayer *pP = GameServer()->m_apPlayers[i];
if(pP && pP->GetTeam() != -1)
aT[pP->GetTeam()]++;
}
2010-05-29 07:25:38 +00:00
if(absolute(aT[0]-aT[1]) >= 2)
{
2010-05-29 07:25:38 +00:00
dbg_msg("game", "Team is NOT balanced (red=%d blue=%d)", aT[0], aT[1]);
if(GameServer()->m_pController->m_UnbalancedTick == -1)
GameServer()->m_pController->m_UnbalancedTick = Server()->Tick();
return false;
}
else
{
2010-05-29 07:25:38 +00:00
dbg_msg("game", "Team is balanced (red=%d blue=%d)", aT[0], aT[1]);
GameServer()->m_pController->m_UnbalancedTick = -1;
return true;
}
}
*//*
2010-05-29 07:25:38 +00:00
bool IGameController::CanChangeTeam(CPlayer *pPlayer, int JoinTeam)
{
2010-05-29 07:25:38 +00:00
int aT[2] = {0, 0};
2010-05-29 07:25:38 +00:00
if (!IsTeamplay() || JoinTeam == -1 || !g_Config.m_SvTeambalanceTime)
return true;
for(int i = 0; i < MAX_CLIENTS; i++)
{
2010-05-29 07:25:38 +00:00
CPlayer *pP = GameServer()->m_apPlayers[i];
if(pP && pP->GetTeam() != -1)
aT[pP->GetTeam()]++;
}
// simulate what would happen if changed team
2010-05-29 07:25:38 +00:00
aT[JoinTeam]++;
if (pPlayer->GetTeam() != -1)
aT[JoinTeam^1]--;
// there is a player-difference of at least 2
2010-05-29 07:25:38 +00:00
if(absolute(aT[0]-aT[1]) >= 2)
{
// player wants to join team with less players
2010-05-29 07:25:38 +00:00
if ((aT[0] < aT[1] && JoinTeam == 0) || (aT[0] > aT[1] && JoinTeam == 1))
return true;
else
return false;
}
else
return true;
}
*//*
2010-05-29 07:25:38 +00:00
void IGameController::DoPlayerScoreWincheck()
2008-01-17 23:09:49 +00:00
{
2010-05-29 07:25:38 +00:00
if(m_GameOverTick == -1 && !m_Warmup)
2008-01-17 23:09:49 +00:00
{
// gather some stats
2010-05-29 07:25:38 +00:00
int Topscore = 0;
int TopscoreCount = 0;
2008-01-17 23:09:49 +00:00
for(int i = 0; i < MAX_CLIENTS; i++)
{
2010-05-29 07:25:38 +00:00
if(GameServer()->m_apPlayers[i])
2008-01-17 23:09:49 +00:00
{
2010-05-29 07:25:38 +00:00
if(GameServer()->m_apPlayers[i]->m_Score > Topscore)
2008-01-17 23:09:49 +00:00
{
2010-05-29 07:25:38 +00:00
Topscore = GameServer()->m_apPlayers[i]->m_Score;
TopscoreCount = 1;
2008-01-17 23:09:49 +00:00
}
2010-05-29 07:25:38 +00:00
else if(GameServer()->m_apPlayers[i]->m_Score == Topscore)
TopscoreCount++;
2008-01-17 23:09:49 +00:00
}
}
2008-01-17 23:09:49 +00:00
// check score win condition
2010-05-29 07:25:38 +00:00
if((g_Config.m_SvScorelimit > 0 && Topscore >= g_Config.m_SvScorelimit) ||
(g_Config.m_SvTimelimit > 0 && (Server()->Tick()-m_RoundStartTick) >= g_Config.m_SvTimelimit*Server()->TickSpeed()*60))
2008-01-17 23:09:49 +00:00
{
2010-05-29 07:25:38 +00:00
if(TopscoreCount == 1)
EndRound();
2008-01-17 23:09:49 +00:00
else
2010-05-29 07:25:38 +00:00
m_SuddenDeath = 1;
2008-01-17 23:09:49 +00:00
}
}
}
2010-05-29 07:25:38 +00:00
void IGameController::DoTeamScoreWincheck()
2007-11-26 20:47:49 +00:00
{
2010-05-29 07:25:38 +00:00
if(m_GameOverTick == -1 && !m_Warmup)
2007-11-26 20:47:49 +00:00
{
// check score win condition
2010-05-29 07:25:38 +00:00
if((g_Config.m_SvScorelimit > 0 && (m_aTeamscore[0] >= g_Config.m_SvScorelimit || m_aTeamscore[1] >= g_Config.m_SvScorelimit)) ||
(g_Config.m_SvTimelimit > 0 && (Server()->Tick()-m_RoundStartTick) >= g_Config.m_SvTimelimit*Server()->TickSpeed()*60))
2007-11-26 20:47:49 +00:00
{
2010-05-29 07:25:38 +00:00
if(m_aTeamscore[0] != m_aTeamscore[1])
EndRound();
2007-11-26 20:47:49 +00:00
else
2010-05-29 07:25:38 +00:00
m_SuddenDeath = 1;
2007-11-26 20:47:49 +00:00
}
}
}
*/
2007-11-26 20:47:49 +00:00
2010-05-29 07:25:38 +00:00
int IGameController::ClampTeam(int Team)
{
2010-05-29 07:25:38 +00:00
if(Team < 0) // spectator
return -1;
//if(IsTeamplay())
// return Team&1;
return 0;
}