#include "pch.h"
ListFSMission CFSMission::s_list;
int CFSMission::s_iMissionID = 1; const DWORD CFSMission::c_sbtPlayer = 0x00000001;
const DWORD CFSMission::c_sbtLeader = 0x00000002;
const float c_flUpdateTimeInterval = 10.0f;
static const char* sideNames[c_cSidesMax] =
{
"Team 1",
"Team 2",
"Team 3",
"Team 4",
"Team 5",
"Team 6"
};
void CFSMission::InitSide(SideID sideID)
{
assert(sideID >= 0 && sideID < c_cSidesMax);
strcpy(m_misdef.rgszName[sideID], sideNames[sideID]);
assert (m_misdef.misparms.rgCivID[sideID] != NA);
m_misdef.rgShipIDLeaders[sideID] = NA;
m_misdef.rgcPlayers [sideID] = 0;
m_misdef.rgfAutoAccept [sideID] = true;
m_misdef.rgfReady [sideID] = false;
m_misdef.rgfForceReady [sideID] = false;
m_misdef.rgfActive [sideID] = true;
m_rgMoney[sideID] = 0;
}
static int InitializeCivList(const CivilizationListIGC* pcivs,
CivID civIDs[])
{
int n = 0;
for (CivilizationLinkIGC* pcl = pcivs->first(); (pcl != NULL); pcl = pcl->next())
{
CivID civID = pcl->data()->GetObjectID();
civIDs[n++] = civID;
}
return n;
}
CFSMission::CFSMission(
const MissionParams& misparms,
char * szDesc,
IMissionSite * psiteMission,
IIgcSite* psiteIGC,
CAdditionalAGCParamData * paagcParamData,
const char* pszStoryText
) :
m_pMission(::CreateMission()), m_psiteMission(psiteMission),
m_psiteIGC(psiteIGC),
m_fLobbyDirty(true),
m_timeLastLobbyMissionInfo(Time::Now() - c_flUpdateTimeInterval), m_nFrame(0),
m_bShouldDelete(false),
m_pszReason(NULL),
m_flGameDuration(0.0f),
m_pttbmNewSetting(NULL),
m_pttbmAltered(NULL),
m_strStoryText(pszStoryText)
{
ZeroMemory(&m_misdef, sizeof(m_misdef));
BEGIN_PFM_CREATE_PREALLOC(g.fm, &m_misdef, S, MISSIONDEF)
END_PFM_CREATE
m_misdef.misparms = misparms;
strcpy_s(m_misdef.szServerName,sizeof(m_misdef.szServerName),g.strLocalAddress);
psiteMission->Create(this);
assert(!g.strLobbyServer.IsEmpty() == !!g.fmLobby.IsConnected());
m_misdef.misparms.bLobbiedGame = g.fmLobby.IsConnected();
#if !defined(ALLSRV_STANDALONE)
m_misdef.misparms.bClubGame = true;
if (m_misdef.misparms.szIGCStaticFile[0] == '\0')
{
strcpy(m_misdef.misparms.szIGCStaticFile, IGC_ENCRYPT_CORE_FILENAME);
}
#else m_misdef.misparms.bClubGame = false;
if (m_misdef.misparms.szIGCStaticFile[0] == '\0')
{
strcpy(m_misdef.misparms.szIGCStaticFile, IGC_STATIC_CORE_FILENAME);
}
m_misdef.misparms.nTotalMaxPlayersPerGame = min(c_cMaxPlayersPerGame, misparms.nTotalMaxPlayersPerGame);
#endif if (m_misdef.misparms.bAutoRestart)
m_misdef.misparms.timeStart = Time::Now() + m_misdef.misparms.fStartCountdown;
m_pMission->SetMissionParams(&m_misdef.misparms);
m_pMission->Initialize(g.timeNow, psiteIGC);
m_pMission->SetPrivateData((DWORD) this); m_pgrpMission = g.fm.CreateGroup(m_misdef.misparms.strGameName);
if (szDesc)
{
assert(lstrlen(szDesc) < sizeof(m_misdef.szDescription));
lstrcpy(m_misdef.szDescription, szDesc);
}
else
{
strncpy(m_misdef.szDescription, m_misdef.misparms.strGameName, sizeof(m_misdef.szDescription));
m_misdef.szDescription[sizeof(m_misdef.szDescription)-1] = '\0';
}
m_misdef.iSideMissionOwner = NA; m_misdef.fAutoAcceptLeaders = true;
m_misdef.fInProgress = false;
m_misdef.stage = STAGE_NOTSTARTED;
#if !defined(ALLSRV_STANDALONE)
extern void DoDecrypt(int size, char* pdata);
m_misdef.misparms.verIGCcore = LoadIGCStaticCore(m_misdef.misparms.szIGCStaticFile, m_pMission, false, DoDecrypt);
#else m_misdef.misparms.verIGCcore = LoadIGCStaticCore(m_misdef.misparms.szIGCStaticFile, m_pMission, false, NULL);
#endif m_misdef.dwCookie = NULL;
const CivilizationListIGC* pcivs = m_pMission->GetCivilizations();
const int cCivsMax = 20;
assert (pcivs->n() < cCivsMax);
CivID civIDs[cCivsMax];
int n = InitializeCivList(pcivs, civIDs);
int iSide = 0;
for (iSide = 0; iSide < c_cSidesMax; iSide++)
{
if (NA == m_misdef.misparms.rgCivID[iSide])
{
if (n == 1)
{
m_misdef.misparms.rgCivID[iSide] = civIDs[0];
n = InitializeCivList(pcivs, civIDs);
}
else
{
int index = randomInt(0, --n);
m_misdef.misparms.rgCivID[iSide] = civIDs[index];
if (index != n)
{
civIDs[index] = civIDs[n];
}
}
}
InitSide(iSide);
}
m_pMission->SetMissionID(s_iMissionID++);
char szRealTeams[] = ": All real teams";
char szBuff[sizeof(m_misdef.misparms.strGameName) + sizeof(szRealTeams)];
wsprintf(szBuff, "%s%s", m_misdef.misparms.strGameName, szRealTeams);
m_pgrpSidesReal = g.fm.CreateGroup(szBuff);
GetSystemTime(&m_stStartTime);
m_pMission->UpdateSides(Time::Now(), &m_misdef.misparms, m_misdef.rgszName);
s_list.last(this); m_nInvitationListID = m_misdef.misparms.nInvitationListID;
if (RequiresInvitation())
{
GetInvitations(m_nInvitationListID, GetMissionID());
}
if (paagcParamData)
{
TechTreeBitMask ttbmBlank;
ttbmBlank.ClearAll();
for (iSide = 0; iSide < c_cSidesMax; iSide++)
{
if (ttbmBlank != paagcParamData->m_ttbmAltered[iSide])
{
MakeOverrideTechBits();
m_pttbmAltered[iSide] = paagcParamData->m_ttbmAltered[iSide];
m_pttbmNewSetting[iSide] = paagcParamData->m_ttbmNewSetting[iSide];
}
if(paagcParamData->m_szTeamName[iSide][0] != '\0')
SetSideName(iSide, paagcParamData->m_szTeamName[iSide]);
}
}
LPCSTR pszGame = GetMissionDef()->misparms.strGameName;
long idGame = GetIGCMission() ? GetIGCMission()->GetMissionID() : -1;
LPCSTR pszContext = GetIGCMission() ? GetIGCMission()->GetContextName() : NULL;
_AGCModule.TriggerContextEvent(NULL, EventID_GameCreated, pszContext,
pszGame, idGame, -1, -1, 0);
}
CFSMission::~CFSMission()
{
LPCSTR pszGame = GetMissionDef()->misparms.strGameName;
long idGame = GetIGCMission() ? GetIGCMission()->GetMissionID() : -1;
LPCSTR pszContext = GetIGCMission() ? GetIGCMission()->GetContextName() : NULL;
_AGCModule.TriggerContextEvent(NULL, EventID_GameDestroyed, pszContext,
pszGame, idGame, -1, -1, 0);
GetAGCGlobal()->RemoveAGCObject(m_pMission, true);
Vacate();
ShipLinkIGC * pShiplink = m_pMission->GetShips()->first();
while (pShiplink)
{
CFSShip * pfsShip = (CFSShip *) pShiplink->data()->GetPrivateData();
pShiplink = pShiplink->next();
assert (pfsShip->IsPlayer());
RemovePlayerFromMission(pfsShip->GetPlayer(), QSR_ServerShutdown);
}
for (std::vector<CFSCluster*>::iterator i(m_pFSClusters.begin()); i != m_pFSClusters.end(); ++i)
delete static_cast<CFSCluster*>(*i);
for (std::vector<CFSSide*>::iterator _i(m_pFSSides.begin()); _i != m_pFSSides.end(); ++_i)
delete static_cast<CFSSide*>(*_i);
if(m_pttbmNewSetting)
delete[] m_pttbmNewSetting;
if(m_pttbmAltered)
delete[] m_pttbmAltered;
SetStage(STAGE_TERMINATE);
g.fm.DeleteGroup(m_pgrpMission);
if (g.fmLobby.IsConnected())
{
BEGIN_PFM_CREATE(g.fmLobby, pfmMissionGone, LS, MISSION_GONE)
END_PFM_CREATE
pfmMissionGone->dwCookie = GetCookie();
g.fmLobby.SendMessages(g.fmLobby.GetServerConnection(), FM_GUARANTEED, FM_FLUSH);
}
LinkFSMission * plinkFSMis;
for (plinkFSMis = s_list.first(); plinkFSMis; plinkFSMis = plinkFSMis->next())
{
CFSMission * pfsMission = plinkFSMis->data();
if (this == pfsMission)
{
delete plinkFSMis;
break;
}
}
assert (plinkFSMis); m_pMission->Terminate();
delete m_pMission;
m_psiteMission->Destroy(this);
g.fm.DeleteGroup(m_pgrpSidesReal);
#if defined(ALLSRV_STANDALONE)
bool bSupposedToConnectToLobby = !(FEDSRV_GUID != g.fm.GetHostApplicationGuid());
if ( (0 == s_list.n()) && (bSupposedToConnectToLobby ? (g.cStaticCoreInfo==0) : true))
{
DisconnectFromLobby();
g.strLobbyServer.SetEmpty();
if (0 == CAdminSession::GetSessionCount())
PostThreadMessage(g.idReceiveThread, WM_QUIT, 0, 0);
}
#endif while (!m_ballots.IsEmpty())
delete m_ballots.PopFront();
}
void CFSMission::AddPlayerToMission(CFSPlayer * pfsPlayer)
{
debugf("Player %s, ship=%d joined mission=%x\n",
pfsPlayer->GetName(), pfsPlayer->GetShipID(),
GetCookie());
assert (pfsPlayer->GetPlayerScoreObject());
OldPlayerLink* popl = GetOldPlayerLink(pfsPlayer->GetName());
if (popl)
{
pfsPlayer->SetBannedSideMask(popl->data().bannedSideMask);
pfsPlayer->SetLastSide(popl->data().lastSide);
PlayerScoreObject * ppso = &(popl->data().pso);
pfsPlayer->GetIGCShip()->SetExperience(0.0f);
pfsPlayer->GetIGCShip()->SetKills(ppso->GetKills());
pfsPlayer->GetIGCShip()->SetDeaths(ppso->GetDeaths());
pfsPlayer->GetIGCShip()->SetEjections(ppso->GetEjections());
pfsPlayer->SetPlayerScoreObject(ppso);
if (popl->data().pclusterLifepod)
pfsPlayer->SetLifepod(popl->data().pclusterLifepod,
popl->data().positionLifepod);
}
else
{
pfsPlayer->GetIGCShip()->SetKills(0);
pfsPlayer->GetIGCShip()->SetDeaths(0);
pfsPlayer->GetIGCShip()->SetEjections(0);
}
g.fm.AddConnectionToGroup(GetGroupMission(), pfsPlayer->GetConnection());
SendLobbyMissionInfo(pfsPlayer);
pfsPlayer->SetSide(this, GetIGCMission()->GetSide(SIDE_TEAMLOBBY));
pfsPlayer->GetIGCShip()->CreateDamageTrack();
SendPlayerInfo(NULL, pfsPlayer, this);
assert(0 == g.fm.CbUsedSpaceInOutbox());
if (g.fmLobby.IsConnected())
{
assert(GetCookie());
BEGIN_PFM_CREATE(g.fmLobby, pfmPlayerJoined, S, PLAYER_JOINED)
FM_VAR_PARM(pfsPlayer->GetName(), CB_ZTS)
FM_VAR_PARM(pfsPlayer->GetCDKey(), CB_ZTS)
END_PFM_CREATE
pfmPlayerJoined->dwMissionCookie = GetCookie();
g.fmLobby.SendMessages(g.fmLobby.GetServerConnection(), FM_GUARANTEED, FM_FLUSH);
}
m_bShouldDelete = false;
SetLobbyIsDirty();
}
void CFSMission::RemovePlayerFromMission(CFSPlayer * pfsPlayer, QuitSideReason reason, const char* szMessageParam)
{
debugf("Player %s, ship=%d quiting mission=%x, reason=%d\n",
pfsPlayer->GetName(), pfsPlayer->GetShipID(),
GetCookie(), reason);
PlayerScoreObject* ppso = pfsPlayer->GetPlayerScoreObject();
if (ppso->Connected())
{
pfsPlayer->GetPlayerScoreObject()->Disconnect(g.timeNow);
}
SaveAsOldPlayer(pfsPlayer, QSRIsBoot(reason));
if (pfsPlayer->GetSide()->GetObjectID() != SIDE_TEAMLOBBY)
RemovePlayerFromSide(pfsPlayer, reason, szMessageParam);
RemoveJoinRequest(pfsPlayer, NULL);
BEGIN_PFM_CREATE(g.fm, pfmQuitMission, CS, QUIT_MISSION)
FM_VAR_PARM(szMessageParam, CB_ZTS)
END_PFM_CREATE
pfmQuitMission->shipID = pfsPlayer->GetShipID();
pfmQuitMission->reason = reason;
g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
pfsPlayer->GetIGCShip()->DeleteDamageTrack();
pfsPlayer->SetSide(NULL, NULL);
g.fm.DeleteConnectionFromGroup(GetGroupMission(), pfsPlayer->GetConnection());
g.fm.DeleteConnectionFromGroup(GetGroupLobbySide(), pfsPlayer->GetConnection());
g.fm.DeleteConnectionFromGroup(GetGroupRealSides(), pfsPlayer->GetConnection());
if (g.fmLobby.IsConnected() && GetCookie())
{
BEGIN_PFM_CREATE(g.fmLobby, pfmPlayerQuit, S, PLAYER_QUIT)
FM_VAR_PARM(pfsPlayer->GetName(), CB_ZTS)
END_PFM_CREATE
pfmPlayerQuit->dwMissionCookie = GetCookie();
g.fmLobby.SendMessages(g.fmLobby.GetServerConnection(), FM_GUARANTEED, FM_FLUSH);
}
if (!HasPlayers(NULL, true) && !GetMissionDef()->misparms.bObjectModelCreated
)
{
m_bShouldDelete = true;
}
else
{
SetLobbyIsDirty();
}
}
void CFSMission::AddPlayerToSide(CFSPlayer * pfsPlayer, IsideIGC * pside)
{
assert (pside);
ShipID shipid = pfsPlayer->GetShipID();
SideID sideid = pside->GetObjectID();
bool fTeamLeader = false;
bool fMissionOwner = false;
ImissionIGC * pMission = GetIGCMission();
pfsPlayer->SetJustJoined(true);
assert (sideid != SIDE_TEAMLOBBY);
CFSSide* pfsSide = CFSSide::FromIGC(pside);
if (pfsPlayer->GetSide() == NULL || pfsPlayer->GetMission() != this)
{
assert(false);
if (pfsPlayer->GetMission())
RemovePlayerFromMission(pfsPlayer, QSR_Quit);
pfsPlayer->GetMission()->AddPlayerToMission(pfsPlayer);
}
else if (pfsPlayer->GetSide()->GetObjectID() != SIDE_TEAMLOBBY)
RemovePlayerFromSide(pfsPlayer, QSR_SwitchingSides);
pfsPlayer->SetLastSide(sideid);
debugf("Player %s, ship=%d joined side %d, mission=%x\n",
pfsPlayer->GetName(), pfsPlayer->GetShipID(),
sideid, GetCookie());
{
OldPlayerLink* popl = GetOldPlayerLink(pfsPlayer->GetName());
if (popl)
{
delete popl;
}
}
RemoveJoinRequest(pfsPlayer, pside);
if (m_misdef.iSideMissionOwner < 0)
fMissionOwner = true;
else
{
IsideIGC * pside = pMission->GetSide(m_misdef.iSideMissionOwner);
if (!HasPlayers(pside, true)) fMissionOwner = true;
}
assert(pside->GetActiveF()); m_misdef.rgcPlayers[sideid]++;
assert(pfsPlayer->GetMoney() == 0);
pfsPlayer->GetIGCShip()->SetWingID(1); if (!HasPlayers(pside, true)) {
fTeamLeader = true;
assert (m_misdef.rgShipIDLeaders[sideid] == NA);
SetLeaderID(sideid, shipid);
if (fMissionOwner) {
fMissionOwner = true;
m_misdef.iSideMissionOwner = sideid;
}
}
assert(IMPLIES(fMissionOwner, fTeamLeader));
assert(IFF(pside->GetActiveF(),
(STAGE_NOTSTARTED == GetStage()) || (HasPlayers(pside, true) || m_misdef.misparms.bAllowEmptyTeams)));
BEGIN_PFM_CREATE(g.fm, pfmJoinSide, S, JOIN_SIDE)
END_PFM_CREATE
pfmJoinSide->shipID = shipid;
pfmJoinSide->sideID = sideid;
if (fTeamLeader)
{
BEGIN_PFM_CREATE(g.fm, pfmSetTeamLeader, CS, SET_TEAM_LEADER)
END_PFM_CREATE
pfmSetTeamLeader->shipID = shipid;
pfmSetTeamLeader->sideID = sideid;
pfsPlayer->GetIGCShip()->SetWingID(0);
}
if (fMissionOwner)
{
BEGIN_PFM_CREATE(g.fm, pfmSetMissionOwner, CS, SET_MISSION_OWNER)
END_PFM_CREATE
pfmSetMissionOwner->shipID = shipid;
pfmSetMissionOwner->sideID = sideid;
}
g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
pfsPlayer->SetTreasureObjectID(NA); pfsPlayer->SetSide(this, pside);
BEGIN_PFM_CREATE(g.fm, pfmSetWingID, CS, SET_WINGID)
END_PFM_CREATE
pfmSetWingID->wingID = pfsPlayer->GetIGCShip()->GetWingID();
pfmSetWingID->shipID = shipid;
pfmSetWingID->bCommanded = true;
g.fm.SendMessages(pfsSide->GetGroup(), FM_GUARANTEED, FM_FLUSH);
if (fTeamLeader)
{
if (m_misdef.misparms.bLockTeamSettings)
{
if (m_misdef.misparms.bSquadGame)
{
const char* pzSquadName = CFSSide::FromIGC(pside)->GetInvitedSquadName();
if(pzSquadName)
{
SquadMembershipLink* pSquadLink = pfsPlayer->GetSquadMembershipList()->first();
for (; pSquadLink; pSquadLink = pSquadLink->next())
{
if (_stricmp(pSquadLink->data()->GetName(), pzSquadName) == 0)
{
SetSideSquad(sideid, pSquadLink->data()->GetID());
break;
}
}
}
}
}
else if (m_misdef.misparms.bSquadGame)
SetSideSquad(sideid, pfsPlayer->GetPreferredSquadToLead());
else
SetSideName(sideid, sideNames[sideid]);
}
if (STAGE_STARTED != GetStage() && STAGE_STARTING != GetStage())
{
g.fm.SetDefaultRecipient((CFMRecipient*) pfsPlayer->GetConnection(),
FM_GUARANTEED);
for (ShipLinkIGC* psl = pside->GetShips()->first(); (psl != NULL); psl = psl->next())
{
IshipIGC* ps = psl->data();
if (ps != pfsPlayer->GetIGCShip())
{
ShipID shipID = ps->GetObjectID();
BEGIN_PFM_CREATE(g.fm, pfmSetWingID, CS, SET_WINGID)
END_PFM_CREATE
pfmSetWingID->wingID = ps->GetWingID();
pfmSetWingID->shipID = shipID;
pfmSetWingID->bCommanded = true;
}
}
g.fm.SendMessages(NULL, FM_GUARANTEED, FM_FLUSH); if (STAGE_NOTSTARTED == GetStage())
CheckForSideAllReady(pside);
}
else
{
CFSPlayer* pfsLeader = GetLeader(pside->GetObjectID());
pfsPlayer->SetAutoDonate((pfsPlayer != pfsLeader) ? pfsLeader : NULL, 0, true);
bool bGenerateCivBriefing = m_strStoryText.IsEmpty();
const char* szBriefingText = bGenerateCivBriefing
? GetBase(pside)->GetCluster()->GetName() : m_strStoryText;
BEGIN_PFM_CREATE(g.fm, pfmSetBriefingText, S, SET_BRIEFING_TEXT)
FM_VAR_PARM(szBriefingText, CB_ZTS)
END_PFM_CREATE
pfmSetBriefingText->fGenerateCivBriefing = bGenerateCivBriefing;
g.fm.SendMessages(pfsPlayer->GetConnection(), FM_GUARANTEED, FM_FLUSH);
SendMissionInfo(pfsPlayer, pside);
{
const ShipListIGC* pships = m_pMission->GetShips();
for (ShipLinkIGC* psl = pships->first(); (psl != NULL); psl = psl->next())
{
IshipIGC* pship = psl->data();
SideID sidFlag = pship->GetFlag();
if (sidFlag != NA)
{
BEGIN_PFM_CREATE(g.fm, pfmGain, S, GAIN_FLAG)
END_PFM_CREATE
pfmGain->sideidFlag = sidFlag;
pfmGain->shipidRecipient = pship->GetObjectID();
pfmGain->bIsTreasureDocked = false; }
}
}
assert (pfsPlayer->GetIGCShip()->GetDeaths() == pfsPlayer->GetPlayerScoreObject()->GetDeaths());
assert (pfsPlayer->GetIGCShip()->GetEjections() == pfsPlayer->GetPlayerScoreObject()->GetEjections());
assert (pfsPlayer->GetIGCShip()->GetChildShips()->n() == 0);
if (pfsPlayer->GetLifepodCluster() && (STAGE_STARTED == GetStage()))
{
g.fm.SendMessages(pfsPlayer->GetConnection(), FM_GUARANTEED, FM_FLUSH);
IhullTypeIGC* pht = pfsPlayer->GetSide()->GetCivilization()->GetLifepod();
pfsPlayer->GetIGCShip()->SetBaseHullType(pht);
pfsPlayer->ShipStatusHullChange(pht);
pfsPlayer->GetIGCShip()->SetPosition(pfsPlayer->GetLifepodPosition());
pfsPlayer->GetIGCShip()->SetVelocity(Vector::GetZero());
Orientation o;
o.Reset();
pfsPlayer->GetIGCShip()->SetOrientation(o);
pfsPlayer->GetIGCShip()->SetCluster(pfsPlayer->GetLifepodCluster());
pfsPlayer->SetLifepod(NULL, Vector::GetZero());
}
else
{
IstationIGC * pstation = GetBase(pside);
pfsPlayer->GetIGCShip()->SetStation(pstation);
pfsPlayer->ShipStatusStart(pstation);
}
if (STAGE_STARTED == GetStage())
{
pfsPlayer->GetPlayerScoreObject()->Connect(g.timeNow);
BEGIN_PFM_CREATE(g.fm, pfmEnterGame, S, ENTER_GAME)
END_PFM_CREATE
if (m_misdef.misparms.IsProsperityGame())
{
for (SideLinkIGC* psl = pMission->GetSides()->first(); (psl != NULL); psl = psl->next())
{
BucketLinkIGC* pbl = psl->data()->GetBuckets()->last();
{
assert (pbl != NULL);
IbucketIGC* pbucket = pbl->data();
assert ((pbucket->GetBucketType() == OT_development) &&
(pbucket->GetBuyable()->GetObjectID() == c_didTeamMoney));
BEGIN_PFM_CREATE(g.fm, pfmBucketStatus, S, BUCKET_STATUS)
END_PFM_CREATE
pfmBucketStatus->timeTotal = pbucket->GetTime();
pfmBucketStatus->moneyTotal = pbucket->GetMoney();
pfmBucketStatus->iBucket = pbucket->GetObjectID();
pfmBucketStatus->sideID = psl->data()->GetObjectID();
}
}
}
g.fm.SendMessages(pfsPlayer->GetConnection(), FM_GUARANTEED, FM_FLUSH);
}
}
}
void CFSMission::RemovePlayerFromSide(CFSPlayer * pfsPlayer, QuitSideReason reason, const char* szMessageParam)
{
IsideIGC * psideOld = pfsPlayer->GetSide();
SideID sideidOld = psideOld->GetObjectID();
pfsPlayer->SetDPGroup(NULL, false);
ShipID shipid = pfsPlayer->GetShipID();
SquadID squadID = psideOld->GetSquadID();
IshipIGC * pshipPlayer = pfsPlayer->GetIGCShip();
ImissionIGC * pMission = GetIGCMission();
bool bTurnOnAutoaccept = false;
bool bWasTeamLeader = false;
pfsPlayer->GetPlayerScoreObject()->Disconnect(g.timeNow);
if(GetStage() != STAGE_STARTED)
pfsPlayer->SetLastSide(SIDE_TEAMLOBBY);
SideID sidFlag = pshipPlayer->GetFlag();
if (sidFlag != NA)
{
const Vector& p = pfsPlayer->GetIGCShip()->GetPosition();
float lm = m_pMission->GetFloatConstant(c_fcidLensMultiplier);
float r = 1.5f * m_pMission->GetFloatConstant(c_fcidRadiusUniverse);
if (p.x*p.x + p.y*p.y + p.z*p.z/(lm*lm) > r*r)
{
((FedSrvSiteBase*)m_psiteIGC)->RespawnFlag(sidFlag, NULL); }
else
{
DataTreasureIGC dt;
dt.treasureCode = c_tcFlag;
dt.treasureID = sidFlag;
dt.amount = 0;
dt.createNow = false;
dt.lifespan = 3600.0f * 24.0f * 10.0f; CreateTreasure(g.timeNow, pfsPlayer->GetIGCShip(), &dt, pfsPlayer->GetIGCShip()->GetPosition(), 100.0f);
}
}
debugf("Player %s, ship=%d quitting side %d, mission=%x\n",
pfsPlayer->GetName(), pfsPlayer->GetShipID(),
pfsPlayer->GetSide() ? pfsPlayer->GetSide()->GetObjectID() : NA,
GetCookie());
pfsPlayer->ShipStatusExit();
{
const ShipListIGC* pshipsChildren = pfsPlayer->GetIGCShip()->GetChildShips();
if (pshipsChildren->first())
{
IclusterIGC* pcluster = pfsPlayer->GetIGCShip()->GetCluster();
IshipIGC* pship = pshipsChildren->first()->data();
pship->Promote();
((CFSShip*)(pship->GetPrivateData()))->ShipStatusRecalculate();
BEGIN_PFM_CREATE(g.fm, pfmPromote, S, PROMOTE)
END_PFM_CREATE
pfmPromote->shipidPromoted = pship->GetObjectID();
if (pcluster)
g.fm.SendMessages(GetGroupSectorFlying(pcluster), FM_GUARANTEED, FM_FLUSH); else
g.fm.SendMessages(CFSSide::FromIGC(psideOld)->GetGroup(), FM_GUARANTEED, FM_FLUSH); }
}
m_misdef.rgcPlayers[sideidOld]--;
CFSPlayer* pfsNewLeader = NULL;
if (m_misdef.rgShipIDLeaders[sideidOld] == shipid)
{
bWasTeamLeader = true;
SideID iSideNewOwner = sideidOld; ShipID shipidNewOwner = NA;
bool fMissionOwner = false;
int cPlayers = GetCountOfPlayers(psideOld, true);
if (cPlayers == 1)
{
if (STAGE_NOTSTARTED == m_misdef.stage)
{
BEGIN_PFM_CREATE(g.fm, pfmAutoAccept, CS, AUTO_ACCEPT)
END_PFM_CREATE
pfmAutoAccept->iSide = sideidOld;
pfmAutoAccept->fAutoAccept = true;
g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
bTurnOnAutoaccept = true;
}
else
{
RejectSideJoinRequests(psideOld);
}
}
if (cPlayers > 1) {
const ShipListIGC * plistShip = psideOld->GetShips();
if (STAGE_STARTED == m_misdef.stage)
{
IshipIGC* pshipNewLeader = PickNewLeader(plistShip, pshipPlayer, 0);
if (pshipNewLeader)
{
pfsNewLeader = ((CFSShip*)(pshipNewLeader->GetPrivateData()))->GetPlayer();
shipidNewOwner = pshipNewLeader->GetObjectID();
}
}
if (pfsNewLeader == NULL)
{
for (ShipLinkIGC * plinkShip = plistShip->first(); plinkShip; plinkShip = plinkShip->next())
{
if (plinkShip->data() != pshipPlayer && ISPLAYER(plinkShip->data()))
{
CFSPlayer* pfsPlayerTemp = ((CFSShip*)(plinkShip->data()->GetPrivateData()))->GetPlayer();
if (pfsPlayerTemp->GetCanLeadSquad(squadID))
{
pfsNewLeader = pfsPlayerTemp;
shipidNewOwner = plinkShip->data()->GetObjectID();
break;
}
else if (!pfsNewLeader)
{
pfsNewLeader = pfsPlayerTemp;
shipidNewOwner = plinkShip->data()->GetObjectID();
}
}
}
assert(pfsNewLeader);
}
SetLeaderID(iSideNewOwner, shipidNewOwner);
if (m_misdef.iSideMissionOwner == sideidOld)
{
fMissionOwner = true;
}
}
else {
SetLeaderID(sideidOld, NA);
if (STAGE_NOTSTARTED == m_misdef.stage)
SetSideSquad(sideidOld, NA);
if (m_misdef.iSideMissionOwner == sideidOld)
{
m_misdef.iSideMissionOwner = NA;
const SideListIGC * plistSide = m_pMission->GetSides();
for (SideLinkIGC * plinkSide = plistSide->first(); plinkSide; plinkSide = plinkSide->next())
{
IsideIGC * pside = plinkSide->data();
if ((psideOld != pside) && HasPlayers(pside, true)) {
iSideNewOwner = pside->GetObjectID();
shipidNewOwner = GetLeader(iSideNewOwner)->GetShipID();
fMissionOwner = true;
assert(m_misdef.rgShipIDLeaders[iSideNewOwner] == shipidNewOwner);
m_misdef.iSideMissionOwner = iSideNewOwner;
break;
}
}
if (m_misdef.iSideMissionOwner == NA)
{
if (m_misdef.misparms.bLockLobby)
{
SetLockLobby(false);
BEGIN_PFM_CREATE(g.fm, pfmLockLobby, CS, LOCK_LOBBY)
END_PFM_CREATE
pfmLockLobby->fLock = false;
}
if (m_misdef.misparms.bLockSides)
{
SetLockSides(false);
BEGIN_PFM_CREATE(g.fm, pfmLockSides, CS, LOCK_SIDES)
END_PFM_CREATE
pfmLockSides->fLock = false;
}
if (!(m_misdef.misparms.bLockGameOpen)) {
m_misdef.misparms.iMinRank = -1;
m_misdef.misparms.iMaxRank = 1000;
}
}
SetLeaderID(sideidOld, NA);
}
}
if (shipidNewOwner != NA) {
BEGIN_PFM_CREATE(g.fm, pfmSetTeamLeader, CS, SET_TEAM_LEADER)
END_PFM_CREATE
pfmSetTeamLeader->shipID = shipidNewOwner;
pfmSetTeamLeader->sideID = iSideNewOwner;
if (fMissionOwner)
{
BEGIN_PFM_CREATE(g.fm, pfmSetMissionOwner, CS, SET_MISSION_OWNER)
END_PFM_CREATE
pfmSetMissionOwner->shipID = shipidNewOwner;
pfmSetMissionOwner->sideID = iSideNewOwner;
}
}
}
g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
Money payday;
if (STAGE_STARTED == m_misdef.stage || STAGE_STARTING == m_misdef.stage)
{
if (pfsNewLeader && (pfsNewLeader->GetIGCShip()->GetAutoDonate() == pshipPlayer))
pfsNewLeader->SetAutoDonate(NULL, 0, false);
for (ShipLinkIGC* psl = psideOld->GetShips()->first(); (psl != NULL); psl = psl->next())
{
if ((psl->data()->GetAutoDonate() == pshipPlayer) &&
((pfsNewLeader == NULL) || (psl->data() != pfsNewLeader->GetIGCShip())))
{
((CFSShip*)(psl->data()->GetPrivateData()))->GetPlayer()->SetAutoDonate(pfsNewLeader, 0, false);
}
}
g.fm.SendMessages(CFSSide::FromIGC(psideOld)->GetGroup(), FM_GUARANTEED, FM_FLUSH);
payday = pfsPlayer->GetMoney() + pfsPlayer->GetIGCShip()->GetValue();
assert(STAGE_STARTING != m_misdef.stage || payday == 0);
}
else
payday = 0;
pfsPlayer->SetMoney(0);
BEGIN_PFM_CREATE(g.fm, pfmSideChange, CS, QUIT_SIDE)
FM_VAR_PARM(szMessageParam, CB_ZTS)
END_PFM_CREATE
pfmSideChange->shipID = shipid;
pfmSideChange->reason = reason;
g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
pfsPlayer->Reset(false);
if (STAGE_STARTED != m_misdef.stage)
pfsPlayer->GetIGCShip()->SetExperience(1.0f);
pfsPlayer->SetSide(this, pMission->GetSide(SIDE_TEAMLOBBY));
GiveSideMoney(psideOld, payday);
bool fDeactivate = (STAGE_NOTSTARTED != m_misdef.stage) && !HasPlayers(psideOld, false);
if (fDeactivate)
DeactivateSide(psideOld); else
CheckForSideAllReady(psideOld); if (bWasTeamLeader && STAGE_NOTSTARTED == m_misdef.stage && squadID != NA)
MaintainSquadLeadership(sideidOld);
if (bTurnOnAutoaccept)
SetAutoAccept(psideOld, true);
if (QSRIsBoot(reason) && (sideidOld >= 0))
{
unsigned char bannedSideMask = pfsPlayer->GetBannedSideMask() | SideMask(sideidOld);
pfsPlayer->SetBannedSideMask(bannedSideMask);
}
}
void CFSMission::AddInvitation(SideID sid, char * szPlayerName)
{
if(sid >= c_cSidesMax)
return;
m_pFSSides[sid]->AddInvitation(szPlayerName);
}
bool CFSMission::IsInvited(CFSPlayer * pPlayer)
{
assert(RequiresInvitation());
for (std::vector<CFSSide*>::iterator _i(m_pFSSides.begin()); _i != m_pFSSides.end(); ++_i)
{
if(static_cast<CFSSide*>(*_i)->IsInvited(pPlayer))
return true;
}
return false;
}
void CFSMission::AddBallot(Ballot * pBallot)
{
m_ballots.PushEnd(pBallot);
}
void CFSMission::TallyVote(CFSPlayer* pfsPlayer, BallotID ballotID, bool bVote)
{
for (BallotList::Iterator iter(m_ballots); !iter.End(); iter.Next())
{
if (iter.Value()->GetBallotID() == ballotID)
{
iter.Value()->CastVote(pfsPlayer, bVote);
break;
}
}
}
bool CFSMission::HasBallots(BallotType iType)
{
for (BallotList::Iterator iter(m_ballots); !iter.End();)
{
if (iter.Value()->GetType() == iType) return true;
iter.Next();
}
return false;
}
bool CFSMission::RemovePlayerByName(const char* szCharacterName, QuitSideReason reason, const char* szMessageParam)
{
ShipLinkIGC * pShiplink = GetIGCMission()->GetShips()->first();
while (pShiplink)
{
CFSShip * pfsShip = (CFSShip *) pShiplink->data()->GetPrivateData();
if (pfsShip->IsPlayer())
{
CFSPlayer * pfsPlayer = pfsShip->GetPlayer();
if (_stricmp(pfsPlayer->GetName(), szCharacterName) == 0)
{
RemovePlayerFromMission(pfsShip->GetPlayer(), reason, szMessageParam);
debugf("Booted duplicate character %s from mission %x.\n",
pfsPlayer->GetName(), GetCookie());
break;
}
}
pShiplink = pShiplink->next();
}
return pShiplink != NULL;
}
bool CFSMission::RemovePlayerByCDKey(const char* szCDKey, QuitSideReason reason, const char* szMessageParam)
{
ShipLinkIGC * pShiplink = GetIGCMission()->GetShips()->first();
while (pShiplink)
{
CFSShip * pfsShip = (CFSShip *) pShiplink->data()->GetPrivateData();
if (pfsShip->IsPlayer())
{
CFSPlayer * pfsPlayer = pfsShip->GetPlayer();
if (_stricmp(pfsPlayer->GetCDKey(), szCDKey) == 0)
{
RemovePlayerFromMission(pfsShip->GetPlayer(), reason, szMessageParam);
debugf("Booted character %s with duplicate CD Key %s from mission %x.\n",
pfsPlayer->GetName(), pfsPlayer->GetCDKey(), GetCookie());
break;
}
}
pShiplink = pShiplink->next();
}
return pShiplink != NULL;
}
int CFSMission::GetCountOfPlayers(IsideIGC * pside, bool bCountGhosts)
{
int cPlayers = 0;
const ShipListIGC * plistShip = pside ? pside->GetShips() : m_pMission->GetShips();
for (ShipLinkIGC * plinkShip = plistShip->first(); plinkShip; plinkShip = plinkShip->next())
{
if (ISPLAYER(plinkShip->data()) && (bCountGhosts || !plinkShip->data()->IsGhost()))
cPlayers++;
}
return cPlayers;
}
int CFSMission::GetSideRankSum(IsideIGC * pside, bool bCountGhosts)
{
int iRankSum = 0;
int iTempRank = 0;
const ShipListIGC * plistShip = pside ? pside->GetShips() : m_pMission->GetShips();
CFSPlayer* pfsPlayer = NULL;
for (ShipLinkIGC * plinkShip = plistShip->first(); plinkShip; plinkShip = plinkShip->next())
{
if (ISPLAYER(plinkShip->data()) && (bCountGhosts || !plinkShip->data()->IsGhost()))
{
pfsPlayer = ((CFSShip*)(plinkShip->data()->GetPrivateData()))->GetPlayer();
iTempRank = pfsPlayer->GetPersistPlayerScore(NA)->GetRank();
iRankSum += (iTempRank < 1) ? 1 : iTempRank;
}
}
return iRankSum;
}
int CFSMission::GetRankThreshold()
{
int iHighestRank = 1;
int iAverageRank = 0;
const ShipListIGC * plistShip = m_pMission->GetShips();
CFSPlayer* pfsPlayer = NULL;
int iTempRank = 0;
for (ShipLinkIGC * plinkShip = plistShip->first(); plinkShip; plinkShip = plinkShip->next())
{
CFSShip* pfsShip = ((CFSShip *) (plinkShip->data())->GetPrivateData());
if (pfsShip)
{
if (pfsShip->IsPlayer())
{
iTempRank = pfsShip->GetPlayer()->GetPersistPlayerScore(NA)->GetRank();
if (iTempRank > iHighestRank)
iHighestRank = iTempRank;
iAverageRank += iTempRank;
}
}
}
iAverageRank = iAverageRank / plistShip->n();
int iThreshold = iHighestRank + ((iAverageRank * iAverageRank) / (iHighestRank + iAverageRank));
return iThreshold;
}
bool CFSMission::HasPlayers(IsideIGC * pside, bool bCountGhosts)
{
const ShipListIGC * plistShip = pside ? pside->GetShips() : m_pMission->GetShips();
for (ShipLinkIGC * plinkShip = plistShip->first(); plinkShip; plinkShip = plinkShip->next())
{
if (ISPLAYER(plinkShip->data()) && (bCountGhosts || !plinkShip->data()->IsGhost()))
return true;
}
return false;
}
IstationIGC * CFSMission::GetBase(IsideIGC * pside)
{
if (pside)
{
for (StationLinkIGC* psl = pside->GetStations()->first(); (psl != NULL); psl = psl->next())
{
IstationIGC* pstation = psl->data();
if (pstation->GetStationType()->HasCapability(c_sabmRestart))
return pstation;
}
}
return NULL;
}
CFSPlayer * CFSMission::GetLeader(SideID sid)
{
assert (NA != sid);
if (sid == SIDE_TEAMLOBBY) return NULL;
ShipID shipid = m_misdef.rgShipIDLeaders[sid];
return NA == shipid ? NULL : CFSShip::GetShipFromID(shipid)->GetPlayer();
}
void CFSMission::SetLeaderID(SideID sideID, ShipID shipID)
{
if (m_misdef.rgShipIDLeaders[sideID] != NA)
{
CFSShip* pfsShip = CFSShip::GetShipFromID(m_misdef.rgShipIDLeaders[sideID]);
assert (pfsShip);
assert (pfsShip->IsPlayer());
pfsShip->GetPlayerScoreObject()->StopCommand(m_pMission->GetLastUpdate());
}
m_misdef.rgShipIDLeaders[sideID] = shipID;
if (shipID != NA)
{
CFSShip* pfsShip = CFSShip::GetShipFromID(shipID);
assert (pfsShip);
assert (pfsShip->IsPlayer());
pfsShip->GetPlayerScoreObject()->StartCommand(m_pMission->GetLastUpdate());
}
}
void CFSMission::SetLeader(CFSPlayer * pfsPlayer)
{
assert(pfsPlayer);
SideID sid = pfsPlayer->GetSide()->GetObjectID();
ShipID shipId = pfsPlayer->GetShipID();
assert(0 <= sid && sid < m_misdef.misparms.nTeams);
CFSPlayer * pfsOldLeader = GetLeader(sid);
assert(pfsOldLeader);
if (pfsOldLeader->GetIGCShip()->GetWingID() == 0)
{
pfsOldLeader->GetIGCShip()->SetWingID(1); BEGIN_PFM_CREATE(g.fm, pfmSetWingID, CS, SET_WINGID)
END_PFM_CREATE
pfmSetWingID->wingID = 1; pfmSetWingID->shipID = pfsOldLeader->GetShipID();
pfmSetWingID->bCommanded = true;
}
pfsPlayer->GetIGCShip()->SetWingID(0);
BEGIN_PFM_CREATE(g.fm, pfmSetWingID, CS, SET_WINGID)
END_PFM_CREATE
pfmSetWingID->wingID = 0;
pfmSetWingID->shipID = shipId;
pfmSetWingID->bCommanded = true;
g.fm.SendMessages(CFSSide::FromIGC(pfsPlayer->GetSide())->GetGroup(), FM_GUARANTEED, FM_FLUSH);
SetLeaderID(sid, shipId);
BEGIN_PFM_CREATE(g.fm, pfmSetTeamLeader, CS, SET_TEAM_LEADER)
END_PFM_CREATE
pfmSetTeamLeader->shipID = shipId;
pfmSetTeamLeader->sideID = sid;
g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
}
void CFSMission::SetSideName(SideID sid, const char* szName)
{
assert(sid >= 0 && sid < c_cSidesMax);
assert(strlen(szName) < c_cbName);
IsideIGC* pside = m_pMission->GetSide(sid);
if (!pside)
return;
ZString strNameOld(m_misdef.rgszName[sid]);
if (szName != m_misdef.rgszName[sid])
{
strncpy(m_misdef.rgszName[sid], szName, c_cbName - 1);
m_misdef.rgszName[sid][c_cbName-1] = '\0';
m_pMission->GetSide(sid)->SetName(m_misdef.rgszName[sid]);
}
BEGIN_PFM_CREATE(g.fm, pfmSetTeamInfo, CS, SET_TEAM_INFO)
END_PFM_CREATE
pfmSetTeamInfo->sideID = sid;
pfmSetTeamInfo->squadID = pside->GetSquadID();
strcpy(pfmSetTeamInfo->SideName, m_misdef.rgszName[sid]);
g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
LPCSTR pszGame = GetMissionDef()->misparms.strGameName;
long idGame = GetIGCMission() ? GetIGCMission()->GetMissionID() : -1;
long idTeam = GetIGCMission()->GetSide(sid)->GetUniqueID();
LPCSTR pszContext = GetIGCMission() ? GetIGCMission()->GetContextName() : NULL;
_AGCModule.TriggerContextEvent(NULL, EventID_TeamInfoChange, pszContext,
strNameOld, idTeam, -1, -1, 3,
"GameID" , VT_I4 , idGame,
"GameName" , VT_LPSTR, pszGame,
"NewTeamName", VT_LPSTR, szName);
};
void CFSMission::SetSideSquad(SideID sid, SquadID squadID)
{
assert(sid >= 0 && sid < c_cSidesMax);
IsideIGC* pside = m_pMission->GetSide(sid);
if (squadID == pside->GetSquadID())
return;
pside->SetSquadID(squadID);
if (squadID != NA)
{
ShipLinkIGC* pslNext;
for (ShipLinkIGC* psl = pside->GetShips()->first(); (psl != NULL); psl = pslNext)
{
pslNext = psl->next();
CFSShip* pcs = (CFSShip *)(psl->data()->GetPrivateData());
if (pcs->IsPlayer())
{
CFSPlayer* pfsPlayer = pcs->GetPlayer();
if (!pfsPlayer->GetIsMemberOfSquad(squadID))
{
RemovePlayerFromSide(pfsPlayer, QSR_SquadChange);
}
}
}
}
const char* szSquadName = NULL;
if (m_misdef.misparms.bLockTeamSettings)
{
szSquadName = m_misdef.rgszName[sid];
}
else
{
CFSPlayer* pfsLeader = GetLeader(sid);
if (squadID != NA)
{
assert(pfsLeader);
for (SquadMembershipLink* pSquadLink = pfsLeader->GetSquadMembershipList()->first();
pSquadLink != NULL; pSquadLink = pSquadLink->next())
{
if (pSquadLink->data()->GetID() == squadID)
szSquadName = pSquadLink->data()->GetName();
}
}
assert((squadID == NA) == (szSquadName == NULL));
}
SetSideName(sid, szSquadName ? szSquadName : sideNames[sid]);
SetLobbyIsDirty();
};
void CFSMission::MaintainSquadLeadership(SideID sid)
{
IsideIGC* pside = m_pMission->GetSide(sid);
SquadID squadID = pside->GetSquadID();
CFSPlayer* pfsLeader = GetLeader(sid);
if (m_misdef.misparms.bLockTeamSettings)
return;
if (pfsLeader && (squadID == NA || !pfsLeader->GetCanLeadSquad(squadID)))
{
squadID = pfsLeader->GetPreferredSquadToLead();
if (squadID == NA)
{
ShipLinkIGC* pslNext;
for (ShipLinkIGC* psl = pside->GetShips()->first(); psl != NULL && squadID == NA; psl = pslNext)
{
pslNext = psl->next();
CFSShip* pcs = (CFSShip *)(psl->data()->GetPrivateData());
if (pcs->IsPlayer())
{
CFSPlayer* pfsPlayer = pcs->GetPlayer();
squadID = pfsPlayer->GetPreferredSquadToLead();
pfsLeader = pfsPlayer;
}
if (squadID != NA)
{
SetLeader(pfsLeader);
}
}
}
SetSideSquad(sid, squadID);
if (squadID == NA)
{
ShipLinkIGC* pslNext;
for (ShipLinkIGC* psl = pside->GetShips()->first(); psl != NULL && squadID == NA; psl = pslNext)
{
pslNext = psl->next();
CFSShip* pcs = (CFSShip *)(psl->data()->GetPrivateData());
if (pcs->IsPlayer())
RemovePlayerFromSide(pcs->GetPlayer(), QSR_SquadChange);
}
}
}
}
void CFSMission::SetStage(STAGE stage)
{
if (m_misdef.stage != stage)
{
assert(m_misdef.stage < stage || stage == STAGE_NOTSTARTED); debugf("SetStage, stage=%d, mission=%x\n", stage, GetCookie());
m_misdef.stage = stage;
m_misdef.fInProgress = stage == STAGE_STARTED;
BEGIN_PFM_CREATE(g.fm, pfmMissionStage, S, MISSION_STAGE)
END_PFM_CREATE
pfmMissionStage->stage = GetStage();
g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
m_pMission->SetMissionStage(stage);
SetLobbyIsDirty();
}
}
void CFSMission::GiveSideMoney(IsideIGC * pside, Money money)
{
assert (money >= 0);
if (money != 0)
{
SideID sideID = pside->GetObjectID();
m_rgMoney[sideID] += money;
DoPayday(pside);
}
}
void CFSMission::SetMissionParams(const MissionParams & misparmsNew)
{
MissionParams misparms = misparmsNew;
assert(GetStage() == STAGE_NOTSTARTED);
assert(misparms.Invalid() == NULL);
misparms.verIGCcore = m_misdef.misparms.verIGCcore;
strncpy(misparms.szIGCStaticFile, m_misdef.misparms.szIGCStaticFile, c_cbFileName);
#if !defined(ALLSRV_STANDALONE)
misparms.bClubGame = true;
#else misparms.bClubGame = false;
#endif if (misparms.bScoresCount)
misparms.iMaxImbalance = 0x7ffe;
int numTeamsOld = m_misdef.misparms.nTeams;
if (numTeamsOld > misparms.nTeams)
{
for (SideID sideID = numTeamsOld - 1; sideID >= misparms.nTeams; sideID--)
{
IsideIGC* pside = m_pMission->GetSide(sideID);
while (pside->GetShips()->first())
{
CFSShip* pship = (CFSShip*)(pside->GetShips()->first()->data()->GetPrivateData());
assert(pship->IsPlayer());
RemovePlayerFromSide(
pship->GetPlayer(),
QSR_SideDestroyed
);
}
}
}
bool bSquadChange = m_misdef.misparms.bSquadGame != misparms.bSquadGame;
m_misdef.misparms = misparms;
m_pMission->SetMissionParams(&misparms);
if (numTeamsOld < misparms.nTeams)
{
for (SideID sideID = numTeamsOld; sideID < misparms.nTeams; sideID++)
{
InitSide(sideID);
}
}
m_pMission->UpdateSides(Time::Now(), &m_misdef.misparms, m_misdef.rgszName);
for (SideLinkIGC* l = m_pMission->GetSides()->first(); l; l = l->next())
{
CheckForSideAllReady(l->data());
}
{
const ShipListIGC* pships = m_pMission->GetShips();
ShipLinkIGC* pshipLinkNext;
for (ShipLinkIGC* pshipLink = pships->first();
(pshipLink != NULL);
pshipLink = pshipLinkNext)
{
pshipLinkNext = pshipLink->next();
CFSPlayer* pfsPlayer = ((CFSShip*)(pshipLink->data()->GetPrivateData()))->GetPlayer();
RankID rank = pfsPlayer->GetPersistPlayerScore(NA)->GetRank();
if ((misparms.iMinRank > rank || misparms.iMaxRank < rank) && !pfsPlayer->CanCheat() && !pfsPlayer->PrivilegedUser())
{
RemovePlayerFromMission(pfsPlayer, QSR_RankLimits);
}
}
}
if (bSquadChange)
{
for (SideID sideID = 0; sideID < misparms.nTeams; ++sideID)
{
if (misparms.bSquadGame)
MaintainSquadLeadership(sideID);
else
SetSideSquad(sideID, NA);
}
}
}
void CFSMission::DelayCountdown(float fDelayLength)
{
if (GetStage() == STAGE_NOTSTARTED || GetStage() == STAGE_STARTING)
{
m_misdef.misparms.timeStart += fDelayLength;
BEGIN_PFM_CREATE(g.fm, pfmStartTime, S, SET_START_TIME)
END_PFM_CREATE
pfmStartTime->timeStart = m_misdef.misparms.timeStart;
g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
}
}
void CFSMission::StartCountdown(float fCountdownLength)
{
if (GetStage() == STAGE_NOTSTARTED || GetStage() == STAGE_STARTING)
{
m_misdef.misparms.timeStart = Time::Now() + fCountdownLength;
BEGIN_PFM_CREATE(g.fm, pfmStartTime, S, SET_START_TIME)
END_PFM_CREATE
pfmStartTime->timeStart = m_misdef.misparms.timeStart;
g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
}
if (GetStage() == STAGE_NOTSTARTED)
{
{
for (SideLinkIGC* l = m_pMission->GetSides()->first(); l; l = l->next())
{
IsideIGC* pside = l->data();
if (m_misdef.misparms.bAllowDevelopments)
pside->SetGlobalAttributeSet(pside->GetCivilization()->GetBaseAttributes());
else
pside->ResetGlobalAttributeSet();
}
}
m_pMission->GenerateMission(Time::Now(), &m_misdef.misparms, m_pttbmAltered, m_pttbmNewSetting);
{
for (SideLinkIGC* l = m_pMission->GetSides()->first(); l; l = l->next())
{
IsideIGC * pside = l->data();
bool bGenerateCivBriefing = m_strStoryText.IsEmpty();
const char* szBriefingText = bGenerateCivBriefing
? GetBase(pside)->GetCluster()->GetName() : m_strStoryText;
BEGIN_PFM_CREATE(g.fm, pfmSetBriefingText, S, SET_BRIEFING_TEXT)
FM_VAR_PARM(szBriefingText, CB_ZTS)
END_PFM_CREATE
pfmSetBriefingText->fGenerateCivBriefing = bGenerateCivBriefing;
g.fm.SendMessages(CFSSide::FromIGC(pside)->GetGroup(), FM_GUARANTEED, FM_FLUSH);
}
}
SetStage(STAGE_STARTING);
{
const ClusterListIGC * pclist = m_pMission->GetClusters();
for (ClusterLinkIGC * l = pclist->first(); (l != NULL); l = l->next())
{
IclusterIGC * pcluster = l->data();
CreateDPGroups(pcluster);
}
}
{
const MissionParams* pmp = m_pMission->GetMissionParams();
float moneyStart = m_pMission->GetFloatConstant(c_fcidStartingMoney);
for (SideLinkIGC* l = m_pMission->GetSides()->first(); l; l = l->next())
{
IsideIGC * pside = l->data();
CFSPlayer* pfsLeader = GetLeader(pside->GetObjectID());
float moneyMultiplier = pmp->fStartingMoney + pside->GetCivilization()->GetBonusMoney();
m_rgMoney[pside->GetObjectID()] = moneyMultiplier > 0.0f
? ((Money)(moneyStart * moneyMultiplier))
: ((Money)0);
if (pfsLeader)
pfsLeader->SetAutoDonate(NULL, 0, false);
const ShipListIGC* pships = pside->GetShips();
for (ShipLinkIGC* pshipLink = pships->first();
(pshipLink != NULL);
pshipLink = pshipLink->next())
{
CFSShip* pfsShip = ((CFSShip*)(pshipLink->data()->GetPrivateData()));
pfsShip->SetMoney(0);
pfsShip->GetPlayer()->SetTreasureObjectID(NA);
pfsShip->GetPlayer()->SetJustJoined(true);
if ((pfsShip != pfsLeader) && pfsShip->IsPlayer())
pfsShip->GetPlayer()->SetAutoDonate(pfsLeader, 0, false);
}
g.fm.SendMessages(CFSSide::FromIGC(pside)->GetGroup(), FM_GUARANTEED, FM_FLUSH);
if (HasPlayers(pside, true))
{
SendMissionInfo(NULL, pside);
}
else
{
if (pside->GetSquadID() != NA)
SetSideSquad(pside->GetObjectID(), NA);
DeactivateSide(pside);
}
const StationListIGC* pstations = pside->GetStations();
assert (pstations->n() >= 1);
const int c_stationsMax = 20;
IstationIGC* stations[c_stationsMax];
int nStations = 0;
{
for (StationLinkIGC* psl = pstations->first(); (psl != NULL); psl = psl->next())
{
IstationIGC* pstation = psl->data();
if (pstation->GetStationType()->HasCapability(c_sabmRestart))
{
assert (nStations < c_stationsMax);
stations[nStations++] = pstation;
}
}
}
assert (nStations >= 1);
IstationIGC* pstation = stations[0];
assert (pstation);
if (nStations == 1)
{
for (ShipLinkIGC* pshipLink = pships->first();
(pshipLink != NULL);
pshipLink = pshipLink->next())
{
pshipLink->data()->SetStation(pstation);
((CFSShip*)(pshipLink->data()->GetPrivateData()))->ShipStatusStart(pstation);
}
}
else
{
int minPerStation = pships->n() / (2 * nStations);
int maxPerStation = pships->n() - minPerStation * (nStations - 1);
int players[c_widMax] = {0, 0, 0, 0, 0,
0, 0, 0, 0, 0};
int assignment[c_widMax] = {-2, -2, -2, -2, -2,
-2, -2, -2, -2, -2};
int unassignedWings = 0;
{
for (ShipLinkIGC* pshipLink = pships->first();
(pshipLink != NULL);
pshipLink = pshipLink->next())
{
IshipIGC* pship = pshipLink->data();
WingID wid = pship->GetWingID();
assert (wid >= 0);
assert (wid < c_widMax);
if (players[wid]++ == 0)
unassignedWings++;
}
}
int population[c_stationsMax];
{
for (int i = 0; (i < nStations); i++)
population[i] = 0;
}
while (unassignedWings-- > 0)
{
int widMax = -1;
{
for (int i = 0; (i < c_widMax); i++)
{
if ((assignment[i] == -2) && ((widMax == -1) || (players[i] >= players[widMax])))
widMax = i;
}
}
assert (widMax != -1);
int stationMin = 0;
{
for (int i = 1; (i < nStations); i++)
{
if (population[i] < population[stationMin])
stationMin = i;
}
}
if (population[stationMin] + players[widMax] <= maxPerStation)
{
population[stationMin] += players[widMax];
assignment[widMax] = stationMin;
}
else
assignment[widMax] = -1;
}
{
for (ShipLinkIGC* pshipLink = pships->first();
(pshipLink != NULL);
pshipLink = pshipLink->next())
{
IshipIGC* pship = pshipLink->data();
WingID wid = pship->GetWingID();
assert (wid >= 0);
assert (wid < c_widMax);
int stationMin;
if (assignment[wid] == -1)
{
stationMin = 0;
{
for (int i = 1; (i < nStations); i++)
{
if (population[i] < population[stationMin])
stationMin = i;
}
}
population[stationMin]++;
}
else
stationMin = assignment[wid];
assert (stationMin >= 0);
IstationIGC* pstation = stations[stationMin];
pshipLink->data()->SetStation(pstation);
((CFSShip*)(pshipLink->data()->GetPrivateData()))->ShipStatusStart(pstation);
}
}
}
if (pmp->bAllowEmptyTeams && !pside->GetActiveF())
{
while (StationLinkIGC* psl = pside->GetStations()->first())
{
IstationIGC* pstation = psl->data();
debugf("removing station %s, cause bAllowEmptyTeams & Inactive side\n",pstation->GetName());
m_psiteIGC->KillStationEvent(pstation,NULL,0);
}
}
else if (pmp->bAllowDevelopments)
{
if (pmp->bAllowEmptyTeams ? pside->GetActiveF() : true) for (DroneTypeLinkIGC* pdl = m_pMission->GetDroneTypes()->first(); (pdl != NULL); pdl = pdl->next())
{
IdroneTypeIGC* pdt = pdl->data();
if ((pdt->GetPilotType() == c_ptMiner) && pstation->CanBuy(pdt))
{
for (int nMiner = 0; nMiner < m_misdef.misparms.nInitialMinersPerTeam; nMiner++)
{
CFSDrone * pfsDrone = CreateStockDrone(pdt, pside);
if (pfsDrone)
{
pfsDrone->GetIGCShip()->SetStation(pstation); }
}
break;
}
}
}
}
}
}
}
void CFSMission::StartGame()
{
if (GetStage() == STAGE_NOTSTARTED)
{
StartCountdown(0.0f);
}
if (GetStage() == STAGE_STARTING)
{
SetStage(STAGE_STARTED);
{
for (ShipLinkIGC* psl = m_pMission->GetShips()->first(); (psl != NULL); psl = psl->next())
{
CFSShip* pfsship = (CFSShip*)(psl->data()->GetPrivateData());
IsideIGC* pside = psl->data()->GetSide();
if (pside->GetObjectID() >= 0)
{
pfsship->GetPlayerScoreObject()->Connect(g.timeNow);
}
}
}
m_timeNextPayday = g.timeNow + m_pMission->GetFloatConstant(c_fcidSecondsBetweenPaydays);
m_psideWon = NULL;
m_pszReason = NULL;
m_bDraw = false;
m_pMission->EnterGame();
m_oldPlayers.purge();
BEGIN_PFM_CREATE(g.fm, pfmEnterGame, S, ENTER_GAME)
END_PFM_CREATE
g.fm.SendMessages(GetGroupRealSides(), FM_GUARANTEED, FM_FLUSH);
LPCSTR pszContext = GetIGCMission() ? GetIGCMission()->GetContextName() : NULL;
GetSite()->SendChat(NULL, CHAT_EVERYONE, NA, NA, "The game has started.");
_AGCModule.TriggerContextEvent(NULL, AllsrvEventID_GameStarted, pszContext,
GetIGCMission()->GetMissionParams()->strGameName, GetMissionID(), -1, -1, 0);
DoPayday();
}
}
void CFSMission::DoPayday(void)
{
const SideListIGC* psides = GetIGCMission()->GetSides();
for (SideLinkIGC* l = psides->first();
(l != NULL);
l = l->next())
{
DoPayday(l->data());
}
}
void CFSMission::DoPayday(IsideIGC* pside)
{
SideID sideID = pside->GetObjectID();
int np = GetCountOfPlayers(pside, true);
if (np != 0)
{
int delta = m_rgMoney[sideID] / np;
if (delta > 0)
{
BEGIN_PFM_CREATE(g.fm, pfmPayday, S, PAYDAY)
END_PFM_CREATE
pfmPayday->dMoney = Money(delta);
g.fm.SendMessages(CFSSide::FromIGC(pside)->GetGroup(), FM_GUARANTEED, FM_FLUSH);
m_rgMoney[sideID] -= delta * np;
const ShipListIGC * plistShip = pside->GetShips();
for(ShipLinkIGC * plinkShip = plistShip->first(); plinkShip; plinkShip = plinkShip->next())
{
CFSShip * pfsShip = (CFSShip *) plinkShip->data()->GetPrivateData();
if (pfsShip->IsPlayer())
{
CFSPlayer* pfsDonate = pfsShip->GetPlayer()->GetAutoDonate();
if (pfsDonate)
pfsDonate->SetMoney(pfsDonate->GetMoney() + delta);
else
pfsShip->SetMoney(pfsShip->GetMoney() + delta);
}
}
}
}
}
void CFSMission::DoTick(Time timeNow)
{
assert (GetStage() == STAGE_STARTED);
ImissionIGC* pm = GetIGCMission();
const MissionParams* pmp = pm->GetMissionParams();
{
if (pmp->IsCountdownGame())
{
if ((timeNow - pmp->timeStart) > pmp->GetCountDownTime())
{
IsideIGC* psideWin = NULL;
const char* pszClue;
if (pmp->IsConquestGame())
{
pszClue = "conquest";
int maxFlags = 0;
for (SideLinkIGC* psl = pm->GetSides()->first(); (psl != NULL); psl = psl->next())
{
IsideIGC* pside = psl->data();
int nFlags = 0;
for (StationLinkIGC* l = pside->GetStations()->first(); (l != NULL); l = l->next())
{
if (l->data()->GetBaseStationType()->HasCapability(c_sabmFlag))
nFlags++;
}
if (nFlags > maxFlags)
{
maxFlags = nFlags;
psideWin = pside;
}
else if (nFlags == maxFlags)
{
psideWin = NULL;
}
}
}
if ((psideWin == NULL) && pmp->IsTerritoryGame())
{
pszClue = "territory";
unsigned char maxSectors = 0;
for (SideLinkIGC* psl = pm->GetSides()->first(); (psl != NULL); psl = psl->next())
{
IsideIGC* pside = psl->data();
int nSectors = pside->GetTerritoryCount();
if (nSectors > maxSectors)
{
maxSectors = nSectors;
psideWin = pside;
}
else if (nSectors == maxSectors)
{
psideWin = NULL;
}
}
}
if ((psideWin == NULL) && pmp->IsProsperityGame())
{
pszClue = "prosperity";
DWORD maxTime = 0;
for (SideLinkIGC* psl = pm->GetSides()->first(); (psl != NULL); psl = psl->next())
{
IsideIGC* pside = psl->data();
IbucketIGC* pbucket = pside->GetBuckets()->last()->data();
assert ((pbucket->GetBucketType() == OT_development) &&
(pbucket->GetBuyable()->GetObjectID() == c_didTeamMoney));
DWORD time = pbucket->GetTime();
if (time > maxTime)
{
maxTime = time;
psideWin = pside;
}
else if (time == maxTime)
{
psideWin = NULL;
}
}
}
if ((psideWin == NULL) && pmp->IsArtifactsGame())
{
pszClue = "artifacts";
short maxFlags = 0;
for (SideLinkIGC* psl = pm->GetSides()->first(); (psl != NULL); psl = psl->next())
{
IsideIGC* pside = psl->data();
short nFlags = pside->GetArtifacts();
if (nFlags > maxFlags)
{
maxFlags = nFlags;
psideWin = pside;
}
else if (nFlags == maxFlags)
{
psideWin = NULL;
}
}
}
if ((psideWin == NULL) && pmp->IsFlagsGame())
{
pszClue = "flags";
short maxFlags = 0;
for (SideLinkIGC* psl = pm->GetSides()->first(); (psl != NULL); psl = psl->next())
{
IsideIGC* pside = psl->data();
short nFlags = pside->GetFlags();
if (nFlags > maxFlags)
{
maxFlags = nFlags;
psideWin = pside;
}
else if (nFlags == maxFlags)
{
psideWin = NULL;
}
}
}
if (psideWin == NULL)
{
pszClue = "kills";
int nKills = -1;
int nDeaths = INT_MAX;
for (SideLinkIGC* psl = pm->GetSides()->first(); (psl != NULL); psl = psl->next())
{
IsideIGC* pside = psl->data();
int k = pside->GetKills();
int d = pside->GetDeaths();
if ((k > nKills) ||
((k == nKills) && (d < nDeaths)))
{
nKills = k;
nDeaths = d;
psideWin = pside;
}
else if ((k == nKills) && (d == nDeaths))
{
psideWin = NULL;
}
}
}
if (psideWin)
{
static char szReason[100];
sprintf(szReason, "The clock has stopped. The winner: %s by %s", psideWin->GetName(), pszClue);
GameOver(psideWin, szReason);
}
else
{
GameOver(NULL, "The clock has stopped. The game is a draw.");
}
}
}
}
if (m_psideWon || m_bDraw)
{
ProcessGameOver();
return;
}
if (timeNow >= m_timeNextPayday)
{
float dtPayday = m_pMission->GetFloatConstant(c_fcidSecondsBetweenPaydays);
float dt = dtPayday + (timeNow - m_timeNextPayday);
m_timeNextPayday = m_timeNextPayday + dtPayday;
if (pmp->bAllowDevelopments)
{
float moneyIncome = m_pMission->GetFloatConstant(c_fcidIncome);
const SideListIGC* psides = GetIGCMission()->GetSides();
{
for (SideLinkIGC* l = psides->first();
(l != NULL);
l = l->next())
{
IsideIGC* pside = l->data();
SideID sideID = pside->GetObjectID();
m_rgMoney[sideID] += (Money)(moneyIncome * (1.0f + pside->GetCivilization()->GetIncomeMoney()));
Money income = 0;
for (StationLinkIGC* psl = pside->GetStations()->first();
(psl != NULL);
psl = psl->next())
{
income += psl->data()->GetStationType()->GetIncome();
}
m_rgMoney[sideID] += income;
}
}
DoPayday();
}
{
for (ClusterLinkIGC* l = GetIGCMission()->GetClusters()->first();
(l != NULL);
l = l->next())
{
IclusterIGC* pcluster = l->data();
bool bHome = pcluster->GetHomeSector();
float treasures = pcluster->GetPendingTreasures() +
dt * (bHome
? pmp->nPlayerSectorTreasureRate
: pmp->nNeutralSectorTreasureRate);
if (treasures >= 1.0f)
{
int n = int(treasures);
treasures -= float(n);
short tsi = bHome ? pmp->tsiPlayerRegenerate : pmp->tsiNeutralRegenerate;
for (int i = n; (i > 0); i--)
{
GetIGCMission()->GenerateTreasure(timeNow, pcluster, tsi);
}
}
pcluster->SetPendingTreasures(treasures);
}
}
}
for (BallotList::Iterator iter(m_ballots); !iter.End();)
{
if (iter.Value()->Update(timeNow))
iter.Remove();
else
iter.Next();
}
}
void CFSMission::Vacate(void)
{
const ShipListIGC * pShips = m_pMission->GetShips();
CFSShip * pfsShip = NULL;
ShipLinkIGC * pShiplink = NULL;
pShiplink = pShips->first();
while (pShiplink)
{
CFSShip * pfsShip = (CFSShip *) pShiplink->data()->GetPrivateData();
pShiplink = pShiplink->next();
if (!pfsShip->IsPlayer())
delete pfsShip->GetDrone();
else
{
pfsShip->Reset(true);
}
}
}
void CFSMission::SaveAsOldPlayer(CFSPlayer* pfsplayer, bool bBooted)
{
OldPlayerLink* popl = GetOldPlayerLink(pfsplayer->GetName());
if (!popl)
{
popl = new OldPlayerLink;
m_oldPlayers.last(popl);
}
OldPlayerInfo& opi = popl->data();
strcpy(opi.name, pfsplayer->GetName());
PlayerScoreObject* ppso = pfsplayer->GetPlayerScoreObject();
opi.pso = *ppso;
opi.sideID = pfsplayer->GetSide()->GetObjectID();
opi.lastSide = pfsplayer->GetLastSide();
if ((GetStage() != STAGE_STARTED) ||
(m_pMission->GetMissionParams()->bAllowDefections))
{
opi.bannedSideMask = pfsplayer->GetBannedSideMask();
if (bBooted)
{
if (opi.sideID < 0)
{
opi.bannedSideMask = 0xff;
}
else
{
opi.bannedSideMask |= SideMask(opi.sideID);
}
}
}
else
{
if (bBooted)
opi.bannedSideMask = 0xff;
else if (opi.sideID >= 0)
opi.bannedSideMask = ~SideMask(opi.sideID);
else
opi.bannedSideMask = pfsplayer->GetBannedSideMask();
}
opi.characterID = pfsplayer->GetCharacterID();
IclusterIGC* pcluster = pfsplayer->GetIGCShip()->GetCluster();
if (pcluster)
{
opi.pclusterLifepod = pcluster;
opi.positionLifepod = pfsplayer->GetIGCShip()->GetSourceShip()->GetPosition();
}
}
void CFSMission::GameOver(IsideIGC * psideWin, const char* pszReason)
{
m_psideWon = psideWin;
m_pszReason = pszReason;
m_bDraw = m_psideWon == NULL;
const ObjectID iTeamObjectID = (psideWin) ? psideWin->GetObjectID() : -1;
const char* pszTeamName = (psideWin) ? psideWin->GetName() : "";
LPCSTR pszContext = GetIGCMission() ? GetIGCMission()->GetContextName() : NULL;
_AGCModule.TriggerContextEvent(NULL, AllsrvEventID_GameEnded, pszContext,
GetIGCMission()->GetMissionParams()->strGameName, GetMissionID(), -1, -1, 3, "Reason", VT_LPSTR, pszReason,
"WinningTeamID", VT_I4, iTeamObjectID, "WinningTeamName", VT_LPSTR, pszTeamName); }
void CFSMission::MakeOverrideTechBits()
{
if (m_pttbmAltered == NULL)
{
m_pttbmAltered = new TechTreeBitMask[c_cSidesMax];
for (int i = 0; i < c_cSidesMax; ++i)
(m_pttbmAltered)[i].ClearAll();
}
if (m_pttbmNewSetting == NULL)
{
m_pttbmNewSetting = new TechTreeBitMask[c_cSidesMax];
for (int i = 0; i < c_cSidesMax; ++i)
(m_pttbmNewSetting)[i].ClearAll();
}
}
void CFSMission::RecordGameResults()
{
#if !defined(ALLSRV_STANDALONE)
CQGameResults* pquery = new CQGameResults(NULL); CQGameResultsData* pqd = pquery->GetData();
strncpy(pqd->szGameID , GetIGCMission()->GetContextName() , sizeofArray(pqd->szGameID));
strncpy(pqd->szName , m_misdef.misparms.strGameName , sizeofArray(pqd->szName));
strncpy(pqd->szWinningTeam, m_psideWon ? m_psideWon->GetName() : "", sizeofArray(pqd->szWinningTeam));
pqd->szGameID[sizeofArray(pqd->szGameID) - 1] = '\0';
pqd->szName[sizeofArray(pqd->szName) - 1] = '\0';
pqd->szWinningTeam[sizeofArray(pqd->szWinningTeam) - 1] = '\0';
pqd->nWinningTeamID = m_psideWon ? m_psideWon->GetObjectID() : NA;
pqd->bIsGoalConquest = m_misdef.misparms.IsConquestGame();
pqd->bIsGoalCountdown = m_misdef.misparms.IsCountdownGame();
pqd->bIsGoalTeamKills = m_misdef.misparms.IsDeathMatchGame();
pqd->bIsGoalProsperity = m_misdef.misparms.IsProsperityGame();
pqd->bIsGoalArtifacts = m_misdef.misparms.IsArtifactsGame();
pqd->bIsGoalFlags = m_misdef.misparms.IsFlagsGame();
pqd->nGoalConquest = m_misdef.misparms.iGoalConquestPercentage;
pqd->nGoalCountdown = m_misdef.misparms.dtGameLength;
pqd->nGoalTeamKills = m_misdef.misparms.nGoalTeamKills;
pqd->fGoalProsperity = m_misdef.misparms.fGoalTeamMoney;
pqd->nGoalArtifacts = m_misdef.misparms.nGoalArtifactsCount;
pqd->nGoalFlags = m_misdef.misparms.nGoalFlagsCount;
pqd->nDuration = GetGameDuration();
g.sql.PostQuery(pquery);
const SideListIGC* pSides = GetIGCMission()->GetSides();
for (SideLinkIGC* itSide = pSides->first(); itSide; itSide = itSide->next())
{
IsideIGC* pside = itSide->data();
assert(pside);
RecordTeamResults(pside);
}
for (OldPlayerLink* itOld = m_oldPlayers.first(); itOld; itOld = itOld->next())
{
OldPlayerInfo& opi = itOld->data();
if (opi.sideID != SIDE_TEAMLOBBY)
RecordPlayerResults(opi.name, &opi.pso, opi.sideID);
}
#endif }
void CFSMission::RecordTeamResults(IsideIGC* pside)
{
#if !defined(ALLSRV_STANDALONE)
CQTeamResults* pquery = new CQTeamResults(NULL);
CQTeamResultsData* pqd = pquery->GetData();
strncpy(pqd->szGameID , GetIGCMission()->GetContextName(), sizeofArray(pqd->szGameID));
strncpy(pqd->szName , pside->GetName() , sizeofArray(pqd->szName));
pqd->szGameID[sizeofArray(pqd->szGameID) - 1] = '\0';
pqd->szName[sizeofArray(pqd->szName) - 1] = '\0';
for (int i=0;i<sizeofArray(pqd->szTechs);i++) pqd->szTechs[i]=0;
pside->GetTechs().ToString(pqd->szTechs, sizeofArray(pqd->szTechs));
pqd->szTechs[sizeofArray(pqd->szTechs)-1]=0;
pqd->nCivID = pside->GetCivilization()->GetObjectID();
pqd->nTeamID = pside->GetObjectID();
pqd->cPlayerKills = pside->GetKills();
pqd->cBaseKills = pside->GetBaseKills();
pqd->cBaseCaptures = pside->GetBaseCaptures();
pqd->cDeaths = pside->GetDeaths();
pqd->cEjections = pside->GetEjections();
pqd->cFlags = pside->GetFlags();
pqd->cArtifacts = pside->GetArtifacts();
pqd->nConquestPercent = pside->GetConquestPercent();
pqd->nProsperityPercentBought = pside->GetProsperityPercentBought();
pqd->nProsperityPercentComplete = pside->GetProsperityPercentComplete();
if (pside->GetActiveF())
pqd->nTimeEndured = GetGameDuration();
else
pqd->nTimeEndured = pside->GetTimeEndured();
g.sql.PostQuery(pquery);
const ShipListIGC* pShips = pside->GetShips();
for (ShipLinkIGC* itShip = pShips->first(); itShip; itShip = itShip->next())
{
IshipIGC* pship = itShip->data();
assert(pship);
if (ISPLAYER(pship))
{
CFSPlayer* pfsPlayer = ((CFSShip*)(pship->GetPrivateData()))->GetPlayer();
PlayerScoreObject* ppso = pfsPlayer->GetPlayerScoreObject();
RecordPlayerResults(pship->GetName(), ppso, pside->GetObjectID());
}
}
#endif }
void CFSMission::RecordPlayerResults(const char* pszName, PlayerScoreObject* ppso, SideID sid)
{
#if !defined(ALLSRV_STANDALONE)
CQPlayerResults* pquery = new CQPlayerResults(NULL);
CQPlayerResultsData* pqd = pquery->GetData();
strncpy(pqd->szGameID , GetIGCMission()->GetContextName(), sizeofArray(pqd->szGameID));
strncpy(pqd->szName , pszName , sizeofArray(pqd->szName) );
pqd->szGameID[sizeofArray(pqd->szGameID) - 1] = '\0';
pqd->szName[sizeofArray(pqd->szName) - 1] = '\0';
pqd->nTeamID = sid;
pqd->cPlayerKills = ppso->GetPlayerKills();
pqd->cBuilderKills = ppso->GetBuilderKills();
pqd->cLayerKills = ppso->GetLayerKills();
pqd->cMinerKills = ppso->GetMinerKills();
pqd->cBaseKills = ppso->GetBaseKills();
pqd->cBaseCaptures = ppso->GetBaseCaptures();
pqd->cPilotBaseKills = ppso->GetPilotBaseKills();
pqd->cPilotBaseCaptures = ppso->GetPilotBaseCaptures();
pqd->cDeaths = ppso->GetDeaths();
pqd->cEjections = ppso->GetEjections();
pqd->cRescues = ppso->GetRescues();
pqd->cFlags = ppso->GetFlags();
pqd->cArtifacts = ppso->GetArtifacts();
pqd->cTechsRecovered = ppso->GetTechsRecovered();
pqd->cAlephsSpotted = ppso->GetWarpsSpotted();
pqd->cAsteroidsSpotted = ppso->GetAsteroidsSpotted();
pqd->fCombatRating = ppso->GetCombatRating();
pqd->fScore = ppso->GetScore();
pqd->nTimePlayed = ppso->GetTimePlayed();
debugf("Writing player results: %s %s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %g %g %d\n",
pqd->szGameID,
pqd->szName,
pqd->nTeamID,
pqd->cPlayerKills,
pqd->cBuilderKills,
pqd->cLayerKills,
pqd->cMinerKills,
pqd->cBaseKills,
pqd->cBaseCaptures,
pqd->cPilotBaseKills,
pqd->cPilotBaseCaptures,
pqd->cDeaths,
pqd->cEjections,
pqd->cRescues,
pqd->cFlags,
pqd->cArtifacts,
pqd->cTechsRecovered,
pqd->cAlephsSpotted,
pqd->cAsteroidsSpotted,
(double)pqd->fCombatRating,
(double)pqd->fScore,
pqd->nTimePlayed
);
g.sql.PostQuery(pquery);
#endif }
void CFSMission::QueueGameoverMessage()
{
BEGIN_PFM_CREATE(g.fm, pfmGameOver, S, GAME_OVER)
FM_VAR_PARM((const char*)(m_pszReason ? m_pszReason : "Your side has been eliminated."), CB_ZTS)
END_PFM_CREATE
for (SideID sideID = 0; sideID < c_cSidesMax; sideID++)
{
IsideIGC* pside = m_pMission->GetSide(sideID);
strcpy(pfmGameOver->rgSides[sideID].sideName, pside ? pside->GetName() : "<bug>");
pfmGameOver->rgSides[sideID].civID = pside ? pside->GetCivilization()->GetObjectID() : -1;
pfmGameOver->rgSides[sideID].color = pside ? pside->GetColor() : Color(0.5, 0.5, 0.5);
pfmGameOver->rgSides[sideID].cKills = pside ? pside->GetKills() : 0;
pfmGameOver->rgSides[sideID].cDeaths = pside ? pside->GetDeaths() : 0;
pfmGameOver->rgSides[sideID].cEjections = pside ? pside->GetEjections() : 0;
pfmGameOver->rgSides[sideID].cBaseKills = pside ? pside->GetBaseKills() : 0;
pfmGameOver->rgSides[sideID].cBaseCaptures = pside ? pside->GetBaseCaptures() : 0;
pfmGameOver->rgSides[sideID].cFlags = pside ? pside->GetFlags() : 0;
pfmGameOver->rgSides[sideID].cArtifacts = pside ? pside->GetArtifacts() : 0;
};
pfmGameOver->nNumSides = m_pMission->GetSides()->n();
pfmGameOver->iSideWinner = m_psideWon ? m_psideWon->GetObjectID() : NA;
pfmGameOver->bEjectPods = m_misdef.misparms.bEjectPods;
const ShipListIGC * plistShip = m_pMission->GetShips();
int nNumPlayers = plistShip->n() + m_oldPlayers.n(); size_t playerlistSize = nNumPlayers * sizeof(PlayerEndgameInfo);
PlayerEndgameInfo* playerlist = (PlayerEndgameInfo*)alloca(playerlistSize);
int nPlayerIndex = 0;
for (ShipLinkIGC * plinkShip = plistShip->first(); plinkShip; plinkShip = plinkShip->next())
{
if (ISPLAYER(plinkShip->data()))
{
CFSPlayer* pfsPlayer = ((CFSShip *)(plinkShip->data()->GetPrivateData()))->GetPlayer();
PlayerScoreObject* ppso = pfsPlayer->GetPlayerScoreObject();
if (ppso->GetTimePlayed() > 0.0f && pfsPlayer->GetSide()->GetObjectID() != SIDE_TEAMLOBBY)
{
strcpy(playerlist[nPlayerIndex].characterName, pfsPlayer->GetName());
playerlist[nPlayerIndex].scoring.Set(pfsPlayer->GetPlayerScoreObject());
playerlist[nPlayerIndex].stats = ppso->GetPersist();
playerlist[nPlayerIndex].sideId = pfsPlayer->GetSide()->GetObjectID();
nPlayerIndex++;
}
}
}
for (OldPlayerLink* popl = m_oldPlayers.first(); (popl != NULL); popl = popl->next())
{
OldPlayerInfo& opi = popl->data();
if (opi.pso.GetTimePlayed() != 0.0f && opi.sideID != SIDE_TEAMLOBBY)
{
strcpy(playerlist[nPlayerIndex].characterName, opi.name);
playerlist[nPlayerIndex].scoring.Set(&(opi.pso));
playerlist[nPlayerIndex].stats = opi.pso.GetPersist();
playerlist[nPlayerIndex].sideId = opi.sideID;
nPlayerIndex++;
}
}
assert(nPlayerIndex <= nNumPlayers);
const int nMaxPlayersPerMsg = 50;
while (nPlayerIndex > 0)
{
int nPlayers = min(nPlayerIndex, nMaxPlayersPerMsg);
nPlayerIndex -= nPlayers;
BEGIN_PFM_CREATE(g.fm, pfmGameOver, S, GAME_OVER_PLAYERS)
FM_VAR_PARM(playerlist + nPlayerIndex, nPlayers * sizeof(PlayerEndgameInfo))
END_PFM_CREATE
}
}
static float GetExpMult(float totalExp, float sideExp, int nSides)
{
const float minExpMult = 0.1f;
if ((nSides < 2) || (sideExp <= 0.0f))
return 1.0f;
float avgExp = (totalExp - sideExp) / float(nSides - 1);
if (sideExp <= avgExp)
return 1.0f;
float m = avgExp / sideExp;
return (m < minExpMult) ? minExpMult : m;
}
void CFSMission::ProcessGameOver()
{
const ShipListIGC * pShips = m_pMission->GetShips();
ShipLinkIGC * pShiplink;
m_flGameDuration = g.timeNow - m_misdef.misparms.timeStart;
float totalExperience = 0.0f;
float sideExperience[c_cSidesMax] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
float dtPlayed[c_cSidesMax] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
float scoreEarned[c_cSidesMax] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
PlayerScoreObject* commander[c_cSidesMax] = {NULL, NULL, NULL, NULL, NULL, NULL};
{
for (pShiplink = pShips->first(); pShiplink; pShiplink = pShiplink->next())
{
CFSShip * pfsShip = (CFSShip *) pShiplink->data()->GetPrivateData();
if (pfsShip->IsPlayer())
{
PlayerScoreObject* ppso = pfsShip->GetPlayerScoreObject();
if (ppso->Connected())
{
ppso->Disconnect(g.timeNow);
IsideIGC* pside = pfsShip->GetSide();
bool bCount = (ppso->GetTimePlayed() > 180.0f) && !m_bDraw;
ppso->EndGame(m_pMission,
(pside == m_psideWon) && bCount && (ppso->GetTimePlayed() > GetGameDuration() / 2.0f),
(pside != m_psideWon) && bCount);
SideID sid = pside->GetObjectID();
if (sid >= 0)
{
float e = ppso->GetTimePlayed() * ppso->GetPersist().GetScore();
totalExperience += e;
sideExperience[sid] += e;
scoreEarned[sid] += ppso->GetScore();
dtPlayed[sid] += ppso->GetTimePlayed();
}
if ((commander[sid] == NULL) ||
(commander[sid]->GetTimeCommanded() < ppso->GetTimeCommanded()))
{
commander[sid] = ppso;
}
}
}
}
}
{
SideID sidWin = m_psideWon ? m_psideWon->GetObjectID() : NA;
for (OldPlayerLink* popl = m_oldPlayers.first(); (popl != NULL); popl = popl->next())
{
OldPlayerInfo & opi = popl->data();
bool bCount = (opi.pso.GetTimePlayed() > 180.0f);
opi.pso.EndGame(m_pMission,
(opi.sideID == sidWin) && bCount && (opi.pso.GetTimePlayed() > GetGameDuration() / 2.0f),
(opi.sideID != sidWin) && bCount);
if (opi.sideID >= 0)
{
float e = opi.pso.GetTimePlayed() * opi.pso.GetPersist().GetScore();
totalExperience += e;
sideExperience[opi.sideID] += e;
scoreEarned[opi.sideID] += opi.pso.GetScore();
dtPlayed[opi.sideID] += opi.pso.GetTimePlayed();
if ((commander[opi.sideID] == NULL) ||
(commander[opi.sideID]->GetTimeCommanded() < opi.pso.GetTimeCommanded()))
{
commander[opi.sideID] = &(opi.pso);
}
}
}
}
{
for (pShiplink = pShips->first(); pShiplink; pShiplink = pShiplink->next())
{
CFSShip * pfsShip = (CFSShip *) pShiplink->data()->GetPrivateData();
if (pfsShip->IsPlayer())
{
IsideIGC* pside = pfsShip->GetSide();
if (pside && pside->GetObjectID() != SIDE_TEAMLOBBY)
{
SideID sid = pside->GetObjectID();
float f = GetExpMult(totalExperience, sideExperience[sid], m_pMission->GetSides()->n());
if (f < 1.0f)
{
PlayerScoreObject* ppso = pfsShip->GetPlayerScoreObject();
ppso->SetScore(ppso->GetScore() * f);
}
}
}
}
for (OldPlayerLink* popl = m_oldPlayers.first(); (popl != NULL); popl = popl->next())
{
OldPlayerInfo & opi = popl->data();
if (opi.sideID != SIDE_TEAMLOBBY)
{
SideID sid = opi.sideID;
float f = GetExpMult(totalExperience, sideExperience[sid], m_pMission->GetSides()->n());
if (f < 1.0f)
{
opi.pso.SetScore(opi.pso.GetScore() * f);
}
}
}
}
{
for (SideLinkIGC* psl = m_pMission->GetSides()->first(); (psl != NULL); psl = psl->next())
{
IsideIGC* pside = psl->data();
SideID sideID = pside->GetObjectID();
PlayerScoreObject* ppso = commander[sideID];
if (ppso)
{
assert (dtPlayed[sideID] >= 0.0f);
float commandScore = scoreEarned[sideID] / dtPlayed[sideID];
{
float f = GetExpMult(totalExperience, sideExperience[sideID], m_pMission->GetSides()->n());
if (f < 1.0f)
{
commandScore *= f;
}
}
ppso->SetCommanderScore(commandScore * ppso->GetTimePlayed());
}
}
}
{
for (pShiplink = pShips->first(); pShiplink; pShiplink = pShiplink->next())
{
CFSShip * pfsShip = (CFSShip *) pShiplink->data()->GetPrivateData();
if (pfsShip->IsPlayer())
{
IsideIGC* pside = pfsShip->GetSide();
if (pside && pside->GetObjectID() != SIDE_TEAMLOBBY)
{
PlayerScoreObject* ppso = pfsShip->GetPlayerScoreObject();
SetCharStats(pfsShip->GetPlayer()->GetCharacterID(), pfsShip->GetPlayer(), pside, *ppso, this);
}
}
}
}
{
for (OldPlayerLink* popl = m_oldPlayers.first(); (popl != NULL); popl = popl->next())
{
OldPlayerInfo & opi = popl->data();
if (opi.sideID != SIDE_TEAMLOBBY)
SetCharStats(opi.characterID, NULL, GetIGCMission()->GetSide(opi.sideID), opi.pso, this);
}
}
if (m_misdef.misparms.bSquadGame && m_misdef.misparms.bScoresCount && m_psideWon
&& m_misdef.misparms.nTeams == 2
&& m_pMission->GetSide(0)->GetSquadID() != m_pMission->GetSide(1)->GetSquadID())
{
RecordSquadGame(m_pMission->GetSides(), m_psideWon);
}
if (m_misdef.misparms.bScoresCount) {
RecordGameResults();
}
g.fm.SetDefaultRecipient(GetGroupMission(), FM_GUARANTEED);
QueueGameoverMessage();
g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
{
for (pShiplink = pShips->first(); pShiplink; pShiplink = pShiplink->next())
{
CFSShip * pfsShip = (CFSShip *) pShiplink->data()->GetPrivateData();
if (pfsShip->IsPlayer())
{
pfsShip->GetPlayer()->SetLifepod(NULL, Vector::GetZero());
PlayerScoreObject* ppso = pfsShip->GetPlayerScoreObject();
ppso->Reset(true);
}
}
}
m_oldPlayers.purge();
Vacate();
while (!m_ballots.IsEmpty())
delete m_ballots.PopFront();
bool bRestartable = !g.fPaused && m_misdef.misparms.bAllowRestart;
#if defined(ALLSRV_STANDALONE)
if (m_misdef.misparms.nTotalMaxPlayersPerGame == 1)
bRestartable = false;
#endif
SetStage(bRestartable ? STAGE_NOTSTARTED : STAGE_OVER); for (SideID sideID = 0; sideID < m_misdef.misparms.nTeams; sideID++)
{
IsideIGC* pside = m_pMission->GetSide(sideID);
if (pside->GetSquadID() != NA)
MaintainSquadLeadership(sideID);
m_misdef.rgfReady [sideID] = false;
m_misdef.rgfForceReady [sideID] = false;
m_misdef.rgfActive [sideID] = true;
m_rgMoney [sideID] = 0;
pside->SetActiveF(true);
bool bAET = m_misdef.misparms.bAllowEmptyTeams;
if (!m_misdef.misparms.bObjectModelCreated)
m_misdef.misparms.bAllowEmptyTeams = false;
if (bAET)
{
BEGIN_PFM_CREATE(g.fm, pfmSideInactive, CS, SIDE_INACTIVE)
END_PFM_CREATE
pfmSideInactive->sideID = 0; pfmSideInactive->bActive = true;
pfmSideInactive->bChangeAET = true;
pfmSideInactive->bAET = false;
g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
}
CheckForSideAllReady(pside);
}
for (SideLinkIGC* psl = m_pMission->GetSides()->first(); (psl != NULL); psl = psl->next())
psl->data()->Reset();
m_pMission->ResetMission();
LPCSTR pszContext = GetIGCMission() ? GetIGCMission()->GetContextName() : NULL;
_AGCModule.TriggerContextEvent(NULL, AllsrvEventID_GameOver, pszContext,
GetIGCMission()->GetMissionParams()->strGameName, GetMissionID(),
-1, -1, 0); if (bRestartable && m_misdef.misparms.bAutoRestart)
{
m_misdef.misparms.timeStart = Time::Now() + m_misdef.misparms.fRestartCountdown;
BEGIN_PFM_CREATE(g.fm, pfmStartTime, S, SET_START_TIME)
END_PFM_CREATE
pfmStartTime->timeStart = m_misdef.misparms.timeStart;
g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
}
}
IsideIGC* CFSMission::CheckForVictoryByStationBuild(IsideIGC* psideTest)
{
return CheckForVictoryByStationKill(NULL, NULL);
}
IsideIGC* CFSMission::CheckForVictoryByStationCapture(IsideIGC* psideTest, IsideIGC* psideOld)
{
return CheckForVictoryByStationKill(NULL, psideOld);
}
IsideIGC* CFSMission::CheckForVictoryByStationKill(IstationIGC* pstationKilled, IsideIGC* psideOld)
{
IsideIGC* psideWon = NULL;
const MissionParams* pmp = m_pMission->GetMissionParams();
if ( (STAGE_STARTED == GetStage()) || ((STAGE_STARTING == GetStage()) && pmp->bAllowEmptyTeams) && (m_psideWon == NULL))
{
const SideListIGC* psides = m_pMission->GetSides();
bool bChange = false;
if (pmp->IsConquestGame())
{
int nStationsTotal = 0;
assert (c_cSidesMax == 6);
int nStationsPerSide[c_cSidesMax] = {0, 0, 0, 0, 0, 0};
{
for (StationLinkIGC* psl = m_pMission->GetStations()->first();
(psl != NULL);
psl = psl->next())
{
IstationIGC* pstation = psl->data();
if ((pstation != pstationKilled) && pstation->GetBaseStationType()->HasCapability(c_sabmFlag))
{
nStationsTotal++;
nStationsPerSide[pstation->GetSide()->GetObjectID()]++;
}
}
}
int nActiveTeams = 0;
if (nStationsTotal != 0)
{
const SideListIGC* psides = m_pMission->GetSides();
for (SideLinkIGC* l = psides->first(); (l != NULL); l = l->next())
{
IsideIGC* pside = l->data();
if (pside->GetActiveF()) nActiveTeams++;
unsigned char conquest = (unsigned char)(100 * nStationsPerSide[pside->GetObjectID()] / nStationsTotal);
if (conquest != pside->GetConquestPercent())
{
bChange = true;
pside->SetConquestPercent(conquest);
if (conquest >= pmp->iGoalConquestPercentage)
psideWon = pside;
}
}
if (pmp->bAllowEmptyTeams && (nActiveTeams == 1))
psideWon = NULL;
}
}
if (pmp->IsTerritoryGame() && (psideWon == NULL))
{
assert (c_cSidesMax == 6);
unsigned char nTerritoriesPerSide[c_cSidesMax] = {0, 0, 0, 0, 0, 0};
const ClusterListIGC* pclusters = m_pMission->GetClusters();
for (ClusterLinkIGC* pcl = pclusters->first(); (pcl != NULL); pcl = pcl->next())
{
IclusterIGC* pcluster = pcl->data();
IsideIGC* psideOwner = NULL;
StationLinkIGC* psl;
for (psl = pcluster->GetStations()->first(); (psl != NULL); psl = psl->next())
{
if (psl->data() != pstationKilled)
{
IsideIGC* pside = psl->data()->GetSide();
if (psideOwner == NULL)
psideOwner = pside;
else if (psideOwner != pside)
break;
}
}
if (psideOwner && (psl == NULL))
nTerritoriesPerSide[psideOwner->GetObjectID()]++;
}
unsigned char nThreashold = (unsigned char)((50 + pclusters->n() * pmp->iGoalTerritoryPercentage) / 100);
for (SideLinkIGC* l = psides->first(); (l != NULL); l = l->next())
{
IsideIGC* pside = l->data();
SideID sideID = pside->GetObjectID();
if (nTerritoriesPerSide[sideID] != pside->GetTerritoryCount())
{
bChange = true;
pside->SetTerritoryCount(nTerritoriesPerSide[sideID]);
if (nTerritoriesPerSide[sideID] >= nThreashold)
psideWon = pside;
}
}
}
if (bChange)
{
BEGIN_PFM_CREATE(g.fm, pfmGameState, S, GAME_STATE)
END_PFM_CREATE
SideID sid = 0;
for (SideLinkIGC* l = psides->first(); (l != NULL); l = l->next())
{
assert (sid == l->data()->GetObjectID());
pfmGameState->conquest[sid] = l->data()->GetConquestPercent();
pfmGameState->territory[sid] = l->data()->GetTerritoryCount();
pfmGameState->nFlags[sid] = l->data()->GetFlags();
pfmGameState->nArtifacts[sid++] = l->data()->GetArtifacts();
}
g.fm.SendMessages(GetGroupRealSides(), FM_GUARANTEED, FM_FLUSH);
}
if ((psideWon == NULL) && psideOld)
{
StationLinkIGC* psl;
for (psl = psideOld->GetStations()->first();
(psl != NULL);
psl = psl->next())
{
IstationIGC* pstation = psl->data();
if ((pstation != pstationKilled) && pstation->GetStationType()->HasCapability(c_sabmRestart))
break;
}
if (psl == NULL)
{
DeactivateSide(psideOld);
}
}
}
return psideWon;
}
IsideIGC* CFSMission::CheckForVictoryByKills(IsideIGC* psideTest)
{
if ((STAGE_STARTED == GetStage()) && (m_psideWon == NULL))
{
const MissionParams* pmp = m_pMission->GetMissionParams();
if (pmp->IsDeathMatchGame())
{
if (psideTest->GetKills() >= pmp->nGoalTeamKills)
{
return psideTest;
}
}
}
return NULL;
}
IsideIGC* CFSMission::CheckForVictoryByInactiveSides(bool& bAllSidesInactive)
{
bAllSidesInactive = true;
IsideIGC* pSideWin = NULL;
const SideListIGC * plistSide = m_pMission->GetSides();
for (SideLinkIGC * plinkSide = plistSide->first(); plinkSide; plinkSide = plinkSide->next())
{
IsideIGC * pside = plinkSide->data();
if (HasPlayers(pside, false) && pside->GetActiveF()) {
bAllSidesInactive = false;
if (pSideWin)
{
pSideWin = NULL;
break;
}
else
pSideWin = pside;
}
}
#if defined(ALLSRV_STANDALONE)
if (m_misdef.misparms.nTotalMaxPlayersPerGame == 1 && GetStage() == STAGE_STARTING)
{
pSideWin = NULL;
}
#endif
if (pSideWin && GetStage() == STAGE_STARTING)
{
bool bFoundNormalPlayer = false;
const ShipListIGC* pships = m_pMission->GetShips();
for (ShipLinkIGC* psl = pships->first(); (psl != NULL); psl = psl->next())
{
CFSShip* pfsShip = (CFSShip *)(psl->data()->GetPrivateData());
if (pfsShip->IsPlayer() && !pfsShip->GetPlayer()->CanCheat())
{
bFoundNormalPlayer = true;
break;
}
}
if (!bFoundNormalPlayer)
pSideWin = NULL;
}
if ((GetStage() == STAGE_STARTING) && m_misdef.misparms.bAllowEmptyTeams)
{
pSideWin = NULL;
}
return pSideWin;
}
IsideIGC* CFSMission::CheckForVictoryByFlags(IsideIGC* psideTest, SideID sidFlag)
{
if ((STAGE_STARTED == GetStage()) && (m_psideWon == NULL))
{
const MissionParams* pmp = m_pMission->GetMissionParams();
if (pmp->IsArtifactsGame() || pmp->IsFlagsGame())
{
BEGIN_PFM_CREATE(g.fm, pfmGameState, S, GAME_STATE)
END_PFM_CREATE
SideID sid = 0;
for (SideLinkIGC* l = m_pMission->GetSides()->first(); (l != NULL); l = l->next())
{
assert (sid == l->data()->GetObjectID());
pfmGameState->conquest[sid] = l->data()->GetConquestPercent();
pfmGameState->territory[sid] = l->data()->GetTerritoryCount();
pfmGameState->nFlags[sid] = l->data()->GetFlags();
pfmGameState->nArtifacts[sid++] = l->data()->GetArtifacts();
}
g.fm.SendMessages(GetGroupRealSides(), FM_GUARANTEED, FM_FLUSH);
if (sidFlag != SIDE_TEAMLOBBY)
{
if (psideTest->GetFlags() >= pmp->nGoalFlagsCount)
{
return psideTest;
}
}
else
{
if (psideTest->GetArtifacts() >= pmp->nGoalArtifactsCount)
{
return psideTest;
}
}
}
}
return NULL;
}
void CFSMission::CreateDPGroups(IclusterIGC * pcluster)
{
ClusterGroups * pcg = new ClusterGroups;
char szDocked[] = "Everyone docked in sector ";
char szFlying[] = "Everyone flying in sector ";
char szBuff[max(sizeof(szDocked), sizeof(szFlying)) + c_cbName + 1];
wsprintf(szBuff, "%s%s", szDocked, pcluster->GetName());
pcg->pgrpClusterDocked = g.fm.CreateGroup(szBuff);
wsprintf(szBuff, "%s%s", szDocked, pcluster->GetName());
pcg->pgrpClusterFlying = g.fm.CreateGroup(szBuff);
((CFSCluster*)pcluster->GetPrivateData())->SetClusterGroups(pcg);
}
void CFSMission::SendLobbyMissionInfo(CFSPlayer * pfsPlayer)
{
ImissionIGC * pMission = GetIGCMission();
g.fm.SetDefaultRecipient((CFMRecipient*)(pfsPlayer->GetConnection()),
FM_GUARANTEED);
g.fm.QueueExistingMsg(GetMissionDef());
BEGIN_PFM_CREATE(g.fm, pfmJoinedMission, S, JOINED_MISSION)
END_PFM_CREATE
pfmJoinedMission->shipID = pfsPlayer->GetShipID();
pfmJoinedMission->dwCookie = GetCookie();
const SideListIGC * pstlist = pMission->GetSides();
SideLinkIGC * pstlink;
for (pstlink = pstlist->first(); pstlink; pstlink = pstlink->next())
ExportObj(pstlink->data(), OT_side, NULL);
g.fm.SendMessages(NULL, FM_GUARANTEED, FM_FLUSH);
const ShipListIGC * pshiplist = pMission->GetShips();
for (ShipLinkIGC * pshiplink = pshiplist->first();
pshiplink;
pshiplink = pshiplink->next())
{
IshipIGC* pship = pshiplink->data();
CFSShip * pfsShip = (CFSShip *)(pship->GetPrivateData());
SendPlayerInfo(pfsPlayer, pfsShip, this, false);
}
g.fm.SendMessages(pfsPlayer->GetConnection(), FM_GUARANTEED, FM_FLUSH);
}
void CFSMission::QueueLobbyMissionInfo()
{
assert(g.fmLobby.IsConnected());
SquadID rgSquadIDs[c_cSidesMax];
int nSquadCount = 0;
{
const SideListIGC * plistSide = m_pMission->GetSides();
for (SideLinkIGC * plinkSide = plistSide->first(); plinkSide; plinkSide = plinkSide->next())
{
SquadID squadID = plinkSide->data()->GetSquadID();
if (squadID != NA && 0 != plinkSide->data()->GetShips()->n()
&& (STAGE_STARTED != GetStage() || plinkSide->data()->GetActiveF()))
{
rgSquadIDs[nSquadCount] = squadID;
++nSquadCount;
}
}
}
char szAddr[16]= "XXX-YYY-ZZZ-TTT"; BEGIN_PFM_CREATE(g.fmLobby, pfmLobbyMissionInfo, LS, LOBBYMISSIONINFO)
FM_VAR_PARM(m_misdef.misparms.strGameName, CB_ZTS)
FM_VAR_PARM(nSquadCount ? rgSquadIDs : NULL, nSquadCount * sizeof(SquadID))
FM_VAR_PARM((PCC)m_strDetailsFiles, CB_ZTS)
FM_VAR_PARM(m_misdef.misparms.szIGCStaticFile,CB_ZTS)
FM_VAR_PARM((PCC)(g.strLocalAddress),CB_ZTS) FM_VAR_PARM(szAddr,16) END_PFM_CREATE
pfmLobbyMissionInfo->dwCookie = GetCookie();
pfmLobbyMissionInfo->dwStartTime = m_misdef.misparms.timeStart.clock() - Time::Now().clock();
pfmLobbyMissionInfo->fGuaranteedSlotsAvailable = false;
pfmLobbyMissionInfo->fAnySlotsAvailable = false;
pfmLobbyMissionInfo->nNumPlayers = GetCountOfPlayers(NULL, false);
if ((m_misdef.misparms.bAllowJoiners || STAGE_NOTSTARTED == GetStage())
&& !m_misdef.misparms.bLockLobby && STAGE_OVER != GetStage())
{
const SideListIGC * plistSide = m_pMission->GetSides();
for (SideLinkIGC * plinkSide = plistSide->first(); plinkSide; plinkSide = plinkSide->next())
{
IsideIGC * pside = plinkSide->data();
int nNumPlayersOnSide = GetCountOfPlayers(pside, false);
int nAvailablePositions = m_misdef.misparms.nMaxPlayersPerTeam - nNumPlayersOnSide;
if ((STAGE_NOTSTARTED == GetStage() || (GetBase(pside) && pside->GetActiveF()))
&& nAvailablePositions && STAGE_OVER != GetStage())
{
pfmLobbyMissionInfo->fAnySlotsAvailable = true;
if (GetAutoAccept(pside)
|| (m_misdef.fAutoAcceptLeaders && !GetLeader(pside->GetObjectID())))
{
pfmLobbyMissionInfo->fGuaranteedSlotsAvailable = true;
}
}
}
}
pfmLobbyMissionInfo->nTeams = m_misdef.misparms.nTeams;
pfmLobbyMissionInfo->nMinRank = m_misdef.misparms.iMinRank;
pfmLobbyMissionInfo->nMaxRank = m_misdef.misparms.iMaxRank;
pfmLobbyMissionInfo->nMaxPlayersPerGame = min(m_misdef.misparms.nTotalMaxPlayersPerGame,
m_misdef.misparms.nTeams
* m_misdef.misparms.nMaxPlayersPerTeam);
pfmLobbyMissionInfo->nMinPlayersPerTeam = m_misdef.misparms.nMinPlayersPerTeam;
pfmLobbyMissionInfo->nMaxPlayersPerTeam = m_misdef.misparms.nMaxPlayersPerTeam;
pfmLobbyMissionInfo->fInProgress = m_misdef.fInProgress;
pfmLobbyMissionInfo->fCountdownStarted = (GetStage() == STAGE_STARTING
|| (GetStage() == STAGE_NOTSTARTED && m_misdef.misparms.bAutoRestart));
pfmLobbyMissionInfo->fMSArena = m_misdef.misparms.bObjectModelCreated;
pfmLobbyMissionInfo->fScoresCount = m_misdef.misparms.bScoresCount;
pfmLobbyMissionInfo->fInvulnerableStations = m_misdef.misparms.bInvulnerableStations;
pfmLobbyMissionInfo->fAllowDevelopments = m_misdef.misparms.bAllowDevelopments;
pfmLobbyMissionInfo->fLimitedLives = m_misdef.misparms.iLives != 0x7fff;
pfmLobbyMissionInfo->fConquest = m_misdef.misparms.IsConquestGame();
pfmLobbyMissionInfo->fDeathMatch = m_misdef.misparms.IsDeathMatchGame();
pfmLobbyMissionInfo->fCountdown = m_misdef.misparms.IsCountdownGame();
pfmLobbyMissionInfo->fProsperity = m_misdef.misparms.IsProsperityGame();
pfmLobbyMissionInfo->fArtifacts = m_misdef.misparms.IsArtifactsGame();
pfmLobbyMissionInfo->fFlags = m_misdef.misparms.IsFlagsGame();
pfmLobbyMissionInfo->fTerritorial = m_misdef.misparms.IsTerritoryGame();
pfmLobbyMissionInfo->fSquadGame = m_misdef.misparms.bSquadGame;
pfmLobbyMissionInfo->fEjectPods = m_misdef.misparms.bEjectPods;
}
void CFSMission::SendMissionInfo(CFSPlayer * pfsPlayer, IsideIGC* pside)
{
ImissionIGC * pMission = GetIGCMission();
g.fm.SetDefaultRecipient(pfsPlayer ?
(CFMRecipient*) pfsPlayer->GetConnection() :
(CFMRecipient*) CFSSide::FromIGC(pside)->GetGroup(),
FM_GUARANTEED);
SideID sideID = pside->GetObjectID();
const ClusterListIGC * pclstlist = pMission->GetClusters();
ClusterLinkIGC * pclstlink;
for (pclstlink = pclstlist->first(); pclstlink; pclstlink = pclstlink->next())
{
IclusterIGC * pcluster = pclstlink->data();
ExportObj(pcluster, OT_cluster, NULL);
{
const WarpListIGC * pwarplist = pcluster->GetWarps();
WarpLinkIGC * pwarplink;
for (pwarplink = pwarplist->first(); pwarplink; pwarplink = pwarplink->next())
{
if (pwarplink->data()->SeenBySide(pside))
ExportObj(pwarplink->data(), OT_warp, NULL);
}
for (pwarplink = pwarplist->first(); pwarplink; pwarplink = pwarplink->next())
{
const WarpBombList* plist = pwarplink->data()->GetBombs();
if (plist->first() && (pwarplink->data()->SeenBySide(pside)))
for (WarpBombLink* p = plist->first(); (p != NULL); p = p->next())
{
BEGIN_PFM_CREATE(g.fm, pfmWB, S, WARP_BOMB)
END_PFM_CREATE
pfmWB->timeExplosion = p->data().timeExplosion;
pfmWB->warpidBombed = pwarplink->data()->GetObjectID();
pfmWB->expendableidMissile = p->data().pmt->GetObjectID();
}
}
}
const AsteroidListIGC * pmdllist = pcluster->GetAsteroids();
AsteroidLinkIGC * pmdllink;
for (pmdllink = pmdllist->first(); pmdllink; pmdllink = pmdllink->next())
{
if (pmdllink->data()->SeenBySide(pside))
{
ExportObj(pmdllink->data(), OT_asteroid, NULL);
IbuildingEffectIGC* pbe = pmdllink->data()->GetBuildingEffect();
if (pbe)
ExportObj(pbe, OT_buildingEffect, NULL);
}
}
const StationListIGC * pstnlist = pcluster->GetStations();
StationLinkIGC * pstnlink;
for (pstnlink = pstnlist->first(); pstnlink; pstnlink = pstnlink->next())
{
if (pstnlink->data()->SeenBySide(pside))
ExportObj(pstnlink->data(), OT_station, NULL);
}
const TreasureListIGC * ptlist = pcluster->GetTreasures();
TreasureLinkIGC * ptlink;
for (ptlink = ptlist->first(); ptlink; ptlink = ptlink->next())
{
if (ptlink->data()->SeenBySide(pside))
ExportObj(ptlink->data(), OT_treasure, NULL);
}
const MineListIGC * pmlist = pcluster->GetMines();
MineLinkIGC * pmlink;
for (pmlink = pmlist->first(); pmlink; pmlink = pmlink->next())
{
if (pmlink->data()->SeenBySide(pside))
ExportObj(pmlink->data(), OT_mine, NULL);
}
const ProbeListIGC * pplist = pcluster->GetProbes();
ProbeLinkIGC * pplink;
for (pplink = pplist->first(); pplink; pplink = pplink->next())
{
if (pplink->data()->SeenBySide(pside))
ExportObj(pplink->data(), OT_probe, NULL);
}
}
BEGIN_PFM_CREATE(g.fm, pfmCreateBuckets, S, CREATE_BUCKETS)
END_PFM_CREATE
pfmCreateBuckets->ttbmDevelopments = pside->GetDevelopmentTechs();
pfmCreateBuckets->ttbmInitial = pside->GetInitialTechs();
{
for (BucketLinkIGC* pbl = pside->GetBuckets()->first(); (pbl != NULL); pbl = pbl->next())
{
IbucketIGC* pbucket = pbl->data();
{
BEGIN_PFM_CREATE(g.fm, pfmBucketStatus, S, BUCKET_STATUS)
END_PFM_CREATE
pfmBucketStatus->timeTotal = pbucket->GetTime();
pfmBucketStatus->moneyTotal = pbucket->GetMoney();
pfmBucketStatus->iBucket = pbucket->GetObjectID();
pfmBucketStatus->sideID = sideID;
}
}
}
for (ShipLinkIGC* psl = pside->GetShips()->first(); (psl != NULL); psl = psl->next())
{
IshipIGC* ps = psl->data();
if (!pfsPlayer || ps != pfsPlayer->GetIGCShip())
{
CFSShip* pcs = (CFSShip *)(ps->GetPrivateData());
if (pcs->IsPlayer())
{
CFSPlayer* pcp = pcs->GetPlayer();
IshipIGC* pshipDonate = ps->GetAutoDonate();
ShipID shipID = ps->GetObjectID();
BEGIN_PFM_CREATE(g.fm, pfmDonate, S, AUTODONATE)
END_PFM_CREATE
pfmDonate->sidDonateTo = pshipDonate ? pshipDonate->GetObjectID() : NA;
pfmDonate->sidDonateBy = shipID;
pfmDonate->amount = 0;
BEGIN_PFM_CREATE(g.fm, pfmMoney, S, SET_MONEY)
END_PFM_CREATE
pfmMoney->shipID = shipID;
pfmMoney->money = pcp->GetMoney();
}
}
}
{
const ShipListIGC * plistShip = m_pMission->GetShips();
for (ShipLinkIGC * plinkShip = plistShip->first(); plinkShip; plinkShip = plinkShip->next())
{
IshipIGC* pship = plinkShip->data();
if (pship->GetSide()->GetObjectID() >= 0)
{
CFSShip* pcs = (CFSShip *)(pship->GetPrivateData());
ShipStatus* pss = pcs->GetShipStatus(sideID);
BEGIN_PFM_CREATE(g.fm, pfmShipStatus, S, SHIP_STATUS)
END_PFM_CREATE
pfmShipStatus->shipID = pship->GetObjectID();
pfmShipStatus->status = *pss;
}
}
}
{
BEGIN_PFM_CREATE(g.fm, pfmGameState, S, GAME_STATE)
END_PFM_CREATE
SideID sid = 0;
for (SideLinkIGC* l = m_pMission->GetSides()->first(); (l != NULL); l = l->next())
{
assert (sid == l->data()->GetObjectID());
pfmGameState->conquest[sid] = l->data()->GetConquestPercent();
pfmGameState->territory[sid] = l->data()->GetTerritoryCount();
pfmGameState->nFlags[sid] = l->data()->GetFlags();
pfmGameState->nArtifacts[sid++] = l->data()->GetArtifacts();
}
}
g.fm.SendMessages(NULL, FM_GUARANTEED, FM_FLUSH); }
CFSMission * CFSMission::GetMission(DWORD dwCookie)
{
for (LinkFSMission * plinkFSMis = s_list.first(); plinkFSMis; plinkFSMis = plinkFSMis->next())
{
CFSMission * pfsMission = plinkFSMis->data();
if (pfsMission->GetCookie() == dwCookie)
return pfsMission;
}
return NULL;
}
CFSMission * CFSMission::GetMissionFromIGCMissionID(DWORD dwIGCMissionID)
{
for (LinkFSMission * plinkFSMis = s_list.first(); plinkFSMis; plinkFSMis = plinkFSMis->next())
{
CFSMission * pfsMission = plinkFSMis->data();
if (pfsMission->m_pMission->GetMissionID() == dwIGCMissionID)
return pfsMission;
}
return NULL;
}
bool CFSMission::FAllReady()
{
{
int minPlayers;
int maxPlayers;
int minTeamRank = 1000000; int maxTeamRank = 1; SideLinkIGC* psl = m_pMission->GetSides()->first();
assert (psl);
minPlayers = m_misdef.misparms.nMaxPlayersPerTeam; maxPlayers = 0; while (true)
{
int n = psl->data()->GetShips()->n();
bool bSkipTeam = false;
if (m_misdef.misparms.bAllowEmptyTeams)
if (n==0 && !m_misdef.rgfActive[psl->data()->GetObjectID()])
bSkipTeam = true; if (!bSkipTeam)
{
if (n < minPlayers)
minPlayers = n;
if (n > maxPlayers)
maxPlayers = n;
int r = GetSideRankSum(psl->data(), false);
if (r < minTeamRank)
minTeamRank = r;
if (r > maxTeamRank)
maxTeamRank = r;
}
psl = psl->next();
if (psl == NULL)
break;
}
int threshold = GetRankThreshold();
if ((minPlayers < m_misdef.misparms.nMinPlayersPerTeam) ||
(maxPlayers > m_misdef.misparms.nMaxPlayersPerTeam) ||
(minPlayers + m_misdef.misparms.iMaxImbalance < maxPlayers) ||
((m_misdef.misparms.iMaxImbalance == 0x7ffe) && (maxTeamRank - minTeamRank) > threshold)) return false;
}
SideID iSide = m_misdef.misparms.nTeams;
while (iSide-- > 0 && (
GetReady(iSide) ||
(m_misdef.misparms.bAllowEmptyTeams && (!m_misdef.rgfActive[iSide]))
));
;
return iSide < 0;
}
SideID CFSMission::PickNewSide(CFSPlayer* pfsPlayer, bool bAllowTeamLobby, unsigned char bannedSideMask)
{
if (bAllowTeamLobby && (GetStage() > STAGE_NOTSTARTED))
return SIDE_TEAMLOBBY;
IsideIGC * psideFewestPlayers = NULL;
IsideIGC * psideLowestRank = NULL;
int nFewestPlayers = 2147483646; int nLowestRank = 2147483646; int nNumPlayers = -1;
int nRankSum = -1;
const SideListIGC * plistSide = m_pMission->GetSides();
for (SideLinkIGC * plinkSide = plistSide->first(); plinkSide; plinkSide = plinkSide->next())
{
IsideIGC* pside = plinkSide->data();
if (m_misdef.rgfActive[pside->GetObjectID()])
if ((SideMask(pside) & bannedSideMask) == 0)
{
nNumPlayers = GetCountOfPlayers(pside, false); nRankSum = GetSideRankSum(pside, false); if (CheckPositionRequest(pfsPlayer, pside) == NA) {
if (nRankSum < nLowestRank)
{
psideLowestRank = pside;
nLowestRank = nRankSum;
}
if (nNumPlayers < nFewestPlayers)
{
psideFewestPlayers = pside;
nFewestPlayers = nNumPlayers;
}
}
}
}
IsideIGC * psideNewSide = psideLowestRank;
int nImbalance = m_misdef.misparms.iMaxImbalance;
if (nImbalance != 0x7fff && nImbalance != 0x7fff && psideNewSide != NULL)
{
int nRankedTeamPlayers = GetCountOfPlayers(psideNewSide, false);
if (nRankedTeamPlayers + 1 > nFewestPlayers + nImbalance)
{
psideNewSide = psideFewestPlayers;
}
}
return psideNewSide
? psideNewSide->GetObjectID()
: SIDE_TEAMLOBBY;
}
DelPositionReqReason CFSMission::CheckPositionRequest(CFSPlayer * pfsPlayer, IsideIGC * pside)
{
assert(pside);
SideID sideID = pside->GetObjectID();
const MissionParams* pmp = m_pMission->GetMissionParams();
IsideIGC* psideCurrent = pfsPlayer->GetSide();
if ((!pmp->bAllowDefections) && (GetStage() == STAGE_STARTED)
&& (sideID != pfsPlayer->GetLastSide()) && (pfsPlayer->GetLastSide() != SIDE_TEAMLOBBY))
return DPR_NoDefections;
if (psideCurrent && psideCurrent->GetObjectID() != SIDE_TEAMLOBBY)
{
if ((!pmp->bAllowDefections) && (GetStage() == STAGE_STARTED))
return DPR_NoDefections;
else if (pmp->bLockSides && sideID != SIDE_TEAMLOBBY) return DPR_SidesLocked;
}
if (sideID != SIDE_TEAMLOBBY)
{
if (!m_misdef.rgfActive[sideID])
return DPR_SideGone;
if (GetStage() == STAGE_OVER)
return DPR_ServerPaused;
if (pfsPlayer->GetBannedSideMask() & SideMask(sideID))
return DPR_Banned;
if (RequiresInvitation() && !CFSSide::FromIGC(pside)->IsInvited(pfsPlayer))
return DPR_PrivateGame;
int nNumPlayers = GetCountOfPlayers(pside, false);
int maxPlayers = pmp->nMaxPlayersPerTeam;
if ((STAGE_NOTSTARTED != GetStage()) && (pmp->iMaxImbalance != 0x7fff))
{
for (SideLinkIGC* psl = m_pMission->GetSides()->first(); (psl != NULL); psl = psl->next())
{
if (psl->data()->GetActiveF())
{
int count = GetCountOfPlayers(psl->data(), false) + pmp->iMaxImbalance;
if (count < maxPlayers)
maxPlayers = count;
}
}
}
if (STAGE_NOTSTARTED != GetStage())
{
if (!GetBase(pside))
return DPR_NoBase;
else if (!pside->GetActiveF())
return DPR_SideDefeated;
}
if (GetCountOfPlayers(pside, false) >= pmp->nMaxPlayersPerTeam)
return DPR_TeamFull;
else if (nNumPlayers >= maxPlayers)
return DPR_TeamBalance;
if ((STAGE_NOTSTARTED != GetStage()) && (pmp->iMaxImbalance == 0x7ffe))
{
int nRequestedSideRank = GetSideRankSum(pside, false);
int nHighestTeamRank = 0;
int nLowestTeamRank = 2147483646;
for (SideLinkIGC* psl = m_pMission->GetSides()->first(); (psl != NULL); psl = psl->next())
{
IsideIGC* pTempSide = psl->data();
if (pTempSide->GetActiveF())
{
int nTempSideRank = GetSideRankSum(pTempSide, false);
if (nTempSideRank < nLowestTeamRank)
nLowestTeamRank = nTempSideRank;
if (nTempSideRank > nHighestTeamRank)
nHighestTeamRank = nTempSideRank;
}
}
if (nRequestedSideRank != nLowestTeamRank)
return DPR_TeamBalance;
#if 0
int nPlayerRank = pfsPlayer->GetPersistPlayerScore(NA)->GetRank();
int nRankThreshold = GetRankThreshold();
int nNewSideRank = nRequestedSideRank + nPlayerRank;
if (nNewSideRank - nLowestTeamRank > nRankThreshold) {
debugf("join blocked would unbalance sides Rank=%d, NewSideRank=%d, RequestedSideRank=%d, LowestTeamRank=%d, RankThreshold=%d\n",
nPlayerRank,nNewSideRank,nRequestedSideRank,nLowestTeamRank,nRankThreshold);
return DPR_TeamBalance;
}
if (nPlayerRank <= 8 && nRequestedSideRank == nLowestTeamRank)
{
int nDifference = nHighestTeamRank - nRequestedSideRank;
if (nDifference > nRankThreshold) {
debugf("join blocked (newbstack) Rank=%d, Difference=%d, RequestedSideRank=%d, HighestTeamRank=%d, RankThreshold=%d\n",
nPlayerRank,nDifference,nRequestedSideRank,nHighestTeamRank,nRankThreshold);
return DPR_TeamBalance;
}
}
#endif
}
if (m_misdef.misparms.bSquadGame)
{
if (nNumPlayers > 0)
{
if (!pfsPlayer->GetIsMemberOfSquad(pside->GetSquadID()))
return DPR_WrongSquad;
}
else
{
if (pfsPlayer->GetPreferredSquadToLead() == NA)
return DPR_CantLeadSquad;
}
}
}
return (DelPositionReqReason)NA;
}
void CFSMission::RequestPosition(CFSPlayer * pfsPlayer, IsideIGC * pside, bool bRejoin)
{
assert(pside);
SideID sideID = pside->GetObjectID();
const MissionParams* pmp = m_pMission->GetMissionParams();
DelPositionReqReason reason = CheckPositionRequest(pfsPlayer, pside);
if (reason != NA)
{
BEGIN_PFM_CREATE(g.fm, pfmDelPosReq, CS, DELPOSITIONREQ)
END_PFM_CREATE
pfmDelPosReq->shipID = pfsPlayer->GetShipID();
pfmDelPosReq->iSide = sideID;
pfmDelPosReq->reason = reason;
g.fm.SendMessages(pfsPlayer->GetConnection(), FM_GUARANTEED, FM_FLUSH);
return;
}
if (pfsPlayer->GetSide()->GetObjectID() != SIDE_TEAMLOBBY)
{
RemovePlayerFromSide(pfsPlayer, QSR_SwitchingSides);
}
if (sideID != SIDE_TEAMLOBBY)
{
if ((!GetLeader(sideID) && m_misdef.fAutoAcceptLeaders)
|| bRejoin
|| m_misdef.rgfAutoAccept[sideID])
{
AddPlayerToSide(pfsPlayer, pside);
}
else {
BEGIN_PFM_CREATE(g.fm, pfmSPositionReq, S, POSITIONREQ)
END_PFM_CREATE
pfmSPositionReq->shipID = pfsPlayer->GetShipID();
pfmSPositionReq->iSide = sideID;
g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
AddJoinRequest(pfsPlayer, pside);
}
}
}
void CFSMission::VacateStation(IstationIGC * pstation)
{
assert (pstation->GetMission() == m_pMission);
IsideIGC* psideGhost = NULL;
const ShipListIGC* pships = pstation->GetShips();
ShipLinkIGC* pshiplink = pships->first();
while (pshiplink)
{
IshipIGC* pship = pshiplink->data();
if (pship->GetParentShip() == NULL)
{
if (pship->IsGhost())
{
psideGhost = pship->GetSide();
pshiplink = pshiplink->next();
}
else
{
for (ShipLinkIGC* psl = pship->GetChildShips()->first();
(psl != NULL);
psl = psl->next())
{
psl->data()->SetStation(NULL);
}
pship->SetStation(NULL);
CFSShip* pfsship = (CFSShip*)(pship->GetPrivateData());
if (pfsship->IsPlayer())
pfsship->GetPlayer()->ForceLoadoutChange();
pshiplink = pships->first();
}
}
else
pshiplink = pshiplink->next();
}
if (psideGhost)
{
for (StationLinkIGC* psl = psideGhost->GetStations()->first(); (psl != NULL); psl = psl->next())
{
IstationIGC* ps = psl->data();
if ((ps != pstation) && ps->GetBaseStationType()->HasCapability(c_sabmRestart))
{
ShipLinkIGC* pshiplink = pships->first();
while (pshiplink)
{
IshipIGC* pship = pshiplink->data();
pshiplink = pshiplink->next();
assert (pship->GetParentShip() == NULL);
assert (pship->IsGhost());
pship->SetStation(ps);
}
break;
}
}
}
}
void CFSMission::AddJoinRequest(CFSPlayer * pfsPlayer, IsideIGC * pside)
{
JoinRequest * pjr = new JoinRequest;
pjr->pfsPlayer = pfsPlayer;
pjr->pSide = pside;
m_listJoinReq.last(pjr);
assert(pfsPlayer->GetMission() == this);
}
void CFSMission::NotifyPlayerBoot(CFSPlayer * pfsPlayer, IsideIGC * pSide)
{
BEGIN_PFM_CREATE(g.fm, pfmDelPosReq, CS, DELPOSITIONREQ)
END_PFM_CREATE
pfmDelPosReq->shipID = pfsPlayer->GetShipID();
pfmDelPosReq->iSide = pSide->GetObjectID();
pfmDelPosReq->reason = DPR_Rejected;
g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
}
bool CFSMission::RejectSideJoinRequests(IsideIGC * pSide)
{
bool fAny = false;
LinkJoinReq* plinkNext;
for (LinkJoinReq* plinkJR = m_listJoinReq.first(); (plinkJR != NULL); plinkJR = plinkNext)
{
plinkNext = plinkJR->next();
JoinRequest * pjr = plinkJR->data();
if (pjr->pSide == pSide)
{
NotifyPlayerBoot(pjr->pfsPlayer, pjr->pSide);
delete plinkJR;
delete pjr;
fAny = true;
}
}
return fAny;
}
bool CFSMission::RemoveJoinRequest(CFSPlayer * pfsPlayer, IsideIGC * psideDest)
{
bool fAny = false;
LinkJoinReq* plinkNext;
for (LinkJoinReq* plinkJR = m_listJoinReq.first(); (plinkJR != NULL); plinkJR = plinkNext)
{
plinkNext = plinkJR->next();
JoinRequest * pjr = plinkJR->data();
if (pjr->pfsPlayer == pfsPlayer || !pfsPlayer)
{
if (!psideDest)
NotifyPlayerBoot(pjr->pfsPlayer, pjr->pSide);
delete plinkJR;
delete pjr;
fAny = true;
}
}
return fAny;
}
void CFSMission::SetAutoAccept(IsideIGC * pside, bool fAccept)
{
assert(IMPLIES(!pside, !fAccept));
SideID sideID = pside ? pside->GetObjectID() : NA;
if (pside)
m_misdef.rgfAutoAccept[sideID] = fAccept;
if (pside && fAccept || !pside)
{
LinkJoinReq* plinkNext;
for (LinkJoinReq* plinkJR = m_listJoinReq.first(); (plinkJR != NULL); plinkJR = plinkNext)
{
plinkNext = plinkJR->next();
JoinRequest * pjr = plinkJR->data();
if (pjr->pSide == pside || !pside)
{
delete plinkJR;
CFSPlayer* pfsPlayer = pjr->pfsPlayer;
delete pjr;
if (pside)
{
RequestPosition(pfsPlayer, pside, false);
}
}
}
}
}
void CFSMission::SetLockLobby(bool bLock)
{
m_misdef.misparms.bLockLobby = bLock;
m_pMission->SetMissionParams(&m_misdef.misparms);
SetLobbyIsDirty();
}
void CFSMission::SetLockSides(bool bLock)
{
m_misdef.misparms.bLockSides = bLock;
m_pMission->SetMissionParams(&m_misdef.misparms);
}
void CFSMission::SetMaxTeamImbalance(int imbalance)
{
m_misdef.misparms.iMaxImbalance = imbalance;
m_pMission->SetMissionParams(&m_misdef.misparms);
}
void CFSMission::FlushSides()
{
assert(GetStage() == STAGE_NOTSTARTED);
{
for (SideLinkIGC* psl = m_pMission->GetSides()->first(); psl != NULL; psl = psl->next())
{
if (GetAutoAccept(psl->data()))
{
SetAutoAccept(psl->data(), false);
BEGIN_PFM_CREATE(g.fm, pfmAutoAccept, CS, AUTO_ACCEPT)
END_PFM_CREATE
pfmAutoAccept->iSide = psl->data()->GetObjectID();
pfmAutoAccept->fAutoAccept = false;
g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_DONT_FLUSH);
}
}
g.fm.PurgeOutBox();
}
{
const ShipListIGC* pships = m_pMission->GetShips();
ShipLinkIGC* pshipLinkNext;
for (ShipLinkIGC* pshipLink = pships->first();
(pshipLink != NULL);
pshipLink = pshipLinkNext)
{
pshipLinkNext = pshipLink->next();
CFSPlayer* pfsPlayer = ((CFSShip*)(pshipLink->data()->GetPrivateData()))->GetPlayer();
SideID sideID = pfsPlayer->GetSide()->GetObjectID();
pfsPlayer->SetBannedSideMask(0);
if (sideID != SIDE_TEAMLOBBY && GetLeader(sideID) != pfsPlayer)
{
RemovePlayerFromSide(pfsPlayer, QSR_FlushSides);
pfsPlayer->SetLastSide(SIDE_TEAMLOBBY);
}
}
}
g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
}
bool CFSMission::GetLockSides()
{
return m_misdef.misparms.bLockSides;
}
void CFSMission::RandomizeSides()
{
assert(GetStage() == STAGE_NOTSTARTED);
{
for (SideLinkIGC* psl = m_pMission->GetSides()->first(); psl != NULL; psl = psl->next())
{
if (GetAutoAccept(psl->data()))
{
SetAutoAccept(psl->data(), false);
BEGIN_PFM_CREATE(g.fm, pfmAutoAccept, CS, AUTO_ACCEPT)
END_PFM_CREATE
pfmAutoAccept->iSide = psl->data()->GetObjectID();
pfmAutoAccept->fAutoAccept = false;
g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_DONT_FLUSH);
}
}
g.fm.PurgeOutBox();
}
{
const ShipListIGC* pships = m_pMission->GetShips();
ShipLinkIGC* pshipLinkNext;
for (ShipLinkIGC* pshipLink = pships->first();
(pshipLink != NULL);
pshipLink = pshipLinkNext)
{
pshipLinkNext = pshipLink->next();
CFSPlayer* pfsPlayer = ((CFSShip*)(pshipLink->data()->GetPrivateData()))->GetPlayer();
SideID sideID = pfsPlayer->GetSide()->GetObjectID();
pfsPlayer->SetBannedSideMask(0);
if (sideID != SIDE_TEAMLOBBY && GetLeader(sideID) != pfsPlayer)
{
RemovePlayerFromSide(pfsPlayer, QSR_BalanceSides);
pfsPlayer->SetLastSide(SIDE_TEAMLOBBY);
}
}
}
IsideIGC* psideLobby = m_pMission->GetSide(SIDE_TEAMLOBBY);
const ShipListIGC* pshipsLobby = psideLobby->GetShips();
bool bPickTeamFailed = false;
CFSPlayer* pshipHighestRank = NULL;
CFSPlayer* pshipTemp = NULL;
while (pshipsLobby->n() > 0 && !bPickTeamFailed)
{
{
ShipLinkIGC* pshipLinkNext;
pshipTemp = NULL;
pshipHighestRank = NULL;
for (ShipLinkIGC* pshipLink = pshipsLobby->first();
(pshipLink != NULL);
pshipLink = pshipLinkNext)
{
pshipLinkNext = pshipLink->next();
pshipTemp = ((CFSShip*)(pshipLink->data()->GetPrivateData()))->GetPlayer();
RankID rank = pshipTemp->GetPersistPlayerScore(NA)->GetRank();
if (pshipTemp->GetReady())
{
if (pshipHighestRank == NULL)
pshipHighestRank = pshipTemp;
if (pshipTemp->GetPersistPlayerScore(NA)->GetRank() > pshipHighestRank->GetPersistPlayerScore(NA)->GetRank())
pshipHighestRank = pshipTemp;
}
}
if (pshipHighestRank == NULL)
{
bPickTeamFailed = true;
break;
}
}
SideID sideID = PickNewSide(pshipHighestRank, true, pshipHighestRank->GetBannedSideMask());
if (sideID == SIDE_TEAMLOBBY)
bPickTeamFailed = true;
else
AddPlayerToSide(pshipHighestRank, m_pMission->GetSide(sideID));
}
{
g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
}
}
void CFSMission::SetSideCiv(IsideIGC * pside, IcivilizationIGC * pciv)
{
pside->SetCivilization(pciv);
CivID civID = pciv->GetObjectID();
for (ShipLinkIGC* psl = pside->GetShips()->first(); (psl != NULL); psl = psl->next())
{
IshipIGC* pship = psl->data();
CFSShip* pfsship = (CFSShip*)(pship->GetPrivateData());
PlayerScoreObject* ppso = pfsship->GetPlayerScoreObject();
ppso->SetPersist(pfsship->GetPlayer()->GetPersistPlayerScore(civID));
}
}
void CFSMission::SetSideActive(SideID sideid, bool bActive)
{
m_misdef.rgfActive[sideid] = bActive;
}
bool CFSMission::GetSideActive(SideID sideid)
{
return (bool)m_misdef.rgfActive[sideid];
}
void CFSMission::DeactivateSide(IsideIGC * pside)
{
assert(pside->GetMission() == m_pMission);
debugf("DeactivateSide side=%d.\n", pside->GetObjectID());
pside->SetActiveF(false);
SideID sideid = pside->GetObjectID();
m_misdef.rgfActive[sideid] =
m_misdef.rgfReady[sideid] = false;
pside->SetTimeEndured(max(0.0f, Time::Now() - m_misdef.misparms.timeStart));
const ShipListIGC* pships = pside->GetShips();
{
ShipLinkIGC* pslNext;
for (ShipLinkIGC* psl = pships->first(); (psl != NULL); psl = pslNext)
{
pslNext = psl->next();
IshipIGC* pship = psl->data();
if (pship->GetBaseHullType())
{
{
const PartListIGC* parts = pship->GetParts();
PartLinkIGC* plink;
while (plink = parts->first()) plink->data()->Terminate();
}
pship->SetAmmo(0);
pship->SetFuel(0.0f);
}
if (pship->GetPilotType() < c_ptPlayer)
{
m_psiteIGC->KillShipEvent(g.timeNow, pship, NULL, 0.0f, pship->GetPosition(), Vector::GetZero());
}
else
{
if ((pship->GetParentShip() == NULL) && (pship->GetCluster() != NULL))
m_psiteIGC->KillShipEvent(g.timeNow, pship, NULL, -1.0f, pship->GetPosition(), Vector::GetZero()); pship->Reset(false);
((CFSShip*)(pship->GetPrivateData()))->ShipStatusExit();
}
}
}
BEGIN_PFM_CREATE(g.fm, pfmSideInactive, CS, SIDE_INACTIVE) END_PFM_CREATE
pfmSideInactive->sideID = pside->GetObjectID();
pfmSideInactive->bActive = false; pfmSideInactive->bChangeAET = false; g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
GetSite()->SendChatf(NULL, CHAT_EVERYONE, NA, NA, "%s is no more.", pside->GetName());
bool bAllSidesInactive;
IsideIGC* psideWin = CheckForVictoryByInactiveSides(bAllSidesInactive);
if (bAllSidesInactive)
{
if (GetStage() == STAGE_STARTING)
StartGame();
GameOver(NULL, "All sides were destroyed");
}
else if (psideWin)
{
if (GetStage() == STAGE_STARTING)
StartGame();
static char szReason[100]; sprintf(szReason, "%s won by outlasting all other sides.", psideWin->GetName());
GameOver(psideWin, szReason);
}
else if ((m_psideWon == NULL) && pships->n())
{
CFMGroup* pgroup = CFSSide::FromIGC(pside)->GetGroup();
g.fm.SetDefaultRecipient(pgroup, FM_GUARANTEED);
QueueGameoverMessage();
g.fm.SendMessages(pgroup, FM_GUARANTEED, FM_FLUSH);
}
}
void CFSMission::SetForceReady(SideID iSide, bool fForceReady)
{
m_misdef.rgfForceReady[iSide] = fForceReady;
if (fForceReady)
SetReady(iSide, true);
else
CheckForSideAllReady(m_pMission->GetSide(iSide));
}
void CFSMission::SetReady(SideID iSide, bool fReady)
{
if (fReady != GetReady(iSide))
{
BEGIN_PFM_CREATE(g.fm, pfmTeamReady, S, TEAM_READY)
END_PFM_CREATE
pfmTeamReady->iSide = iSide;
pfmTeamReady->fReady =
m_misdef.rgfReady[iSide] = fReady; g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
}
}
void CFSMission::PlayerReadyChange(CFSPlayer * pfsPlayer)
{
if (pfsPlayer->GetSide()->GetObjectID() != SIDE_TEAMLOBBY)
CheckForSideAllReady(pfsPlayer->GetSide());
}
void CFSMission::CheckForSideAllReady(IsideIGC * pside)
{
SideID sideid = pside->GetObjectID();
if (GetCountOfPlayers(pside, false) < m_misdef.misparms.nMinPlayersPerTeam)
SetReady(sideid, false);
else if (GetForceReady(pside->GetObjectID()))
SetReady(sideid, true);
else
{
bool fReady = true;
const ShipListIGC * plistShip = pside->GetShips();
for(ShipLinkIGC * plinkShip = plistShip->first(); plinkShip; plinkShip = plinkShip->next())
{
CFSShip * pfsShip = (CFSShip *) plinkShip->data()->GetPrivateData();
if (pfsShip->IsPlayer())
{
CFSPlayer * pfsPlayer = pfsShip->GetPlayer();
if (!pfsPlayer->GetReady())
{
fReady = false;
break;
}
}
}
SetReady(sideid, fReady);
}
}
void CFSMission::CreateCluster(IclusterIGC * pIclusterIGC)
{
CFSCluster * pCFSCluster = new CFSCluster(pIclusterIGC);
m_pFSClusters.push_back(pCFSCluster);
}
void CFSMission::DeleteCluster(IclusterIGC * pIclusterIGC)
{
CFSCluster * pFSCluster = (CFSCluster *) pIclusterIGC->GetPrivateData();
if (pFSCluster)
{
std::vector<CFSCluster*>::iterator i = std::find(m_pFSClusters.begin(), m_pFSClusters.end(), pFSCluster);
assert(i != m_pFSClusters.end());
delete static_cast<CFSCluster*>(*i);
m_pFSClusters.erase(i);
}
}
void CFSMission::CreateSide(IsideIGC * pIsideIGC)
{
CFSSide * pCFSSide = new CFSSide(pIsideIGC, this);
m_pFSSides.push_back(pCFSSide);
}
void CFSMission::DeleteSide(IsideIGC * pIsideIGC)
{
CFSSide * pFSSide = (CFSSide *) pIsideIGC->GetPrivateData();
if (pFSSide)
{
std::vector<CFSSide*>::iterator i = std::find(m_pFSSides.begin(), m_pFSSides.end(), pFSSide);
assert(i != m_pFSSides.end()); delete (CFSSide*)(*i);
m_pFSSides.erase(i);
}
}
void CFSMission::UpdateLobby(Time now)
{
if (m_fLobbyDirty && (now - m_timeLastLobbyMissionInfo >= c_flUpdateTimeInterval)
&& (GetCookie() != NULL || !g.fmLobby.IsConnected()))
{
m_fLobbyDirty = false;
if (g.fmLobby.IsConnected())
{
QueueLobbyMissionInfo();
g.fmLobby.SendMessages(g.fmLobby.GetServerConnection(), FM_GUARANTEED, FM_FLUSH);
}
m_timeLastLobbyMissionInfo = now;
SetSessionDetails();
}
}
void CFSMission::SetLobbyIsDirty()
{
m_fLobbyDirty = true;
UpdateLobby(Time::Now());
}
bool Ballot::Update(const Time& now)
{
if (m_bCanceled)
return true;
if (m_timeExpiration < now || AllVotesAreIn())
{
if (HasPassed())
OnPassed();
else
OnFailed();
return true;
}
else
return false;
}
void Ballot::Cancel()
{
if (!m_bCanceled)
{
m_bCanceled = true;
}
}
void Ballot::CastVote(CFSPlayer* pfsPlayer, bool bVote)
{
if (m_vShips.Remove(pfsPlayer->GetShipID()) != -1)
{
SideID sideID = pfsPlayer->GetSide()->GetObjectID();
assert(sideID >= 0);
if (sideID >= 0 && m_cAbstaining[sideID] > 0)
{
--m_cAbstaining[sideID];
if (bVote)
++m_cInFavor[sideID];
else
++m_cOpposed[sideID];
}
}
}
BallotID Ballot::GetBallotID()
{
return m_ballotID;
}
BallotType Ballot::GetType()
{
return m_type;
}
void Ballot::Init(CFSPlayer* pfsInitiator, const ZString& strProposalName, const ZString& strBallotText)
{
assert(pfsInitiator);
float c_fVoteDuration = 30.0f;
m_pgroup = CFSSide::FromIGC(pfsInitiator->GetSide())->GetGroup();
m_pmission = pfsInitiator->GetMission();
m_chattarget = CHAT_TEAM;
m_groupID = pfsInitiator->GetSide()->GetObjectID();
m_strProposal = strProposalName;
m_ballotID = s_ballotIDNext++;
m_timeExpiration = Time::Now() + c_fVoteDuration;
m_bCanceled = false;
for (SideID sideID = 0; sideID < c_cSidesMax; ++sideID)
{
m_cAbstaining[sideID] = 0;
m_cInFavor[sideID] = 0;
m_cOpposed[sideID] = 0;
}
assert(pfsInitiator->GetSide());
const ShipListIGC* shipsList = pfsInitiator->GetSide()->GetShips();
m_vShips.Reserve(shipsList->n());
SideID sideIDInitiator = m_groupID;
for (ShipLinkIGC* shipLink = shipsList->first(); shipLink; shipLink = shipLink->next())
{
CFSShip * pfsShip = (CFSShip*)shipLink->data()->GetPrivateData();
if (pfsShip->IsPlayer())
{
++m_cAbstaining[sideIDInitiator];
m_vShips.PushEnd(pfsShip->GetShipID());
}
}
BEGIN_PFM_CREATE(g.fm, pfmBallot, S, BALLOT)
FM_VAR_PARM((PCC)(strBallotText), CB_ZTS)
END_PFM_CREATE
pfmBallot->ballotID = m_ballotID;
pfmBallot->timeExpiration = m_timeExpiration;
pfmBallot->otInitiator = OT_ship;
pfmBallot->oidInitiator = pfsInitiator->GetShipID();
pfmBallot->bHideToLeader = m_bHideToLeader; g.fm.SendMessages(m_pgroup, FM_GUARANTEED, FM_FLUSH);
CastVote(pfsInitiator, true);
}
void Ballot::Init(CFSSide* pfsideInitiator, const ZString& strProposalName, const ZString& strBallotText)
{
assert(pfsideInitiator);
float c_fVoteDuration = 30.0f;
m_pgroup = pfsideInitiator->GetMission()->GetGroupRealSides();
m_pmission = pfsideInitiator->GetMission();
m_chattarget = CHAT_EVERYONE;
m_groupID = NA;
m_strProposal = strProposalName;
m_ballotID = s_ballotIDNext++;
m_timeExpiration = Time::Now() + c_fVoteDuration;
m_bCanceled = false;
for (SideID sideID = 0; sideID < c_cSidesMax; ++sideID)
{
m_cAbstaining[sideID] = 0;
m_cInFavor[sideID] = 0;
m_cOpposed[sideID] = 0;
}
const ShipListIGC* shipsList = pfsideInitiator->GetMission()->GetIGCMission()->GetShips();
m_vShips.Reserve(shipsList->n());
SideID sideIDInitiator = pfsideInitiator->GetSideIGC()->GetObjectID();
assert(sideIDInitiator >= 0);
for (ShipLinkIGC* shipLink = shipsList->first(); shipLink; shipLink = shipLink->next())
{
CFSShip * pfsShip = (CFSShip*)shipLink->data()->GetPrivateData();
IsideIGC* pside = pfsShip->GetSide();
SideID sideIDPlayer = pside->GetObjectID();
if (pfsShip->IsPlayer() && pside->GetActiveF() && sideIDPlayer >= 0 && sideIDPlayer != sideIDInitiator)
{
++m_cAbstaining[sideIDPlayer];
m_vShips.PushEnd(pfsShip->GetShipID());
}
}
BEGIN_PFM_CREATE(g.fm, pfmBallot, S, BALLOT)
FM_VAR_PARM((PCC)(strBallotText), CB_ZTS)
END_PFM_CREATE
pfmBallot->ballotID = m_ballotID;
pfmBallot->timeExpiration = m_timeExpiration;
pfmBallot->otInitiator = OT_side;
pfmBallot->oidInitiator = pfsideInitiator->GetSideIGC()->GetObjectID();
pfmBallot->bHideToLeader = false; g.fm.SendMessages(m_pgroup, FM_GUARANTEED, FM_FLUSH);
}
ZString Ballot::GetTallyString()
{
ZString strMessage;
bool bFirst = true;
for (SideID sideID = 0; sideID < c_cSidesMax; ++sideID)
{
if (m_cAbstaining[sideID] + m_cInFavor[sideID] + m_cOpposed[sideID])
{
if (bFirst)
{
bFirst = false;
strMessage += "(";
}
else
strMessage += ", ";
if (m_chattarget != CHAT_TEAM)
strMessage += ZString(m_pmission->GetIGCMission()->GetSide(sideID)->GetName()) + ":" ;
if (m_cInFavor[sideID])
strMessage += " " + ZString(m_cInFavor[sideID]) + " for";
if (m_cOpposed[sideID])
strMessage += " " + ZString(m_cOpposed[sideID]) + " against";
if (m_cAbstaining[sideID])
strMessage += " " + ZString(m_cAbstaining[sideID]) + " abstained";
}
}
if (!bFirst)
strMessage += ")";
return strMessage;
}
void Ballot::OnPassed()
{
ZString strMessage = m_strProposal + " has passed. " + GetTallyString();
m_pmission->GetSite()->SendChat(NULL, m_chattarget, m_groupID, NA,
strMessage, c_cidNone, NA, NA, NULL, true);
}
void Ballot::OnFailed()
{
ZString strMessage = m_strProposal + " has been defeated. " + GetTallyString();
m_pmission->GetSite()->SendChat(NULL, m_chattarget, m_groupID, NA,
strMessage, c_cidNone, NA, NA, NULL, true);
}
bool Ballot::HasPassed()
{
for (SideID sideID = 0; sideID < c_cSidesMax; ++sideID)
{
if (m_cAbstaining[sideID] + m_cInFavor[sideID] + m_cOpposed[sideID])
{
if (m_cInFavor[sideID] <= m_cOpposed[sideID] + m_cAbstaining[sideID])
{
return false;
}
}
}
return true;
}
bool Ballot::AllVotesAreIn()
{
for (SideID sideID = 0; sideID < c_cSidesMax; ++sideID)
{
if (m_cAbstaining[sideID] != 0)
return false;
}
return true;
}
BallotID Ballot::s_ballotIDNext = 0;
MutinyBallot::MutinyBallot(CFSPlayer* pfsInitiator)
{
m_pside = pfsInitiator->GetSide();
m_idInitiatorShip = pfsInitiator->GetShipID();
m_bHideToLeader = true;
m_type = BALLOT_MUTINY; Init(pfsInitiator, pfsInitiator->GetName() + ZString("'s proposal to mutiny"), pfsInitiator->GetName() + ZString(" has proposed to munity. "));
}
void MutinyBallot::OnPassed()
{
Ballot::OnPassed();
SideID sideID = m_pside->GetObjectID();
if (sideID >= 0 && STAGE_STARTED == m_pmission->GetStage())
{
CFSShip* pfssNewLeader = CFSShip::GetShipFromID(m_idInitiatorShip);
if (pfssNewLeader && pfssNewLeader->IsPlayer() &&
pfssNewLeader->GetSide() == m_pside)
{
CFSPlayer * pfspNewLeader = pfssNewLeader->GetPlayer();
if (pfspNewLeader->GetSide() == m_pside)
{
CFSPlayer * pfspOldLeader = m_pmission->GetLeader(sideID);
assert(pfspOldLeader);
if (pfspOldLeader == pfssNewLeader) return;
pfspNewLeader->SetAutoDonate(NULL,0,false);
Money money = pfspOldLeader->GetMoney();
pfspOldLeader->SetAutoDonate(pfspNewLeader,money,true);
BEGIN_PFM_CREATE(g.fm, pfmMoneyChange, S, MONEY_CHANGE)
END_PFM_CREATE
pfmMoneyChange->dMoney = -money;
pfmMoneyChange->sidTo = pfspOldLeader->GetShipID();
pfmMoneyChange->sidFrom = NA;
g.fm.SendMessages(pfspOldLeader->GetConnection(), FM_GUARANTEED, FM_FLUSH);
m_pmission->SetLeader(pfspNewLeader);
}
}
}
}
ResignBallot::ResignBallot(CFSPlayer* pfsInitiator)
{
m_pside = pfsInitiator->GetSide();
m_bHideToLeader = false; m_type = BALLOT_RESIGN; Init(pfsInitiator, pfsInitiator->GetName() + ZString("'s proposal to resign"), pfsInitiator->GetName() + ZString(" has proposed resigning. "));
}
void ResignBallot::OnPassed()
{
Ballot::OnPassed();
SideID sideID = m_pside->GetObjectID();
if (sideID >= 0 && STAGE_STARTED == m_pmission->GetStage())
{
m_pmission->DeactivateSide(m_pside);
}
}
OfferDrawBallot::OfferDrawBallot(CFSPlayer* pfsInitiator)
{
m_pfside = CFSSide::FromIGC(pfsInitiator->GetSide());
m_bHideToLeader = false; m_type = BALLOT_OFFERDRAW; Init(pfsInitiator, pfsInitiator->GetName() + ZString("'s proposal to offer a draw"), pfsInitiator->GetName() + ZString(" has proposed offering a draw. "));
}
void OfferDrawBallot::OnPassed()
{
Ballot::OnPassed();
m_pmission->GetSite()->SendChat(NULL, m_chattarget, m_groupID, NA,
"A draw is being offered to the other teams.", c_cidNone, NA, NA, NULL, true);
m_pmission->AddBallot(new AcceptDrawBallot(m_pfside));
}
AcceptDrawBallot::AcceptDrawBallot(CFSSide* pfsideInitiator)
{
m_bHideToLeader = false; m_type = BALLOT_ACCEPTDRAW; Init(pfsideInitiator, pfsideInitiator->GetSideIGC()->GetName() + ZString("'s offer of a draw"), pfsideInitiator->GetSideIGC()->GetName() + ZString(" has offered a draw. "));
}
void AcceptDrawBallot::OnPassed()
{
Ballot::OnPassed();
m_pmission->GameOver(NULL, "The game was declared a draw");
}