#ifndef _CLINTLIB_
#define _CLINTLIB_
class MissionInfo;
class SideInfo;
class PlayerInfo;
class ChatInfo;
class IClientEventSink;
class IClientEventSource;
class IAutoDownload;
class IAutoUpdateSink;
struct CachedPart
{
TRef<IpartTypeIGC> ppt;
Mount mount;
bool bDuplicated;
};
typedef Slist_utl<CachedPart> CachedPartList;
typedef Slink_utl<CachedPart> CachedPartLink;
struct CachedLoadout
{
TRef<IhullTypeIGC> pht;
CachedPartList cpl;
};
typedef Slist_utl<CachedLoadout> CachedLoadoutList;
typedef Slink_utl<CachedLoadout> CachedLoadoutLink;
class IClientEventSource : public IObject
{
public:
virtual void AddSink(IClientEventSink* psink) = 0;
virtual void RemoveSink(IClientEventSink* psink) = 0;
virtual void OnAddMission(MissionInfo* pMissionDef) = 0;
virtual void OnDelMission(MissionInfo* pMissionDef) = 0;
virtual void OnMissionCountdown(MissionInfo* pMissionDef) = 0;
virtual void OnMissionStarted(MissionInfo* pMissionDef) = 0;
virtual void OnMissionEnded(MissionInfo* pMissionDef) = 0;
virtual void OnLockLobby(bool bLock) = 0;
virtual void OnLockSides(bool bLock) = 0;
virtual void OnFoundPlayer(MissionInfo* pMissionDef) = 0;
virtual void OnEnterMission() = 0;
virtual void OnAddPlayer(MissionInfo* pMissionDef, SideID sideID, PlayerInfo* pPlayerInfo) = 0;
virtual void OnDelPlayer(MissionInfo* pMissionDef, SideID sideID, PlayerInfo* pPlayerInfo, QuitSideReason reason, const char* szMessageParam = NULL) = 0;
virtual void OnAddRequest(MissionInfo* pMissionDef, SideID sideID, PlayerInfo* pPlayerInfo) = 0;
virtual void OnDelRequest(MissionInfo* pMissionDef, SideID sideID, PlayerInfo* pPlayerInfo, DelPositionReqReason reason) = 0;
virtual void OnTeamInactive(MissionInfo* pMissionDef, SideID sideID) = 0;
virtual void OnTeamReadyChange(MissionInfo* pMissionDef, SideID sideID, bool fTeamReady) = 0;
virtual void OnTeamForceReadyChange(MissionInfo* pMissionDef, SideID sideID, bool fTeamForceReady) = 0;
virtual void OnTeamAutoAcceptChange(MissionInfo* pMissionDef, SideID sideID, bool fAutoAccept) = 0;
virtual void OnTeamCivChange(MissionInfo* pMissionDef, SideID sideID, CivID civID) = 0;
virtual void OnTeamNameChange(MissionInfo* pMissionDef, SideID sideID) = 0;
virtual void OnPlayerStatusChange(MissionInfo* pMissionDef, SideID sideID, PlayerInfo* pPlayerInfo) = 0;
virtual void OnMoneyChange(PlayerInfo* pPlayerInfo) = 0;
virtual void OnBucketChange(BucketChange bc, IbucketIGC* b) = 0;
virtual void OnTechTreeChanged(SideID sid) = 0;
virtual void OnStationCaptured(StationID stationID, SideID sideID) = 0;
virtual void OnModelTerminated(ImodelIGC* pmodel) = 0;
virtual void OnLoadoutChanged(IpartIGC* ppart, LoadoutChange lc) = 0;
virtual void OnPurchaseCompleted(bool bAllPartsBought) = 0;
virtual void OnTurretStateChanging(bool bTurret) = 0;
virtual void OnShipStatusChange(PlayerInfo* pplayer) = 0;
virtual void OnBoardShip(IshipIGC* pshipChild, IshipIGC* pshipParent) = 0;
virtual void OnBoardFailed(IshipIGC* pshipRequestedParent) = 0;
virtual void OnDiscoveredStation(IstationIGC* pstation) = 0;
virtual void OnDiscoveredAsteroid(IasteroidIGC* pasteroid) = 0;
virtual void OnClusterChanged(IclusterIGC* pcluster) = 0;
virtual void OnGameoverStats() = 0;
virtual void OnGameoverPlayers() = 0;
virtual void OnDeleteChatMessage(ChatInfo* pchatInfo) = 0;
virtual void OnNewChatMessage() = 0;
virtual void OnClearChat() = 0;
virtual void OnChatMessageChange() = 0;
virtual void OnLostConnection(const char * szReason) = 0;
virtual void OnEnterModalState() = 0;
virtual void OnLeaveModalState() = 0;
virtual void OnLogonClub() = 0;
virtual void OnLogonClubFailed(bool bRetry, const char * szReason) = 0;
virtual void OnLogonLobby() = 0;
virtual void OnLogonLobbyFailed(bool bRetry, const char * szReason) = 0;
virtual void OnLogonGameServer() = 0;
virtual void OnLogonGameServerFailed(bool bRetry, const char * szReason) = 0;
virtual void OnServersList(int cCores, char *Cores, int cServers, char *Servers) = 0;
};
class IClientEventSink : public IObject
{
public:
static TRef<IClientEventSink> CreateDelegate(IClientEventSink* psink);
virtual void OnAddMission(MissionInfo* pMissionDef) {};
virtual void OnDelMission(MissionInfo* pMissionDef) {};
virtual void OnMissionCountdown(MissionInfo* pMissionDef) {};
virtual void OnMissionStarted(MissionInfo* pMissionDef) {};
virtual void OnMissionEnded(MissionInfo* pMissionDef) {};
virtual void OnLockLobby(bool bLock) {};
virtual void OnLockSides(bool bLock) {};
virtual void OnFoundPlayer(MissionInfo* pMissionDef) {};
virtual void OnEnterMission() {};
virtual void OnAddPlayer(MissionInfo* pMissionDef, SideID sideID, PlayerInfo* pPlayerInfo) {};
virtual void OnDelPlayer(MissionInfo* pMissionDef, SideID sideID, PlayerInfo* pPlayerInfo, QuitSideReason reason, const char* szMessageParam = NULL) {};
virtual void OnAddRequest(MissionInfo* pMissionDef, SideID sideID, PlayerInfo* pPlayerInfo) {};
virtual void OnDelRequest(MissionInfo* pMissionDef, SideID sideID, PlayerInfo* pPlayerInfo, DelPositionReqReason reason) {};
virtual void OnTeamInactive(MissionInfo* pMissionDef, SideID sideID) {};
virtual void OnTeamReadyChange(MissionInfo* pMissionDef, SideID sideID, bool fTeamReady) {};
virtual void OnTeamForceReadyChange(MissionInfo* pMissionDef, SideID sideID, bool fTeamForceReady) {};
virtual void OnTeamAutoAcceptChange(MissionInfo* pMissionDef, SideID sideID, bool fAutoAccept) {};
virtual void OnTeamCivChange(MissionInfo* pMissionDef, SideID sideID, CivID civID) {};
virtual void OnTeamNameChange(MissionInfo* pMissionDef, SideID sideID) {};
virtual void OnPlayerStatusChange(MissionInfo* pMissionDef, SideID sideID, PlayerInfo* pPlayerInfo) {};
virtual void OnMoneyChange(PlayerInfo* pPlayerInfo) {};
virtual void OnBucketChange(BucketChange bc, IbucketIGC* b){};
virtual void OnTechTreeChanged(SideID sid){};
virtual void OnStationCaptured(StationID stationID, SideID sideID) {};
virtual void OnModelTerminated(ImodelIGC* pmodel) {};
virtual void OnLoadoutChanged(IpartIGC* ppart, LoadoutChange lc) {};
virtual void OnPurchaseCompleted(bool bAllPartsBought) {};
virtual void OnTurretStateChanging(bool bTurret) {}
virtual void OnShipStatusChange(PlayerInfo* pplayer) {};
virtual void OnBoardShip(IshipIGC* pshipChild, IshipIGC* pshipParent) {};
virtual void OnBoardFailed(IshipIGC* pshipRequestedParent) {};
virtual void OnDiscoveredStation(IstationIGC* pstation) {};
virtual void OnDiscoveredAsteroid(IasteroidIGC* pasteroid) {};
virtual void OnClusterChanged(IclusterIGC* pcluster) {};
virtual void OnGameoverStats() {};
virtual void OnGameoverPlayers() {};
virtual void OnDeleteChatMessage(ChatInfo* pchatInfo) {};
virtual void OnNewChatMessage() {};
virtual void OnClearChat() {};
virtual void OnChatMessageChange() {};
virtual void OnLostConnection(const char * szReason) {};
virtual void OnEnterModalState() {};
virtual void OnLeaveModalState() {};
virtual void OnLogonClub() {};
virtual void OnLogonClubFailed(bool bRetry, const char * szReason) {};
virtual void OnLogonLobby() {};
virtual void OnLogonLobbyFailed(bool bRetry, const char * szReason) {};
virtual void OnLogonGameServer() {};
virtual void OnLogonGameServerFailed(bool bRetry, const char * szReason) {};
virtual void OnServersList(int cCores, char *Cores, int cServers, char *Servers) {} ;
};
class ChatInfo : public IObject
{
private:
ZString m_strMessage;
Color m_colorMessage;
TRef<ImodelIGC> m_pmodelTarget;
CommandID m_cidCommand;
ChatTarget m_ctRecipient;
bool m_bFromPlayer;
bool m_bFromObjectModel;
bool m_bFromLeader;
public:
void SetChat(ChatTarget ctRecipient,
const ZString& strText,
CommandID cid,
ImodelIGC* pmodelTarget,
const Color& color,
bool bFromPlayer,
bool bFromObjectModel,
bool bFromLeader);
ChatTarget GetChatTarget(void) const { return m_ctRecipient; }
const ZString& GetMessage(void) const { return m_strMessage; }
const Color& GetColor(void) const { return m_colorMessage; }
CommandID GetCommandID(void) const { return m_cidCommand; }
ImodelIGC* GetTarget(void) const { return m_pmodelTarget; }
bool IsFromPlayer(void) const { return m_bFromPlayer; }
bool IsFromLeader(void) const { return m_bFromLeader; }
bool IsFromObjectModel(void) const { return m_bFromObjectModel; }
void ClearTarget(void);
};
typedef Slist_utl<ChatInfo> ChatList;
typedef Slink_utl<ChatInfo> ChatLink;
class BallotInfo
{
ZString m_strBallotText;
BallotID m_ballotID;
Time m_timeExpiration;
public:
BallotInfo(const ZString& strBallotText, BallotID ballotID, Time timeExpiration)
: m_strBallotText(strBallotText), m_ballotID(ballotID), m_timeExpiration(timeExpiration) {};
const ZString& GetBallotText() const { return m_strBallotText; }
Time GetBallotExpirationTime() const { return m_timeExpiration; }
BallotID GetBallotID() const { return m_ballotID; }
};
typedef TList<BallotInfo> BallotList;
class PlayerInfo : public IObject
{
FMD_S_PLAYERINFO m_fmPlayerInfo;
TRef<IshipIGC> m_pship;
ImissionIGC* m_pmission;
ShipStatus m_shipStatus;
PersistPlayerScoreObject* m_vPersistPlayerScores;
int m_cPersistPlayerScores;
PersistPlayerScoreObject m_persist; bool m_bMute;
unsigned int m_ping; unsigned int m_loss; public:
PlayerInfo(void);
~PlayerInfo();
void GetConnectionData(unsigned int * ping,unsigned int * loss)
{
*ping = m_ping;
*loss = m_loss;
}
void SetConnectionData(unsigned int ping, unsigned int loss)
{
m_ping = ping;
m_loss = loss;
}
IshipIGC* GetShip(void) const
{
return m_pship;
}
void SetShip(IshipIGC* pship)
{
m_pship = pship;
if (pship)
pship->SetPrivateData((DWORD)this);
}
void SetMission(ImissionIGC* pmission)
{
m_pmission = pmission;
}
bool GetMute(void) const
{
return m_bMute;
}
void SetMute(bool bMute)
{
m_bMute = bMute;
}
void Set(FMD_S_PLAYERINFO* pfmPlayerInfo);
void Update(FMD_CS_PLAYER_READY* pfmPlayerReady) { m_fmPlayerInfo.fReady = pfmPlayerReady->fReady; }
bool IsMissionOwner(void) const { return m_fmPlayerInfo.fMissionOwner; }
void SetMissionOwner(bool fMissionOwner) { m_fmPlayerInfo.fMissionOwner = fMissionOwner; }
bool IsTeamLeader(void) const { return m_fmPlayerInfo.fTeamLeader; }
void SetTeamLeader(bool fTeamLeader) { m_fmPlayerInfo.fTeamLeader = fTeamLeader; }
bool IsReady(void) const { return m_fmPlayerInfo.fReady; }
void SetReady(bool fReady) { m_fmPlayerInfo.fReady = fReady; }
bool IsHuman(void) const { return m_fmPlayerInfo.dtidDrone == NA; }
DroneTypeID GetDroneTypeID(void) const { return m_fmPlayerInfo.dtidDrone; }
short MissionKills(void) const { return m_pship->GetKills(); }
short MissionDeaths(void) const { return m_pship->GetDeaths(); }
short MissionEjections(void) const { return m_pship->GetEjections(); }
void AddDeath() {
m_pship->AddDeath();
}
void AddEjection() {
m_pship->AddEjection();
}
void AddKill() {
m_pship->AddKill();
}
RankID Rank() const {
return GetPersistScore().GetRank();
}
bool PrivilegedUser()
{
size_t nameLen;
nameLen=strlen(m_fmPlayerInfo.CharacterName);
if ( (nameLen>2) && ( ((strncmp(m_fmPlayerInfo.CharacterName,"?",1))==0) || ((strncmp(m_fmPlayerInfo.CharacterName,"+",1))==0)
|| ((strncmp(m_fmPlayerInfo.CharacterName,"$",1))==0) ) ) return true;
if ( (nameLen>4) && ( (_stricmp(m_fmPlayerInfo.CharacterName+(nameLen-3),"@Hq"))==0 ) ) return true;
if ( (nameLen>4) && ( (_stricmp(m_fmPlayerInfo.CharacterName+(nameLen-4),"@Dev"))==0 ) ) return true;
if ( (nameLen>6) && ( (_stricmp(m_fmPlayerInfo.CharacterName+(nameLen-6),"@Alleg"))==0 ) ) return true;
if ( (nameLen>5) && ( (_stricmp(m_fmPlayerInfo.CharacterName+(nameLen-5),"@Zone"))==0 ) ) return true;
return false;
}
const PersistPlayerScoreObject& GetPersistScore() const { return GetPersistScore(GetCivID()); }
const PersistPlayerScoreObject& GetPersistScore(CivID civId) const;
void UpdateScore(PersistPlayerScoreObject& ppso);
CivID GetCivID() const;
SideID SideID() const { return m_fmPlayerInfo.iSide; }
void SetSideID(::SideID sideID) { m_fmPlayerInfo.iSide = sideID; };
ShipID ShipID() const { return m_fmPlayerInfo.shipID; }
LPCSTR CharacterName() const { return m_fmPlayerInfo.CharacterName; }
Money GetMoney() const { return m_fmPlayerInfo.money; }
void SetMoney(Money money) { m_fmPlayerInfo.money = money; }
const ShipStatus& GetShipStatus(void) const { return m_shipStatus; }
void SetShipStatus(const ShipStatus& ss)
{
ShipStatus ssOld = m_shipStatus;
m_shipStatus = ss;
if ((ssOld.GetSectorID() != ss.GetSectorID()) ||
((ssOld.GetState() == c_ssFlying) != (ss.GetState() == c_ssFlying)) ||
(ssOld.GetUnknown() != ss.GetUnknown()))
{
if ((!ssOld.GetUnknown()) && (ssOld.GetSectorID() != NA))
{
IclusterIGC* pcluster = m_pmission->GetCluster(ssOld.GetSectorID());
assert (pcluster);
if (pcluster)
pcluster->GetClusterSite()->MoveShip();
else
assert(false);
}
if ((!ss.GetUnknown()) && (ss.GetSectorID() != NA))
{
IclusterIGC* pcluster = m_pmission->GetCluster(ss.GetSectorID());
assert (pcluster);
if (pcluster)
pcluster->GetClusterSite()->MoveShip();
else
{
assert(false);
m_shipStatus.SetSectorID(NA);
}
}
}
}
void ResetShipStatus(void)
{
ShipStatus ssOld = m_shipStatus;
m_shipStatus.Reset();
if ((!ssOld.GetUnknown()) && (ssOld.GetSectorID() != NA))
{
IclusterIGC* pcluster = m_pmission->GetCluster(ssOld.GetSectorID());
if (pcluster)
pcluster->GetClusterSite()->MoveShip();
}
}
void Reset(bool bFull)
{
SetMoney(0);
GetShip()->Reset(bFull);
ResetShipStatus();
}
HullID LastSeenShipType() const { return m_shipStatus.GetHullID(); };
SectorID LastSeenSector() const { return m_shipStatus.GetSectorID(); };
StationID LastSeenStation() const { return m_shipStatus.GetStationID(); };
::ShipID LastSeenParent() const { return m_shipStatus.GetParentID(); };
ShipState LastSeenState() const { return m_shipStatus.GetState(); };
bool StatusIsCurrent() const { return !m_shipStatus.GetUnknown(); }
bool GetDetected() const { return !m_shipStatus.GetDetected(); }
};
typedef Slist_utlListWrapper<PlayerInfo> PlayerList;
typedef Slist_utlListWrapper<PlayerInfo>::Link PlayerLink;
typedef TListListWrapper<IntItemIDWrapper<ShipID> > ShipList;
class SideInfo
{
protected:
ShipList m_listShipIDMembers;
ShipList m_listShipIDRequests;
SideID m_sideID;
public:
SideInfo(SideID sideID)
{ m_sideID = sideID; }
~SideInfo(){}
void AddPlayer(ShipID shipID) { m_listShipIDMembers.PushEnd(shipID); };
void RemovePlayer(ShipID shipID) { m_listShipIDMembers.Remove(shipID); };
bool FindPlayer(ShipID shipID) { return m_listShipIDMembers.Find(shipID); };
void AddRequest(ShipID shipID) { m_listShipIDRequests.PushEnd(shipID); };
void RemoveRequest(ShipID shipID) { m_listShipIDRequests.Remove(shipID); };
bool FindRequest(ShipID shipID) { return m_listShipIDRequests.Find(shipID); };
ShipList& GetMembers() { return m_listShipIDMembers; }
List* GetMemberList() { return new ListDelegate(&m_listShipIDMembers); }
ShipList& GetRequests() { return m_listShipIDRequests; }
List* GetRequestList() { return new ListDelegate(&m_listShipIDRequests); }
SideID GetSideID() { return m_sideID; };
};
class MissionInfo
{
protected:
FMD_S_MISSIONDEF* m_pfmMissionDef;
TMapListWrapper<SideID, SideInfo*> m_mapSideInfo;
SideInfo m_sideLobby;
int m_nNumPlayers;
ZString m_strGameDetailsFiles;
SquadID squadIDs[c_cSidesMax];
bool m_fGuaranteedSlotsAvailable;
bool m_fAnySlotsAvailable;
bool m_fCountdownStarted;
public:
MissionInfo(DWORD dwCookie);
~MissionInfo();
void Update(FMD_S_MISSIONDEF* pfmMissionDef);
void Update(FMD_LS_LOBBYMISSIONINFO* pfmLobbyMissionInfo);
void UpdateStartTime(Time timeStart);
void SetInProgress(bool fInProgress) { m_pfmMissionDef->fInProgress = fInProgress; }
void SetCountdownStarted(bool fCountdownStarted) { m_fCountdownStarted = fCountdownStarted; }
STAGE GetStage() { return m_pfmMissionDef->stage; }
void SetStage(STAGE stage) { m_pfmMissionDef->stage = stage; };
void AddPlayer(PlayerInfo* pPlayerInfo);
void RemovePlayer(PlayerInfo* pPlayerInfo);
bool FindPlayer(SideID sideID, ShipID shipID);
void AddRequest(SideID sideID, ShipID shipID);
void RemoveRequest(SideID sideID, ShipID shipID);
bool FindRequest(SideID sideID, ShipID shipID);
bool GetAnySlotsAreAvailable() { return m_fAnySlotsAvailable; };
bool GetGuaranteedSlotsAreAvailable() { return m_fGuaranteedSlotsAvailable; };
void SetLockLobby(bool bLock) { m_pfmMissionDef->misparms.bLockLobby = bLock; };
bool GetLockLobby() { return m_pfmMissionDef->misparms.bLockLobby; };
void SetLockSides(bool bLock) { m_pfmMissionDef->misparms.bLockSides = bLock; };
bool GetLockSides() { return m_pfmMissionDef->misparms.bLockSides; };
SideID NumSides() { return m_pfmMissionDef->misparms.nTeams; }
bool InProgress() { return !!m_pfmMissionDef->fInProgress; }
bool CountdownStarted() { return m_fCountdownStarted; }
LPCSTR Name() { return m_pfmMissionDef->misparms.strGameName; }
LPCSTR Description() { return m_pfmMissionDef->szDescription; }
DWORD GetCookie() { return m_pfmMissionDef->dwCookie; }
SideID MissionOwnerSideID() { return m_pfmMissionDef->iSideMissionOwner; }
ShipID MissionOwnerShipID() { return SideLeaderShipID( MissionOwnerSideID() ); }
bool AutoAcceptLeaders() { return m_pfmMissionDef->fAutoAcceptLeaders; }
int MaxPlayers() { return m_pfmMissionDef->misparms.nTotalMaxPlayersPerGame; }
int NumPlayers() { return m_nNumPlayers; };
int AvailablePositions() { return MaxPlayers() - NumPlayers(); }
int GuaranteedPositions();
unsigned char MinPlayersPerTeam() { return m_pfmMissionDef->misparms.nMinPlayersPerTeam; }
unsigned char MaxPlayersPerTeam() { return m_pfmMissionDef->misparms.nMaxPlayersPerTeam; }
short MaxImbalance() { return m_pfmMissionDef->misparms.iMaxImbalance; }
bool ScoresCount() { return m_pfmMissionDef->misparms.bScoresCount; }
bool GoalConquest() { return m_pfmMissionDef->misparms.IsConquestGame(); }
bool GoalDeathMatch() { return m_pfmMissionDef->misparms.IsDeathMatchGame(); }
bool GoalCountdown() { return m_pfmMissionDef->misparms.IsCountdownGame(); }
bool GoalProsperity() { return m_pfmMissionDef->misparms.IsProsperityGame(); }
bool GoalArtifacts() { return m_pfmMissionDef->misparms.IsArtifactsGame(); }
bool GoalFlags() { return m_pfmMissionDef->misparms.IsFlagsGame(); }
bool GoalTerritory() { return m_pfmMissionDef->misparms.IsTerritoryGame(); }
bool WasObjectModelCreated() { return m_pfmMissionDef->misparms.bObjectModelCreated; }
bool AllowDevelopments() { return m_pfmMissionDef->misparms.bAllowDevelopments; }
bool LimitedLives() { return m_pfmMissionDef->misparms.iLives != 0x7fff; }
Time StartTime() { assert(InProgress()); return m_pfmMissionDef->misparms.timeStart; }
const MissionParams& GetMissionParams() { return m_pfmMissionDef->misparms; }
const FMD_S_MISSIONDEF& GetMissionDef() { return *m_pfmMissionDef; }
void PurgePlayers();
short GetMinRank() { return m_pfmMissionDef->misparms.iMinRank; };
short GetMaxRank() { return m_pfmMissionDef->misparms.iMaxRank; };
int GetSlotsLeft() { return m_pfmMissionDef->misparms.nMaxPlayersPerTeam
* m_pfmMissionDef->misparms.nTeams
- m_nNumPlayers; };
const ZString& GetDetailsFiles() { return m_strGameDetailsFiles; }
void SetAllowEmptyTeams(bool bValue) { m_pfmMissionDef->misparms.bAllowEmptyTeams = bValue;}
LPCSTR SideName(SideID sideID) { return (sideID == SIDE_TEAMLOBBY) ? "Not on a team" : m_pfmMissionDef->rgszName[sideID]; }
ShipID SideLeaderShipID(SideID sideID) { return (sideID == SIDE_TEAMLOBBY) ? NA : m_pfmMissionDef->rgShipIDLeaders[sideID]; }
bool SideAutoAccept(SideID sideID) { return (sideID == SIDE_TEAMLOBBY) ? true : !!m_pfmMissionDef->rgfAutoAccept[sideID]; }
bool SideReady(SideID sideID) { return (sideID == SIDE_TEAMLOBBY) ? true : !!m_pfmMissionDef->rgfReady[sideID]; }
bool SideForceReady(SideID sideID) { return (sideID == SIDE_TEAMLOBBY) ? true : !!m_pfmMissionDef->rgfForceReady[sideID]; }
char SideMaxPlayers(SideID sideID) { return (sideID == SIDE_TEAMLOBBY) ? 1000 : m_pfmMissionDef->misparms.nMaxPlayersPerTeam; }
char SideNumPlayers(SideID sideID) { return (sideID == SIDE_TEAMLOBBY) ? 0 : m_pfmMissionDef->rgcPlayers[sideID]; }
int SideAvailablePositions(SideID sideID) { return (sideID == SIDE_TEAMLOBBY) ? 1000 : (SideMaxPlayers(sideID) - SideNumPlayers(sideID)); }
int SideActive(SideID sideID) { return (sideID == SIDE_TEAMLOBBY) ? true : (m_pfmMissionDef->rgfActive[sideID] != 0); }
bool HasSquad(SquadID squadID);
void SetSideActive(SideID sideID, bool fActive)
{ assert(sideID != SIDE_TEAMLOBBY); m_pfmMissionDef->rgfActive[sideID] = fActive; }
void SetSideAutoAccept(SideID sideID, bool fAutoAccept)
{ assert(sideID != SIDE_TEAMLOBBY); m_pfmMissionDef->rgfAutoAccept[sideID] = fAutoAccept; }
void SetSideReady(SideID sideID, bool fReady)
{ assert(sideID != SIDE_TEAMLOBBY); m_pfmMissionDef->rgfReady[sideID] = fReady; }
void SetSideForceReady(SideID sideID, bool fForceReady)
{ assert(sideID != SIDE_TEAMLOBBY); m_pfmMissionDef->rgfForceReady[sideID] = fForceReady; }
void SetSideLeader(PlayerInfo* pPlayerInfo);
void SetSideName(SideID sideID, const char* szName)
{ assert(sideID != SIDE_TEAMLOBBY); strcpy(m_pfmMissionDef->rgszName[sideID], szName);
m_mapSideInfo.GetSink()(); }
void SetSideSquadID(SideID sideID, SquadID squadID)
{ assert(sideID != SIDE_TEAMLOBBY); squadIDs[sideID] = squadID; m_mapSideInfo.GetSink()(); }
SideInfo* GetSideInfo(SideID sideID);
List* GetSideList();
const char * GetIGCStaticFile()
{ return m_pfmMissionDef->misparms.szIGCStaticFile; }
int GetIGCStaticVer()
{ return m_pfmMissionDef->misparms.verIGCcore;}
};
typedef TVector<Money> MoneyVector;
class BucketStatusArray : public MoneyVector, public IObjectSingle
{
};
class CfgInfo
{
private:
ZString m_szConfigFile; public:
void SetCfgFile(const char * szConfig); CfgInfo() :
dwLobbyPort(2302),
m_szConfigFile("") {
}
void Load(const char * szConfig);
DWORD GetCfgProfileString(const char *c_szCfgApp,const char *c_szKeyName,const char *c_szDefaultValue,char *szStr,DWORD dwSize); ZString strClubLobby;
ZString strPublicLobby;
ZString strClub;
ZString strZAuth;
ZString strClubMessageURL;
ZString strPublicMessageURL;
ZString strZoneEventsURL;
ZString strZoneEventDetailsURL;
ZString strTrainingURL;
ZString strPassportUpdateURL;
GUID guidZoneAuth;
int crcFileList;
int nFilelistSize;
ZString strFilelistSite;
ZString strFilelistDirectory;
int crcClubMessageFile;
int crcPublicMessageFile;
bool bUsePassport;
DWORD dwLobbyPort; };
struct LANServerInfo : public IObject
{
LANServerInfo(REFGUID guidSession_, const ZString& strGameName_, short nNumPlayers_, short nMaxPlayers_)
: strGameName(strGameName_), nNumPlayers(nNumPlayers_), nMaxPlayers(nMaxPlayers_)
{ memcpy(&guidSession, &guidSession_, sizeof(GUID)); }
GUID guidSession;
ZString strGameName;
short nNumPlayers;
short nMaxPlayers;
};
class BaseClient :
public IIgcSite,
IFedMessagingSite
{
public:
enum
{
lockdownDonating = 1,
lockdownLoadout = 2,
lockdownTeleporting = 4
};
typedef int LockdownCriteria;
private:
PlayerInfo* m_pPlayerInfo;
IshipIGC* m_ship;
IclusterIGC* m_viewCluster;
bool m_bInGame;
bool m_bWaitingForGameRestart;
ZString m_strLockDownReason;
bool m_bLaunchAfterDisembark;
ShipID m_sidBoardAfterDisembark;
StationID m_sidTeleportAfterDisembark;
TRef<ImodelIGC> m_pmodelServerTarget;
LockdownCriteria m_lockdownCriteria;
TRef<IshipIGC> m_pshipLastSender;
CfgInfo m_cfginfo;
Money m_money;
Money m_moneyLastRequest;
RankInfo* m_vRankInfo;
short m_cRankInfo;
StaticMapInfo* m_vStaticMapInfo;
short m_cStaticMapInfo;
ZString m_strCDKey;
BallotList m_listBallots;
public: enum MessageType
{
c_mtNone,
c_mtGuaranteed,
c_mtNonGuaranteed
};
struct ConnectInfo {
public:
ConnectInfo() :
pZoneTicket(NULL),
cbZoneTicket(0)
{
ZeroMemory(&ftLastArtUpdate, sizeof(ftLastArtUpdate));
ZeroMemory(szName, sizeof(szName));
}
FILETIME ftLastArtUpdate;
ZString strServer;
char szName [c_cbName];
DWORD dwPort; LPBYTE pZoneTicket;
CB cbZoneTicket;
GUID guidSession;
};
bool m_fLoggedOn : 1;
bool m_fZoneClub : 1;
bool m_fIsLobbied : 1;
bool m_fLoggedOnToLobby : 1;
bool m_fLoggedOnToClub : 1;
bool m_serverOffsetValidF : 1;
bool m_terminatedF : 1;
FedMessaging m_fm;
FedMessaging m_fmLobby;
FedMessaging m_fmClub;
ConnectInfo m_ci; DWORD m_serverLag;
DWORD m_serverOffset;
DWORD m_lobbyServerOffset;
Time m_timeLastPing;
Time m_timeLastPingServer;
Time m_timeLastServerMessage;
Time m_lastSend;
Time m_lastLagCheck;
int m_cUnansweredPings;
float m_sync;
Cookie m_cookie;
MessageType m_messageType;
char m_szCharName[c_cbName];
char m_szClubCharName[c_cbName]; char m_szLobbyCharName[c_cbName]; char m_szIGCStaticFile[30];
int m_nMemberID; ImissionIGC* m_pCoreIGC;
MissionInfo* m_pMissionInfo;
DWORD m_dwCookieToJoin;
char m_strPasswordToJoin[c_cbGamePassword];
Mount m_selectedWeapon;
int m_oldStateM;
ZString m_strBriefingText;
bool m_bGenerateCivBriefing;
bool bInitTrekJoyStick; Time m_lastUpdate;
Time m_now;
TMap<StationID, TRef<BucketStatusArray> > m_mapBucketStatusArray;
TMapListWrapper<DWORD, MissionInfo*> m_mapMissions;
TRef<ListDelegate> m_plistMissions;
PlayerList m_listPlayers;
TRef<IClientEventSource> m_pClientEventSource;
ChatList m_chatList;
ChatLink* m_plinkSelectedChat;
TRef<IchaffIGC> m_pchaffLastCreated;
CachedLoadoutList m_loadouts;
IAutoDownload * m_pAutoDownload;
#ifdef USEAUTH
TRef<IZoneAuthClient> m_pzac;
#endif
TList<TRef<LANServerInfo> >* m_plistFindServerResults;
public:
BaseClient();
virtual ~BaseClient();
virtual void Initialize(Time timeNow);
virtual void Reinitialize(Time timeNow);
virtual void Terminate();
virtual void FlushGameState();
virtual void CreateMissionReq();
virtual void ServerListReq(); virtual void CreateMissionReq(const char *szServer, const char *szAddr, const char *szIGCStaticFile, const char *szGameName); virtual void JoinMission(MissionInfo * pMission, const char* szMissionPassword);
virtual IAutoUpdateSink * OnBeginAutoUpdate(IAutoUpdateSink * pSink, bool bConnectToLobby) { return NULL; }
virtual bool ShouldCheckFiles() { return false; }
void HandleAutoDownload(DWORD dwTimeAlloted);
virtual const char* GetArtPath() { return NULL; } virtual bool ResetStaticData(const char * szIGCStaticFile, ImissionIGC** ppStaticIGC, Time tNow, bool bEncrypt);
virtual Time ServerTimeFromClientTime(Time timeClient)
{
ShouldBe(!GetNetwork() || m_serverOffsetValidF);
return Time(timeClient.clock() + m_serverOffset);
}
virtual Time ClientTimeFromServerTime(Time timeServer)
{
ShouldBe(!GetNetwork() || m_serverOffsetValidF);
return Time(timeServer.clock() - m_serverOffset);
}
virtual HRESULT ConnectToLobby(ConnectInfo * pci); virtual HRESULT ConnectToServer(ConnectInfo & ci, DWORD dwCookie, Time now, const char* szPassword, bool bStandalonePrivate);
virtual HRESULT ConnectToClub(ConnectInfo * pci);
virtual void FindStandaloneServersByName(const char* szName, TList<TRef<LANServerInfo> >& listResults);
bool LoggedOn()
{
return m_fLoggedOn;
}
bool LoggedOnToLobby()
{
return m_fLoggedOnToLobby;
}
bool LoggedOnToClub()
{
return m_fLoggedOnToClub;
}
virtual void OverrideCamera(ImodelIGC* pmodel) {}
const ZString& GetCDKey()
{
return m_strCDKey;
}
virtual void SetCDKey(const ZString& strCDKey);
virtual void OnLogonAck(bool fValidated, bool bRetry, LPCSTR szFailureReason) = 0;
virtual void OnLogonLobbyAck(bool fValidated, bool bRetry, LPCSTR szFailureReason) = 0;
virtual void OnLogonClubAck(bool fValidated, bool bRetry, LPCSTR szFailureReason) {};
virtual void Disconnect();
virtual void DisconnectLobby();
virtual void DisconnectClub();
void SetCookie(Cookie cookie)
{
m_cookie = cookie;
}
Cookie GetCookie()
{
return m_cookie;
}
void SetMessageType(MessageType mt);
void SendMessages();
void SendLobbyMessages()
{
m_fmLobby.SendMessages(m_fmLobby.GetServerConnection(), FM_GUARANTEED, FM_FLUSH);
}
void SendClubMessages()
{
m_fmClub.SendMessages(m_fmClub.GetServerConnection(), FM_GUARANTEED, FM_FLUSH);
}
virtual HRESULT ReceiveMessages(void);
virtual HRESULT OnSessionLost(char * szReason, FedMessaging * pthis);
virtual void OnSessionFound(FedMessaging * pthis, FMSessionDesc * pSessionDesc);
virtual HRESULT HandleMsg(FEDMESSAGE* pfm, Time lastUpdate, Time now);
bool GetIsZoneClub()
{
return m_fZoneClub;
}
void SetIsZoneClub(bool fzc)
{
m_fZoneClub = fzc;
}
bool GetIsLobbied()
{
return m_fIsLobbied;
}
void SetIsLobbied(bool fzc)
{
m_fIsLobbied = fzc;
}
#ifdef USEAUTH
TRef<IZoneAuthClient> GetZoneAuthClient()
{
return m_pzac;
}
TRef<IZoneAuthClient> CreateZoneAuthClient()
{
m_pzac = ::CreateZoneAuthClient();
return m_pzac;
}
void FreeZoneAuthClient()
{
m_pzac = NULL;
}
#endif
virtual HRESULT OnSessionLost(FedMessaging * pthis);
virtual void OnMessageNAK(FedMessaging * pthis, DWORD dwTime, CFMRecipient * prcp);
inline ImissionIGC* GetCore() { return m_pCoreIGC; }
PlayerInfo* MyPlayerInfo() { return m_pPlayerInfo; }
MissionInfo* MyMission() { return m_pMissionInfo; }
bool MyMissionInProgress();
inline bool IsInGame(void) const { return m_bInGame; };
inline bool IsWaitingForGameRestart(void) const { return m_bWaitingForGameRestart; };
const ZString& GetBriefingText(void) const { return m_strBriefingText; }
inline bool GenerateCivBriefing(void) const { return m_bGenerateCivBriefing; }
inline IsideIGC* GetSide(void) const { return m_ship->GetSide(); }
inline SideID GetSideID(void) const { IsideIGC* s = GetSide(); return s ? s->GetObjectID() : NA; }
TList<SquadMembership>& GetSquadMemberships() { return m_squadmemberships; }
virtual void SaveSquadMemberships(const char* szCharacterName);
virtual void RestoreSquadMemberships(const char* szCharacterName);
bool HasPlayerSquad(MissionInfo* pMission);
void SetPlayerInfo(PlayerInfo* ppinfo);
inline PlayerInfo* GetPlayerInfo(void) const { return m_pPlayerInfo; }
PlayerList * GetPlayerList() { return(&m_listPlayers); }
List* PlayerList() { return new ListDelegate(&m_listPlayers); }
void SetMoney(Money m);
inline Money GetMoney() const { return m_pPlayerInfo ? m_pPlayerInfo->GetMoney() : 0; }
inline ShipID GetShipID() const { return m_ship->GetObjectID(); }
inline IshipIGC* GetShip() const { return m_ship; }
inline IclusterIGC* GetCluster() const {assert (m_ship); return m_viewCluster ? m_viewCluster : (m_ship ? m_ship->GetCluster() : NULL); }
IclusterIGC* GetChatCluster() const
{
IclusterIGC* pcluster = GetCluster();
if (!pcluster)
{
IstationIGC* pstation = m_ship->GetStation();
assert (pstation);
if (pstation)
pcluster = pstation->GetCluster();
}
assert (pcluster);
return pcluster;
}
void CreateBuildingEffect(Time now, IasteroidIGC* pasteroid, IshipIGC* pshipBuilder)
{
assert (pasteroid);
assert (pshipBuilder);
assert (pshipBuilder->GetPilotType() == c_ptBuilder);
assert (pshipBuilder->GetBaseData());
assert (pshipBuilder->GetCluster());
IbuildingEffectIGC* pbe = pshipBuilder->GetCluster()->CreateBuildingEffect(now,
pasteroid,
NULL,
pshipBuilder,
pasteroid->GetRadius(),
((IstationTypeIGC*)(pshipBuilder->GetBaseData()))->GetRadius(),
pshipBuilder->GetPosition() - pshipBuilder->GetOrientation().GetBackward() * pshipBuilder->GetRadius(),
pasteroid->GetPosition());
}
IclusterIGC* GetCluster(IshipIGC* pship, ImodelIGC* pmodel)
{
IclusterIGC* pcluster = pmodel->GetCluster();
if (pcluster == NULL)
{
if (pmodel->GetObjectType() == OT_ship)
{
PlayerInfo* ppi = (PlayerInfo*)(((IshipIGC*)pmodel)->GetPrivateData());
if (ppi->StatusIsCurrent())
pcluster = m_pCoreIGC->GetCluster(ppi->LastSeenSector());
}
}
else if (!pship->CanSee(pmodel))
pcluster = NULL;
return pcluster;
}
IclusterIGC* GetRipcordCluster(IshipIGC* pship, HullAbilityBitMask habm)
{
PlayerInfo* ppi = (PlayerInfo*)(pship->GetPrivateData());
if (ppi->StatusIsCurrent() && (ppi->LastSeenState() == c_ssFlying))
{
SectorID sid = ppi->LastSeenSector();
if (sid != NA)
{
IhullTypeIGC* pht = m_pCoreIGC->GetHullType(ppi->LastSeenShipType());
if (pht && pht->HasCapability(habm))
{
IclusterIGC* pcluster = pship->GetCluster();
return pcluster
? pcluster
: m_pCoreIGC->GetCluster(ppi->LastSeenSector());
}
}
}
return NULL;
}
void SetWing(WingID wid, IshipIGC* pship = NULL)
{
if (pship == NULL)
pship = m_ship;
pship->SetWingID(wid);
if (m_fm.IsConnected())
{
SetMessageType(BaseClient::c_mtGuaranteed);
BEGIN_PFM_CREATE(m_fm, pfmSetWingID, CS, SET_WINGID)
END_PFM_CREATE
pfmSetWingID->shipID = pship->GetObjectID();
pfmSetWingID->wingID = wid;
}
}
void RequestRipcord(IshipIGC* pship, IclusterIGC* pcluster)
{
if (pship == m_ship)
{
SetMessageType(BaseClient::c_mtGuaranteed);
BEGIN_PFM_CREATE(m_fm, pfmRequest, C, RIPCORD_REQUEST)
END_PFM_CREATE;
pfmRequest->sidRipcord = pcluster ? pcluster->GetObjectID() : NA;
}
}
IclusterIGC* GetViewCluster() const { return m_viewCluster; }
virtual void SetViewCluster(IclusterIGC* pcluster, const Vector* pposition = NULL);
virtual void RequestViewCluster(IclusterIGC* pcluster, ImodelIGC* pmodelTarget = NULL) { SetViewCluster(pcluster); }
virtual void ResetShip(void);
virtual void ResetClusterScanners(IsideIGC* pside);
virtual void BuyLoadout(IshipIGC* pshipLoadout, bool bLaunch);
virtual IshipIGC* CreateEmptyShip(ShipID sid = -2);
virtual IshipIGC* CopyCurrentShip(void);
virtual void PreviousWeapon();
virtual bool SendUpdate(Time now);
IweaponIGC* GetWeapon();
virtual void NextWeapon();
virtual void SetSelectedWeapon(Mount id);
bool flyingF(void) const
{
return
(m_ship != NULL)
&& (m_ship->GetCluster() != NULL);
}
bool autoPilot() { return m_ship->GetAutopilot(); }
void SetAutoPilot(bool autoPilot);
void CheckServerLag(Time now);
ChatList* GetChatList(void) { return &m_chatList; }
MissionInfo* GetLobbyMission(DWORD dwCookie);
PlayerLink* FindPlayerLink(ShipID shipID);
PlayerInfo* FindAndCreatePlayerLink (ShipID shipID);
PlayerInfo* FindPlayer(ShipID shipID);
PlayerInfo* FindPlayer(const char* szName);
PlayerInfo* FindPlayerByPrefix(const char* szNamePrefix);
ZString LookupRankName(RankID rank, CivID civ = -1);
const StaticMapInfo& GetStaticMapInfo(int index) { assert(index >= 0 && index < m_cStaticMapInfo); return m_vStaticMapInfo[index]; };
int GetNumStaticMaps() { return m_cStaticMapInfo; };
List* GetMissionList();
void QuitMission();
Money GetBucketStatus(StationID stationID, short iBucket);
Money AddMoneyToBucket(IbucketIGC* b, Money m);
void DonateMoney(PlayerInfo* pPlayerInfo, Money money);
FedMessaging* GetNetwork()
{
return &m_fm;
}
FedMessaging* GetFMLobby()
{
return &m_fmLobby;
}
bool ParseShellCommand(const char* pszCommand);
virtual void SendChat(IshipIGC* pshipSender,
ChatTarget ctRecipient,
ObjectID oidRecipient,
SoundID soundID,
const char* pszText,
CommandID cid = c_cidNone,
ObjectType otTarget = NA,
ObjectID oidTarget = NA,
ImodelIGC* pmodelTarget = NULL,
bool bObjectModel = false);
virtual void ReceiveChat(IshipIGC* pshipSender,
ChatTarget ctRecipient,
ObjectID oidRecipient,
SoundID voiceOver,
const char* szText,
CommandID cid,
ObjectType otTarget,
ObjectID oidTarget,
ImodelIGC* pmodelTarget = NULL,
bool bObjectModel = false);
void ScrollChatUp(void);
void ScrollChatDown(void);
ChatInfo* GetCurrentMessage(void);
BallotInfo* GetCurrentBallot();
void Vote(bool bAgree);
void SkipCurrentBallot();
IClientEventSource* GetClientEventSource() { return m_pClientEventSource; }
void SendAllMissions(IClientEventSink* pSink);
void SendAllPlayers(IClientEventSink* pSink, MissionInfo* pMissionInfo, SideID sideID);
void SendAllRequests(IClientEventSink* pSink, MissionInfo* pMissionInfo, SideID sideID);
void SendAllBucketStatus(IClientEventSink* pSink, StationID stationID);
virtual void TerminateModelEvent(ImodelIGC* model);
virtual void KillAsteroidEvent(IasteroidIGC* pasteroid, bool explodeF);
virtual void KillProbeEvent(IprobeIGC* pprobe);
virtual void KillMineEvent(ImineIGC* pmine);
virtual void KillMissileEvent(ImissileIGC* pmissile, const Vector& position);
virtual void KillShipEvent(Time now, IshipIGC* ship, ImodelIGC* launcher, float amount, const Vector& p1, const Vector& p2);
virtual void DamageStationEvent(IstationIGC* station, ImodelIGC* launcher, DamageTypeID type, float amount, float leakage);
virtual void KillStationEvent(IstationIGC* station, ImodelIGC* launcher, float amount, float leakage);
virtual void FireMissile(IshipIGC* pship, ImagazineIGC* pmagazine,
Time timeFired, ImodelIGC* pTarget, float lock);
virtual void FireExpendable(IshipIGC* pShip,
IdispenserIGC* pDispenser,
Time timeFired);
virtual void BucketChangeEvent(BucketChange bc, IbucketIGC* b);
virtual void SideBuildingTechChange(IsideIGC* s);
virtual void SideDevelopmentTechChange(IsideIGC* s);
virtual void StationTypeChange(IstationIGC* s);
virtual void LoadoutChangeEvent(IshipIGC* pship, IpartIGC* ppart, LoadoutChange lc);
virtual bool Reload(IshipIGC* pship, IlauncherIGC* plauncher, EquipmentType type);
static short BuyPartOnBudget(IshipIGC* pship,
IpartTypeIGC* ppt,
Mount mount,
Money* pbudget)
{
Money price = ppt->GetPrice();
short amount;
if (price != 0)
{
if (IlauncherTypeIGC::IsLauncherType(ppt->GetEquipmentType()))
{
amount = ppt->GetAmount(pship);
if (price * amount > *pbudget)
{
assert (price > 0);
amount = *pbudget / price;
}
price *= amount;
}
else
amount = (*pbudget >= price) ? 0x7fff : 0;
}
else
amount = 0x7fff;
if (amount != 0)
{
*pbudget -= price;
pship->CreateAndAddPart(ppt, mount, amount);
}
return amount;
}
static void TryToBuyParts(IshipIGC* pship,
IstationIGC* pstation,
Money* pbudget,
IhullTypeIGC* pht,
const PartTypeListIGC* ppartsShip)
{
assert (pship);
assert (pstation);
assert (*pbudget >= 0);
assert (pship->GetBaseHullType() == pht);
for (PartTypeLinkIGC* ptl = ppartsShip->first();
(ptl != NULL);
ptl = ptl->next())
{
IpartTypeIGC* ppt = ptl->data();
if (pstation->CanBuy(ppt))
{
ppt = (IpartTypeIGC*)(pstation->GetSuccessor(ppt));
assert (pstation->CanBuy(ppt));
EquipmentType et = ppt->GetEquipmentType();
Mount iMountMax = (et == ET_Weapon)
? pht->GetMaxWeapons()
: 1;
for (Mount i = 0; (i < iMountMax); i++)
{
if ((pship->GetMountedPart(et, i) == NULL) && pht->CanMount(ppt, i))
{
if (BuyPartOnBudget(pship, ppt, i, pbudget) == 0)
break; }
}
}
}
}
void ClearLoadout(void)
{
m_loadouts.purge();
m_bLaunchAfterDisembark = false;
m_sidBoardAfterDisembark = NA;
m_sidTeleportAfterDisembark = NA;
}
void DisembarkAndLaunch()
{
m_bLaunchAfterDisembark = true;
BoardShip(NULL);
}
void DisembarkAndBuy(IshipIGC* pship, bool fLaunch)
{
CachedLoadoutLink* pcll = SaveLoadout(pship);
m_loadouts.first(pcll);
m_bLaunchAfterDisembark = fLaunch;
BoardShip(NULL);
}
void DisembarkAndBoard(IshipIGC* pship)
{
m_sidBoardAfterDisembark = pship->GetObjectID();
BoardShip(NULL);
}
void DisembarkAndTeleport(IstationIGC* pstation)
{
m_sidTeleportAfterDisembark = pstation->GetObjectID();
BoardShip(NULL);
}
void SaveLoadout(void)
{
SaveLoadout(m_ship);
}
CachedLoadoutLink* SaveLoadout(IshipIGC* pship)
{
IhullTypeIGC* pht = pship->GetBaseHullType();
CachedLoadoutLink* pcll = GetLoadoutLink(pht);
if (pcll)
{
pcll->data().cpl.purge();
pcll->unlink();
}
else
{
pcll = new CachedLoadoutLink;
pcll->data().pht = pht;
}
assert (pcll);
m_loadouts.first(pcll);
{
for (PartLinkIGC* ppl = pship->GetParts()->first(); (ppl != NULL); ppl = ppl->next())
{
CachedPartLink* cpl = new CachedPartLink;
cpl->data().ppt = ppl->data()->GetPartType();
cpl->data().mount = ppl->data()->GetMountID();
CachedPartLink* cplAfter;
for (cplAfter = pcll->data().cpl.first(); ((cplAfter != NULL) &&
(cplAfter->data().mount < cpl->data().mount)); cplAfter = cplAfter->next())
{
}
if (cplAfter != NULL)
cplAfter->txen(cpl);
else
pcll->data().cpl.last(cpl);
}
}
return pcll;
}
Money RestoreLoadout(IshipIGC* pshipSource,
IshipIGC* pshipSink,
IstationIGC* pstation,
Money budget)
{
assert (pshipSink->GetBaseHullType() == NULL);
assert (pshipSink->GetParts()->n() == 0);
assert (pshipSink->GetChildShips()->n() == 0);
CachedLoadoutLink* pcll = m_loadouts.first();
IhullTypeIGC* phtBase = pshipSource->GetBaseHullType();
if (pcll && (pcll->data().pht == phtBase))
{
IhullTypeIGC* pht = pcll->data().pht;
const PartListIGC* pparts = pshipSource->GetParts();
IhullTypeIGC* phtSuccessor = (pstation->CanBuy(pht))
? (IhullTypeIGC*)(pstation->GetSuccessor(pht))
: pht;
assert (pht->GetPrice() == phtSuccessor->GetPrice());
budget -= phtSuccessor->GetPrice();
pshipSink->SetBaseHullType(phtSuccessor);
{
for (CachedPartLink* l = pcll->data().cpl.first(); (l != NULL); l = l->next())
l->data().bDuplicated = false;
}
{
for (PartLinkIGC* l = pparts->first(); (l != NULL); l = l->next())
{
IpartIGC* ppart = l->data();
Mount mount = ppart->GetMountID();
if (mount >= 0)
{
IpartTypeIGC* ppt = ppart->GetPartType();
if (phtSuccessor->CanMount(ppt, mount))
{
if (pstation->CanBuy(ppt))
BuyPartOnBudget(pshipSink, (IpartTypeIGC*)(pstation->GetSuccessor(ppt)), mount, &budget);
else
{
Money price = ppt->GetPrice();
short amount = ppart->GetAmount();
if (price != 0)
{
if (IlauncherTypeIGC::IsLauncherType(ppt->GetEquipmentType()))
{
if (price * amount > budget)
{
assert (price > 0);
amount = budget / price;
}
price *= amount;
}
else if (budget >= price)
amount = 0;
}
if (amount != 0)
{
budget -= price;
pshipSink->CreateAndAddPart(ppt, mount, amount);
}
}
{
for (CachedPartLink* l = pcll->data().cpl.last(); (l != NULL); l = l->txen())
{
if ((l->data().ppt == ppt) && !l->data().bDuplicated)
{
l->data().bDuplicated = true;
break;
}
}
}
}
else
debugf("**** successor unable to mount %s/%s\n", phtSuccessor->GetName(), ppt->GetName());
}
}
}
Mount cargo = -c_maxCargo;
for (CachedPartLink* l = pcll->data().cpl.first(); (l != NULL); l = l->next())
{
CachedPart& cpl = l->data();
if (!cpl.bDuplicated)
{
IpartTypeIGC* ppt;
if (pstation->CanBuy(cpl.ppt))
{
ppt = (IpartTypeIGC*)(pstation->GetSuccessor(cpl.ppt));
}
else
ppt = pstation->GetSimilarPart(cpl.ppt);
if (ppt)
{
EquipmentType et = ppt->GetEquipmentType();
if ((cpl.mount == 0) && IlauncherTypeIGC::IsLauncherType(et) &&
(pshipSink->GetMountedPart(et, 0) == NULL)) {
BuyPartOnBudget(pshipSink, ppt, 0, &budget); }
else if (cargo < 0)
{
BuyPartOnBudget(pshipSink, ppt, cargo++, &budget);
}
}
}
}
if (pht != phtSuccessor)
{
TryToBuyParts(pshipSink, pstation, &budget, phtSuccessor, phtSuccessor->GetPreferredPartTypes());
}
}
else if (phtBase && !phtBase->HasCapability(c_habmLifepod))
budget = ReplaceLoadout(pshipSink, pstation, phtBase, budget);
else
budget = ReplaceLoadout(pshipSink, pstation, (CachedLoadout*)NULL, budget);
return budget;
}
Money ReplaceLoadout(IshipIGC* pship,
IstationIGC* pstation,
IhullTypeIGC* phulltype,
Money budget)
{
CachedLoadoutLink* pcll = GetLoadoutLink(phulltype);
if (pcll)
budget = ReplaceLoadout(pship, pstation, &(pcll->data()), budget);
else BuyDefaultLoadout(pship, pstation, phulltype, &budget);
return budget;
}
Money ReplaceLoadout(IshipIGC* pship,
IstationIGC* pstation,
CachedLoadout* pcl,
Money budget)
{
assert (pship->GetChildShips()->n() == 0);
assert (pship->GetParts()->n() == 0);
if (pcl == NULL)
pcl = m_loadouts.first() ? &(m_loadouts.first()->data()) : NULL;
if (pcl && pcl->pht && pstation->CanBuy(pcl->pht) && (pcl->pht->GetPrice() <= budget))
{
IhullTypeIGC* pht = (IhullTypeIGC*)(pstation->GetSuccessor(pcl->pht));
budget -= pht->GetPrice();
assert (budget >= 0);
pship->SetBaseHullType(pht);
for (CachedPartLink* l = pcl->cpl.first(); (l != NULL); l = l->next())
{
CachedPart& cpl = l->data();
IpartTypeIGC* ppt;
if (pstation->CanBuy(cpl.ppt))
{
ppt = (IpartTypeIGC*)(pstation->GetSuccessor(cpl.ppt));
}
else
ppt = pstation->GetSimilarPart(ppt);
if (ppt)
{
if (pht->CanMount(ppt, cpl.mount))
BuyPartOnBudget(pship, ppt, cpl.mount, &budget);
else
debugf("**** successor unable to mount %s/%s\n", pht->GetName(), ppt->GetName());
}
}
}
else
{
HullTypeLinkIGC* phtl = m_pCoreIGC->GetHullTypes()->first();
while (true)
{
assert (phtl != NULL);
IhullTypeIGC* pht = phtl->data();
if ((pht->GetGroupID() >= 0) && pstation->CanBuy(pht) && (pht->GetPrice() <= budget))
{
pht = (IhullTypeIGC*)(pstation->GetSuccessor(pht));
budget -= pht->GetPrice();
assert (budget >= 0);
BuyDefaultLoadout(pship, pstation, pht, &budget);
break;
}
phtl = phtl->next();
}
}
return budget;
}
void RestoreLoadout(IstationIGC* pstation)
{
IshipIGC* pship = CreateEmptyShip(-3);
assert (pship);
RestoreLoadout(m_ship, pship, pstation, m_ship->GetValue() + GetMoney());
BuyLoadout(pship, false);
pship->Terminate();
pship->Release();
}
void ReplaceLoadout(IstationIGC* pstation, bool bLaunch = false)
{
IshipIGC* pship = CreateEmptyShip(-3);
assert (pship);
ReplaceLoadout(pship, pstation, (CachedLoadout*)NULL, GetMoney());
BuyLoadout(pship, bLaunch);
pship->Terminate();
pship->Release();
}
void BuyDefaultLoadout(IshipIGC* pship, IstationIGC* pstation, IhullTypeIGC* pht, Money* pbudget)
{
assert (pship);
assert (pship->GetChildShips()->n() == 0);
{
const PartListIGC* pparts = pship->GetParts();
PartLinkIGC* ppl;
while (ppl = pparts->first()) ppl->data()->Terminate();
}
assert (pship->GetParts()->n() == 0);
assert (pht);
pship->SetBaseHullType(pht);
assert (pstation);
TryToBuyParts(pship, pstation, pbudget, pht, pht->GetPreferredPartTypes());
Mount cargo = -c_maxCargo;
{
IpartIGC* ppart = pship->GetMountedPart(ET_Magazine, 0);
if (ppart)
BuyPartOnBudget(pship, ppart->GetPartType(), cargo++, pbudget);
}
{
IpartIGC* ppart = pship->GetMountedPart(ET_Dispenser, 0);
if (ppart)
BuyPartOnBudget(pship, ppart->GetPartType(), cargo++, pbudget);
}
IpartTypeIGC* pptFuel;
if (pship->GetMountedPart(ET_Afterburner, 0) != NULL)
{
pptFuel = m_pCoreIGC->GetFuelPack();
assert (pptFuel);
assert (pptFuel->GetGroupID() >= 0);
if (!pstation->CanBuy(pptFuel))
pptFuel = NULL;
}
else
pptFuel = NULL;
IpartTypeIGC* pptAmmo;
{
bool bCarryAmmo = false;
for (Mount i = 0; (i < pht->GetMaxWeapons()); i++)
{
IweaponIGC* pweapon = (IweaponIGC*)(pship->GetMountedPart(ET_Weapon, i));
if (pweapon && (pweapon->GetAmmoPerShot() > 0))
{
bCarryAmmo = true;
break;
}
}
if (bCarryAmmo)
{
pptAmmo = m_pCoreIGC->GetAmmoPack();
assert (pptAmmo);
assert (pptAmmo->GetGroupID() >= 0);
if (!pstation->CanBuy(pptAmmo))
pptAmmo = NULL;
}
else
pptAmmo = NULL;
}
bool bBuyFuel = true;
do
{
if (pptFuel && bBuyFuel)
{
pship->CreateAndAddPart(pptFuel, cargo++, 0x7fff);
bBuyFuel = (pptAmmo == NULL);
}
else if (pptAmmo)
{
pship->CreateAndAddPart(pptAmmo, cargo++, 0x7fff);
bBuyFuel = true;
}
else
break;
}
while (cargo < 0);
}
CachedLoadoutLink* GetLoadoutLink(IhullTypeIGC* pht)
{
for (CachedLoadoutLink* pcll = m_loadouts.first(); (pcll != NULL); pcll = pcll->next())
{
if (pcll->data().pht == pht)
return pcll;
}
return NULL;
}
virtual void DropPart(IpartIGC* ppart)
{
assert (ppart);
assert (m_ship->GetStation() == NULL);
assert (m_ship->GetCluster());
assert (ppart->GetShip() == m_ship);
if (m_fm.IsConnected())
{
SetMessageType(BaseClient::c_mtGuaranteed);
BEGIN_PFM_CREATE(m_fm, pdata, CS, DROP_PART)
END_PFM_CREATE
pdata->et = ppart->GetEquipmentType();
pdata->mount = ppart->GetMountID();
}
ppart->Terminate();
}
virtual void SwapPart(IpartIGC* ppart, Mount mountNew)
{
assert (ppart);
assert (mountNew >= -c_maxCargo);
assert (ppart->GetShip() == m_ship);
EquipmentType et = ppart->GetEquipmentType();
Mount mountOld = ppart->GetMountID();
IpartIGC* ppartNew = m_ship->GetMountedPart(et, mountNew);
if (ppartNew)
{
ppart->SetMountID(c_mountNA);
ppartNew->SetMountID(mountOld);
}
ppart->SetMountID(mountNew);
if (m_fm.IsConnected())
{
SetMessageType(BaseClient::c_mtGuaranteed);
BEGIN_PFM_CREATE(m_fm, pdata, CS, SWAP_PART)
END_PFM_CREATE
pdata->etOld = et;
pdata->mountOld = mountOld;
pdata->mountNew = mountNew;
}
if((et == ET_Magazine || et == ET_ChaffLauncher || et == ET_Afterburner || et == ET_Dispenser)
&& mountNew >= 0 && mountOld != c_mountNA)
{
Reload(m_ship, (IlauncherIGC*)ppart, et);
}
}
virtual void ForwardSquadMessage(FEDMESSAGE* pSquadMessage) {} virtual void ForwardCharInfoMessage(FEDMESSAGE* pCharInfoMessage) {} virtual void ForwardLeaderBoardMessage(FEDMESSAGE* pLeaderBoardMessage) {} virtual void OnReload(IpartIGC* ppart, bool bConsumed) {};
virtual void OnQuitSide();
virtual void OnJoinSide();
virtual void OnEnterGame();
virtual void OnQuitMission(QuitSideReason reason, const char* szMessageParam = NULL);
virtual void AddPlayerToMission(PlayerInfo* pPlayer);
virtual void AddPlayerToSide(PlayerInfo* pPlayerInfo, SideID sideID);
virtual void RemovePlayerFromMission(PlayerInfo* pPlayerInfo, QuitSideReason reason, const char* szMessageParam = NULL);
virtual void RemovePlayerFromSide(PlayerInfo* pPlayerInfo, QuitSideReason reason, const char* szMessageParam = NULL);
void SetZoneClubID(int nMemberID) { m_nMemberID = nMemberID; }
int GetZoneClubID() { return m_nMemberID; }
IshipIGC* GetLastSender(void) const
{
return m_pshipLastSender;
}
void SetLastSender(IshipIGC* pship)
{
m_pshipLastSender = pship;
}
Money GetLastMoneyRequest(void) const
{
return m_moneyLastRequest;
}
void SetLastMoneyRequest(Money m)
{
m_moneyLastRequest = m;
}
virtual void StartLockDown(const ZString& strReason, LockdownCriteria criteria);
virtual void EndLockDown(LockdownCriteria criteria);
bool IsLockedDown()
{
return m_lockdownCriteria != 0;
};
const ZString& GetLockDownReason()
{
assert(IsLockedDown());
return m_strLockDownReason;
};
void BoardShip(IshipIGC* pshipBoard);
CfgInfo & GetCfgInfo()
{
return m_cfginfo;
}
protected:
TList<SquadMembership> m_squadmemberships;
virtual void CreateDummyShip();
virtual void DestroyDummyShip();
virtual void ModifyShipData(DataShipIGC* pds) {}
};
#endif