/* ** Copyright (C) 1996, 1997 Microsoft Corporation. All Rights Reserved. ** ** File: stationIGC.cpp ** ** Author: ** ** Description: ** Implementation of the CstationIGC class. This file was initially created by ** the ATL wizard for the core object. ** ** History: */ // stationIGC.cpp : Implementation of CstationIGC #include "pch.h" #include "stationIGC.h" #include ///////////////////////////////////////////////////////////////////////////// // CstationIGC HRESULT CstationIGC::Initialize(ImissionIGC* pMission, Time now, const void* data, int dataSize) { TmodelIGC::Initialize(pMission, now, data, dataSize); HRESULT rc = S_OK; debugf("Station initialize %d\n", ((DataStationIGC*)data)->stationID); ZRetailAssert (data && (dataSize == sizeof(DataStationIGC))); { DataStationIGC* dataStation = (DataStationIGC*)data; //Does this station already exist IstationIGC* pstation = pMission->GetStation(dataStation->stationID); if (pstation) { //Uh-oh ... black magic time. //The station already exists, so modify it by changing (the pre-existing) station's hull type and name. pstation->SetBaseStationType(pMission->GetStationType(dataStation->stationTypeID)); pstation->SetName(dataStation->name); pstation->SetFraction(dataStation->bpHull); pstation->SetShieldFraction(dataStation->bpShield); //Certain things should not be changed by the export assert (pstation->GetSide()->GetObjectID() == dataStation->sideID); assert (pstation->GetCluster()->GetObjectID() == dataStation->clusterID); //Set the return code so the existing object is not terminated rc = E_ABORT; } else { m_stationID = dataStation->stationID; SetBaseStationType(pMission->GetStationType(dataStation->stationTypeID)); assert (m_myStationType.GetStationType()); SetPosition(dataStation->position); { Orientation o(dataStation->forward, dataStation->up); SetOrientation(o); } SetRotation(dataStation->rotation); SetName(dataStation->name); SetSide(pMission->GetSide(dataStation->sideID)); IclusterIGC* cluster = pMission->GetCluster(dataStation->clusterID); assert (cluster); SetCluster(cluster); pMission->AddStation(this); //Let the IGC site know about the new station GetMyMission()->GetIgcSite()->StationTypeChange(this); m_hullFraction = dataStation->bpHull; SetShieldFraction(dataStation->bpShield); } m_timeLastDamageReport = now; } return rc; } int CstationIGC::Export(void* data) const { if (data) { DataStationIGC* dataStation = (DataStationIGC*)data; dataStation->stationTypeID = m_myStationType.GetObjectID(); dataStation->stationID = m_stationID; dataStation->position = GetPosition(); { const Orientation& o = GetOrientation(); dataStation->forward = o.GetForward(); dataStation->up = o.GetUp(); } dataStation->rotation = GetRotation(); assert (GetCluster()); dataStation->clusterID = GetCluster()->GetObjectID(); UTL::putName(dataStation->name, GetName()); dataStation->sideID = GetSide()->GetObjectID(); dataStation->bpHull = m_hullFraction; dataStation->bpShield = m_shieldFraction; } return sizeof(DataStationIGC); } DamageResult CstationIGC::ReceiveDamage(DamageTypeID type, float amount, Time timeCollision, const Vector& position1, const Vector& position2, ImodelIGC* launcher) { IsideIGC* pside = GetSide(); const MissionParams* pmp = GetMyMission()->GetMissionParams(); if (pmp->bInvulnerableStations || (m_myStationType.HasCapability(c_sabmPedestal)) || (launcher && (amount >= 0.0f) && (!GetMyMission()->GetMissionParams()->bAllowFriendlyFire) && (pside == launcher->GetSide()))) { return c_drNoDamage; } DamageResult dr; float maxArmor = (float)m_myStationType.GetMaxArmorHitPoints(); float dtmArmor = GetMyMission()->GetDamageConstant(type, m_myStationType.GetArmorDefenseType()); assert (dtmArmor >= 0.0f); if (amount < 0.0f) { m_hullFraction -= amount * dtmArmor / maxArmor; if (m_hullFraction > 1.0f) m_hullFraction = 1.0f; else GetThingSite ()->RemoveDamage (m_hullFraction); dr = c_drNoDamage; } else { float dtmShield = GetMyMission()->GetDamageConstant(type, m_myStationType.GetShieldDefenseType()); if (dtmShield != 0.0f) { dr = c_drShieldDamage; if (launcher && (launcher->GetObjectType() == OT_ship)) amount *= ((IshipIGC*)launcher)->GetExperienceMultiplier(); IIgcSite* pigc = GetMyMission()->GetIgcSite(); pigc->DamageStationEvent(this, launcher, type, amount); float maxShield = (float)m_myStationType.GetMaxShieldHitPoints(); float absorbed = amount * dtmShield / maxShield; if (m_shieldFraction >= absorbed) { SetShieldFraction(m_shieldFraction - absorbed); } else { if (dtmArmor != 0.0f) { dr = c_drHullDamage; absorbed -= m_shieldFraction; if (m_hullFraction > 0.0f) { float dmg = (absorbed * maxShield * dtmArmor) / (maxArmor * dtmShield); m_hullFraction -= dmg; if (m_hullFraction <= 0.0f) { m_hullFraction = 0.0f; pigc->KillStationEvent(this, launcher, amount); dr = c_drKilled; } else if ((type & c_dmgidNoDebris) == 0) GetThingSite ()->AddDamage (position2 - position1, m_hullFraction); } } SetShieldFraction(0.0f); } } else dr = c_drNoDamage; } return dr; } void CstationIGC::SetBaseStationType(IstationTypeIGC* pst) { assert (pst); IclusterIGC* pclusterOld; Vector positionOld; Orientation orientationOld; Rotation rotationOld; if (m_myStationType.GetStationType()) { assert (GetSide()); pclusterOld = GetCluster(); positionOld = GetPosition(); orientationOld = GetOrientation(); rotationOld = GetRotation(); //Move the station to the null cluster while all the black magic happens SetCluster(NULL); FreeThingSite(); } else assert (!GetSide()); m_myStationType.SetStationType(pst); { HRESULT rc = Load(0, m_myStationType.GetModelName(), m_myStationType.GetTextureName(), m_myStationType.GetIconName(), c_mtStatic | c_mtDamagable | c_mtHitable | c_mtSeenBySide | c_mtPredictable | c_mtScanner); assert (SUCCEEDED(rc)); } SetRadius(m_myStationType.GetRadius()); SetMass(0.0f); SetSignature(m_myStationType.GetSignature()); m_undockPosition = 0; IsideIGC* pside = GetSide(); if (pside) { //Set the station hit test to allow ships of its own side to enter its shields HitTest* pht = GetHitTest(); pht->SetUseTrueShapeSelf(pside); pht->SetShape(c_htsConvexHullMax); //We have a side, which means we had a station type before (see above) and the following //data is valid: SetPosition(positionOld); SetOrientation(orientationOld); SetRotation(rotationOld); SetCluster(pclusterOld); //The upgrade really should not be less capable than its predecessor but let's be paranoid pside->ResetBuildingTechs(); //Let the IGC site know GetMyMission()->GetIgcSite()->StationTypeChange(this); } } void CstationIGC::AddShip(IshipIGC* pship) { AddIbaseIGC((BaseListIGC*)&m_shipsDocked, pship); //At a station implies not in a cluster pship->SetCluster(NULL); } void CstationIGC::DeleteShip(IshipIGC* s) { DeleteIbaseIGC((BaseListIGC*)&m_shipsDocked, s); } IshipIGC* CstationIGC::GetShip(ShipID id) const { return (IshipIGC*)GetIbaseIGC((BaseListIGC*)&m_shipsDocked, id); } const ShipListIGC* CstationIGC::GetShips(void) const { return &m_shipsDocked; } void CstationIGC::Launch(IshipIGC* pship) { Orientation orientation; Vector position; position.x = random(-0.5f, 0.5f); position.y = random(-0.5f, 0.5f); position.z = random(-0.5f, 0.5f); Vector forward; const Orientation& o = GetOrientation(); float vLaunch = GetMyMission()->GetFloatConstant(c_fcidExitStationSpeed); int nLaunchSlots = m_myStationType.GetLaunchSlots(); if (nLaunchSlots == 0) { switch (m_undockPosition++) { case 4: { m_undockPosition = 0; } //No break case 0: { forward = o.GetRight(); } break; case 1: { forward = o.GetUp(); } break; case 2: { forward = -o.GetRight(); } break; case 3: { forward = -o.GetUp(); } break; } position += forward * (GetRadius() + pship->GetRadius() + vLaunch * 0.5f); } else { position += m_myStationType.GetLaunchPosition(m_undockPosition) * o; forward = m_myStationType.GetLaunchDirection(m_undockPosition) * o; position += forward * (pship->GetRadius() + vLaunch * 0.5f); m_undockPosition = (m_undockPosition + 1) % nLaunchSlots; } orientation.Set(forward, o.GetForward()); IclusterIGC* pcluster = GetCluster(); Time lastUpdate = pcluster->GetLastUpdate(); pship->SetPosition(position + GetPosition()); pship->SetOrientation(orientation); pship->SetVelocity(forward * vLaunch); pship->SetCurrentTurnRate(c_axisYaw, 0.0f); pship->SetCurrentTurnRate(c_axisPitch, 0.0f); pship->SetCurrentTurnRate(c_axisRoll, 0.0f); pship->SetCluster(pcluster); } bool CstationIGC::InGarage(IshipIGC* pship, const Vector& position) { bool bInside = false; int i = (pship->GetBaseHullType()->HasCapability(c_habmFighter) ? m_myStationType.GetLandSlots() : m_myStationType.GetCapLandSlots()) - 1; if (i >= 0) { HitTest* pht = pship->GetHitTest(); HitTestShape kMax = pht->GetTrueShape(); HitTestShape kMin; if (kMax > 0) { assert (kMax != 0); kMin = 0; } else { kMin = kMax++; } const Orientation& orientationStation = GetOrientation(); const Orientation& orientationShip = pship->GetOrientation(); Vector dp = position - GetPosition(); do { int j = m_myStationType.GetLandPlanes(i) - 1; assert (j >= 0); do { Vector direction = m_myStationType.GetLandDirection(i, j) * orientationStation; Vector point = m_myStationType.GetLandPosition(i, j) * orientationStation; int k = kMin; do { Vector pMin = pht->GetMinExtreme(k, dp, orientationShip, direction); if ((pMin - point) * direction < 0.0f) break; } while (++k < kMax); if (k < kMax) break; } while (j-- > 0); if (j == -1) { //Found a place to land bInside = true; break; } } while (i-- > 0); } return bInside; } void CstationIGC::RepairAndRefuel(IshipIGC* pship) const { assert ((pship->GetParentShip() == NULL) && (pship->GetBaseHullType() != NULL)); //Fully mount all parts { for (PartLinkIGC* ppl = pship->GetParts()->first(); (ppl != NULL); ppl = ppl->next()) { ppl->data()->SetMountedFraction(1.0f); } } if (m_myStationType.HasCapability(c_sabmRepair)) { pship->SetFraction(1.0f); } { IafterburnerIGC* a = (IafterburnerIGC*)(pship->GetMountedPart(ET_Afterburner, 0)); if (a) a->Deactivate(); } { IshieldIGC* s = (IshieldIGC*)(pship->GetMountedPart(ET_Shield, 0)); if (s) s->SetFraction(1.0f); } { IafterburnerIGC* pafter = (IafterburnerIGC*)(pship->GetMountedPart(ET_Afterburner, 0)); if (pafter) pafter->Deactivate(); } //Give a full load of fuel and ammo const IhullTypeIGC* pht = pship->GetHullType(); if (m_myStationType.HasCapability(c_sabmReload)) { short maxAmmo = pht->GetMaxAmmo(); short maxFuel = short(pht->GetMaxFuel()); pship->SetAmmo(maxAmmo); pship->SetFuel(maxFuel); for (PartLinkIGC* ppl = pship->GetParts()->first(); (ppl != NULL); ppl = ppl->next()) { IpartIGC* ppart = ppl->data(); if (ppart->GetObjectType() == OT_pack) { IpackIGC* ppack = (IpackIGC*)ppart; ppack->SetAmount(ppack->GetPackType() == c_packAmmo ? maxAmmo : maxFuel); } } } pship->SetEnergy(pht->GetMaxEnergy()); } //Ibase HRESULT MyStationType::Initialize(ImissionIGC* pMission, Time now, const void* data, int length) { assert (false); return E_FAIL; } void MyStationType::Terminate(void) { assert (false); } void MyStationType::Update(Time now) { assert (false); } ObjectType MyStationType::GetObjectType(void) const { return OT_stationType; } ObjectID MyStationType::GetObjectID(void) const { return m_pStationData->stationTypeID; } // ItypeIGC const void* MyStationType::GetData(void) const { return m_pStationData; } // IbuyableIGC const char* MyStationType::GetModelName(void) const { return m_pStationData->modelName; } const char* MyStationType::GetName(void) const { return m_pStationData->name; } const char* MyStationType::GetDescription(void) const { return m_pStationData->description; } Money MyStationType::GetPrice(void) const { return m_pStationData->price; } DWORD MyStationType::GetTimeToBuild(void) const { return m_pStationData->timeToBuild; } BuyableGroupID MyStationType::GetGroupID(void) const { return m_pStationData->groupID; } const TechTreeBitMask& MyStationType::GetRequiredTechs(void) const { return m_pStationData->ttbmRequired; } const TechTreeBitMask& MyStationType::GetEffectTechs(void) const { return m_pStationData->ttbmEffects; } // IstationTypeIGC float MyStationType::GetSignature(void) const { return m_pStationData->signature; } float MyStationType::GetRadius(void) const { return m_pStationData->radius; } float MyStationType::GetScannerRange(void) const { return m_pStationData->scannerRange * m_pstation->GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaScanRange); } HitPoints MyStationType::GetMaxArmorHitPoints(void) const { return m_pStationData->maxArmorHitPoints * m_pstation->GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaMaxArmorStation); } DefenseTypeID MyStationType::GetArmorDefenseType(void) const { return m_pStationData->defenseTypeArmor; } HitPoints MyStationType::GetMaxShieldHitPoints(void) const { return m_pStationData->maxShieldHitPoints * m_pstation->GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaMaxShieldStation); } DefenseTypeID MyStationType::GetShieldDefenseType(void) const { return m_pStationData->defenseTypeShield; } float MyStationType::GetArmorRegeneration(void) const { return m_pStationData->armorRegeneration * m_pstation->GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaArmorRegenerationStation); } float MyStationType::GetShieldRegeneration(void) const { return m_pStationData->shieldRegeneration * m_pstation->GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaShieldRegenerationStation); } Money MyStationType::GetIncome(void) const { return m_pStationData->income; } const TechTreeBitMask& MyStationType::GetLocalTechs(void) const { return m_pStationData->ttbmLocal; } StationAbilityBitMask MyStationType::GetCapabilities(void) const { return m_pStationData->sabmCapabilities; } bool MyStationType::HasCapability(StationAbilityBitMask sabm) const { return (m_pStationData->sabmCapabilities & sabm) != 0; } const char* MyStationType::GetTextureName(void) const { return m_pStationData->textureName; } const char* MyStationType::GetBuilderName(void) const { return m_pStationData->builderName; } const char* MyStationType::GetIconName(void) const { return m_pStationData->iconName; } IstationTypeIGC* MyStationType::GetSuccessorStationType(const IsideIGC* pside) { return m_pStationType->GetSuccessorStationType(pside); } AsteroidAbilityBitMask MyStationType::GetBuildAABM(void) const { return m_pStationData->aabmBuild; } int MyStationType::GetLaunchSlots(void) const { return m_pStationType->GetLaunchSlots(); } const Vector& MyStationType::GetLaunchPosition(int slotID) const { return m_pStationType->GetLaunchPosition(slotID); } const Vector& MyStationType::GetLaunchDirection(int slotID) const { return m_pStationType->GetLaunchDirection(slotID); } int MyStationType::GetLandSlots(void) const { return m_pStationType->GetLandSlots(); } int MyStationType::GetCapLandSlots(void) const { return m_pStationType->GetCapLandSlots(); } int MyStationType::GetLandPlanes(int slotID) const { return m_pStationType->GetLandPlanes(slotID); } const Vector& MyStationType::GetLandPosition(int slotID, int planeID) const { return m_pStationType->GetLandPosition(slotID, planeID); } const Vector& MyStationType::GetLandDirection(int slotID, int planeID) const { return m_pStationType->GetLandDirection(slotID, planeID); } SoundID MyStationType::GetInteriorSound() const { return m_pStationType->GetInteriorSound(); } SoundID MyStationType::GetInteriorAlertSound() const { return m_pStationType->GetInteriorAlertSound(); } SoundID MyStationType::GetExteriorSound() const { return m_pStationType->GetExteriorSound(); } SoundID MyStationType::GetConstructorNeedRockSound() const { return m_pStationType->GetConstructorNeedRockSound(); } SoundID MyStationType::GetConstructorUnderAttackSound() const { return m_pStationType->GetConstructorUnderAttackSound(); } SoundID MyStationType::GetConstructorDestroyedSound() const { return m_pStationType->GetConstructorDestroyedSound(); } SoundID MyStationType::GetCompletionSound() const { return m_pStationType->GetCompletionSound(); } SoundID MyStationType::GetUnderAttackSound() const { return m_pStationType->GetUnderAttackSound(); } SoundID MyStationType::GetCriticalSound() const { return m_pStationType->GetCriticalSound(); } SoundID MyStationType::GetDestroyedSound() const { return m_pStationType->GetDestroyedSound(); } SoundID MyStationType::GetCapturedSound() const { return m_pStationType->GetCapturedSound(); } SoundID MyStationType::GetEnemyCapturedSound() const { return m_pStationType->GetEnemyCapturedSound(); } SoundID MyStationType::GetEnemyDestroyedSound() const { return m_pStationType->GetEnemyDestroyedSound(); } StationClassID MyStationType::GetClassID() const { return m_pStationType->GetClassID(); } IdroneTypeIGC* MyStationType::GetConstructionDroneType(void) const { return m_pStationType->GetConstructionDroneType(); }