#ifndef _FSSHIP_H_
#define _FSSHIP_H_
#define GETFSSHIP(pship) ((CFSShip *) (pship)->GetPrivateData())
#define ISPLAYER(pship) (GETFSSHIP(pship)->IsPlayer())
typedef TLargeBitMask<c_cPlayersMax + c_cDronesMax> ShipDirtyMask;
class CFSMission;
class CFSPlayer;
class CFSDrone;
class CAdminUser;
const short c_chatBudgetMax = 100;
const short c_chatBudgetCost = 20;
const int c_cbLoadout = sizeof(ShipLoadout) + 20 * sizeof(ExpandedPartData);
class CFSShip {
public:
Money GetMoney() {return m_money;} void SetMoney(Money money) {assert(money >= 0); m_money = money;}
void AddKill()
{
m_pShip->AddKill();
m_plrscore.AddKill();
}
void AddDeath()
{
m_pShip->AddDeath();
m_plrscore.AddDeath();
}
void AddEjection()
{
m_pShip->AddEjection();
m_plrscore.AddEjection();
}
bool GetHasUpdate(void) const { return m_bHasUpdate; }
void SetHasUpdate(void) { m_bHasUpdate = true; }
void ClearHasUpdate(void) { m_bHasUpdate = false; }
float GetDeviation(void) const { return m_deviation; }
void SetDeviation(float f) { m_deviation = f; }
bool IsPlayer() {return m_fIsPlayer;}
CFSPlayer * GetPlayer()
{
assert(IsPlayer());
return (CFSPlayer *) this;
}
CFSDrone * GetDrone()
{
assert(!IsPlayer());
return (CFSDrone *) this;
}
IshipIGC * GetIGCShip() const {return m_pShip;}
ShipID GetShipID() {return m_pShip->GetObjectID();}
IclusterIGC * GetCluster()
{
IstationIGC * pstation = m_pShip->GetStation();
return pstation ? pstation->GetCluster() : m_pShip->GetCluster();
}
IsideIGC* GetSide() {return m_pShip->GetSide();}
virtual void SetSide(CFSMission * pfsMission, IsideIGC * pside);
IstationIGC * GetStation() {return m_pShip->GetStation();}
const char * GetName() {return m_pShip->GetName();}
static CFSShip * GetShipFromID(ShipID shipID)
{
assert (shipID < c_cShipsMax && shipID >= 0);
return m_rgpfsShip[shipID];
}
void AnnounceExit(IclusterIGC* pclusterOld, ShipDeleteReason sdr);
void ShipStatusSpotted(IsideIGC* pside);
void ShipStatusExit(void);
void ShipStatusHidden(IsideIGC* pside);
void ShipStatusHullChange(IhullTypeIGC* pht);
void ShipStatusDocked(IstationIGC* pstation);
void ShipStatusLaunched(void);
void ShipStatusStart(IstationIGC* pstation);
void ShipStatusRestart(IstationIGC* pstation);
void ShipStatusWarped(IwarpIGC* pwarp);
void ShipStatusRecalculate(void);
ShipStatus* GetShipStatus(SideID sid)
{
assert (sid >= 0);
assert (sid < c_cSidesMax);
return &(m_rgShipStatus[sid]);
}
ShipStatus* GetOldShipStatus(SideID sid)
{
assert (sid >= 0);
assert (sid < c_cSidesMax);
return &(m_rgOldShipStatus[sid]);
}
void QueueLoadoutChange(bool bForce = false);
virtual void Launch(IstationIGC* pstation);
virtual void Dock(IstationIGC * pstation) = 0;
CFSMission * GetMission() {return m_pfsMission;}
void HitWarp(IwarpIGC * pwarp);
void CaptureStation(IstationIGC * pstation);
virtual void Reset(bool bFull);
void SetTreasureData(ObjectID oid, short amount)
{
assert (m_oidTreasure == NA);
m_oidTreasure = oid;
m_amountTreasure = amount;
}
void SetTreasureObjectID(TreasureID oid)
{
m_oidTreasure = oid;
}
ObjectID GetTreasureObjectID(void) const
{
return m_oidTreasure;
}
short GetTreasureAmount(void) const
{
return m_amountTreasure;
}
virtual void SetCluster(IclusterIGC * pcluster, bool bViewOnly = false);
PlayerScoreObject* GetPlayerScoreObject(void)
{
return &m_plrscore;
}
void SetPlayerScoreObject(PlayerScoreObject* pplrscore)
{
if (pplrscore)
m_plrscore = *pplrscore;
else
m_plrscore.Reset(true);
}
bool OkToWarp(void) const
{
return m_warpState == warpReady;
}
void SetWarpState(void)
{
m_warpState = warpNoUpdate;
}
void ResetWarpState(void)
{
m_warpState = warpReady;
}
protected:
CFSShip(TRef<IshipIGC> pShip, bool fIsPlayer);
~CFSShip();
enum WarpState
{ warpNoUpdate,
warpWaiting,
warpReady
} m_warpState;
Time m_timeNextWarp;
private:
PlayerScoreObject m_plrscore;
ShipStatus m_rgShipStatus[c_cSidesMax];
ShipStatus m_rgOldShipStatus[c_cSidesMax];
CFSMission * m_pfsMission;
TRef<IshipIGC> m_pShip; Money m_money;
bool m_fIsPlayer; static ShipID m_shipidNext; static int m_cShips;
static CFSShip* m_rgpfsShip[c_cShipsMax]; ObjectID m_oidTreasure;
short m_amountTreasure;
bool m_bHasUpdate;
float m_deviation;
friend void FedSrvSiteBase::ChangeCluster(IshipIGC* pship,
IclusterIGC* pclusterOld,
IclusterIGC* pclusterNew);
friend HRESULT FedSrvSiteBase::OnAppMessage(FedMessaging * pthis, CFMConnection & cnxn, FEDMESSAGE * pfm);
};
const unsigned char c_ucNone = 0;
const unsigned char c_ucShipUpdate = 1;
const unsigned char c_ucActiveTurretUpdate = 2;
const unsigned char c_ucInactiveTurretUpdate = 3;
class CFSPlayer :
public CFSShip,
public CAdminSponsor<CAdminUser>
{
public:
CFSPlayer(CFMConnection * pcnxn, int characterId, const char * szCDKey,
TRef<IshipIGC> pShip, bool fCanCheat);
virtual ~CFSPlayer();
CFMGroup * GetGroup() {return m_pgrp;}
virtual void Launch(IstationIGC* pstation);
virtual void Dock(IstationIGC * pstation);
static DWORD GetMaxLatency() {return m_latencyMax;}
static DWORD GetAverageLatency() {return m_cUpdates ? m_latencyTotal / m_cUpdates : 0;}
static void ResetLatency()
{
m_cUpdates = 0;
m_latencyMax = 0;
m_latencyTotal = 0;
}
unsigned char GetLastUpdate(void) const
{
return m_ucLastUpdate;
}
void ResetLastUpdate(void)
{
m_ucLastUpdate = c_ucNone;
}
void SetShipUpdate(const ClientShipUpdate& su);
const ClientShipUpdate& GetShipUpdate(void) const { return m_su; }
void SetActiveTurretUpdate(const ClientActiveTurretUpdate& atu);
const ClientActiveTurretUpdate& GetActiveTurretUpdate(void) const { return m_atu; }
void SetInactiveTurretUpdate(void);
bool GetReady()
{
return m_fReady;
}
void SetReady(bool fReady);
void UnreadyNoSide(void)
{
assert(GetSide() == NULL);
m_fReady = false;
}
bool IsMissionOwner();
Cookie GetCookie()
{
return m_cookie;
}
Cookie NewCookie()
{
ResetLastUpdate();
return ++m_cookie;
}
int GetCharacterID()
{
return m_characterId;
}
const char* GetCDKey()
{
return m_strCDKey;
}
virtual void SetSide(CFSMission * pmission, IsideIGC * pside);
bool CanCheat()
{
return m_fCanCheat;
}
bool PrivilegedUser()
{
size_t nameLen;
nameLen=strlen(GetName());
if ( (nameLen>2) && ( ((strncmp(GetName(),"?",1))==0) || ((strncmp(GetName(),"+",1))==0)
|| ((strncmp(GetName(),"$",1))==0) ) ) return true;
if ( (nameLen>3) && ( (_stricmp(GetName()+(nameLen-3),"@HQ"))==0 ) ) return true;
if ( (nameLen>4) && ( (_stricmp(GetName()+(nameLen-4),"@Dev"))==0 ) ) return true;
if ( (nameLen>6) && ( (_stricmp(GetName()+(nameLen-6),"@Alleg"))==0 ) ) return true;
if ( (nameLen>5) && ( (_stricmp(GetName()+(nameLen-5),"@Zone"))==0 ) ) return true;
return false;
}
CFSPlayer* GetAutoDonate(void) const
{
IshipIGC* pship = GetIGCShip()->GetAutoDonate();
return pship ? ((CFSShip*)(pship->GetPrivateData()))->GetPlayer()
: NULL;
}
void SetAutoDonate(CFSPlayer* pplayer, Money amount, bool bSend = true);
CFMConnection * GetConnection()
{
return m_pcnxn;
}
static CFSPlayer * GetPlayerFromConnection(CFMConnection & cnxn)
{
return (CFSPlayer *)cnxn.GetPrivateData();
}
void SetDPGroup(CFSCluster* pfsCluster, bool bFlying);
virtual void SetCluster(IclusterIGC * pcluster, bool bViewOnly = false);
PersistPlayerScoreObjectList * GetPersistPlayerScoreObjectList()
{
return &m_perplrscoreList;
}
PersistPlayerScoreObject * GetPersistPlayerScore(CivID civID)
{
PersistPlayerScoreObjectLink * pl;
for (pl = m_perplrscoreList.first(); pl; pl = pl->next())
if (pl->data()->GetCivID() == civID)
return pl->data();
PersistPlayerScoreObject * pperplrsco = new PersistPlayerScoreObject;
pperplrsco->SetCivID(civID);
m_perplrscoreList.last(pperplrsco);
return pperplrsco;
}
SquadMembershipList * GetSquadMembershipList()
{
return &m_pSquadMembershipList;
}
bool GetIsMemberOfSquad(SquadID squadID);
bool GetCanLeadSquad(SquadID squadID);
SquadID GetPreferredSquadToLead();
void SetLifepod(IclusterIGC* pcluster, const Vector& position)
{
m_pclusterLifepod = pcluster;
m_positionLifepod = position;
}
IclusterIGC* GetLifepodCluster(void) const
{
return m_pclusterLifepod;
}
const Vector& GetLifepodPosition(void) const
{
return m_positionLifepod;
}
unsigned char GetBannedSideMask(void) const
{
return m_bannedSideMask;
}
void SetBannedSideMask(unsigned char bsm)
{
m_bannedSideMask = bsm;
}
void OrBannedSideMask(unsigned char bsm)
{
m_bannedSideMask |= bsm;
}
SideID GetLastSide(void) const
{
return m_lastSide;
}
void SetLastSide(SideID side)
{
m_lastSide = side;
}
virtual void Reset(bool bFull)
{
m_chatBudget = c_chatBudgetMax;
SetDPGroup(NULL, false);
if (bFull)
{
SetBannedSideMask(0);
SetLastSide(SIDE_TEAMLOBBY);
}
GetPlayerScoreObject()->Disconnect(g.timeNow);
GetPlayerScoreObject()->Reset(bFull);
CFSShip::Reset(bFull);
}
void IncrementChatBudget(void)
{
if (m_chatBudget < c_chatBudgetMax)
m_chatBudget++;
}
bool DecrementChatBudget(bool bPay)
{
bool bSend;
if (bPay)
{
bSend = m_chatBudget >= c_chatBudgetCost;
m_chatBudget -= c_chatBudgetCost;
if (m_chatBudget < -c_chatBudgetCost)
m_chatBudget = -c_chatBudgetCost;
}
else
bSend = m_chatBudget >= 0;
return bSend;
}
void ForceLoadoutChange(void);
void SaveDesiredLoadout(void)
{
{
IpartIGC* ppart = GetIGCShip()->GetMountedPart(ET_Magazine, 0);
m_ptDesiredLoadout[0] = (ppart && (ppart->GetPrice() == 0)) ? ppart->GetPartType() : NULL;
}
{
IpartIGC* ppart = GetIGCShip()->GetMountedPart(ET_Dispenser, 0);
m_ptDesiredLoadout[1] = (ppart && (ppart->GetPrice() == 0)) ? ppart->GetPartType() : NULL;
}
{
IpartIGC* ppart = GetIGCShip()->GetMountedPart(ET_ChaffLauncher, 0);
m_ptDesiredLoadout[2] = (ppart && (ppart->GetPrice() == 0)) ? ppart->GetPartType() : NULL;
}
for (Mount i = 0; (i < c_maxCargo); i++)
{
IpartIGC* ppart = GetIGCShip()->GetMountedPart(NA, -1 - i);
m_ptDesiredLoadout[i + 3] = (ppart &&
(ppart->GetPrice() == 0) &&
(IlauncherIGC::IsLauncher(ppart->GetObjectType())))
? ppart->GetPartType()
: NULL;
}
}
IpartTypeIGC** GetDesiredLoadout(void)
{
return m_ptDesiredLoadout;
}
bool GetJustJoined() {return b_JustJoined; };
void SetJustJoined(bool b_joined) {b_JustJoined = b_joined; };
private:
IpartTypeIGC* m_ptDesiredLoadout[c_maxCargo + 3];
bool RemoveFromSide(bool fSendSideChange);
SideID m_lastSide;
unsigned char m_bannedSideMask;
short m_chatBudget;
PersistPlayerScoreObjectList m_perplrscoreList;
SquadMembershipList m_pSquadMembershipList;
CFSCluster* m_pfsClusterFlying;
unsigned char m_ucLastUpdate;
ClientActiveTurretUpdate m_atu;
ClientShipUpdate m_su;
Time m_timeUpdate;
Time m_dwStartTime;
int m_characterId; CFMGroup * m_pgrp; bool m_fInUse : 1;
bool m_fReady : 1;
bool m_fCanCheat : 1;
Cookie m_cookie;
static int m_latencyTotal; static int m_cUpdates;
static int m_latencyMax;
CFMConnection * m_pcnxn;
IclusterIGC* m_pclusterLifepod;
Vector m_positionLifepod;
ZString m_strCDKey;
bool b_JustJoined;
friend void FedSrvSiteBase::ChangeCluster(IshipIGC* pship,
IclusterIGC* pclusterOld,
IclusterIGC* pclusterNew);
friend HRESULT FedSrvSiteBase::OnAppMessage(FedMessaging * pthis, CFMConnection & cnxn, FEDMESSAGE * pfm);
};
class CFSDrone : public CFSShip
{
public:
CFSDrone(IshipIGC* pship);
~CFSDrone();
virtual void Launch(IstationIGC* pstation);
virtual void Dock(IstationIGC * pstation);
void SetLastDamageReport(Time t)
{
m_timeLastDamageReport = t;
}
Time GetLastDamageReport(void) const
{
return m_timeLastDamageReport;
}
DroneTypeID GetDroneTypeID(void) const
{
return m_dtid;
}
void SetDroneTypeID(DroneTypeID dtid)
{
m_dtid = dtid;
}
private:
Time m_timeLastDamageReport;
DroneTypeID m_dtid;
bool m_fInUse : 1;
bool m_fUpdateToggle; static char m_rgfsDrone[];
static int m_cDrones;
static int m_ifsdNext; };
#endif