/* ** Copyright (C) 1996, 1997 Microsoft Corporation. All Rights Reserved. ** ** File: shipIGC.h ** ** Author: ** ** Description: ** Header for the CshipIGC class. This file was initially created by ** the ATL wizard. ** ** History: */ // shipIGC.h : Declaration of the CshipIGC #ifndef __SHIPIGC_H_ #define __SHIPIGC_H_ #include "modelIGC.h" const float c_dtCheckRunaway = 31.0f; //Must be slightly longer than ripcord time for drones. class CshipIGC; class MyHullType : public IhullTypeIGC { public: MyHullType(CshipIGC* pship) : m_pship(pship), m_pHullType(NULL) { } ~MyHullType(void) { if (m_pHullType) m_pHullType->Release(); } //IbaseIGC virtual HRESULT Initialize(ImissionIGC* pMission, Time now, const void* data, int length); virtual void Terminate(void); virtual void Update(Time now); virtual ObjectType GetObjectType(void) const; virtual ObjectID GetObjectID(void) const; //ItypeIGC virtual const void* GetData(void) const; //IbuyableIGC virtual const char* GetName(void) const; virtual const char* GetDescription(void) const; virtual const char* GetModelName(void) const; virtual const TechTreeBitMask& GetRequiredTechs(void) const; virtual const TechTreeBitMask& GetEffectTechs(void) const; virtual Money GetPrice(void) const; virtual DWORD GetTimeToBuild(void) const; virtual BuyableGroupID GetGroupID(void) const; //IhullTypeIGC virtual float GetLength(void) const; virtual float GetMaxSpeed(void) const; virtual float GetMaxTurnRate(Axis axis) const; virtual float GetTurnTorque(Axis axis) const; virtual float GetThrust(void) const; virtual float GetSideMultiplier(void) const; virtual float GetBackMultiplier(void) const; virtual float GetScannerRange(void) const; virtual float GetMaxEnergy(void) const; virtual float GetRechargeRate(void) const; virtual HitPoints GetHitPoints(void) const; virtual DefenseTypeID GetDefenseType(void) const; virtual bool CanMount(IpartTypeIGC* ppt, Mount mountID) const; virtual PartMask GetPartMask(EquipmentType et, Mount mountID) const; virtual short GetCapacity(EquipmentType et) const; virtual Mount GetMaxWeapons(void) const; virtual Mount GetMaxFixedWeapons(void) const; virtual const HardpointData& GetHardpointData(Mount hardpointID) const; virtual const char* GetTextureName(void) const; virtual const char* GetIconName(void) const; virtual float GetMass(void) const; virtual float GetSignature(void) const; virtual HullAbilityBitMask GetCapabilities(void) const; virtual bool HasCapability(HullAbilityBitMask habm) const; virtual const Vector& GetCockpit(void) const; virtual const Vector& GetWeaponPosition(Mount mount) const; virtual const Orientation& GetWeaponOrientation(Mount mount) const; virtual float GetScale() const; virtual short GetMaxAmmo(void) const; virtual float GetMaxFuel(void) const; virtual float GetECM(void) const; virtual float GetRipcordSpeed(void) const; virtual float GetRipcordCost(void) const; virtual IhullTypeIGC* GetSuccessorHullType(void) const; /* virtual const char* GetPilotHUDName(void) const; virtual const char* GetObserverHUDName(void) const; */ virtual SoundID GetInteriorSound(void) const; virtual SoundID GetExteriorSound(void) const; virtual SoundID GetMainThrusterInteriorSound(void) const; virtual SoundID GetMainThrusterExteriorSound(void) const; virtual SoundID GetManuveringThrusterInteriorSound(void) const; virtual SoundID GetManuveringThrusterExteriorSound(void) const; virtual const PartTypeListIGC* GetPreferredPartTypes(void) const; virtual IObject* GetIcon(void) const; virtual int GetLaunchSlots(void) const; virtual const Vector& GetLaunchPosition(int slotID) const; virtual const Vector& GetLaunchDirection(int slotID) const; virtual int GetLandSlots(void) const; virtual int GetLandPlanes(int slotID) const; virtual const Vector& GetLandPosition(int slotID, int planeID) const; virtual const Vector& GetLandDirection(int slotID, int planeID) const; private: IhullTypeIGC* GetHullType(void) const { return m_pHullType; } void SetHullType(IhullTypeIGC* pht) { if (m_pHullType) m_pHullType->Release(); m_pHullType = pht; if (pht) { pht->AddRef(); m_pHullData = (DataHullTypeIGC*)(pht->GetData()); } else m_pHullData = NULL; } const CshipIGC* m_pship; IhullTypeIGC* m_pHullType; const DataHullTypeIGC* m_pHullData; friend class CshipIGC; }; class CshipIGC : public TmodelIGC { public: CshipIGC(void); /* DWORD __stdcall AddRef(void) { return TmodelIGC::AddRef(); } DWORD __stdcall Release(void) { return TmodelIGC::Release(); } */ public: // IbaseIGC virtual HRESULT Initialize(ImissionIGC* pMission, Time now, const void* data, int length); virtual void Terminate(void); virtual void Update(Time now); virtual int Export(void* data) const; virtual ObjectType GetObjectType(void) const { return OT_ship; } virtual ObjectID GetObjectID(void) const { return m_shipID; } // ImodelIGC virtual void SetCluster(IclusterIGC* cluster) { IclusterIGC* pclusterOld = GetCluster(); if (cluster || pclusterOld) { //Can't move to a cluster or move to a cluster without a hull assert ((!cluster) || (m_myHullType.GetHullType() != NULL) || (m_pshipParent != NULL)); assert (GetSide() != NULL); SetRipcordModel(NULL); if (cluster != pclusterOld) { if (pclusterOld) pclusterOld->DeleteShip(this); TmodelIGC::SetCluster(cluster); if (cluster) { //Can't be in a cluster and in a station simultaneously assert (m_station == NULL); cluster->AddShip(this); m_maxMineAmount = 0.0f; m_maxMineLauncher = NULL; } } if (cluster) { //Do this even if the cluster does not change: the ship //mostly likely teleported to a new position. Time lastUpdate = cluster->GetLastUpdate(); SetMyLastUpdate(lastUpdate); SetBB(lastUpdate, lastUpdate, 0.0f); } SetStateBits(oneWeaponIGC | allWeaponsIGC, 0); //Stop shooting any weapons. { //Move the children of this ship to the new cluster as well for (ShipLinkIGC* psl = m_shipsChildren.first(); (psl != NULL); psl = psl->next()) { psl->data()->SetCluster(cluster); } } GetMyMission()->GetIgcSite()->ChangeCluster(this, pclusterOld, cluster); if (pclusterOld == NULL) ResetWaypoint(); } } virtual void HandleCollision(Time timeCollision, float tCollision, const CollisionEntry& entry, ImodelIGC* pModel); virtual void SetSide(IsideIGC* pside); //override the default SetSide method virtual float GetSignature(void) const { return TmodelIGC::GetSignature() * m_cloaking; } virtual void Move(float t) { if (m_pshipParent == NULL) TmodelIGC::Move(t); } virtual void Move(void) { if (m_pshipParent == NULL) TmodelIGC::Move(); } virtual void SetBB(Time tStart, Time tStop, float dt) { if (m_pshipParent == NULL) TmodelIGC::SetBB(tStart, tStop, dt); } virtual SideID GetFlag(void) const { return m_sidFlag; } virtual void SetFlag(SideID sid) { m_sidFlag = sid; } // IdamageIGC virtual DamageResult ReceiveDamage(DamageTypeID type, float amount, Time timeCollision, const Vector& position1, const Vector& position2, ImodelIGC* launcher); virtual float GetFraction(void) const { return m_fraction; } virtual void SetFraction(float newVal) { assert (newVal >= 0.0f); assert (newVal <= 1.0f); m_fraction = newVal; if (newVal > m_fractionLastOrder) m_fractionLastOrder = newVal; GetThingSite ()->RemoveDamage (m_fraction); } virtual float GetHitPoints(void) const { return m_fraction * m_myHullType.GetHitPoints(); } // IscannerIGC bool InScannerRange(ImodelIGC* pModel) const { assert (pModel); bool rc; if (m_pshipParent == NULL) { IclusterIGC* pcluster = GetCluster(); if (pcluster && (pModel->GetCluster() == pcluster)) { if (pModel->GetFlag() == NA) { float m = m_myHullType.GetScannerRange() * pModel->GetSignature(); { IsideIGC* pside = pModel->GetSide(); if (pside) m /= pside->GetGlobalAttributeSet().GetAttribute(c_gaSignature); } float r = GetRadius() + pModel->GetRadius() + m; //Get the difference in positions in the local coordinate space. Vector deltaP = GetOrientation().TimesInverse(GetPosition() - pModel->GetPosition()); if (deltaP.z < 0.0f) deltaP.z *= 4.0f; rc = (deltaP.LengthSquared() <= r * r) && LineOfSightExist(pcluster, this, pModel); } else rc = true; } else rc = false; } else rc = false; return rc; } bool CanSee(ImodelIGC* pModel) const { assert (pModel); IsideIGC* side = GetSide(); return (pModel->GetSide() == side) || //Always see things on our side pModel->SeenBySide(side) || InScannerRange(pModel); //or we can see it ourselves } // IshipIGC virtual void SetObjectID(ObjectID id) { m_shipID = id; } virtual Money GetValue(void) const { //Money for the hull Money money = m_myHullType.GetHullType() ? m_myHullType.GetPrice() : 0; //Money for the parts for (PartLinkIGC* ppartlink = m_parts.first(); ppartlink; ppartlink = ppartlink->next()) money += ppartlink->data()->GetPrice(); return money; } virtual void SetMission(ImissionIGC* pMission); virtual void ReInitialize(DataShipIGC * dataShip, Time now); virtual void SetShipID(ShipID shipID) { m_shipID = shipID; } virtual IstationIGC* GetStation(void) const { return m_station; } virtual void SetStation(IstationIGC* s) { IstationIGC* pstationOld = m_station; if (pstationOld != s) { if (m_station) { m_station->DeleteShip(this); m_station->Release(); } m_station = s; if (s) { if (m_pshipParent == NULL) { IafterburnerIGC* pafter = (IafterburnerIGC*)(m_mountedOthers[ET_Afterburner]); if (pafter) pafter->Deactivate(); //The station is a no smoking area if ((m_fOre > 0.0f) && (s->GetStationType()->HasCapability(c_sabmUnload))) { IsideIGC* pside = GetSide(); GetMyMission()->GetIgcSite()->PaydayEvent(pside, m_fOre * GetMyMission()->GetFloatConstant(c_fcidValueHe3) * pside->GetGlobalAttributeSet().GetAttribute(c_gaMiningYield)); m_fOre = 0.0f; } ResetDamageTrack(); } s->AddRef(); s->AddShip(this); //This also sets the ship's cluster to NULL assert (GetCluster() == NULL); if (m_bAutopilot) { if (m_pilotType >= c_ptPlayer) { //Players always exit autopilot when docking m_bAutopilot = false; } else { if ((m_commandTargets[c_cmdAccepted] == s) && (m_commandIDs[c_cmdAccepted] == c_cidGoto)) { //We docked with the station under autopilot ... that order is complete SetCommand(c_cmdAccepted, NULL, c_cidNone); } else { SetCommand(c_cmdPlan, NULL, c_cidNone); } } } } GetMyMission()->GetIgcSite()->ChangeStation(this, pstationOld, s); } } virtual void Reset(bool bFull) { m_nKills = 0; if (bFull) { m_nDeaths = 0; m_nEjections = 0; } m_experience = bFull ? 1.0f : 0.0f; SetFlag(NA); ResetDamageTrack(); SetAutoDonate(NULL); SetCommand(c_cmdQueued, NULL, c_cidNone); SetCommand(c_cmdAccepted, NULL, c_cidNone); SetCommand(c_cmdCurrent, NULL, c_cidNone); SetCommand(c_cmdPlan, NULL, c_cidNone); if (m_station) { m_station->DeleteShip(this); m_station->Release(); m_station = NULL; } SetRipcordModel(NULL); SetCluster(NULL); //TmodelIGC::SetCluster(NULL); assert (m_station == NULL); if (m_pshipParent != NULL) { SetParentShip(NULL); assert (m_myHullType.GetHullType() == NULL); } else { PartLinkIGC* pl; while (pl = m_parts.first()) //intentional assignment pl->data()->Terminate(); //Blow away the children ShipLinkIGC* psl; while (psl = m_shipsChildren.first()) //intentional assignment { psl->data()->SetParentShip(NULL); } } SetBaseHullType(GetSide()->GetCivilization()->GetLifepod()); } virtual float GetTorqueMultiplier(void) const { static const float c_fMultiplierAtZero = 0.50f; float fraction = GetVelocity().Length() / m_myHullType.GetMaxSpeed(); return c_fMultiplierAtZero + (1.0f - c_fMultiplierAtZero) * 2.0f * fraction / (fraction + 1.0f); } virtual float GetCurrentTurnRate(Axis axis) const { return m_turnRates[axis]; } virtual void SetCurrentTurnRate(Axis axis, float newVal) { m_turnRates[axis] = newVal; } virtual const IhullTypeIGC* GetHullType(void) const { return &m_myHullType; } virtual IhullTypeIGC* GetBaseHullType(void) const { return m_myHullType.GetHullType(); } virtual void SetBaseHullType(IhullTypeIGC* newVal); virtual void AddPart(IpartIGC* part); virtual void DeletePart(IpartIGC* part); virtual const PartListIGC* GetParts(void) const { return &m_parts; } virtual IpartIGC* GetMountedPart(EquipmentType type, Mount mount) const; virtual void MountPart(IpartIGC* p, Mount mountNew, Mount* pmountOld); virtual const Vector& GetCockpit(void) const { return m_cockpit; } virtual short GetAmmo(void) const { return m_ammo; } virtual void SetAmmo(short newVal) { short maxAmmo = m_myHullType.GetMaxAmmo(); if (newVal > maxAmmo) newVal = maxAmmo; short oldAmmo = m_ammo; m_ammo = newVal; if ((newVal == 0) && (oldAmmo > 0) && (GetMyLastUpdate() >= m_timeReloadAmmo)) { m_timeReloadAmmo = GetMyLastUpdate() + 0.5f / GetMyMission()->GetFloatConstant(c_fcidMountRate); IIgcSite* pigc = GetMyMission()->GetIgcSite(); if (!pigc->Reload(this, NULL, ET_Weapon)) { pigc->PostNotificationText(this, false, "Ammo depleted."); } else { pigc->PlayNotificationSound(salReloadingAmmoSound, this); pigc->PlayNotificationSound(startReloadSound, this); pigc->PostNotificationText(this, false, "Reloading ammo..."); } } } virtual float GetFuel(void) const { return m_fuel; } virtual void SetFuel(float newVal) { float maxFuel = m_myHullType.GetMaxFuel(); if (newVal > maxFuel) newVal = maxFuel; float oldFuel = m_fuel; m_fuel = newVal; if ((newVal == 0.0f) && (oldFuel > 0.0f) && (GetMyLastUpdate() >= m_timeReloadFuel)) { m_timeReloadFuel = GetMyLastUpdate() + 0.5f / GetMyMission()->GetFloatConstant(c_fcidMountRate); IIgcSite* pigc = GetMyMission()->GetIgcSite(); if (!pigc->Reload(this, NULL, ET_Afterburner)) { pigc->PostNotificationText(this, false, "Fuel depleted."); } else { pigc->PlayNotificationSound(salReloadingFuelSound, this); pigc->PlayNotificationSound(startReloadSound, this); pigc->PostNotificationText(this, false, "Reloading fuel..."); } } } virtual float GetEnergy(void) const { return m_energy; } virtual void SetEnergy(float newVal) { m_energy = newVal; } virtual float GetCloaking(void) const { return m_cloaking; } virtual void SetCloaking(float newVal) { m_cloaking = newVal; } virtual bool GetVectorLock(void) const { return (m_stateM & coastButtonIGC) ? true : false; } virtual void SetVectorLock(bool bVectorLock) { if (bVectorLock) m_stateM |= coastButtonIGC; else m_stateM &= ~coastButtonIGC; } virtual const ControlData& GetControls(void) const { return m_controls; } virtual void SetControls(const ControlData& newVal) { m_controls = newVal; } virtual const Vector& GetEngineVector(void) const { return m_engineVector; } virtual int GetStateM(void) const { return m_stateM; } virtual void SetStateM(int newVal); virtual void SetStateBits(int mask, int newBits) { SetStateM((m_stateM & (~mask)) | (newBits & mask)); } virtual ImodelIGC* GetCommandTarget(Command i) const { assert (i >= 0); assert (i < c_cmdMax); return m_commandTargets[i]; } virtual CommandID GetCommandID(Command i) const { assert (i >= 0); assert (i < c_cmdMax); return m_commandIDs[i]; } virtual void SetCommand(Command i, ImodelIGC* target, CommandID cid) { assert (i >= 0); assert (i < c_cmdMax); CommandID cidOld = m_commandIDs[i]; ImodelIGC* pmodelOld = m_commandTargets[i]; //if ((target != pmodelOld) || (cid != m_commandIDs[i])) { m_commandTargets[i] = target; if (target) { target->AddRef(); if (target->GetObjectType() == OT_buoy) ((IbuoyIGC*)target)->AddConsumer(); } m_commandIDs[i] = cid; switch (i) { case c_cmdCurrent: { if ((pmodelOld != target) && m_mountedOthers[ET_Magazine]) ((ImagazineIGC*)m_mountedOthers[ET_Magazine])->SetLock(0.0f); } break; case c_cmdPlan: { //Clear the drilling mask (either it wasn't set or it no longer applies). m_stateM &= ~drillingMaskIGC; ResetWaypoint(); m_fractionLastOrder = m_fraction; m_timeRanAway = GetMyLastUpdate(); m_bRunningAway = false; } break; case c_cmdAccepted: { if (m_bAutopilot && (m_pilotType < c_ptPlayer)) { SetCommand(c_cmdCurrent, target, cid); SetCommand(c_cmdPlan, target, cid); } } break; } if (pmodelOld) { if (pmodelOld->GetObjectType() == OT_buoy) ((IbuoyIGC*)pmodelOld)->ReleaseConsumer(); pmodelOld->Release(); } if ((i == c_cmdAccepted || i == c_cmdCurrent) && (cidOld != cid || pmodelOld != target)) GetMyMission()->GetIgcSite()->CommandChangedEvent(i, this, target, cid); } } virtual void ExecuteTurretMove(Time timeStart, Time timeStop, Orientation* pOrientation); virtual void PreplotShipMove(Time timeStop); virtual void PlotShipMove(Time timeStop); virtual void ExecuteShipMove(Time timeStop); virtual void ExecuteShipMove(Time timeStart, Time timeStop, Vector* pVelocity, Orientation* pOrientation); virtual short ExportShipLoadout(ShipLoadout* ploadout) { if (ploadout) { ploadout->hullID = m_myHullType.GetObjectID(); assert (ploadout->hullID != NA); ExpandedPartData* ppd = ploadout->PartData0(); for (PartLinkIGC* ppl = m_parts.first(); (ppl != NULL); ppl = ppl->next()) { IpartIGC* ppart = ppl->data(); ppd->partID = ppart->GetPartType()->GetObjectID(); ppd->mountID = ppart->GetMountID(); ppd->amount = ppart->GetAmount(); (ppd++)->fractionMounted = ppart->GetMountedFraction(); } } return sizeof(ShipLoadout) + sizeof(ExpandedPartData) * m_parts.n(); } virtual bool EquivalentShip(IshipIGC* pship) const { if (m_myHullType.GetHullType() != pship->GetBaseHullType()) return false; else { Mount maxWeapons = m_myHullType.GetMaxWeapons(); for (Mount i = 0; (i < maxWeapons); i++) { IpartIGC* p1 = m_mountedWeapons[i]; IpartIGC* p2 = pship->GetMountedPart(ET_Weapon, i); if ((p1 != NULL) || (p2 != NULL)) { if ((p1 == NULL) || (p2 == NULL) || (p1->GetPartType() != p2->GetPartType())) { return false; } } } for (Mount j = 0; (j < ET_MAX); j++) { IpartIGC* p1 = GetMountedPart(j, 0); IpartIGC* p2 = pship->GetMountedPart(j, 0); if ((p1 != NULL) || (p2 != NULL)) { if ((p1 == NULL) || (p2 == NULL) || (p1->GetPartType() != p2->GetPartType()) || (p1->GetAmount() != p2->GetAmount())) { return false; } } } for (Mount k = -1; (k >= -c_maxCargo); k--) { IpartIGC* p1 = m_mountedCargos[k + c_maxCargo]; IpartIGC* p2 = pship->GetMountedPart(NA, k); if ((p1 != NULL) || (p2 != NULL)) { if ((p1 == NULL) || (p2 == NULL) || (p1->GetPartType() != p2->GetPartType()) || (p1->GetAmount() != p2->GetAmount())) { return false; } } } } return true; } virtual void ProcessShipLoadout(short cbLoadout, const ShipLoadout* ploadout, bool bReady) { //Did the hull change? { IhullTypeIGC* pht = m_myHullType.GetHullType(); if ((pht == NULL) || (ploadout->hullID != pht->GetObjectID())) { //Yes ... change it. Trash all the parts first, though { PartLinkIGC* ppl; while (ppl = m_parts.first()) //Intentional ppl->data()->Terminate(); } SetBaseHullType(GetMyMission()->GetHullType(ploadout->hullID)); } } const ExpandedPartData* ppartLC = ploadout->PartData0(); const ExpandedPartData* ppdLastPart = ploadout->PartDataN(cbLoadout); PartLinkIGC* pplShip = m_parts.first(); //Walk both lists in parallel, looking for differences while (true) { if (ppartLC != ppdLastPart) { //We have a part in the message if (pplShip) { //We have a corresponding part on the ship ... are they the same part? IpartIGC* ppart = pplShip->data(); if (ppart->GetPartType()->GetObjectID() == ppartLC->partID) { //Yes //has the mount changed? if (ppart->GetMountID() != ppartLC->mountID) { //Is there another part already mounted in the desired slot? //If so, remove it IpartIGC* ppartMounted = GetMountedPart(ppart->GetEquipmentType(), ppartLC->mountID); if (ppartMounted) ppartMounted->Terminate(); ppart->SetMountID(ppartLC->mountID); } //has the quantity changed (for parts where that matters)? ObjectType type = ppart->GetObjectType(); if (ppartLC->amount != ppart->GetAmount()) { ppart->SetAmount(ppartLC->amount); } //In any case ... set the mounted fraction to agree with the fraction specified in the part definition if (bReady) ppart->Arm(); else ppart->SetMountedFraction(ppartLC->fractionMounted); //Go to the next part pair. pplShip = pplShip->next(); ppartLC++; } else { //No ... delete this part and go to the next part on the ship //while not advancing the ppartLC pointer pplShip = pplShip->next(); ppart->Terminate(); } } else { //No corresponding part on the ship: create one IpartIGC* ppart = CreateAndAddPart(ppartLC); if (bReady) ppart->Arm(); else ppart->SetMountedFraction(ppartLC->fractionMounted); ppartLC++; } } else if (pplShip) { //No part in the message but one on the ship. Nuke it. IpartIGC* ppart = pplShip->data(); //Go to the next part before the nuke pplShip = pplShip->next(); ppart->Terminate(); } else { //No parts in either the message or the ship //All done. break; } } } virtual bool PurchaseShipLoadout(short cbLoadout, const ShipLoadout* ploadout) { assert (m_station); //Did the hull change? IhullTypeIGC* pht = m_myHullType.GetHullType(); if ((pht == NULL) || (ploadout->hullID != pht->GetObjectID())) { pht = GetMyMission()->GetHullType(ploadout->hullID); if (!(pht && m_station->CanBuy(pht))) return false; //Can't buy the hull: abort //Select the successor of the part. pht = (IhullTypeIGC*)(m_station->GetSuccessor(pht)); } //So far so good ... trash the parts PartListIGC partsOld; { PartLinkIGC* ppl; while (ppl = m_parts.first()) //Intentional { IpartIGC* ppart = ppl->data(); ppart->AddRef(); ppart->SetShip(NULL, NA); partsOld.last(ppart); } } if (pht != m_myHullType.GetHullType()) SetBaseHullType(pht); const ExpandedPartData* ppdNext = ploadout->PartData0(); const ExpandedPartData* ppdLastPart = ploadout->PartDataN(cbLoadout); bool bComplete = true; while (ppdNext < ppdLastPart) { IpartTypeIGC* ppt = GetMyMission()->GetPartType(ppdNext->partID); if (ppt && m_myHullType.CanMount(ppt, ppdNext->mountID) && (GetMountedPart(ppt->GetEquipmentType(), ppdNext->mountID) == NULL)) { //Use an upgraded version if available if (m_station->CanBuy(ppt)) { ppt = (IpartTypeIGC*)(m_station->GetSuccessor(ppt)); assert (m_myHullType.CanMount(ppt, ppdNext->mountID)); IpartIGC* ppart = CreateAndAddPart(ppt, ppdNext->mountID, ppdNext->amount); ppart->Arm(); } else { //Can't buy the part: can we re-use an existing part? for (PartLinkIGC* pplOld = partsOld.first(); (pplOld != NULL); pplOld = pplOld->next()) { if (ppt == pplOld->data()->GetPartType()) { IpartIGC* ppart = pplOld->data(); ppart->SetShip(this, ppdNext->mountID); ppart->Arm(); ppart->Release(); delete pplOld; //If this is an expendable ... scavenge all the old parts to fill it up if (IlauncherTypeIGC::IsLauncherType(ppt->GetEquipmentType())) { short maxAmmo = ppdNext->amount; short ammo = ppart->GetAmount(); if (ammo < maxAmmo) { PartLinkIGC* pplNext; for (PartLinkIGC* pplOther = partsOld.first(); (pplOther != NULL); pplOther = pplNext) { pplNext = pplOther->next(); IpartIGC* ppartOther = pplOther->data(); if (ppartOther->GetPartType() == ppt) { short newAmmo = ammo + ppartOther->GetAmount(); if (newAmmo > maxAmmo) { ppartOther->SetAmount(maxAmmo - newAmmo); newAmmo = maxAmmo; } else { ppartOther->Terminate(); ppartOther->Release(); delete pplOther; } ppart->SetAmount(newAmmo); } } } } break; } } } } else bComplete = false; ppdNext++; } { PartLinkIGC* ppl; while (ppl = partsOld.first()) //Intentional { ppl->data()->Terminate(); ppl->data()->Release(); delete ppl; } } return bComplete; } virtual void ExportFractions(CompactShipFractions* pfractions) const { pfractions->SetHullFraction(m_fraction); { IshieldIGC* s = (IshieldIGC*)(m_mountedOthers[ET_Shield]); pfractions->SetShieldFraction(s ? s->GetFraction() : 0.0f); } pfractions->SetFuel(m_myHullType.GetMaxFuel(), m_fuel); pfractions->SetAmmo(m_myHullType.GetMaxAmmo(), m_ammo); pfractions->SetEnergy(m_myHullType.GetMaxEnergy(), m_energy); } #define SetSC pshipupdate->stateM.Set(m_stateM); \ pshipupdate->controls.Set(m_controls); #define SetOVTP pshipupdate->orientation.Set(GetOrientation()); \ pshipupdate->velocity.Set(GetVelocity()); \ pshipupdate->turnRates.Set(m_turnRates); \ { \ IafterburnerIGC* p = (IafterburnerIGC*)(m_mountedOthers[ET_Afterburner]); \ pshipupdate->power = (p ? BytePercentage(p->GetPower()) : BytePercentage(0.0f)); \ } #define SetF pshipupdate->fractions.SetHullFraction(m_fraction); \ { \ IshieldIGC* s = (IshieldIGC*)(m_mountedOthers[ET_Shield]); \ pshipupdate->fractions.SetShieldFraction(s ? s->GetFraction() : 0.0f); \ } \ pshipupdate->fractions.SetFuel(m_myHullType.GetMaxFuel(), m_fuel); \ pshipupdate->fractions.SetAmmo(m_myHullType.GetMaxAmmo(), m_ammo); \ pshipupdate->fractions.SetEnergy(m_myHullType.GetMaxEnergy(), m_energy); virtual void ExportShipUpdate(ServerLightShipUpdate* pshipupdate) const { pshipupdate->shipID = m_shipID; SetSC; } virtual void ExportShipUpdate(Time timeReference, const Vector& positionReference, ServerHeavyShipUpdate* pshipupdate) const { assert (GetPosition().LengthSquared() != 0.0f); pshipupdate->shipID = m_shipID; pshipupdate->time.Set(timeReference, GetMyLastUpdate()); pshipupdate->position.Set(positionReference, GetPosition()); SetSC; SetOVTP; SetF; } virtual void ExportShipUpdate(ClientShipUpdate* pshipupdate) const { assert (GetPosition().LengthSquared() != 0.0f); //Message generated on the client so convert to server time pshipupdate->time = GetMyMission()->GetIgcSite()->ServerTimeFromClientTime(GetMyLastUpdate()); pshipupdate->position = GetPosition(); SetSC; SetOVTP; pshipupdate->orientation.Validate(); } virtual void ExportShipUpdate(ServerSingleShipUpdate* pshipupdate) const { pshipupdate->shipID = m_shipID; pshipupdate->time = GetMyLastUpdate(); pshipupdate->position = GetPosition(); SetSC; SetOVTP; SetF; } #undef SetSC #undef SetOVTP #undef SetF virtual void ExportShipUpdate(ClientActiveTurretUpdate* pshipupdate) const { pshipupdate->time = GetMyMission()->GetIgcSite()->ServerTimeFromClientTime(GetMyLastUpdate()); pshipupdate->controls.Set(m_controls); pshipupdate->orientation.Set(GetOrientation()); } virtual void ProcessFractions(const CompactShipFractions& fractions); virtual ShipUpdateStatus ProcessShipUpdate(const ServerLightShipUpdate& shipupdate); virtual ShipUpdateStatus ProcessShipUpdate(Time timeReference, Vector positionReference, const ServerHeavyShipUpdate& shipupdate); virtual ShipUpdateStatus ProcessShipUpdate(const ClientShipUpdate& shipupdate); virtual ShipUpdateStatus ProcessShipUpdate(const ServerSingleShipUpdate& shipupdate, bool bOrient = true); virtual ShipUpdateStatus ProcessShipUpdate(Time timeReference, const ServerActiveTurretUpdate& shipupdate); virtual ShipUpdateStatus ProcessShipUpdate(const ClientActiveTurretUpdate& shipupdate); virtual void SetPrivateData(DWORD dwPrivate) { m_dwPrivate = dwPrivate; } virtual DWORD GetPrivateData(void) const { return m_dwPrivate; } Mount HitTreasure(TreasureCode treasureCode, ObjectID objectID, short amount) { assert (m_myHullType.GetHullType()); switch (treasureCode) { case c_tcPart: { IpartTypeIGC* ppt = GetMyMission()->GetPartType(objectID); assert (ppt); //Can we carry the thing? EquipmentType et = ppt->GetEquipmentType(); Mount maxMounts = (et == ET_Weapon) ? m_myHullType.GetMaxWeapons() : 1; //Try to mount the part in each possible location IpartIGC* ppart; Mount mount; short a; for (mount = 0; (mount < maxMounts); mount++) { if (m_myHullType.CanMount(ppt, mount)) { ppart = *PartLocation(et, mount); if (ppart == NULL) break; if ((ppart->GetPartType() == ppt) && IlauncherIGC::IsLauncher(ppart->GetObjectType())) { short maxAmount = ppt->GetAmount(this); a = ppart->GetAmount(); if ((a < maxAmount) && ((a + amount) <= maxAmount)) break; } } } if (mount == maxMounts) { //No place to mount it ... see if there is room in cargo for (mount = -1; (mount >= -c_maxCargo); mount--) { ppart = *PartLocation(NA, mount); if (ppart == NULL) break; if ((ppart->GetPartType() == ppt) && IlauncherIGC::IsLauncher(ppart->GetObjectType())) { short maxAmount = ppt->GetAmount(this); a = ppart->GetAmount(); if ((a < maxAmount) && ((a + amount) <= maxAmount)) break; } } if (mount < -c_maxCargo) { //No place to put it in cargo GetMyMission()->GetIgcSite()->PlayNotificationSound(salCargoFullSound, this); return c_mountNA; } } GetMyMission()->GetIgcSite()->PlayNotificationSound(pickUpPartSound, this); if (ppart) ppart->SetAmount(a + amount); else CreateAndAddPart(ppt, mount, amount); return mount; } break; case c_tcDevelopment: { IbucketIGC* pb = (IbucketIGC*)GetIbaseIGC((BaseListIGC*)(GetSide()->GetBuckets()), objectID); if (pb && !pb->GetCompleteF()) { pb->ForceComplete(GetMyLastUpdate()); } } break; case c_tcPowerup: { if (objectID & c_pcHull) SetFraction(1.0f); if (objectID & c_pcShield) { IshieldIGC* pshield = (IshieldIGC*)(m_mountedOthers[ET_Shield]); if (pshield) pshield->SetFraction(1.0f); } if (objectID & c_pcEnergy) m_energy = m_myHullType.GetMaxEnergy(); if (objectID & c_pcFuel) SetFuel(FLT_MAX); if (objectID & c_pcAmmo) SetAmmo(0x7fff); } break; case c_tcFlag: { assert (m_sidFlag == NA); assert (objectID != NA); m_sidFlag = objectID; } break; } return c_mountNA; } virtual ImissileIGC* GetLastMissileFired(void) const { return m_pmissileLast; } virtual void SetLastMissileFired(ImissileIGC* pmissile) { if (m_pmissileLast) m_pmissileLast->Release(); m_pmissileLast = pmissile; if (pmissile) pmissile->AddRef(); } virtual void Promote(void); virtual void SetParentShip(IshipIGC* pship); virtual IshipIGC* GetParentShip(void) const { return m_pshipParent; } virtual Mount GetTurretID(void) const { return m_turretID; } virtual void SetTurretID(Mount turretID) { if (m_turretID != turretID) { assert (m_pshipParent); if (m_turretID != NA) { assert (!m_pshipParent->GetHullType()->GetHardpointData(m_turretID).bFixed); IweaponIGC* pw = (IweaponIGC*)(m_pshipParent->GetMountedPart(ET_Weapon, m_turretID)); if (pw) { assert (pw->GetGunner() == this); pw->SetGunner(NULL); } } m_turretID = turretID; if (m_turretID != NA) { IweaponIGC* pw = (IweaponIGC*)(m_pshipParent->GetMountedPart(ET_Weapon, m_turretID)); if (pw) { assert (!m_pshipParent->GetHullType()->GetHardpointData(m_turretID).bFixed); pw->SetGunner(this); } } GetMyMission()->GetIgcSite()->LoadoutChangeEvent(this, NULL, c_lcTurretChange); GetMyMission()->GetIgcSite()->LoadoutChangeEvent(m_pshipParent, NULL, c_lcPassengerMove); } } virtual IshipIGC* GetGunner(Mount turretID) const { IweaponIGC* pweapon = (IweaponIGC*)*PartLocation(ET_Weapon, turretID); if (pweapon) { return pweapon->GetGunner(); } else { // we have to manually walk through the child ships for (ShipLinkIGC* psl = m_shipsChildren.first(); (psl != NULL); psl = psl->next()) { IshipIGC* pshipChild = psl->data(); if (pshipChild->GetTurretID() == turretID) return pshipChild; } return NULL; } } virtual const ShipListIGC* GetChildShips(void) const { return &m_shipsChildren; } virtual void AddChildShip(IshipIGC* pship) { assert (pship); AddIbaseIGC((BaseListIGC*)&m_shipsChildren, pship); } virtual void DeleteChildShip(IshipIGC* pship) { assert (pship); DeleteIbaseIGC((BaseListIGC*)&m_shipsChildren, pship); } virtual IshipIGC* GetSourceShip(void) { return m_pshipParent ? m_pshipParent : this; } virtual IpartIGC* CreateAndAddPart(const PartData* ppd) { return CreateAndAddPart(GetMyMission()->GetPartType(ppd->partID), ppd->mountID, ppd->amount); } virtual IpartIGC* CreateAndAddPart(IpartTypeIGC* ppt, Mount mount, short amount) { assert (ppt); assert (GetMountedPart(ppt->GetEquipmentType(), mount) == NULL); assert (m_myHullType.CanMount(ppt, mount)); IpartIGC* part = GetMyMission()->CreatePart(GetMyLastUpdate(), ppt); assert (part); part->SetShip(this, mount); assert (part->GetShip() == this); assert (part->GetMountID() == mount); part->SetAmount(amount); part->Release(); return part; //Bad form to return after a release but it is not dead since the ship holds a pointer } virtual WingID GetWingID(void) const { return m_wingID; } virtual void SetWingID(WingID wid) { m_wingID = wid; } virtual bool fRipcordActive(void) const { return m_pmodelRipcord != NULL; } virtual float GetRipcordTimeLeft(void) const { assert(fRipcordActive()); return m_dtRipcordCountdown; } virtual void ResetRipcordTimeLeft(void) { assert (m_myHullType.GetHullType()); m_dtRipcordCountdown = m_myHullType.GetRipcordSpeed(); } virtual PilotType GetPilotType(void) const { return m_pilotType; } virtual AbilityBitMask GetOrdersABM(void) const { return m_abmOrders; } virtual bool GetAutopilot(void) const { return m_bAutopilot; } virtual void SetAutopilot(bool bAutopilot); virtual bool LegalCommand(CommandID cid) const { bool bLegal = true; switch (m_pilotType) { case c_ptCarrier: { bLegal = (cid == c_cidDefault) || (cid == c_cidGoto) || (cid == c_cidJoin) || (cid == c_cidDoNothing); } break; case c_ptMiner: { bLegal = (cid == c_cidDefault) || (cid == c_cidGoto) || (cid == c_cidJoin) || (cid == c_cidDoNothing) || (cid == c_cidMine); } break; case c_ptLayer: { bLegal = (cid == c_cidDefault) || (cid == c_cidGoto) || (cid == c_cidJoin) || (cid == c_cidDoNothing) || (cid == c_cidBuild); } break; case c_ptBuilder: { bLegal = ((m_stateM & (drillingMaskIGC | buildingMaskIGC)) == 0) && ((cid == c_cidDefault) || (cid == c_cidGoto) || (cid == c_cidJoin) || (cid == c_cidDoNothing) || (cid == c_cidBuild)); } break; case c_ptWingman: { bLegal = (cid == c_cidDefault) || (cid == c_cidGoto) || (cid == c_cidAttack) || (cid == c_cidPickup) || (cid == c_cidDoNothing); } break; case c_ptPlayer: case c_ptCheatPlayer: { bLegal = (cid >= c_cidDefault) && (cid < c_cidMine); } } return bLegal; } virtual bool LegalCommand(CommandID cid, ImodelIGC* pmodel) const { bool bLegal = true; if ((pmodel == NULL) || ((m_stateM & buildingMaskIGC) != 0) || (pmodel == (ImodelIGC*)this) || (pmodel->GetMission() != GetMyMission()) || (pmodel->GetObjectType() == OT_buoy && ((IbuoyIGC*)pmodel)->GetBuoyType() == c_buoyCluster && ((IbuoyIGC*)pmodel)->GetCluster() == GetCluster())) { bLegal = (cid == c_cidDoNothing); } else { ObjectType type = pmodel->GetObjectType(); bool bFriendly = pmodel->GetSide() == GetSide(); switch (cid) { case c_cidNone: { bLegal = false; } break; case c_cidDefault: case c_cidGoto: { bLegal = (m_pilotType >= c_ptPlayer) || (type != OT_station) || bFriendly; } break; case c_cidAttack: { bLegal = ((m_pilotType == c_ptWingman) || (m_pilotType >= c_ptPlayer)) && (type != OT_warp) && (type != OT_treasure) && !bFriendly; } break; case c_cidCapture: { bLegal = (m_pilotType >= c_ptPlayer) && (type == OT_station) && !bFriendly; } break; case c_cidDefend: { bLegal = (m_pilotType >= c_ptPlayer); } break; case c_cidPickup: { if (((m_pilotType == c_ptWingman) || (m_pilotType >= c_ptPlayer)) && (m_pshipParent == NULL)) { if (type == OT_ship) { IhullTypeIGC* pht = ((IshipIGC*)pmodel)->GetBaseHullType(); bLegal = (pht && m_myHullType.GetHullType() && ((pht->HasCapability(c_habmLifepod) && m_myHullType.GetHullType()->HasCapability(c_habmRescue)) || (pht->HasCapability(c_habmRescue) && m_myHullType.GetHullType()->HasCapability(c_habmLifepod)))); } else if (type != OT_treasure) bLegal = false; } else bLegal = false; } break; case c_cidRepair: { //Can only repair friendly ships or stations bLegal = (m_pilotType >= c_ptPlayer) && ((type == OT_ship) || (type == OT_station)) && bFriendly; } break; case c_cidJoin: { //Can only join other ships bLegal = type == OT_ship; } break; case c_cidBuild: { if (m_pilotType == c_ptLayer) bLegal = (type == OT_buoy) || (type == OT_warp); else if (m_pilotType == c_ptBuilder) { bLegal = (type == OT_asteroid) && ((IasteroidIGC*)pmodel)->HasCapability(m_abmOrders); } else bLegal = false; } break; case c_cidMine: { if (m_pilotType == c_ptMiner) bLegal = (type == OT_asteroid) && ((IasteroidIGC*)pmodel)->HasCapability(m_abmOrders); else bLegal = false; } } } return bLegal; } virtual void Complain(SoundID sid, const char* pszMsg) { if (GetMyLastUpdate() >= m_timeLastComplaint + m_dtTimeBetweenComplaints) { //There is another side here at the asteroid ... complain m_timeLastComplaint = GetMyLastUpdate(); if (m_dtTimeBetweenComplaints < 600.0f) m_dtTimeBetweenComplaints *= random(1.5f, 2.5f); GetMyMission()->GetIgcSite()->SendChat(this, CHAT_TEAM, GetSide()->GetObjectID(), sid, pszMsg); } } virtual IshipIGC* GetAutoDonate(void) const { return m_pshipAutoDonate; } virtual void SetAutoDonate(IshipIGC* pship) { assert (pship != this); //Anyone donating to me now donates to my new target if (pship) { IsideIGC* pside = GetSide(); assert (pside); assert (pship->GetSide() == pside); assert (pship->GetAutoDonate() == NULL); //Was anyone on my ide donating to me ... if so, they start donating to the new person for (ShipLinkIGC* psl = pside->GetShips()->first(); (psl != NULL); psl = psl->next()) { if (psl->data()->GetAutoDonate() == this) psl->data()->SetAutoDonate(pship == psl->data() ? NULL : pship); } } m_pshipAutoDonate = pship; } virtual short GetKills(void) const { return m_nKills; } virtual void SetKills(short n) { m_nKills = n; } virtual void AddKill(void) { m_nKills++; GetSide()->AddKill(); } virtual short GetDeaths(void) const { return m_nDeaths; } virtual void SetDeaths(short n) { m_nDeaths = n; } virtual void AddDeath(void) { m_nDeaths++; GetSide()->AddDeath(); } virtual short GetEjections(void) const { return m_nEjections; } virtual void SetEjections(short n) { m_nEjections = n; } virtual void AddEjection(void) { m_nEjections++; GetSide()->AddEjection(); } virtual float GetExperienceMultiplier(void) const { const float c_maxBonus = 0.5f; const float c_halfExperience = 4.0f; return 1.0f + c_maxBonus * m_experience / (m_experience + c_halfExperience); } virtual float GetExperience(void) const { return m_experience; } virtual void SetExperience(float f) { m_experience = f; } virtual void AddExperience(void) { m_experience += 1.0f; } virtual ImodelIGC* GetRipcordModel(void) const { return m_pmodelRipcord; } virtual void SetRipcordModel(ImodelIGC* pmodel) { //Turn off cloak if ripcording if (pmodel && (m_stateM & cloakActiveIGC)) SetStateM(m_stateM & ~cloakActiveIGC); if (m_pmodelRipcord && (m_pmodelRipcord->GetObjectType() == OT_ship)) ((IshipIGC*)(ImodelIGC*)m_pmodelRipcord)->AdjustRipcordDebt(-m_ripcordCost); m_pmodelRipcord = pmodel; if (m_pmodelRipcord && (m_pmodelRipcord->GetObjectType() == OT_ship)) ((IshipIGC*)(ImodelIGC*)m_pmodelRipcord)->AdjustRipcordDebt(m_ripcordCost); } virtual ImodelIGC* FindRipcordModel(IclusterIGC* pcluster); virtual float GetRipcordDebt(void) const { return m_ripcordDebt; } virtual void AdjustRipcordDebt(float delta) { m_ripcordDebt += delta; } virtual bool OkToLaunch(Time now) { //Spend 10 seconds docked (MyLastUpdate is not being updated while docked) if (now > GetMyLastUpdate() + 10.0f) { IclusterIGC* pcluster = m_station->GetCluster(); const Vector& positionMe = m_station->GetPosition(); if (LegalCommand(m_commandIDs[c_cmdAccepted], m_commandTargets[c_cmdAccepted]) || PickDefaultOrder(pcluster, positionMe, true)) { assert (m_station); IsideIGC* psideMe = GetSide(); int cEnemy = 0; int cFriend = 0; float d2Enemy = FLT_MAX; float d2Friend = FLT_MAX; for (ShipLinkIGC* psl = m_station->GetCluster()->GetShips()->first(); (psl != NULL); psl = psl->next()) { IshipIGC* pship = psl->data(); if ((pship->GetPilotType() >= c_ptPlayer) && (pship->GetParentShip() == NULL) && !pship->GetBaseHullType()->HasCapability(c_habmLifepod)) { IsideIGC* pside = pship->GetSide(); if (pside == psideMe) { cFriend++; float d2 = (positionMe - pship->GetPosition()).LengthSquared(); if (d2 < d2Friend) d2Friend = d2; } else if (pship->SeenBySide(psideMe)) { cEnemy++; float d2 = (positionMe - pship->GetPosition()).LengthSquared(); if (d2 < d2Enemy) d2Enemy = d2; } } } if (cFriend >= cEnemy) return true; else { static const float c_d2AlwaysRun = 1000.0f; if ((d2Enemy > c_d2AlwaysRun * c_d2AlwaysRun) && (d2Enemy >= d2Friend)) { return true; } } } SetMyLastUpdate(now); } return false; } virtual DamageTrack* GetDamageTrack(void) { return m_damageTrack; } virtual void CreateDamageTrack(void) { delete m_damageTrack; m_damageTrack = GetMyMission()->CreateDamageTrack(); } virtual void DeleteDamageTrack(void) { delete m_damageTrack; m_damageTrack = NULL; } virtual void ResetDamageTrack(void) { if (m_damageTrack) m_damageTrack->Reset(); } virtual void AddMineDamage(DamageTypeID type, float amount, Time timeCollision, ImodelIGC* pmodelLauncher, const Vector& position1, const Vector& position2) { if (amount > m_maxMineAmount) { m_maxMineType = type; m_maxMineAmount = amount; m_maxMineTime = timeCollision; m_maxMineP1 = position1; m_maxMineP2 = position2; m_maxMineLauncher = pmodelLauncher; } } virtual void ApplyMineDamage(void) { if (m_maxMineAmount > 0.0f) { if (m_maxMineTime > m_timeLastMineExplosion + 0.5f) { m_timeLastMineExplosion = m_maxMineTime; GetCluster()->GetClusterSite()->AddExplosion(m_maxMineP2, 1.5f, c_etMine); } TRef pmodelLauncher = m_maxMineLauncher; m_maxMineLauncher = NULL; float amount = m_maxMineAmount; m_maxMineAmount = 0.0f; ReceiveDamage(m_maxMineType, amount, m_maxMineTime, m_maxMineP1, m_maxMineP2, pmodelLauncher); } } virtual WarningMask GetWarningMask(void) const { return m_warningMask; } virtual void SetWarningMaskBit(WarningMask wm) { m_warningMask |= wm; } virtual void ClearWarningMaskBit(WarningMask wm) { m_warningMask &= ~wm; } //Builders ... virtual void SetBaseData(IbaseIGC* pbase) { m_pbaseData = pbase; if (m_pilotType == c_ptBuilder) { assert (pbase->GetObjectType() == OT_stationType); m_abmOrders = ((IstationTypeIGC*)pbase)->GetBuildAABM(); } else { assert (m_pilotType == c_ptLayer); assert ((pbase->GetObjectType() == OT_mineType) || (pbase->GetObjectType() == OT_probeType)); } } virtual IbaseIGC* GetBaseData(void) const { return m_pbaseData; } virtual CommandID GetDefaultOrder(ImodelIGC* pmodel) { IsideIGC* psideHim = pmodel->GetSide(); ObjectType type = pmodel->GetObjectType(); CommandID cid = c_cidGoto; switch (m_pilotType) { case c_ptMiner: case c_ptBuilder: { if ((psideHim == NULL) && (type == OT_asteroid) && ((IasteroidIGC*)pmodel)->HasCapability(m_abmOrders)) { cid = (m_pilotType == c_ptMiner) ? c_cidMine : c_cidBuild; } } break; case c_ptLayer: { if ((type == OT_buoy) || (type == OT_warp)) cid = c_cidBuild; } break; case c_ptWingman: case c_ptPlayer: case c_ptCheatPlayer: { if (psideHim == GetSide()) { cid = c_cidDefend; if (m_pshipParent == NULL) { if (type == OT_ship) { IhullTypeIGC* pht = ((IshipIGC*)pmodel)->GetBaseHullType(); if (pht && m_myHullType.GetHullType()) { if ( (pht->HasCapability(c_habmLifepod) && m_myHullType.GetHullType()->HasCapability(c_habmRescue)) || (pht->HasCapability(c_habmRescue) && m_myHullType.GetHullType()->HasCapability(c_habmLifepod)) ) cid = c_cidPickup; } } else if (m_myHullType.GetHullType()) { if (type == OT_station) { StationAbilityBitMask sabm = ((IstationIGC*)pmodel)->GetStationType()->GetCapabilities(); HullAbilityBitMask habm = m_myHullType.GetCapabilities(); if ((habm & c_habmFighter) == 0) { if (sabm & c_sabmCapLand) cid = c_cidGoto; } else if (habm & c_habmLifepod) { if (sabm & (c_sabmRescue | c_sabmLand)) cid = c_cidGoto; } else if (sabm & c_sabmLand) cid = c_cidGoto; } else if (type == OT_probe) { if (m_myHullType.HasCapability(c_habmLifepod) && ((IprobeIGC*)pmodel)->GetProbeType()->HasCapability(c_eabmRescue | c_eabmRescueAny)) { cid = c_cidGoto; } } } } } else if (type == OT_treasure) cid = c_cidPickup; else if (type == OT_probe) { cid = c_cidAttack; if (m_myHullType.GetHullType() && m_myHullType.HasCapability(c_habmLifepod) && ((IprobeIGC*)pmodel)->GetProbeType()->HasCapability(c_eabmRescueAny)) { cid = c_cidGoto; } } else if (psideHim != NULL) cid = c_cidAttack; } } return cid; } virtual short GetLaunchSlot(void) { m_nextLaunchSlot = (m_nextLaunchSlot + 1) % m_myHullType.GetHullType()->GetLaunchSlots(); return m_nextLaunchSlot; } //Miners virtual float GetOre(void) const { return m_fOre; } bool PickDefaultOrder(IclusterIGC* pcluster, const Vector& position, bool bDocked) { bool fGaveOrder = false; //No orders ... pick something switch (m_pilotType) { case c_ptMiner: { float capacity = GetMyMission()->GetFloatConstant(c_fcidCapacityHe3) * GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaMiningCapacity); if (m_fOre < capacity / 2.0f) { ImodelIGC* pmodel = FindTarget(this, c_ttNeutral | c_ttAsteroid | c_ttNearest | c_ttLeastTargeted | c_ttAnyCluster | c_ttCowardly, NULL, pcluster, &position, NULL, m_abmOrders); if (pmodel) { SetCommand(c_cmdAccepted, pmodel, c_cidMine); fGaveOrder = true; } } if ((!m_commandTargets[c_cmdCurrent]) && ((m_fOre > 0.0f) || !bDocked)) { ImodelIGC* pmodel = NULL; if (m_fOre > 0.0f) pmodel = FindTarget(this, c_ttFriendly | c_ttStation | c_ttNearest | c_ttAnyCluster, NULL, pcluster, &position, NULL, c_sabmUnload); if (pmodel == NULL) pmodel = FindTarget(this, c_ttFriendly | c_ttStation | c_ttNearest | c_ttAnyCluster, NULL, pcluster, &position, NULL, c_sabmLand); if (pmodel) { SetCommand(c_cmdAccepted, pmodel, c_cidGoto); fGaveOrder = true; } } } break; case c_ptBuilder: { if ((m_abmOrders == c_aabmBuildable) && !bDocked) break; ImodelIGC* pmodel = FindTarget(this, c_ttNeutral | c_ttAsteroid | c_ttNearest | c_ttLeastTargeted | c_ttAnyCluster | c_ttCowardly, NULL, pcluster, &position, NULL, m_abmOrders); if (pmodel) { assert (m_pbaseData); CommandID cid = (m_abmOrders != c_aabmBuildable) ? c_cidBuild : c_cidGoto; SetCommand(c_cmdAccepted, pmodel, cid); fGaveOrder = true; if (cid == c_cidBuild) GetMyMission()->GetIgcSite()->SendChatf(this, CHAT_TEAM, GetSide()->GetObjectID(), droneInTransitSound, "Building %s at %s", ((IstationTypeIGC*)(IbaseIGC*)m_pbaseData)->GetName(), GetModelName(pmodel)); } } break; case c_ptLayer: { if (!bDocked) break; ImodelIGC* pmodel = FindTarget(this, c_ttNeutral | c_ttAsteroid | c_ttNearest | c_ttLeastTargeted | c_ttAnyCluster | c_ttCowardly, NULL, pcluster, &position, NULL, 0); if (pmodel) { SetCommand(c_cmdAccepted, pmodel, c_cidGoto); fGaveOrder = true; } } break; case c_ptWingman: { ImodelIGC* pmodel = FindTarget(this, c_ttEnemy | c_ttShip | c_ttNearest, NULL, pcluster, &position, NULL, 0); if (pmodel) { SetCommand(c_cmdAccepted, pmodel, c_cidAttack); fGaveOrder = true; GetMyMission()->GetIgcSite()->SendChatf(this, CHAT_TEAM, GetSide()->GetObjectID(), droneInTransitSound, "Attacking %s", GetModelName(pmodel)); } } break; } if (!fGaveOrder) SetCommand(c_cmdAccepted, NULL, c_cidNone); return (m_commandIDs[c_cmdAccepted] != c_cidNone); } bool IsGhost(void) const { assert (GetMyMission()); return m_nDeaths > GetMyMission()->GetMissionParams()->iLives; } virtual bool InGarage(IshipIGC* pship, float tCollision) const; float GetEndurance(void) const { float e; if (m_myHullType.GetHullType() && m_myHullType.GetHullType()->HasCapability(c_habmLifepod) && GetCluster()) { e = (m_timeToDie - GetLastUpdate()) / GetMyMission()->GetFloatConstant(c_fcidLifepodEndurance); if (e < 0.0f) e = 0.0f; else if (e > 1.0f) e = 1.0f; } else e = 1.0f; return e; } bool IsUsingAreaOfEffectWeapon(void) const { if (m_pshipParent != NULL) { if (m_turretID != NA) { IweaponIGC* pweapon = (IweaponIGC*)(m_pshipParent->GetMountedPart(ET_Weapon, m_turretID)); if (pweapon && pweapon->GetProjectileType()->GetBlastRadius() > 0.0f) return true; } } else { IhullTypeIGC* pht = m_myHullType.GetHullType(); if (pht) { for (Mount mount = 0; mount < pht->GetMaxFixedWeapons(); ++mount) { IweaponIGC* pweapon = m_mountedWeapons[mount]; if (pweapon && pweapon->GetProjectileType()->GetBlastRadius() > 0.0f) return true; } } } return false; } private: bool bShouldUseRipcord(IclusterIGC* pcluster); void WarpShip(Time timeUpdate, float deltaT, Vector* position, Vector* velocity, Orientation* orientation); void CalculateShip(Time timeUpdate, float deltaT, Vector* position, Vector* velocity, Orientation* orientation); bool IsSafeToRipcord(void); void ResetWaypoint(void); IpartIGC* const* PartLocation(EquipmentType type, Mount mount) const; DWORD m_dwPrivate; // private data for consumer MyHullType m_myHullType; IstationIGC* m_station; TRef m_pmodelRipcord; IshipIGC* m_pshipParent; ShipListIGC m_shipsChildren; PartListIGC m_parts; IweaponIGC* m_mountedWeapons[c_maxMountedWeapons]; IpartIGC* m_mountedOthers[ET_MAX]; IpartIGC* m_mountedCargos[c_maxCargo]; TRef m_pclusterRequestRipcord; DamageTrack* m_damageTrack; TRef m_pshipAutoDonate; TRef m_pbaseData; Vector m_cockpit; GotoPlan m_gotoplan; ControlData m_controls; int m_stateM; float m_energy; float m_cloaking; float m_turnRates[3]; float m_dtRipcordCountdown; float m_fraction; float m_fractionLastOrder; float m_fuel; float m_ripcordDebt; float m_ripcordCost; Vector m_engineVector; Time m_timeLastComplaint; Time m_timeRanAway; Time m_timeLastMineExplosion; Time m_timeReloadAmmo; Time m_timeReloadFuel; Time m_timeToDie; Time m_timeRequestRipcord; float m_experience; float m_maxMineAmount; Time m_maxMineTime; Vector m_maxMineP1; Vector m_maxMineP2; TRef m_maxMineLauncher; DamageTypeID m_maxMineType; short m_nKills; short m_nDeaths; short m_nEjections; short m_ammo; ImissileIGC* m_pmissileLast; ImodelIGC* m_commandTargets[c_cmdMax]; float m_dtTimeBetweenComplaints; float m_fOre; AbilityBitMask m_abmOrders; WingID m_wingID; CommandID m_commandIDs[c_cmdMax]; ShipID m_shipID; SideID m_sidFlag; Mount m_turretID; short m_nextLaunchSlot; PilotType m_pilotType; bool m_bAutopilot; bool m_bRunningAway; WarningMask m_warningMask; }; #endif //__SHIPIGC_H_