#include "pch.h"
#include "shipIGC.h"
#include <math.h>
#include <limits.h>
float c_fRunAway = 0.75f;
const float c_dtTimeBetweenComplaints = 30.0f;
CshipIGC::CshipIGC(void)
:
m_fuel(0.0f),
m_stateM(0),
m_station(NULL),
m_pmissileLast(NULL),
m_damageTrack(NULL),
m_dwPrivate(0),
m_myHullType(this),
m_cloaking(1.0f),
m_pshipParent(NULL),
m_turretID(NA),
m_bAutopilot(false),
m_gotoplan(this),
m_dtTimeBetweenComplaints(c_dtTimeBetweenComplaints),
m_nKills(0),
m_nDeaths(0),
m_nEjections(0),
m_sidFlag(NA),
m_ripcordDebt(0.0f)
{
SetExperience(1.0f);
m_myHullType.AddRef();
{
for (Command i = 0; (i < c_cmdMax); i++)
{
m_commandTargets[i] = NULL;
m_commandIDs[i] = c_cidNone;
}
}
{
for (Mount i = 0; (i < c_maxMountedWeapons); i++)
m_mountedWeapons[i] = NULL;
}
{
for (Mount i = 0; (i < ET_MAX); i++)
m_mountedOthers[i] = NULL;
}
{
for (Mount i = 0; (i < c_maxCargo); i++)
m_mountedCargos[i] = NULL;
}
}
void CshipIGC::ReInitialize(DataShipIGC * dataShip, Time now)
{
ImissionIGC * pmission = GetMyMission();
assert (IMPLIES(!pmission, dataShip->sideID == NA));
m_fuel = 0.0f;
m_ammo = 0;
m_energy = 0.0f;
{
PartLinkIGC* ppartlink;
while (ppartlink = GetParts()->first()) ppartlink->data()->Terminate();
}
m_myHullType.SetHullType(NULL);
SetMass(0.0f);
SetLastUpdate(now);
SetName(dataShip->name);
m_pilotType = dataShip->pilotType;
m_abmOrders = dataShip->abmOrders;
if (dataShip->baseObjectID == NA)
m_pbaseData = NULL;
else if (m_pilotType == c_ptBuilder)
{
m_pbaseData = pmission->GetStationType(dataShip->baseObjectID);
assert (m_pbaseData);
}
else if (m_pilotType == c_ptLayer)
{
m_pbaseData = pmission->GetExpendableType(dataShip->baseObjectID);
assert (m_pbaseData);
}
else
assert (false);
m_turnRates[c_axisYaw] = m_turnRates[c_axisPitch] = m_turnRates[c_axisRoll] =
m_controls.jsValues[c_axisYaw] = m_controls.jsValues[c_axisPitch] = m_controls.jsValues[c_axisRoll] = 0.0f;
m_controls.jsValues[c_axisThrottle] = -1.0f;
IsideIGC * pside = pmission ? pmission->GetSide(dataShip->sideID) : NULL;
SetSide(pside);
m_shipID = dataShip->shipID;
m_wingID = 0; m_nDeaths = dataShip->nDeaths;
m_nEjections = dataShip->nEjections;
m_nKills = dataShip->nKills;
if (dataShip->hullID == NA)
{
FreeThingSite();
}
else
{
assert (pside);
SetBaseHullType(GetMyMission()->GetHullType(dataShip->hullID));
assert (m_myHullType.GetData());
{
ThingSite* pThingSite = GetThingSite();
assert (pThingSite);
pThingSite->SetTrailColor(pside->GetColor());
}
{
const PartData* pd = (PartData*)(((char*)dataShip) + dataShip->partsOffset);
for (Mount i = 0; (i < dataShip->nParts); i++)
{
CreateAndAddPart(&(pd[i]));
}
}
assert (GetMass() > 0.0f); }
}
HRESULT CshipIGC::Initialize(ImissionIGC* pMission, Time now, const void* data, int dataSize)
{
ZRetailAssert (data && (dataSize >= sizeof(DataShipIGC)));
DataShipIGC* dataShip = (DataShipIGC*) data;
IshipIGC* pshipReplace = pMission->GetShip(dataShip->shipID);
if (pshipReplace)
{
pshipReplace->ReInitialize(dataShip, now);
return E_ABORT;
}
TmodelIGC<IshipIGC>::Initialize(pMission, now, data, dataSize);
ReInitialize(dataShip, now);
pMission->AddShip(this);
m_timeLastComplaint = now;
m_timeLastMineExplosion = now;
m_timeRanAway = now;
m_timeReloadAmmo = now;
m_timeReloadFuel = now;
m_bRunningAway = false;
return S_OK;
}
void CshipIGC::Terminate(void)
{
AddRef();
if ((m_pilotType == c_ptBuilder) && ((m_stateM & buildingMaskIGC) != 0))
{
assert (m_commandIDs[c_cmdPlan] != NULL);
assert (m_commandTargets[c_cmdPlan]->GetObjectType() == OT_asteroid);
IbuildingEffectIGC* pbe = ((IasteroidIGC*)(ImodelIGC*)m_commandTargets[c_cmdPlan])->GetBuildingEffect();
if (pbe)
{
pbe->BuilderTerminated();
GetMyMission()->GetIgcSite()->KillBuildingEffectEvent(pbe);
}
}
if (m_damageTrack)
{
delete m_damageTrack;
m_damageTrack = NULL;
}
m_fraction = 0.0f;
m_pbaseData = NULL;
if (m_pmissileLast)
{
m_pmissileLast->Release();
m_pmissileLast = NULL;
}
SetRipcordModel(NULL);
SetParentShip(NULL);
{
ShipLinkIGC* psl;
while (psl = m_shipsChildren.first()) {
psl->data()->SetParentShip(NULL);
}
}
{
PartLinkIGC* l;
while (l = m_parts.first()) l->data()->Terminate();
}
TmodelIGC<IshipIGC>::Terminate();
Release();
}
void CshipIGC::Update(Time now)
{
assert (GetCluster() != NULL);
Time lastUpdate = GetMyLastUpdate();
if ((now > lastUpdate) && (m_pshipParent == NULL))
{
m_warningMask = 0;
float dt = (now - lastUpdate);
if (m_pmodelRipcord)
{
IIgcSite* pigc = GetMyMission()->GetIgcSite();
if (pigc->ContinueRipcord(this, m_pmodelRipcord))
{
m_dtRipcordCountdown -= dt;
if (m_dtRipcordCountdown <= 0.0f)
{
if (pigc->UseRipcord(this, m_pmodelRipcord))
SetRipcordModel(NULL);
else
m_dtRipcordCountdown = 0.0f;
}
}
else
SetRipcordModel(NULL);
}
if((m_myHullType.GetRechargeRate() > 0.0f)||(m_energy != 0.0f))
{
m_energy += m_myHullType.GetRechargeRate() * dt;
float eMax = m_myHullType.GetMaxEnergy();
if (m_energy > eMax)
m_energy = eMax;
else if (m_energy < 0.0f)
m_energy = 0.0f;
}
{
if (m_mountedOthers[ET_Cloak])
m_mountedOthers[ET_Cloak]->Update(now);
}
{
Mount maxWeapons = m_myHullType.GetMaxWeapons();
Mount maxFixedWeapons = m_myHullType.GetMaxFixedWeapons();
Mount selectedWeapon = (m_stateM & selectedWeaponMaskIGC) >> selectedWeaponShiftIGC;
for (Mount i = maxFixedWeapons; (i > 0); i--)
{
IweaponIGC* w = m_mountedWeapons[(i + selectedWeapon) % maxFixedWeapons];
if (w)
{
assert (!w->GetGunner());
w->Update(now);
}
}
for (Mount j = maxFixedWeapons; (j < maxWeapons); j++)
{
IweaponIGC* w = m_mountedWeapons[j];
if (w)
{
IshipIGC* pshipGunner = w->GetGunner();
if (pshipGunner)
{
Orientation o = pshipGunner->GetOrientation();
pshipGunner->ExecuteTurretMove(lastUpdate, now, &o);
pshipGunner->SetOrientation(o);
}
w->Update(now);
}
}
}
if (m_mountedOthers[ET_Shield])
m_mountedOthers[ET_Shield]->Update(now);
if (m_mountedOthers[ET_Magazine])
m_mountedOthers[ET_Magazine]->Update(now);
if (m_mountedOthers[ET_Dispenser])
m_mountedOthers[ET_Dispenser]->Update(now);
if (m_mountedOthers[ET_ChaffLauncher])
m_mountedOthers[ET_ChaffLauncher]->Update(now);
if (m_mountedOthers[ET_Afterburner])
m_mountedOthers[ET_Afterburner]->Update(now);
if (m_myHullType.GetHullType()->HasCapability(c_habmLifepod) &&
(now > m_timeToDie))
{
GetMyMission()->GetIgcSite()->KillShipEvent(now, this, NULL, 1.0f, GetPosition(), Vector::GetZero());
}
else
{
const Vector& position = GetPosition();
float lm = GetMyMission()->GetFloatConstant(c_fcidLensMultiplier);
float r2 = position.x * position.x + position.y * position.y +
(position.z * position.z / (lm * lm));
float ru = GetMyMission()->GetFloatConstant(c_fcidRadiusUniverse);
float oob = GetMyMission()->GetFloatConstant(c_fcidOutOfBounds) * ru * ru;
if (r2 > oob)
{
if (m_pilotType < c_ptPlayer) {
debugf("mmf ship out of bounds %s %f %f %f\n",GetName(),position.x, position.y, position.z);
}
m_warningMask |= c_wmOutOfBounds;
float d = dt *
(r2 - oob) /
(50.0f * oob); assert (d >= 0.0f);
float oldFraction = m_fraction;
m_fraction -= d;
assert (m_fraction <= 1.0f);
if (m_fraction > 0.0f)
GetMyMission()->GetIgcSite()->DamageShipEvent(now, this, NULL, c_dmgidCollision, d, d, position, position * 2.0f);
else
{
m_fraction = 0.0f;
if (oldFraction > 0.0f) GetMyMission()->GetIgcSite()->KillShipEvent(now, this, NULL, d, position, position * 2.0f);
}
assert (m_fraction >= 0.0f);
}
if (m_pilotType >= c_ptPlayer)
{
IclusterIGC* pcluster = GetCluster();
if (pcluster != NULL) {
float cost = pcluster->GetCost();
if (cost > 0.0f)
{
m_warningMask |= c_wmCrowdedSector;
float maxDamage = m_myHullType.GetHitPoints();
if (m_mountedOthers[ET_Shield])
maxDamage += ((IshieldIGC*)m_mountedOthers[ET_Shield])->GetMaxStrength();
float d = cost * maxDamage;
ReceiveDamage(c_dmgidCollision, d, now, position, Vector::GetZero(), NULL);
}
}
}
}
}
TmodelIGC<IshipIGC>::Update(now);
}
int CshipIGC::Export(void* data) const
{
if (data)
{
DataShipIGC* dataShip = (DataShipIGC*)data;
dataShip->hullID = m_myHullType.GetObjectID();
dataShip->shipID = m_shipID;
dataShip->sideID = GetSide()->GetObjectID();
dataShip->nKills = m_nKills;
dataShip->nDeaths = m_nDeaths;
dataShip->nEjections = m_nEjections;
UTL::putName(dataShip->name, GetName());
dataShip->pilotType = m_pilotType;
dataShip->abmOrders = m_abmOrders;
dataShip->baseObjectID = m_pbaseData
? m_pbaseData->GetObjectID() : NA;
dataShip->nParts = m_parts.n();
dataShip->partsOffset = sizeof(DataShipIGC);
{
PartData* pd = (PartData*)(((char*)dataShip) + dataShip->partsOffset);
for (PartLinkIGC* l = m_parts.first();
(l != NULL);
l = l->next())
{
IpartIGC* part = l->data();
assert (part->GetPartType());
pd->partID = part->GetPartType()->GetObjectID();
pd->mountID = part->GetMountID();
(pd++)->amount = part->GetAmount();
}
}
}
return sizeof(DataShipIGC) + sizeof(PartData) * m_parts.n();
}
static const float sqrt1o2 = 0.70710678118654752440084436210485f;
static const float sqrt1o3 = 0.57735026918962576450914878050196f;
static const float directions[][3] = {
{ 1.0f, 0.0f, 0.0f},
{-1.0f, 0.0f, 0.0f},
{ 0.0f, 1.0f, 0.0f},
{ 0.0f, -1.0f, 0.0f},
{ 0.0f, 0.0f, 1.0f},
{ 0.0f, 0.0f, -1.0f},
{ sqrt1o2, sqrt1o2, 0.0f },
{-sqrt1o2, sqrt1o2, 0.0f },
{ sqrt1o2, -sqrt1o2, 0.0f },
{-sqrt1o2, -sqrt1o2, 0.0f },
{ sqrt1o2, 0.0f, sqrt1o2 },
{-sqrt1o2, 0.0f, sqrt1o2 },
{ sqrt1o2, 0.0f, -sqrt1o2 },
{-sqrt1o2, 0.0f, -sqrt1o2 },
{ 0.0f, sqrt1o2, sqrt1o2 },
{ 0.0f, -sqrt1o2, sqrt1o2 },
{ 0.0f, sqrt1o2, -sqrt1o2 },
{ 0.0f, -sqrt1o2, -sqrt1o2 },
{ sqrt1o3, sqrt1o3, sqrt1o3 },
{-sqrt1o3, sqrt1o3, sqrt1o3 },
{ sqrt1o3, -sqrt1o3, sqrt1o3 },
{-sqrt1o3, -sqrt1o3, sqrt1o3 },
{ sqrt1o3, sqrt1o3, -sqrt1o3 },
{-sqrt1o3, sqrt1o3, -sqrt1o3 },
{ sqrt1o3, -sqrt1o3, -sqrt1o3 },
{-sqrt1o3, -sqrt1o3, -sqrt1o3 }
};
static const int c_maxAttempts = sizeof(directions) / sizeof(directions[0]);
static void Separate(const CollisionEntry& entry,
bool fEqualBounce,
Vector* pPosition1,
Vector* pPosition2,
Vector* pNormal)
{
HitTest* pHitTest1 = entry.m_pHitTest1;
HitTest* pHitTest2 = entry.m_pHitTest2;
*pPosition1 = pHitTest1->GetPosition() + entry.m_tCollision * pHitTest1->GetVelocity();
*pPosition2 = fEqualBounce
? (pHitTest2->GetPosition() + entry.m_tCollision * pHitTest2->GetVelocity())
: pHitTest2->GetPosition(); Vector dP = *pPosition1 - *pPosition2;
if ((dP.x == 0.0f) && (dP.y == 0.0f) && (dP.z == 0.0f))
{
dP = Vector::RandomDirection();
*pPosition1 += dP;
}
const Orientation& o1 = pHitTest1->GetOrientation();
const Orientation& o2 = pHitTest2->GetOrientation();
Orientation o = o1.TimesInverse(o2);
Vector dpLocal = o2.TimesInverse(dP);
Vector directionBest;
double distanceBest;
{
directionBest = dpLocal;
if (entry.m_hts1 >= c_htsConvexHullMin)
directionBest += pHitTest1->GetCenter(entry.m_hts1) * o;
if (entry.m_hts2 >= c_htsConvexHullMin)
directionBest -= pHitTest2->GetCenter(entry.m_hts2);
directionBest.SetNormalize();
Vector eA = pHitTest1->GetMinExtreme(entry.m_hts1, dpLocal,
o, directionBest);
Vector eB = pHitTest2->GetMaxExtreme(entry.m_hts2, directionBest);
Vector delta = eA - eB;
distanceBest = (delta * directionBest);
}
int attempt = 0;
do
{
const Vector& direction = *((Vector*)(directions[attempt]));
Vector eA = pHitTest1->GetMinExtreme(entry.m_hts1, dpLocal,
o, direction);
Vector eB = pHitTest2->GetMaxExtreme(entry.m_hts2, direction);
Vector delta = eA - eB;
double distance = (delta * direction);
if (distance >= 0.0)
{
directionBest = direction;
distanceBest = 0.0;
break;
}
if (distance > distanceBest)
{
directionBest = direction;
distanceBest = distance;
}
}
while (++attempt < c_maxAttempts);
*pNormal = directionBest * pHitTest2->GetOrientation();
float s = float(distanceBest - 0.5);
*pPosition1 -= (s * (fEqualBounce ? 0.5f : 1.0f)) * *pNormal;
if (fEqualBounce)
{
*pPosition2 += (s * 0.5f) * *pNormal;
}
}
void CshipIGC::HandleCollision(Time timeCollision,
float tCollision,
const CollisionEntry& entry,
ImodelIGC* pModel)
{
const float c_impactDamageCoefficient = 1.0f / 128.0f;
const float c_impactJiggleCoefficient = 1.0f / 20.0f;
ObjectType type = pModel->GetObjectType();
switch (type)
{
case OT_warp:
{
GetMyMission()->GetIgcSite()->HitWarpEvent(this, (IwarpIGC*)pModel);
}
break;
case OT_station:
{
IstationIGC* pStation = (IstationIGC*)pModel;
const IstationTypeIGC* pst = pStation->GetStationType();
if (pst->HasCapability(m_myHullType.HasCapability(c_habmFighter)
? c_sabmLand
: c_sabmCapLand))
{
IsideIGC* pside1 = GetSide();
IsideIGC* pside2 = pModel->GetSide();
if (pside1 == pside2)
{
if (pStation->InGarage(this, GetPosition() + GetVelocity() * tCollision))
{
if (GetMyMission()->GetIgcSite()->DockWithStationEvent(this, pStation))
break;
}
}
else if (m_myHullType.HasCapability(c_habmBoard) &&
(!GetMyMission()->GetMissionParams()->bInvulnerableStations) &&
(pStation->GetShieldFraction() < GetMyMission()->GetFloatConstant(c_fcidDownedShield)))
{
if (pStation->InGarage(this, GetPosition() + GetVelocity() * tCollision))
{
if (GetMyMission()->GetIgcSite()->DockWithStationEvent(this, pStation))
break;
}
}
}
else if (m_myHullType.HasCapability(c_habmLifepod) &&
pst->HasCapability(c_sabmRescue) &&
(GetSide() == pModel->GetSide()))
{
if (GetMyMission()->GetIgcSite()->RescueShipEvent(this, NULL))
break;
}
}
case OT_buildingEffect:
case OT_asteroid:
{
if (((m_stateM & drillingMaskIGC) != 0) && (type != OT_station))
{
assert (m_pilotType == c_ptBuilder);
if (type == OT_asteroid)
{
if (m_bAutopilot && (((IasteroidIGC*)pModel)->GetBuildingEffect() == NULL))
{
GetMyMission()->GetIgcSite()->CreateBuildingEffect(timeCollision, (IasteroidIGC*)pModel, this);
}
const Vector& backward = GetOrientation().GetBackward();
pModel->GetThingSite()->AddHullHit(GetPosition() - backward * GetRadius() - pModel->GetPosition(),
backward);
}
break;
}
}
case OT_probe:
{
if ((type == OT_probe) && m_myHullType.HasCapability(c_habmLifepod))
{
IprobeTypeIGC* ppt = ((IprobeIGC*)pModel)->GetProbeType();
ExpendableAbilityBitMask eabm = ppt->GetCapabilities();
if ((eabm & c_eabmRescueAny) ||
((eabm & c_eabmRescue) && (GetSide() == pModel->GetSide())))
{
if (GetMyMission()->GetIgcSite()->RescueShipEvent(this, NULL))
break;
}
}
if (((IdamageIGC*)pModel)->GetFraction() > 0.0f)
{
const Vector& velocity1 = GetVelocity();
Vector position1;
Vector position2;
Vector normal;
Separate(entry, false,
&position1, &position2, &normal);
IclusterIGC* cluster = GetCluster(); AddRef();
pModel->AddRef();
const float cElasticity = 0.75; float oldSpeed1 = velocity1 * normal;
Vector perpendicular1 = velocity1 - oldSpeed1 * normal;
Vector vElastic1 = perpendicular1 - (oldSpeed1 * normal);
Vector newVelocity1 = vElastic1 * cElasticity;
if (!(newVelocity1 * newVelocity1 >= 0.0f)) {
debugf("mmf Igc shipIGC.cpp ~835 newVelocity1^2 debug build would have called assert and exited, commented out and set to zero for now\n");
newVelocity1.x = 0.0f; newVelocity1.y = 0.0f; newVelocity1.z = 0.0f;
}
float damage2 = (velocity1 - newVelocity1).LengthSquared() * c_impactDamageCoefficient;
float damage1 = 2.0f * damage2;
float hp1 = GetHitPoints();
if (m_mountedOthers[ET_Shield])
hp1 = ((IshieldIGC*)m_mountedOthers[ET_Shield])->GetFraction() *
((IshieldIGC*)m_mountedOthers[ET_Shield])->GetMaxStrength();
float hp2 = ((IdamageIGC*)pModel)->GetHitPoints();
IIgcSite* igcsite = GetMyMission()->GetIgcSite();
DamageResult dr1 = c_drNoDamage;
DamageResult dr2 = c_drNoDamage;
if (!m_myHullType.HasCapability(c_habmLifepod))
{
if (hp2 > 0.0f)
{
dr1 = ReceiveDamage(c_dmgidCollision,
(hp2 * damage1 / (hp2 + damage1)),
timeCollision,
position1, position2,
(type == OT_buildingEffect) ? ((IbuildingEffectIGC*)pModel)->GetAsteroid() : pModel);
}
assert (pModel->GetAttributes() & c_mtDamagable);
if (hp1 > 0.0f)
{
dr2 = ((IdamageIGC*)pModel)->ReceiveDamage(c_dmgidCollision,
hp1 * damage2 / (hp1 + damage2),
timeCollision,
position2, position1,
this);
}
}
if ((dr1 != c_drKilled) && (dr2 != c_drKilled))
{
SetPosition(position1);
SetVelocity(newVelocity1);
cluster->RecalculateCollisions(tCollision, this, pModel);
}
igcsite->PlaySoundEffect(collisionSound, this);
igcsite->PlayFFEffect(effectBounce, this);
igcsite->PlayVisualEffect(effectJiggle, this, 2.0f * damage1 * c_impactJiggleCoefficient);
pModel->Release();
Release();
}
}
break;
case OT_treasure:
case OT_missile:
case OT_mine:
{
pModel->HandleCollision(timeCollision, tCollision, entry, this);
}
break;
case OT_ship:
{
IIgcSite* igcsite = GetMyMission()->GetIgcSite();
bool bFriendly = GetSide() == pModel->GetSide();
if (bFriendly)
{
HullAbilityBitMask habmMe = m_myHullType.GetCapabilities();
HullAbilityBitMask habmHim = ((IshipIGC*)pModel)->GetHullType()->GetCapabilities();
if (habmHim & c_habmLifepod)
{
if ((habmMe & c_habmRescue) && igcsite->RescueShipEvent((IshipIGC*)pModel, this))
break;
}
else if (habmMe & c_habmLifepod)
{
if ((habmHim & c_habmRescue) && igcsite->RescueShipEvent(this, (IshipIGC*)pModel))
break;
}
else if ( (habmHim & c_habmCarrier) && (this->GetPilotType() == c_ptPlayer) ) {
if ((habmMe & c_habmLandOnCarrier) &&
((IshipIGC*)pModel)->InGarage(this, tCollision) &&
igcsite->LandOnCarrierEvent((IshipIGC*)pModel, this, tCollision))
break;
}
else if ( (habmMe & c_habmCarrier) && (((IshipIGC*)pModel)->GetPilotType() == c_ptPlayer) ) {
if ((habmHim & c_habmLandOnCarrier) &&
InGarage((IshipIGC*)pModel, tCollision) &&
igcsite->LandOnCarrierEvent(this, (IshipIGC*)pModel, tCollision))
break;
}
}
const Vector& velocity1 = GetVelocity();
const Vector& velocity2 = pModel->GetVelocity();
Vector position1;
Vector position2;
Vector normal;
Separate(entry, true,
&position1, &position2, &normal);
IclusterIGC* cluster = GetCluster(); AddRef();
pModel->AddRef();
float oldSpeed1 = velocity1 * normal;
float oldSpeed2 = velocity2 * normal;
Vector vInelastic;
float newSpeed1;
float newSpeed2;
const float cElasticity = 0.75; {
float mass1 = GetMass();
assert (mass1 > 0.0f);
float mass2 = pModel->GetMass();
assert (mass2 > 0.0f);
vInelastic = velocity1 * (mass1 / (mass1 + mass2)) +
velocity2 * (mass2 / (mass1 + mass2));
newSpeed1 = (oldSpeed1 * (mass1 - mass2) + 2.0f * oldSpeed2 * mass2) / (mass1 + mass2);
newSpeed2 = (oldSpeed2 * (mass2 - mass1) + 2.0f * oldSpeed1 * mass1) / (mass1 + mass2);
}
Vector perpendicular1 = velocity1 - oldSpeed1 * normal;
Vector perpendicular2 = velocity2 - oldSpeed2 * normal;
Vector vElastic1 = perpendicular1 + (newSpeed1 * normal);
Vector vElastic2 = perpendicular2 + (newSpeed2 * normal);
Vector newVelocity1 = vInelastic * (1.0f - cElasticity) + vElastic1 * cElasticity;
Vector newVelocity2 = vInelastic * (1.0f - cElasticity) + vElastic2 * cElasticity;
if (!(newVelocity1 * newVelocity1 >= 0.0f)) {
debugf("mmf Igc shipIGC.cpp ~1008 newVelocity1^2 debug build would have called assert and exited, commented out and set to zero for now\n");
newVelocity1.x = 0.0f; newVelocity1.y = 0.0f; newVelocity1.z = 0.0f;
}
if (!(newVelocity2 * newVelocity2 >= 0.0f)) {
debugf("mmf Igc shipIGC.cpp ~1013 newVelocity2^2 debug build would have called assert and exited, commented out and set to zero for now\n");
newVelocity2.x = 0.0f; newVelocity2.y = 0.0f; newVelocity2.z = 0.0f;
}
float base1 = (velocity1 - newVelocity1).LengthSquared() * c_impactDamageCoefficient;
float base2 = (velocity2 - newVelocity2).LengthSquared() * c_impactDamageCoefficient;
float damage1 = 2.0f * base1 + base2;
float damage2 = base1 + 2.0f * base2;
float hp1 = GetHitPoints();
if (m_mountedOthers[ET_Shield])
hp1 += ((IshieldIGC*)m_mountedOthers[ET_Shield])->GetFraction() *
((IshieldIGC*)m_mountedOthers[ET_Shield])->GetMaxStrength();
float hp2 = ((IdamageIGC*)pModel)->GetHitPoints();
{
IshieldIGC* pshield = (IshieldIGC*)(((IshipIGC*)pModel)->GetMountedPart(ET_Shield, 0));
if (pshield)
hp2 += pshield->GetFraction() * pshield->GetMaxStrength();
}
SetPosition(position1);
SetVelocity(newVelocity1);
pModel->SetPosition(position2);
pModel->SetVelocity(newVelocity2);
if (!(bFriendly &&
(m_myHullType.GetHullType()->HasCapability(c_habmLifepod) ||
((IshipIGC*)pModel)->GetBaseHullType()->HasCapability(c_habmLifepod))))
{
if (hp2 > 0.0f)
{
this->ReceiveDamage(c_dmgidCollision,
hp2 * damage1 / (hp2 + damage1),
timeCollision,
position1, position2,
(IshipIGC*)pModel);
}
if (hp1 > 0.0f)
{
((IdamageIGC*)pModel)->ReceiveDamage(c_dmgidCollision,
hp1 * damage2 / (hp1 + damage2),
timeCollision,
position2, position1,
this);
}
}
igcsite->PlaySoundEffect(collisionSound, this);
igcsite->PlayFFEffect(effectBounce, this);
igcsite->PlayVisualEffect(effectJiggle, this, (2.0f * damage1 + damage2) * c_impactJiggleCoefficient);
igcsite->PlaySoundEffect(collisionSound, pModel);
igcsite->PlayFFEffect(effectBounce, pModel);
igcsite->PlayVisualEffect(effectJiggle, pModel, (damage1 + 2.0f * damage2) * c_impactJiggleCoefficient);
cluster->RecalculateCollisions(tCollision, this, pModel);
pModel->Release();
Release();
}
break;
default:
{
assert (false);
}
}
}
DamageResult CshipIGC::ReceiveDamage(DamageTypeID type,
float amount,
Time timeCollision,
const Vector& position1,
const Vector& position2,
ImodelIGC* launcher)
{
IsideIGC* pside = GetSide();
if (launcher &&
(!GetMyMission()->GetMissionParams()->bAllowFriendlyFire) &&
(pside == launcher->GetSide()) &&
(amount >= 0.0f))
{
return c_drNoDamage;
}
DamageResult dr;
float maxHP = m_myHullType.GetHitPoints();
float dtmArmor = GetMyMission()->GetDamageConstant(type, m_myHullType.GetDefenseType());
assert (dtmArmor >= 0.0f);
float leakage;
if (amount < 0.0f)
{
m_fraction -= amount * dtmArmor / maxHP;
if (m_fraction > 1.0f)
m_fraction = 1.0f;
GetThingSite ()->RemoveDamage (m_fraction);
leakage = 0.0f;
dr = c_drNoDamage;
}
else
{
dr = c_drShieldDamage;
if (launcher)
{
if (launcher->GetObjectType() == OT_ship)
amount *= ((IshipIGC*)launcher)->GetExperienceMultiplier();
if (m_damageTrack && (launcher->GetMission() == GetMyMission()))
m_damageTrack->ApplyDamage(timeCollision, launcher, amount);
}
if (m_mountedOthers[ET_Shield])
{
Vector deltaP = position2 - position1;
leakage = ((IshieldIGC*)(m_mountedOthers[ET_Shield]))->ApplyDamage(timeCollision, type, amount, deltaP);
}
else
{
leakage = amount;
}
float oldFraction = m_fraction;
if (leakage > 0.0f)
{
leakage *= dtmArmor;
m_fraction -= leakage / maxHP;
dr = c_drHullDamage;
}
if (m_fraction > 0.0f)
{
if ((type & c_dmgidNoDebris) == 0)
GetThingSite ()->AddDamage (position2 - position1, m_fraction);
GetMyMission()->GetIgcSite()->DamageShipEvent(timeCollision, this, launcher, type, amount, leakage, position1, position2);
}
else
{
m_fraction = 0.0f;
if (oldFraction > 0.0f) {
DamageBucketLink* pdmglink = NULL;
ImodelIGC* pcredit = launcher;
DamageTrack* pdt = this->GetDamageTrack();
if (pdt)
{
pdmglink = pdt->GetDamageBuckets()->first();
if (pdmglink)
{
if (pdmglink->data()->model()->GetMission() == GetMyMission())
pcredit = pdmglink->data()->model();
}
}
GetMyMission()->GetIgcSite()->KillShipEvent(timeCollision, this, pcredit, amount, position1, position2);
dr = c_drKilled;
}
}
}
assert (m_fraction >= 0.0f);
assert (m_fraction <= 1.0f);
return dr;
}
void CshipIGC::SetBaseHullType(IhullTypeIGC* newVal)
{
assert (m_pshipParent == NULL);
SetStateM(0);
ResetDamageTrack();
assert (newVal);
IsideIGC* pside = GetSide();
IclusterIGC* pclusterOld = GetCluster();
Vector positionOld;
if (pclusterOld)
{
positionOld = GetPosition();
pclusterOld->DeleteModel(this);
GetThingSite()->SetCluster(this, NULL);
}
assert (m_parts.n() == 0);
if (m_shipsChildren.first())
{
Mount oldFixed = m_myHullType.GetHullType()->GetMaxFixedWeapons();
Mount newFixed = newVal->GetMaxFixedWeapons();
Mount maxTurrets = newVal->GetMaxWeapons() - newFixed;
for (ShipLinkIGC* psl = m_shipsChildren.first(); (psl != NULL); psl = psl->next())
{
IshipIGC* pship = psl->data();
Mount tid = pship->GetTurretID();
if (tid != NA)
{
tid -= oldFixed;
if (tid >= maxTurrets)
pship->SetTurretID(NA);
else if (oldFixed != newFixed)
pship->SetTurretID(tid + newFixed);
}
}
}
m_myHullType.SetHullType(newVal);
SetMass(m_myHullType.GetMass());
SetRipcordModel(NULL);
m_ripcordCost = newVal->GetRipcordCost();
if (newVal->HasCapability(c_habmLifepod))
m_timeToDie = GetLastUpdate() + GetMyMission()->GetFloatConstant(c_fcidLifepodEndurance);
{
HRESULT hr = Load(0,
m_myHullType.GetModelName(),
m_myHullType.GetTextureName(),
m_myHullType.GetIconName(),
c_mtDamagable | c_mtHitable | c_mtCastRay | c_mtSeenBySide | c_mtScanner);
ZSucceeded(hr);
}
SetRadius(0.5f * m_myHullType.GetLength());
HitTest* pht = GetHitTest();
m_cockpit = pht->GetFrameOffset("cockpt");
pht->SetUseTrueShapeOther(pside);
m_fOre = 0.0f;
m_fuel = 0.0f;
m_ammo = 0;
m_nextLaunchSlot = 0;
m_warningMask = 0;
m_fraction = 1.0f;
m_fractionLastOrder = 1.0f;
m_energy = 0.0f;
SetSignature(m_myHullType.GetSignature());
m_engineVector = Vector::GetZero();
if (pclusterOld)
{
SetPosition(positionOld);
pclusterOld->AddModel(this);
GetThingSite()->SetCluster(this, pclusterOld);
}
GetMyMission()->GetIgcSite()->LoadoutChangeEvent(this, NULL, c_lcHullChange);
ResetWaypoint();
}
void CshipIGC::AddPart(IpartIGC* part)
{
assert (part);
ZVerify(m_parts.last(part));
part->AddRef();
assert (part->GetPartType());
SetMass(GetMass() + part->GetMass());
GetMyMission()->GetIgcSite()->LoadoutChangeEvent(this, part, c_lcAdded);
assert (GetMass() > 0.0f); }
void CshipIGC::DeletePart(IpartIGC* part)
{
assert (part);
part->SetMountID(c_mountNA);
int iPart = 0; part->AddRef();
for (PartLinkIGC* l = m_parts.first(); (l != NULL); l = l->next())
{
iPart++; IpartIGC* p = l->data();
if (p == part)
{
SetMass(GetMass() - part->GetMass());
delete l;
p->Release();
break;
}
}
GetMyMission()->GetIgcSite()->LoadoutChangeEvent(this, part, c_lcRemoved);
part->Release();
assert (GetMass() > 0.0f); }
IpartIGC* const* CshipIGC::PartLocation(EquipmentType type,
Mount mountID) const
{
IpartIGC* const* partLocation;
if (mountID < 0)
{
assert (mountID >= -c_maxCargo);
partLocation = &m_mountedCargos[mountID + c_maxCargo];
}
else
{
switch (type)
{
case ET_Weapon:
{
assert (mountID < c_maxMountedWeapons);
partLocation = (IpartIGC* const*)&(m_mountedWeapons[mountID]);
}
break;
default:
{
assert (type < ET_MAX);
assert (mountID == 0);
partLocation = &m_mountedOthers[type];
}
break;
}
assert (partLocation);
}
return partLocation;
}
IpartIGC* CshipIGC::GetMountedPart(EquipmentType type,
Mount mountID) const
{
return *PartLocation(type, mountID);
}
void CshipIGC::MountPart(IpartIGC* part,
Mount mountNew,
Mount* pmountOld)
{
assert (part);
IpartTypeIGC* partType = part->GetPartType();
assert (partType);
part->SetMountedFraction(0.0f);
EquipmentType et = partType->GetEquipmentType();
if (*pmountOld >= -c_maxCargo)
{
IpartIGC** plOld = (IpartIGC**)PartLocation(et, *pmountOld);
assert (*plOld == part);
*plOld = NULL;
}
if (mountNew >= -c_maxCargo)
{
assert (m_myHullType.CanMount(partType, mountNew));
IpartIGC** plNew = (IpartIGC**)PartLocation(et, mountNew);
assert (*plNew == NULL);
*plNew = part;
}
*pmountOld = mountNew;
GetMyMission()->GetIgcSite()->LoadoutChangeEvent(this, part, (mountNew < 0) ? c_lcDismounted : c_lcMounted);
}
void CshipIGC::SetStateM(int newVal)
{
if (m_pshipParent == NULL)
{
if ((m_station == NULL) && (m_mountedOthers[ET_Cloak] != NULL))
{
if (m_pmodelRipcord)
newVal &= ~cloakActiveIGC;
int newCloak = (newVal & cloakActiveIGC);
if (newCloak != (m_stateM & cloakActiveIGC))
{
GetMyMission()->GetIgcSite()->PlayNotificationSound(newCloak
? salCloakEngageSound
: salCloakDisengageSound, this);
}
}
}
m_stateM = newVal;
}
void CshipIGC::ExecuteTurretMove(Time timeStart,
Time timeStop,
Orientation* pOrientation)
{
float dT = timeStop - timeStart;
float l = m_controls.jsValues[c_axisYaw] * m_controls.jsValues[c_axisYaw] +
m_controls.jsValues[c_axisPitch] * m_controls.jsValues[c_axisPitch] +
m_controls.jsValues[c_axisRoll] * m_controls.jsValues[c_axisRoll];
if (l > 1.0f)
l = 1.0f / sqrt(l);
else
l = 1.0f;
float oldTurnRate2 = m_turnRates[c_axisYaw] * m_turnRates[c_axisYaw] +
m_turnRates[c_axisPitch] * m_turnRates[c_axisPitch];
static const float c_minRate = RadiansFromDegrees(7.5f);
static const float c_maxRate = RadiansFromDegrees(75.0f);
float slewVelocity = (c_minRate + 0.5f * (c_maxRate - c_minRate)) +
(0.5f * (c_maxRate - c_minRate)) * m_controls.jsValues[c_axisThrottle];
for (int i = 0; (i < 3); i++)
m_turnRates[i] = m_controls.jsValues[i] * l * slewVelocity;
pOrientation->Yaw( m_turnRates[c_axisYaw] * dT);
pOrientation->Pitch(-m_turnRates[c_axisPitch] * dT);
pOrientation->Roll( m_turnRates[c_axisRoll] * dT);
assert (m_pshipParent);
assert (m_turretID >= m_pshipParent->GetHullType()->GetMaxFixedWeapons());
assert (m_turretID < m_pshipParent->GetHullType()->GetMaxWeapons());
{
pOrientation->Renormalize();
}
}
void CshipIGC::PreplotShipMove(Time timeStop)
{
IclusterIGC* pcluster = GetCluster();
const Vector& positionMe = GetPosition();
if (m_bAutopilot && (m_pshipParent == NULL) && ((m_stateM & buildingMaskIGC) == 0))
{
if (m_pilotType < c_ptCarrier) {
if (m_timeRanAway + c_dtCheckRunaway <= timeStop)
{
bool bDamage = true;
bool bRunAway = true;
if (m_pilotType == c_ptWingman)
{
if ( (m_mountedWeapons[0] && m_mountedWeapons[0]->GetProjectileType()->GetPower() < 0.0 ) || ( m_commandTargets[c_cmdAccepted] && (m_commandTargets[c_cmdAccepted]->GetObjectType() == OT_station) ) )
{
bRunAway = false;
}
else
{
bRunAway = m_fraction < m_fractionLastOrder; }
}
else if ((m_pilotType == c_ptBuilder) || (m_pilotType == c_ptLayer))
{
if (m_fraction < m_fractionLastOrder)
{
if (m_commandIDs[c_cmdAccepted] == c_cidBuild)
{
assert ((m_pilotType == c_ptBuilder) || (m_pilotType == c_ptLayer));
assert (m_commandTargets[c_cmdAccepted]);
ImodelIGC* pmodel = FindTarget(this, c_ttFriendly | c_ttStation | c_ttNearest,
NULL, NULL, NULL, NULL, c_sabmRepair);
if (pmodel)
{
if (m_commandTargets[c_cmdAccepted]->GetCluster() == GetCluster())
{
if ((positionMe - m_commandTargets[c_cmdAccepted]->GetPosition()).LengthSquared() <=
(positionMe - pmodel->GetPosition()).LengthSquared())
{
bRunAway = false;
}
}
}
else
bRunAway = false;
}
}
else
bRunAway = false;
}
else
{
if ( ! (m_pilotType == c_ptMiner) ) {
if (m_pilotType != 1) {
debugf ("mmf shipIGC.cpp assert (m_pilotType == c_ptMiner), m_pilotType = %d\n",
m_pilotType);
}
}
if (m_fraction >= 0.95f) {
IshieldIGC* pshield = (IshieldIGC*)(m_mountedOthers[ET_Shield]);
if ((pshield == NULL) || (pshield->GetFraction() >= 0.75f))
{
bDamage = false;
IsideIGC* psideMe = GetSide();
int cEnemy = 0;
int cFriend = 0;
float d2Enemy = FLT_MAX;
float d2Friend = FLT_MAX;
for (ShipLinkIGC* psl = pcluster->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 (CanSee(pship) && SeenBySide(pside))
{
cEnemy++;
float d2 = (positionMe - pship->GetPosition()).LengthSquared();
if (d2 < d2Enemy)
d2Enemy = d2;
}
}
}
if (cFriend >= cEnemy)
bRunAway = false;
else
{
static const float c_d2AlwaysRun = 1000.0f;
if (d2Enemy > c_d2AlwaysRun * c_d2AlwaysRun)
bRunAway = (d2Enemy < d2Friend);
}
}
}
}
if (bRunAway)
{
if (!m_bRunningAway)
{
ImodelIGC* pmodel = FindTarget(this, c_ttFriendly | c_ttStation | c_ttNearest | c_ttAnyCluster,
NULL, NULL, NULL, NULL, c_sabmRepair);
if (pmodel)
{
SetCommand(c_cmdPlan, pmodel, c_cidGoto);
if (m_pilotType == c_ptBuilder)
GetMyMission()->GetIgcSite()->SendChat(this, CHAT_TEAM, GetSide()->GetObjectID(),
constructorRunningSound, "Constructor heading for cover.");
else if (bDamage)
GetMyMission()->GetIgcSite()->SendChat(this, CHAT_TEAM, GetSide()->GetObjectID(),
droneTooMuchDamageSound, "Forget this. I have to go get repaired");
else
GetMyMission()->GetIgcSite()->SendChat(this, CHAT_TEAM, GetSide()->GetObjectID(),
droneEnemyOnScopeSound, "Enemy spotted; returning to base.");
m_bRunningAway = true;
m_timeRanAway = timeStop;
}
}
}
else if (m_bRunningAway)
{
SetCommand(c_cmdPlan, NULL, c_cidNone);
assert (m_bRunningAway == false); m_timeRanAway = timeStop;
}
}
if (!LegalCommand(m_commandIDs[c_cmdPlan], m_commandTargets[c_cmdPlan]))
{
if (LegalCommand(m_commandIDs[c_cmdAccepted], m_commandTargets[c_cmdAccepted]))
{
SetCommand(c_cmdPlan, m_commandTargets[c_cmdAccepted], m_commandIDs[c_cmdAccepted]);
}
else
{
PickDefaultOrder(pcluster, positionMe, false);
}
}
if (m_pilotType == c_ptMiner)
{
int stateM = 0;
if (m_commandTargets[c_cmdPlan] && (m_commandTargets[c_cmdPlan]->GetCluster() == pcluster))
{
if (m_commandIDs[c_cmdPlan] == c_cidMine)
{
assert (m_commandTargets[c_cmdPlan]->GetObjectType() == OT_asteroid);
assert (((IasteroidIGC*)(ImodelIGC*)m_commandTargets[c_cmdPlan])->HasCapability(m_abmOrders));
Vector dp = m_commandTargets[c_cmdPlan]->GetPosition() - positionMe;
float distance2 = dp.LengthSquared();
float radius = m_commandTargets[c_cmdPlan]->GetRadius() + GetRadius() + 30.0f;
if ((distance2 < radius * radius) && (GetVelocity().LengthSquared() < 1.0f))
{
stateM = wantsToMineMaskIGC;
}
else if (m_gotoplan.GetMaskWaypoints() == 0)
ResetWaypoint(); }
else if ((m_fOre > 0.0f) &&
(m_commandIDs[c_cmdPlan] == c_cidGoto) &&
(m_commandTargets[c_cmdPlan]->GetObjectType() == OT_station))
{
IstationIGC* pstation = (IstationIGC*)((ImodelIGC*)m_commandTargets[c_cmdPlan]);
if (pstation->GetBaseStationType()->HasCapability(c_sabmTeleportUnload))
{
Vector dp = pstation->GetPosition() - positionMe;
float distance2 = dp.LengthSquared();
float radius = pstation->GetRadius() + GetRadius() + 100.0f;
if (distance2 < radius * radius)
{
IsideIGC* pside = GetSide();
GetMyMission()->GetIgcSite()->PaydayEvent(pside,
m_fOre *
GetMyMission()->GetFloatConstant(c_fcidValueHe3) *
pside->GetGlobalAttributeSet().GetAttribute(c_gaMiningYield));
m_fOre = 0.0f;
PickDefaultOrder(pcluster, positionMe, false);
}
}
}
}
SetStateBits(miningMaskIGC | wantsToMineMaskIGC, stateM);
}
}
}
}
void CshipIGC::PlotShipMove(Time timeStop)
{
if (m_bAutopilot && (m_pshipParent == NULL))
{
Time timeStart = GetMyLastUpdate();
{
if (m_pclusterRequestRipcord && (m_timeRequestRipcord > timeStart) && (GetCluster() != m_pclusterRequestRipcord))
{
if (IsSafeToRipcord())
{
GetMyMission()->GetIgcSite()->RequestRipcord(this, m_pclusterRequestRipcord);
m_pclusterRequestRipcord = NULL;
}
else
{
m_timeRequestRipcord = timeStart + 5.0f;
}
}
}
bool bControlsSet = false;
float dT = timeStop - timeStart;
if (m_pilotType == c_ptMiner)
{
if ((m_stateM & wantsToMineMaskIGC) != 0)
{
IclusterIGC* pcluster = GetCluster();
IsideIGC* pside = GetSide();
short nFriendly = 0;
short nEnemy = 0;
IshipIGC* pshipMin;
{
float fOreMin = FLT_MAX;
for (ShipLinkIGC* psl = pcluster->GetShips()->first();
(psl != NULL);
psl = psl->next())
{
IshipIGC* pship = psl->data();
if (((pship->GetStateM() & wantsToMineMaskIGC) != 0) &&
(pship->GetCommandTarget(c_cmdPlan) == m_commandTargets[c_cmdPlan]))
{
if (pship->GetSide() == pside)
{
nFriendly++;
float fOre = pship->GetOre();
if (fOre < fOreMin)
{
fOreMin = fOre;
pshipMin = pship;
}
}
else
nEnemy++;
}
}
}
assert (nFriendly > 0);
if (nEnemy == 0)
{
if (nFriendly > 1)
{
{
for (ShipLinkIGC* psl = pcluster->GetShips()->first();
(psl != NULL);
psl = psl->next())
{
IshipIGC* pship = psl->data();
if (((pship->GetStateM() & wantsToMineMaskIGC) != 0) &&
(pship->GetCommandTarget(c_cmdCurrent) == m_commandTargets[c_cmdPlan]) &&
(pship->GetSide() == pside) &&
pship != pshipMin)
{
pship->SetStateBits(miningMaskIGC | wantsToMineMaskIGC, 0);
{
ImodelIGC* pmodel = FindTarget(pship, c_ttFriendly | c_ttStation | c_ttNearest | c_ttAnyCluster,
NULL, NULL, NULL, NULL, c_sabmUnload | c_sabmLand);
if (pmodel)
{
float capacity = GetMyMission()->GetFloatConstant(c_fcidCapacityHe3) *
GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaMiningCapacity);
pship->SetCommand(c_cmdPlan, pmodel, c_cidGoto);
if (pship->GetOre() < capacity)
GetMyMission()->GetIgcSite()->SendChat(pship, CHAT_TEAM, GetSide()->GetObjectID(),
droneComingHomeEmptySound, "Coming home empty");
}
else { pship->SetCommand(c_cmdAccepted, NULL, c_cidNone);
}
}
}
}
}
}
pshipMin->SetStateBits(miningMaskIGC | wantsToMineMaskIGC, miningMaskIGC);
}
else
{
for (ShipLinkIGC* psl = GetCluster()->GetShips()->first();
(psl != NULL);
psl = psl->next())
{
IshipIGC* pship = psl->data();
if (((pship->GetStateM() & wantsToMineMaskIGC) != 0) &&
(pship->GetCommandTarget(c_cmdCurrent) == m_commandTargets[c_cmdPlan]))
{
pship->Complain(droneTooCrowdedSound, "Miner requesting unoccupied He3 asteriod.");
pship->SetStateBits(miningMaskIGC | wantsToMineMaskIGC, 0);
}
}
}
}
if ((m_stateM & miningMaskIGC) != 0)
{
IasteroidIGC* pasteroid = ((IasteroidIGC*)(ImodelIGC*)m_commandTargets[c_cmdPlan]);
const GlobalAttributeSet& ga = GetSide()->GetGlobalAttributeSet();
float minedOre = dT * ga.GetAttribute(c_gaMiningRate);
float capacity = GetMyMission()->GetFloatConstant(c_fcidCapacityHe3) * ga.GetAttribute(c_gaMiningCapacity);
if (m_fOre + minedOre >= capacity)
{
minedOre = capacity - m_fOre;
{
ImodelIGC* pmodel = FindTarget(this, c_ttFriendly | c_ttStation | c_ttNearest | c_ttAnyCluster,
NULL, NULL, NULL, NULL, c_sabmUnload);
if (pmodel)
SetCommand(c_cmdPlan, pmodel, c_cidGoto);
}
}
float actualOre = pasteroid->MineOre(minedOre);
m_fOre += actualOre;
if (actualOre != minedOre)
{
PickDefaultOrder(GetCluster(), GetPosition(), false);
}
Vector dp = pasteroid->GetPosition() - GetPosition();
turnToFace(dp, dT, this, &m_controls, 1.0f);
m_controls.jsValues[c_axisRoll] = 1.0f;
m_controls.jsValues[c_axisThrottle] = -1.0f;
SetStateBits(weaponsMaskIGC | (buttonsMaskIGC & ~miningMaskIGC), 0);
return;
}
}
else if (m_pilotType == c_ptBuilder)
{
if ((m_stateM & buildingMaskIGC) != 0)
{
this->m_controls.jsValues[c_axisYaw] = 0.0f;
this->m_controls.jsValues[c_axisPitch] = 0.0f;
this->m_controls.jsValues[c_axisRoll] = 1.0f;
this->m_controls.jsValues[c_axisThrottle] = -0.8f;
return;
}
else if ((m_stateM & drillingMaskIGC) != 0)
{
assert (m_commandTargets[c_cmdPlan]);
assert (m_commandTargets[c_cmdPlan]->GetObjectType() == OT_asteroid);
Vector dp = GetPosition() - m_commandTargets[c_cmdPlan]->GetPosition();
const Vector& axis = m_commandTargets[c_cmdPlan]->GetRotation().axis();
float radius = GetRadius() + m_commandTargets[c_cmdPlan]->GetRadius() + 25.0f;
float dot = axis * dp;
float distance2 = dp.LengthSquared();
float offset2 = distance2 - dot*dot;
if ((offset2 < 50.0f) && (distance2 < radius * radius))
{
this->m_controls.jsValues[c_axisYaw] = 0.0f;
this->m_controls.jsValues[c_axisPitch] = 0.0f;
this->m_controls.jsValues[c_axisRoll] = 1.0f;
this->m_controls.jsValues[c_axisThrottle] = 0.0f;
return;
}
else
{
assert (m_commandTargets[c_cmdPlan]->GetObjectType() == OT_asteroid);
SetStateM(0);
}
}
}
if (m_commandTargets[c_cmdPlan] == NULL)
{
if ((m_pilotType < c_ptCarrier) && (m_commandIDs[c_cmdPlan] != c_cidDoNothing))
{
switch (m_pilotType)
{
case c_ptMiner:
Complain(droneWhereToSound, "Miner requesting He3 asteriod.");
break;
case c_ptBuilder:
Complain(
((IstationTypeIGC*)(IbaseIGC*)m_pbaseData)->GetConstructorNeedRockSound(),
"Constructor requesting asteroid.");
break;
case c_ptLayer:
if (m_pbaseData->GetObjectType() == OT_mineType)
Complain(droneWhereToLayMinefieldSound, "Minefield requesting location.");
else
Complain(droneWhereToLayTowerSound, "Tower requesting location.");
break;
}
}
int state = 0;
Dodge(this, NULL, &state);
SetStateBits(backwardButtonIGC |
forwardButtonIGC |
leftButtonIGC |
rightButtonIGC |
upButtonIGC |
downButtonIGC |
afterburnerButtonIGC |
coastButtonIGC |
oneWeaponIGC | allWeaponsIGC, state);
m_controls.Reset();
}
else
{
m_dtTimeBetweenComplaints = c_dtTimeBetweenComplaints;
if (((m_pilotType == c_ptWingman) || (m_pilotType == c_ptCheatPlayer)) &&
(m_commandTargets[c_cmdPlan]->GetCluster() == GetCluster()))
{
if ( m_commandIDs[c_cmdPlan] == c_cidAttack )
{
float fShootSkill = 0.75f;
float fTurnSkill = 0.75f;
int state = 0;
bool bDodge = Dodge(this, NULL, &state);
Vector direction;
float t = solveForLead(this,
m_commandTargets[c_cmdPlan],
m_mountedWeapons[0],
&direction,
fShootSkill);
float da = turnToFace(direction, dT, this, &m_controls, fTurnSkill);
m_controls.jsValues[c_axisThrottle] = 0.5f + ((pi - da) / (2.0f * pi));
const float c_fMaxOffAngle = 0.10f;
float lifespan = m_mountedWeapons[0]->GetLifespan();
SetStateBits(~selectedWeaponMaskIGC,
((da <= c_fMaxOffAngle) && (t <= lifespan * 0.9f))
? (state | allWeaponsIGC)
: state);
return;
}
else if ( m_commandIDs[c_cmdPlan] == c_cidRepair && m_mountedWeapons[0]->GetProjectileType()->GetPower()<0.0 )
{
float fShootSkill = 1.00f;
float fTurnSkill = 1.00f;
int state = 0;
bool bDodge = Dodge(this, NULL, &state);
Vector direction;
float t = solveForLead(this,
m_commandTargets[c_cmdPlan],
m_mountedWeapons[0],
&direction,
fShootSkill);
float da = turnToFace(direction, dT, this, &m_controls, fTurnSkill);
m_controls.jsValues[c_axisThrottle] = 0.5f + ((pi - da) / (2.0f * pi));
const float c_fMaxOffAngle = 0.10f;
float lifespan = m_mountedWeapons[0]->GetLifespan();
if ((!bDodge) && (t <= lifespan * 0.25f))
{
state = leftButtonIGC;
if (da < pi * 0.5f)
{
if (da > c_fMaxOffAngle)
{
state |= backwardButtonIGC;
}
else
state |= forwardButtonIGC;
}
}
SetStateBits(~selectedWeaponMaskIGC,
((da <= c_fMaxOffAngle) && (t <= lifespan * 0.9f))
? (state | allWeaponsIGC)
: state);
return;
}
else if (m_commandIDs[c_cmdPlan] == c_cidDefend)
{
}
}
if (m_gotoplan.Execute(timeStart, dT, true))
{
if (m_commandIDs[c_cmdPlan] == c_cidGoto)
{
{
ImodelIGC* pmodelPlan = m_commandTargets[c_cmdPlan];
for (Command i = 0; (i < c_cmdMax); i++)
{
if (m_commandTargets[i] == pmodelPlan)
SetCommand(i, NULL, c_cidNone);
}
}
}
else if (m_commandIDs[c_cmdPlan] == c_cidBuild)
{
if (m_pilotType == c_ptBuilder)
{
assert (m_commandTargets[c_cmdPlan]->GetObjectType() == OT_asteroid);
assert (((IasteroidIGC*)((ImodelIGC*)m_commandTargets[c_cmdPlan]))->HasCapability(m_abmOrders));
SetStateM(drillingMaskIGC);
this->m_controls.jsValues[c_axisYaw] = 0.0f;
this->m_controls.jsValues[c_axisPitch] = 0.0f;
this->m_controls.jsValues[c_axisRoll] = 1.0f;
this->m_controls.jsValues[c_axisThrottle] = 0.0f; }
else
{
assert (m_pilotType == c_ptLayer);
assert (m_commandTargets[c_cmdPlan]->GetObjectType() == OT_buoy);
GetMyMission()->GetIgcSite()->LayExpendable(timeStart, (IexpendableTypeIGC*)(IbaseIGC*)m_pbaseData, this);
}
}
}
}
}
}
void CshipIGC::ExecuteShipMove(Time timeStop)
{
Vector v = GetVelocity();
Orientation o = GetOrientation();
ExecuteShipMove(GetMyLastUpdate(), timeStop, &v, &o);
SetVelocity(v);
SetOrientation(o);
}
void CshipIGC::ExecuteShipMove(Time timeStart,
Time timeStop,
Vector* pVelocity,
Orientation* pOrientation)
{
if (timeStop > timeStart)
{
float dT = timeStop - timeStart;
assert (dT > 0.0f);
float thrust = m_myHullType.GetThrust();
float thrust2 = thrust * thrust;
assert (GetMass() > 0.0f);
float thrustToVelocity = dT / GetMass();
if (!m_pmodelRipcord)
{
float l = m_controls.jsValues[c_axisYaw] * m_controls.jsValues[c_axisYaw] +
m_controls.jsValues[c_axisPitch] * m_controls.jsValues[c_axisPitch] +
m_controls.jsValues[c_axisRoll] * m_controls.jsValues[c_axisRoll];
if (l > 1.0f)
l = 1.0f / sqrt(l);
else
l = 1.0f;
float tm = GetTorqueMultiplier() * thrustToVelocity;
for (int i = 0; (i < 3); i++)
{
float desiredRate = m_controls.jsValues[i] * l * m_myHullType.GetMaxTurnRate(i);
float maxDelta = tm * m_myHullType.GetTurnTorque(i);
if (desiredRate < m_turnRates[i] - maxDelta)
m_turnRates[i] -= maxDelta;
else if (desiredRate > m_turnRates[i] + maxDelta)
m_turnRates[i] += maxDelta;
else
m_turnRates[i] = desiredRate;
}
}
pOrientation->Yaw( m_turnRates[c_axisYaw] * dT);
pOrientation->Pitch(-m_turnRates[c_axisPitch] * dT);
pOrientation->Roll( m_turnRates[c_axisRoll] * dT);
pOrientation->Renormalize();
const Vector& myBackward = pOrientation->GetBackward();
float speed = pVelocity->Length();
float maxSpeed = m_myHullType.GetMaxSpeed();
assert (maxSpeed > 0.0f);
Vector drag;
{
double f = exp(double(double(-thrust) * double(thrustToVelocity) / (double)maxSpeed)); drag = *pVelocity * float((1.0 - f) / double(thrustToVelocity));
}
m_engineVector.x = m_engineVector.y = m_engineVector.z = 0.0f; bool afterF = (m_stateM & afterburnerButtonIGC) != 0;
float thrustRatio = 0.0f;
{
IafterburnerIGC* afterburner = (IafterburnerIGC*)(m_mountedOthers[ET_Afterburner]);
if (afterburner)
{
float abThrust = afterburner->GetMaxThrust();
if (afterF) {
thrustRatio = abThrust / thrust;
}
afterburner->IncrementalUpdate(timeStart, timeStop, false);
float power = afterburner->GetPower();
if (power != 0.0f)
{
drag += (power * abThrust) * myBackward;
}
}
}
if (!m_pmodelRipcord)
{
Vector localThrust;
if (m_stateM & (leftButtonIGC | rightButtonIGC |
upButtonIGC | downButtonIGC |
forwardButtonIGC | backwardButtonIGC))
{
int x = ((m_stateM & leftButtonIGC) ? -1 : 0) + ((m_stateM & rightButtonIGC) ? 1 : 0);
int y = ((m_stateM & downButtonIGC) ? -1 : 0) + ((m_stateM & upButtonIGC) ? 1 : 0);
int z = ((m_stateM & backwardButtonIGC) ? 1 : 0) + ((m_stateM & forwardButtonIGC) ? -1 : 0);
if (x || y || z)
{
localThrust.x = (thrust * (float)x);
localThrust.y = (thrust * (float)y);
localThrust.z = (thrust * (float)z);
}
else
localThrust = Vector::GetZero();
}
else
{
if ((m_stateM & coastButtonIGC) && !afterF)
localThrust = pOrientation->TimesInverse(drag);
else
{
float negDesiredSpeed;
if (afterF)
negDesiredSpeed = maxSpeed * (-1.0f - thrustRatio);
else
negDesiredSpeed = (-0.5f * (1.0f + m_controls.jsValues[c_axisThrottle])) *
((speed > maxSpeed) ? speed : maxSpeed);
Vector desiredVelocity = myBackward * negDesiredSpeed;
if (thrustToVelocity == 0.0f) debugf("shipIGC.cpp ~2394 thrustToVelocity = 0 about to devide by zero\n");
localThrust = pOrientation->TimesInverse((desiredVelocity - *pVelocity) / thrustToVelocity + drag);
}
}
{
float sm = m_myHullType.GetSideMultiplier();
if (sm == 0.0f) debugf("shipIGC.cpp ~2403 sm = 0 about to devide by zero\n");
if ((m_myHullType.GetBackMultiplier()==0.0f)&&(localThrust.z<=0.0f))
debugf("shipIGC.cpp ~2405 backmultip = 0 about to devide by zero\n");
Vector scaledThrust(localThrust.x / sm,
localThrust.y / sm,
localThrust.z <= 0.0f ? localThrust.z : (localThrust.z / m_myHullType.GetBackMultiplier()));
float r2 = scaledThrust.LengthSquared();
if (r2 == 0.0f)
m_engineVector = Vector::GetZero();
else if (r2 <= thrust2)
{
m_engineVector = localThrust * *pOrientation;
}
else
{
m_engineVector = (localThrust * *pOrientation) * (thrust / (float)sqrt(r2));
}
}
}
*pVelocity += thrustToVelocity * (m_engineVector - drag);
if ((*pVelocity * *pVelocity) > 640000.0f) {
debugf("mmf pVelocity^2 = %g ship = %s\n",(*pVelocity * *pVelocity),GetName());
}
if (!(*pVelocity * *pVelocity >= 0.0f)) {
debugf("mmf pVelocity^2 < 0.0 ship = %s\n",GetName());
debugf("pVelocity x=%g y=%g z=%g\n",(*pVelocity).x,(*pVelocity).y,(*pVelocity).z);
debugf("Igc shipIGC.cpp debug build would have called assert and exited, commented out for now\n");
}
}
}
void CshipIGC::ProcessFractions(const CompactShipFractions& fractions)
{
SetFraction(fractions.GetHullFraction());
if (m_mountedOthers[ET_Shield])
((IshieldIGC*)(m_mountedOthers[ET_Shield]))->SetFraction(fractions.GetShieldFraction());
SetFuel(fractions.GetFuel(m_myHullType.GetMaxFuel()));
SetAmmo(fractions.GetAmmo(m_myHullType.GetMaxAmmo()));
SetEnergy(fractions.GetEnergy(m_myHullType.GetMaxEnergy()));
}
#define GetSC { \
int stateM; \
shipupdate.stateM.Export(&stateM); \
SetStateM(stateM); \
} \
shipupdate.controls.Export(&m_controls);
#define GetOVTP Vector velocity; \
shipupdate.velocity.Export(&velocity); \
Orientation orientation; \
shipupdate.orientation.Export(&orientation); \
shipupdate.turnRates.Export(m_turnRates); \
if (m_mountedOthers[ET_Afterburner]) \
((IafterburnerIGC*)(m_mountedOthers[ET_Afterburner]))->SetPower(shipupdate.power);
#define GetF SetFraction(shipupdate.fractions.GetHullFraction()); \
if (m_mountedOthers[ET_Shield]) \
((IshieldIGC*)(m_mountedOthers[ET_Shield]))->SetFraction(shipupdate.fractions.GetShieldFraction()); \
SetFuel(shipupdate.fractions.GetFuel(m_myHullType.GetMaxFuel())); \
SetAmmo(shipupdate.fractions.GetAmmo(m_myHullType.GetMaxAmmo())); \
SetEnergy(shipupdate.fractions.GetEnergy(m_myHullType.GetMaxEnergy()));
static inline bool LegalPosition(const Vector& position)
{
float l = position * position;
return (l > 0.0f) &&
(l < 90000.0f * 90000.0f);
}
ShipUpdateStatus CshipIGC::ProcessShipUpdate(const ServerLightShipUpdate& shipupdate)
{
GetSC;
return c_susAccepted;
}
ShipUpdateStatus CshipIGC::ProcessShipUpdate(Time timeReference,
Vector positionReference,
const ServerHeavyShipUpdate& shipupdate)
{
ShipUpdateStatus rc;
Time timeUpdate;
shipupdate.time.Export(timeReference, &timeUpdate);
timeUpdate = GetMyMission()->GetIgcSite()->ClientTimeFromServerTime(timeUpdate);
float deltaT = GetMyLastUpdate() - timeUpdate;
if ((deltaT < 1.5f) && (deltaT > -1.5f))
{
Vector position;
shipupdate.position.Export(positionReference, &position);
if (LegalPosition(position))
{
rc = c_susAccepted;
GetSC;
GetOVTP;
GetF;
WarpShip(timeUpdate, deltaT, &position, &velocity, &orientation);
}
else
rc = c_susInvalid;
}
else
rc = c_susOutOfDate;
return rc;
}
ShipUpdateStatus CshipIGC::ProcessShipUpdate(const ClientShipUpdate& shipupdate)
{
ShipUpdateStatus rc;
float deltaT = GetMyLastUpdate() - shipupdate.time;
if ((deltaT < 1.5f) && (deltaT > -1.5f) && LegalPosition(shipupdate.position))
{
GetSC;
GetOVTP;
Vector position = shipupdate.position;
if (LegalPosition(position))
{
CalculateShip(shipupdate.time, deltaT, &position, &velocity, &orientation);
SetOrientation(orientation); float d = (GetPosition() - position).LengthSquared();
if (d < 400.0f)
{
rc = c_susAccepted;
SetPosition(position);
SetVelocity(velocity);
}
else
{
debugf("Position error %10.2f %10.4f (%s)\n", sqrt(d), deltaT, GetName());
rc = c_susRejected;
}
}
else
rc = c_susInvalid;
}
else
rc = c_susOutOfDate;
return rc;
}
ShipUpdateStatus CshipIGC::ProcessShipUpdate(const ServerSingleShipUpdate& shipupdate, bool bOrient)
{
GetSC;
GetOVTP;
GetF;
Vector position = shipupdate.position;
assert (LegalPosition(shipupdate.position));
float deltaT = GetMyLastUpdate() - shipupdate.time;
if ((deltaT < 1.5f) && (deltaT > -1.5f))
{
CalculateShip(shipupdate.time, deltaT, &position, &velocity, &orientation);
}
SetPosition(position);
SetVelocity(velocity);
if (bOrient)
SetOrientation(orientation);
return c_susAccepted;
}
#undef GetSC
#undef GetOVTP
#undef GetF
void CshipIGC::CalculateShip(Time timeUpdate, float deltaT, Vector* pPosition, Vector* pVelocity, Orientation* pOrientation)
{
if (deltaT <= 0.0f)
{
*pPosition += *pVelocity * deltaT;
pOrientation->Roll( -m_turnRates[c_axisRoll] * deltaT);
pOrientation->Pitch( m_turnRates[c_axisPitch] * deltaT);
pOrientation->Yaw( -m_turnRates[c_axisYaw] * deltaT);
pOrientation->Renormalize();
}
else
{
int n = 1 + (int)(deltaT / c_fTimeIncrement);
Time thisTime = timeUpdate;
for (int i = 1; (i <= n); i++)
{
Time nextTime = timeUpdate + (deltaT * (((float)i) / ((float)n)));
ExecuteShipMove(thisTime, nextTime,
pVelocity,
pOrientation);
*pPosition += *pVelocity * (nextTime - thisTime);
thisTime = nextTime;
}
}
}
void CshipIGC::WarpShip(Time timeUpdate, float deltaT, Vector* pPosition, Vector* pVelocity, Orientation* pOrientation)
{
CalculateShip(timeUpdate, deltaT, pPosition, pVelocity, pOrientation);
SetPosition(*pPosition);
SetVelocity(*pVelocity);
SetOrientation(*pOrientation);
}
ShipUpdateStatus CshipIGC::ProcessShipUpdate(Time timeReference,
const ServerActiveTurretUpdate& shipupdate)
{
ShipUpdateStatus rc;
Time timeUpdate;
shipupdate.time.Export(timeReference, &timeUpdate);
timeUpdate = GetMyMission()->GetIgcSite()->ClientTimeFromServerTime(timeUpdate);
float deltaT = GetMyLastUpdate() - timeUpdate;
if ((deltaT < 1.5f) && (deltaT > -1.5f))
{
rc = c_susAccepted;
SetStateM(weaponsMaskIGC);
shipupdate.controls.Export(&m_controls);
Orientation orientation;
shipupdate.orientation.Export(&orientation);
{
int n = 1 + (int)(float(fabs(deltaT)) / c_fTimeIncrement);
Time thisTime = timeUpdate;
for (int i = 1; (i <= n); i++)
{
Time nextTime = timeUpdate + (deltaT * (((float)i) / ((float)n)));
ExecuteTurretMove(thisTime,
nextTime,
&(orientation));
thisTime = nextTime;
}
}
SetOrientation(orientation);
}
else
rc = c_susOutOfDate;
return rc;
}
ShipUpdateStatus CshipIGC::ProcessShipUpdate(const ClientActiveTurretUpdate& shipupdate)
{
ShipUpdateStatus rc;
float deltaT = GetMyLastUpdate() - shipupdate.time;
if ((deltaT < 1.5f) && (deltaT > -1.5f))
{
rc = c_susAccepted;
SetStateM(weaponsMaskIGC);
shipupdate.controls.Export(&m_controls);
Orientation orientation;
shipupdate.orientation.Export(&orientation);
{
int n = 1 + (int)(float(fabs(deltaT)) / c_fTimeIncrement);
Time thisTime = shipupdate.time;
for (int i = 1; (i <= n); i++)
{
Time nextTime = shipupdate.time + (deltaT * (((float)i) / ((float)n)));
ExecuteTurretMove(thisTime,
nextTime,
&(orientation));
thisTime = nextTime;
}
}
SetOrientation(orientation);
}
else
rc = c_susOutOfDate;
return rc;
}
void CshipIGC::SetSide(IsideIGC* pside) {
IsideIGC* psideOld = GetSide();
if (psideOld != pside)
{
if (psideOld)
{
for (ShipLinkIGC* psl = psideOld->GetShips()->first();
(psl != NULL);
psl = psl->next())
{
if (psl->data()->GetAutoDonate() == this)
psl->data()->SetAutoDonate(NULL);
}
}
m_pshipAutoDonate = NULL;
SetCluster(NULL);
SetParentShip(NULL);
ShipLinkIGC* psl;
while (psl = m_shipsChildren.first()) {
psl->data()->SetParentShip(NULL);
}
if (m_station)
{
m_station->DeleteShip(this);
m_station->Release();
m_station = NULL;
}
assert (m_station == NULL);
if (psideOld)
psideOld->DeleteShip(this);
TmodelIGC<IshipIGC>::SetSide(pside);
if (pside)
pside->AddShip(this);
}
}
void CshipIGC::SetMission(ImissionIGC* pMission)
{
ImissionIGC* pmisionOld = GetMyMission();
if (pMission != pmisionOld)
{
AddRef();
SetSide(NULL);
{
PartLinkIGC* l;
while (l = m_parts.first()) l->data()->Terminate();
}
m_ammo = 0;
m_fuel = 0.0f;
{
for (Command i = 0; (i < c_cmdMax); i++)
{
if (m_commandTargets[i])
{
m_commandTargets[i]->Release();
m_commandTargets[i] = NULL;
}
m_commandIDs[i] = c_cidNone;
}
}
m_myHullType.SetHullType(NULL);
SetMass(0.0f);
FreeThingSite();
{
if (pmisionOld)
{
pmisionOld->DeleteShip(this);
SetMyMission(NULL);
}
}
assert (!GetMyMission());
assert (GetStation() == NULL);
assert (GetCluster() == NULL);
assert (GetSide() == NULL);
assert (m_myHullType.GetHullType() == NULL);
if (pMission)
{
SetMyMission(pMission);
pMission->AddShip(this);
}
m_stateM = 0;
Release();
}
}
void CshipIGC::Promote(void)
{
assert (m_pshipParent);
IshipIGC* pshipParent = m_pshipParent;
Mount turretid = m_turretID;
SetParentShip(NULL);
SetBaseHullType(pshipParent->GetBaseHullType());
{
for (PartLinkIGC* ppl = pshipParent->GetParts()->first(); (ppl != NULL); ppl = ppl->next())
{
IpartIGC* ppart = ppl->data();
IpartIGC* ppartNew = CreateAndAddPart(ppart->GetPartType(), ppart->GetMountID(), ppart->GetAmount());
ppartNew->SetMountedFraction(ppart->GetMountedFraction());
if (IlauncherIGC::IsLauncher(ppart->GetObjectType()))
{
((IlauncherIGC*)ppartNew)->SetTimeFired(GetMyLastUpdate());
}
}
SetAmmo(pshipParent->GetAmmo());
SetFuel(pshipParent->GetFuel());
SetEnergy(pshipParent->GetEnergy());
}
{
const ShipListIGC* pships = pshipParent->GetChildShips();
ShipLinkIGC* psl;
while (psl = pships->first()) {
IshipIGC* pship = psl->data();
Mount turretID = pship->GetTurretID();
pship->SetParentShip(this);
pship->SetTurretID(turretID);
}
}
const Vector& position = pshipParent->GetPosition();
SetPosition(position);
SetVelocity(pshipParent->GetVelocity());
SetOrientation(pshipParent->GetOrientation());
SetFraction(pshipParent->GetFraction());
{
IshieldIGC* pshield = (IshieldIGC*)(pshipParent->GetMountedPart(ET_Shield, 0));
if (pshield)
{
assert (m_mountedOthers[ET_Shield]);
((IshieldIGC*)(m_mountedOthers[ET_Shield]))->SetFraction(pshield->GetFraction());
}
}
pshipParent->SetParentShip(this);
pshipParent->SetTurretID(turretid);
IclusterIGC* pcluster = GetCluster();
if (pcluster)
{
const ModelListIGC* pmodels = pcluster->GetModels();
ModelLinkIGC* pmlParent = pmodels->find(pshipParent);
ModelLinkIGC* pmlThis = pmodels->find(this);
pmlParent->data(this);
pmlThis->data(pshipParent);
}
}
void CshipIGC::SetParentShip(IshipIGC* pshipParent)
{
if (m_pshipParent != pshipParent)
{
debugf("Parent of %s changing to ", GetName());
IshipIGC* pshipOldParent = m_pshipParent;
if (pshipParent)
{
debugf("%s\n", pshipParent->GetName());
{
ShipLinkIGC* psl;
while (psl = m_shipsChildren.first()) {
debugf("%s <- %s \n", this->GetName(), psl->data()->GetName());
psl->data()->SetParentShip(NULL);
}
}
assert (m_shipsChildren.n() == 0);
assert (pshipParent->GetParentShip() == NULL);
if (pshipOldParent == NULL)
{
{
PartLinkIGC* l;
while (l = m_parts.first()) l->data()->Terminate();
}
m_fuel = 0.0f;
m_ammo = 0;
m_energy = 0.0f;
m_myHullType.SetHullType(NULL);
SetMass(0.0f);
HRESULT hr = Load(0, NULL, NULL, NULL, c_mtNotPickable);
ZSucceeded(hr);
SetVisibleF(false);
IclusterIGC* pcluster = GetCluster();
if (pcluster)
{
pcluster->GetClusterSite()->DeleteScanner(GetSide()->GetObjectID(), this);
}
assert (m_turretID == NA);
}
else
{
if (m_turretID != NA)
{
IweaponIGC* pw = (IweaponIGC*)(pshipOldParent->GetMountedPart(ET_Weapon, m_turretID));
if (pw)
pw->SetGunner(NULL);
m_turretID = NA;
}
pshipOldParent->DeleteChildShip(this);
pshipOldParent->Release();
}
pshipParent->AddRef();
m_pshipParent = pshipParent;
pshipParent->AddChildShip(this);
if (pshipOldParent)
GetMyMission()->GetIgcSite()->LoadoutChangeEvent(pshipOldParent, NULL, c_lcRemovePassenger);
GetMyMission()->GetIgcSite()->LoadoutChangeEvent(pshipParent, NULL, c_lcAddPassenger);
GetMyMission()->GetIgcSite()->LoadoutChangeEvent(this, NULL, c_lcTurretChange);
}
else
{
debugf("NULL\n");
assert (pshipOldParent != NULL);
if (m_turretID != NA)
{
IweaponIGC* pw = (IweaponIGC*)(pshipOldParent->GetMountedPart(ET_Weapon, m_turretID));
if (pw)
pw->SetGunner(NULL);
m_turretID = NA;
}
pshipOldParent->DeleteChildShip(this);
pshipOldParent->Release();
m_pshipParent = NULL;
IclusterIGC* pcluster = GetCluster();
if (pcluster)
{
pcluster->GetClusterSite()->AddScanner(GetSide()->GetObjectID(), this);
}
GetMyMission()->GetIgcSite()->LoadoutChangeEvent(pshipOldParent, NULL, c_lcRemovePassenger);
GetMyMission()->GetIgcSite()->LoadoutChangeEvent(this, NULL, c_lcDisembark);
}
}
}
struct ShipPair
{
IshipIGC* pship;
IclusterIGC* pcluster;
};
typedef Slist_utl<ShipPair> ShipPairList;
typedef Slink_utl<ShipPair> ShipPairLink;
ImodelIGC* CshipIGC::FindRipcordModel(IclusterIGC* pcluster)
{
IsideIGC* pside = GetSide();
IIgcSite* pigc = GetMyMission()->GetIgcSite();
ShipPairList pairs;
if (m_pilotType >= c_ptPlayer)
{
HullAbilityBitMask habm = m_myHullType.HasCapability(c_habmCanLtRipcord)
? (c_habmIsRipcordTarget | c_habmIsLtRipcordTarget)
: c_habmIsRipcordTarget;
for (ShipLinkIGC* psl = pside->GetShips()->first(); (psl != NULL); psl = psl->next())
{
IshipIGC* pship = psl->data();
if (pship != GetSourceShip())
{
IclusterIGC* pc = pigc->GetRipcordCluster(pship, habm);
if (pc)
{
ShipPairLink* spl = new ShipPairLink;
spl->data().pship = pship;
spl->data().pcluster = pc;
pairs.last(spl);
}
}
}
}
const Vector* positionGoal = NULL;
{
ImodelIGC* pmodelGoal = m_commandTargets[c_cmdCurrent];
if (!pmodelGoal)
pmodelGoal = m_commandTargets[c_cmdAccepted];
if (pmodelGoal)
{
if (pmodelGoal->SeenBySide(pside) &&
(pigc->GetCluster(this, pmodelGoal) == pcluster))
{
positionGoal = &(pmodelGoal->GetPosition());
}
}
}
WarpListIGC warps;
ClusterListIGC clustersVisited;
float ripcordSpeed = m_myHullType.GetRipcordSpeed();
while (true)
{
assert (pcluster);
ImodelIGC* pmodelRipcord = FindTarget(this, positionGoal ? (c_ttFriendly | c_ttStation | c_ttNearest) : (c_ttFriendly | c_ttStation),
NULL, pcluster, positionGoal, NULL,
c_sabmRipcord);
if ((pmodelRipcord == NULL) && (m_pilotType >= c_ptPlayer))
{
float d2Goal = FLT_MAX;
{
for (ProbeLinkIGC* ppl = pcluster->GetProbes()->last(); (ppl != NULL); ppl = ppl->txen())
{
IprobeIGC* pprobe = ppl->data();
if ((pprobe->GetSide() == pside) && pprobe->GetCanRipcord(ripcordSpeed))
{
if (positionGoal)
{
float d2 = (pprobe->GetPosition() - *positionGoal).LengthSquared();
if (d2 < d2Goal)
{
pmodelRipcord = pprobe;
d2Goal = d2;
}
}
else
{
pmodelRipcord = pprobe;
break;
}
}
}
}
if (pmodelRipcord == NULL)
{
float debtMin = FLT_MAX;
for (ShipPairLink* psl = pairs.first(); (psl != NULL); psl = psl->next())
{
if (psl->data().pcluster == pcluster)
{
float debt = psl->data().pship->GetRipcordDebt();
if (positionGoal == NULL)
{
if (debt < debtMin)
{
debtMin = debt;
pmodelRipcord = psl->data().pship;
}
}
else
{
float d2 = (psl->data().pship->GetPosition() - *positionGoal).LengthSquared();
if ((debt < debtMin) ||
((debt == debtMin) && (d2 < d2Goal)))
{
debtMin = debt;
d2Goal = d2;
pmodelRipcord = psl->data().pship;
}
}
}
}
}
}
if (pmodelRipcord)
return pmodelRipcord;
clustersVisited.first(pcluster);
{
for (WarpLinkIGC* l = pcluster->GetWarps()->first(); (l != NULL); l = l->next())
{
IwarpIGC* w = l->data();
if (CanSee(w))
{
IwarpIGC* pwarpDestination = w->GetDestination();
if (pwarpDestination)
{
IclusterIGC* pclusterOther = pwarpDestination->GetCluster();
if (clustersVisited.find(pclusterOther) == NULL)
{
warps.last(pwarpDestination);
}
}
}
}
}
WarpLinkIGC* plink = warps.first();
if (plink == NULL)
return NULL;
IwarpIGC* pwarp = plink->data();
delete plink;
pcluster = pwarp->GetCluster();
positionGoal = &(pwarp->GetPosition());
}
}
void CshipIGC::SetAutopilot(bool bAutopilot)
{
m_bAutopilot = bAutopilot;
if (bAutopilot)
SetCommand(c_cmdPlan, m_commandTargets[c_cmdCurrent], m_commandIDs[c_cmdCurrent]);
else
SetCommand(c_cmdPlan, NULL, c_cidNone);
}
void CshipIGC::ResetWaypoint(void)
{
m_pclusterRequestRipcord = NULL;
if (GetCluster() != NULL)
{
if (m_commandTargets[c_cmdPlan])
{
Waypoint::Objective o;
switch (m_commandTargets[c_cmdPlan]->GetObjectType())
{
case OT_ship:
{
o = (m_commandIDs[c_cmdPlan] == c_cidPickup)
? Waypoint::c_oEnter
: Waypoint::c_oGoto;
}
break;
case OT_asteroid:
{
o = (m_commandIDs[c_cmdPlan] == c_cidBuild) && (m_pilotType == c_ptBuilder)
? Waypoint::c_oEnter
: Waypoint::c_oGoto;
}
break;
case OT_station:
{
o = Waypoint::c_oGoto;
if (m_myHullType.GetHullType())
{
if ((m_commandIDs[c_cmdPlan] == c_cidGoto) || (m_commandIDs[c_cmdPlan] == c_cidNone))
{
if (m_commandTargets[c_cmdPlan]->GetSide() == GetSide())
{
const IstationTypeIGC* pst = ((IstationIGC*)m_commandTargets[c_cmdPlan])->GetStationType();
HullAbilityBitMask habm = m_myHullType.GetCapabilities();
if ((habm & c_habmFighter) == 0)
{
if (pst->HasCapability(c_sabmCapLand))
o = Waypoint::c_oEnter;
}
else if (habm & c_habmLifepod)
{
if (pst->HasCapability(c_sabmLand | c_sabmRescue))
o = Waypoint::c_oEnter;
}
else if (pst->HasCapability(c_sabmLand))
o = Waypoint::c_oEnter;
}
}
}
}
break;
case OT_warp:
{
if ((m_commandIDs[c_cmdPlan] == c_cidBuild) && (m_pilotType == c_ptLayer))
{
DataBuoyIGC db;
const Vector& p = m_commandTargets[c_cmdPlan]->GetPosition();
const Orientation& orientation = m_commandTargets[c_cmdPlan]->GetOrientation();
IexpendableTypeIGC* pet = (IexpendableTypeIGC*)(IbaseIGC*)m_pbaseData;
assert (pet);
if (pet->GetObjectType() == OT_mineType)
{
DataMineTypeIGC* pdmt = (DataMineTypeIGC*)(pet->GetData());
db.position = p -
orientation.GetBackward() *
pdmt->radius;
}
else
{
assert (pet->GetObjectType() == OT_probeType);
IprobeTypeIGC* ppt = (IprobeTypeIGC*)pet;
float rMajor;
IprojectileTypeIGC* pprojectile = ppt->GetProjectileType();
if (ppt)
rMajor = pprojectile->GetLifespan() * pprojectile->GetSpeed() * 0.5f;
else
rMajor = ppt->GetScannerRange() * 0.4f;
db.position = p -
(orientation.GetBackward() *
rMajor) +
Vector::RandomPosition(rMajor / 3.0f);
}
db.clusterID = m_commandTargets[c_cmdPlan]->GetCluster()->GetObjectID();
db.type = c_buoyWaypoint;
IbuoyIGC* b = (IbuoyIGC*)(GetMission()->CreateObject(GetMyLastUpdate(), OT_buoy, &db, sizeof(db)));
assert (b);
SetCommand(c_cmdPlan, b, c_cidBuild);
b->Release();
return; }
else
o = ((m_commandIDs[c_cmdPlan] == c_cidGoto) || (m_commandIDs[c_cmdPlan] == c_cidPickup) || (m_commandIDs[c_cmdPlan] == c_cidNone))
? Waypoint::c_oEnter
: Waypoint::c_oGoto;
}
break;
case OT_treasure:
{
o = ((m_commandIDs[c_cmdPlan] == c_cidGoto) || (m_commandIDs[c_cmdPlan] == c_cidPickup) || (m_commandIDs[c_cmdPlan] == c_cidNone))
? Waypoint::c_oEnter
: Waypoint::c_oGoto;
}
break;
case OT_probe:
{
o = Waypoint::c_oGoto;
if (((m_commandIDs[c_cmdPlan] == c_cidGoto) || (m_commandIDs[c_cmdPlan] == c_cidNone)) &&
m_myHullType.GetHullType() && m_myHullType.HasCapability(c_habmLifepod))
{
IprobeTypeIGC* ppt = ((IprobeIGC*)(m_commandTargets[c_cmdPlan]))->GetProbeType();
ExpendableAbilityBitMask eabm = ppt->GetCapabilities();
if ((eabm & c_eabmRescueAny) ||
((eabm & c_eabmRescue) && (m_commandTargets[c_cmdPlan]->GetSide() == GetSide())))
{
o = Waypoint::c_oEnter;
}
}
}
break;
default:
o = Waypoint::c_oGoto;
}
m_gotoplan.Set(o, m_commandTargets[c_cmdPlan]);
if (m_bAutopilot)
{
IIgcSite* pigc = GetMyMission()->GetIgcSite();
IclusterIGC* pclusterTarget = pigc->GetCluster(this, m_commandTargets[c_cmdPlan]);
if (pclusterTarget && bShouldUseRipcord(pclusterTarget))
{
if (IsSafeToRipcord())
pigc->RequestRipcord(this, pclusterTarget);
else
{
m_pclusterRequestRipcord = pclusterTarget;
m_timeRequestRipcord = GetMyLastUpdate() + 5.0f;
}
}
else if (m_pmodelRipcord)
pigc->RequestRipcord(this, NULL);
}
}
else
{
m_gotoplan.Reset();
if (m_pmodelRipcord)
GetMyMission()->GetIgcSite()->RequestRipcord(this, NULL);
}
}
else
{
if (m_commandTargets[c_cmdPlan] == NULL)
m_gotoplan.Reset();
}
}
bool CshipIGC::IsSafeToRipcord(void)
{
float speed2 = GetVelocity().LengthSquared();
if (speed2 < 1.0f)
return true;
float tRipcord = m_myHullType.GetRipcordSpeed();
float v0 = float(sqrt(speed2));
float vMax = m_myHullType.GetMaxSpeed();
float thrust = m_myHullType.GetThrust();
float mass = GetMass();
float k = thrust / (vMax * mass);
float s = v0 * float(1.0 - exp(-k * tRipcord)) / k;
int state = 0;
Dodge(this, NULL, &state, false, 1.0f + s / v0); return (state == 0);
}
bool CshipIGC::bShouldUseRipcord(IclusterIGC* pcluster)
{
if ((m_myHullType.GetHullType() == NULL) || m_myHullType.HasCapability(c_habmNoRipcord))
return false;
IclusterIGC* pclusterShip = GetCluster();
if (pcluster == pclusterShip)
return NULL;
int dShip = GetDistance(this, pcluster, pclusterShip);
IsideIGC* pside = GetSide();
ClusterListIGC shipRipcords;
if (m_pilotType >= c_ptPlayer)
{
IIgcSite* pigc = GetMyMission()->GetIgcSite();
HullAbilityBitMask habm = m_myHullType.HasCapability(c_habmCanLtRipcord)
? (c_habmIsRipcordTarget | c_habmIsLtRipcordTarget)
: c_habmIsRipcordTarget;
for (ShipLinkIGC* psl = pside->GetShips()->first(); (psl != NULL); psl = psl->next())
{
IshipIGC* ps = psl->data();
if (ps != this)
{
IclusterIGC* pc = pigc->GetRipcordCluster(ps, habm);
if (pc)
{
if (pcluster == pc)
return true;
if (shipRipcords.find(pc) == NULL)
shipRipcords.last(pc);
}
}
}
}
WarpListIGC warpsOne;
WarpListIGC warpsTwo;
ClusterListIGC clustersVisited;
WarpListIGC* pwlOneAway = &warpsOne;
WarpListIGC* pwlTwoAway = &warpsTwo;
float ripcordSpeed = m_myHullType.GetRipcordSpeed();
while (true)
{
assert (pcluster);
ImodelIGC* pmodelRipcord = FindTarget(this, c_ttFriendly | c_ttStation,
NULL, pcluster, NULL, NULL,
c_sabmRipcord);
if (pmodelRipcord)
return true;
if (m_pilotType >= c_ptPlayer)
{
if (shipRipcords.find(pcluster))
return true;
for (ProbeLinkIGC* ppl = pcluster->GetProbes()->first(); (ppl != NULL); ppl = ppl->next())
{
IprobeIGC* pprobe = ppl->data();
if ((pprobe->GetSide() == pside) && pprobe->GetCanRipcord(ripcordSpeed))
return true;
}
}
clustersVisited.first(pcluster);
{
for (WarpLinkIGC* l = pcluster->GetWarps()->first(); (l != NULL); l = l->next())
{
IwarpIGC* w = l->data();
if (CanSee(w))
{
IwarpIGC* pwarpDestination = w->GetDestination();
if (pwarpDestination)
{
IclusterIGC* pclusterOther = pwarpDestination->GetCluster();
if (clustersVisited.find(pclusterOther) == NULL)
{
pwlTwoAway->last(pwarpDestination);
}
}
}
}
}
if (pwlOneAway->n() == 0)
{
if ((pwlTwoAway->n() == 0) || (dShip-- <= 1))
return false; WarpListIGC* pwl = pwlOneAway;
pwlOneAway = pwlTwoAway;
pwlTwoAway = pwl;
}
assert (pwlOneAway->n() > 0);
WarpLinkIGC* plink = pwlOneAway->first();
IwarpIGC* pwarp = plink->data();
delete plink;
pcluster = pwarp->GetCluster();
}
}
bool CshipIGC::InGarage(IshipIGC* pship, float tCollision) const
{
bool bInside = false;
int i = m_myHullType.GetHullType()->GetLandSlots() - 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 = (pship->GetPosition() - GetPosition()) +
(pship->GetVelocity() - GetVelocity()) * tCollision;
do
{
int j = m_myHullType.GetHullType()->GetLandPlanes(i) - 1;
assert (j >= 0);
do
{
Vector direction = m_myHullType.GetHullType()->GetLandDirection(i, j) * orientationStation;
Vector point = m_myHullType.GetHullType()->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)
{
bInside = true;
break;
}
}
while (i-- > 0);
}
return bInside;
}
HRESULT MyHullType::Initialize(ImissionIGC* pMission, Time now, const void* data, int length)
{
assert (false);
return E_FAIL;
}
void MyHullType::Terminate(void)
{
assert (false);
}
void MyHullType::Update(Time now)
{
assert (false);
}
ObjectType MyHullType::GetObjectType(void) const
{
return OT_hullType;
}
ObjectID MyHullType::GetObjectID(void) const
{
return m_pHullData ? m_pHullData->hullID : NA;
}
const void* MyHullType::GetData(void) const
{
return m_pHullData;
}
const char* MyHullType::GetModelName(void) const
{
return m_pHullData->modelName;
}
const char* MyHullType::GetName(void) const
{
return m_pHullData->name;
}
const char* MyHullType::GetDescription(void) const
{
return m_pHullData->description;
}
Money MyHullType::GetPrice(void) const
{
return m_pHullData->price;
}
DWORD MyHullType::GetTimeToBuild(void) const
{
return m_pHullData->timeToBuild;
}
BuyableGroupID MyHullType::GetGroupID(void) const
{
return m_pHullData->groupID;
}
const TechTreeBitMask& MyHullType::GetRequiredTechs(void) const
{
return m_pHullData->ttbmRequired;
}
const TechTreeBitMask& MyHullType::GetEffectTechs(void) const
{
return m_pHullData->ttbmEffects;
}
float MyHullType::GetMass(void) const
{
return m_pHullData->mass;
}
float MyHullType::GetSignature(void) const
{
return m_pHullData->signature;
}
float MyHullType::GetLength(void) const
{
return (float)(m_pHullData->length);
}
float MyHullType::GetMaxSpeed(void) const
{
return m_pHullData->speed * m_pship->GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaMaxSpeed);
}
float MyHullType::GetMaxTurnRate(Axis axis) const
{
assert (axis >= 0);
assert (axis <= 3);
return m_pHullData->maxTurnRates[axis] * m_pship->GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaTurnRate);
}
float MyHullType::GetTurnTorque(Axis axis) const
{
assert (axis >= 0);
assert (axis <= 3);
return m_pHullData->turnTorques[axis] * m_pship->GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaTurnTorque);
}
float MyHullType::GetThrust(void) const
{
return m_pHullData->thrust * m_pship->GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaThrust);
}
float MyHullType::GetSideMultiplier(void) const
{
return m_pHullData->sideMultiplier;
}
float MyHullType::GetBackMultiplier(void) const
{
return m_pHullData->backMultiplier;
}
float MyHullType::GetScannerRange(void) const
{
return m_pHullData->scannerRange * m_pship->GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaScanRange);
}
float MyHullType::GetMaxEnergy(void) const
{
return m_pHullData->maxEnergy * m_pship->GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaMaxEnergy);
}
float MyHullType::GetRechargeRate(void) const
{
return m_pHullData->rechargeRate;
}
HitPoints MyHullType::GetHitPoints(void) const
{
return (HitPoints)(m_pHullData->hitPoints * m_pship->GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaMaxArmorShip));
}
DefenseTypeID MyHullType::GetDefenseType(void) const
{
return m_pHullData->defenseType;
}
PartMask MyHullType::GetPartMask(EquipmentType et, Mount mountID) const
{
assert (m_pHullType);
return m_pHullType->GetPartMask(et, mountID);
}
short MyHullType::GetCapacity(EquipmentType et) const
{
assert (m_pHullType);
return m_pHullType->GetCapacity(et);
}
Mount MyHullType::GetMaxWeapons(void) const
{
return m_pHullData->maxWeapons;
}
Mount MyHullType::GetMaxFixedWeapons(void) const
{
return m_pHullData->maxFixedWeapons;
}
const HardpointData& MyHullType::GetHardpointData(Mount hardpointID) const
{
assert ((hardpointID >= 0) && (hardpointID < m_pHullData->maxWeapons));
return ((HardpointData*)(((char*)m_pHullData) + m_pHullData->hardpointOffset))[hardpointID];
}
const char* MyHullType::GetTextureName(void) const
{
return m_pHullData->textureName;
}
const char* MyHullType::GetIconName(void) const
{
return m_pHullData->iconName;
}
HullAbilityBitMask MyHullType::GetCapabilities(void) const
{
return m_pHullData->habmCapabilities;
}
bool MyHullType::HasCapability(HullAbilityBitMask habm) const
{
return (m_pHullData->habmCapabilities & habm) != 0;
}
const Vector& MyHullType::GetCockpit(void) const
{
assert (m_pHullType);
return m_pHullType->GetCockpit();
}
const Vector& MyHullType::GetWeaponPosition(Mount mount) const
{
assert (m_pHullType);
return m_pHullType->GetWeaponPosition(mount);
}
const Orientation& MyHullType::GetWeaponOrientation(Mount mount) const
{
assert (m_pHullType);
return m_pHullType->GetWeaponOrientation(mount);
}
float MyHullType::GetScale() const
{
return m_pHullType->GetScale();
}
float MyHullType::GetMaxFuel(void) const
{
return m_pHullData->maxFuel;
}
float MyHullType::GetECM(void) const
{
return m_pHullData->ecm;
}
float MyHullType::GetRipcordSpeed(void) const
{
return m_pHullData->ripcordSpeed / m_pship->GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaRipcordTime);
}
float MyHullType::GetRipcordCost(void) const
{
return m_pHullData->ripcordCost;
}
short MyHullType::GetMaxAmmo(void) const
{
return m_pHullData->maxAmmo;
}
bool MyHullType::CanMount(IpartTypeIGC* ppt, Mount mountID) const
{
assert (m_pHullType);
return m_pHullType->CanMount(ppt, mountID);
}
IhullTypeIGC* MyHullType::GetSuccessorHullType(void) const
{
assert (m_pHullType);
return m_pHullType->GetSuccessorHullType();
}
SoundID MyHullType::GetInteriorSound(void) const
{
return m_pHullData->interiorSound;
}
SoundID MyHullType::GetExteriorSound(void) const
{
return m_pHullData->exteriorSound;
}
SoundID MyHullType::GetMainThrusterInteriorSound(void) const
{
return m_pHullData->mainThrusterInteriorSound;
}
SoundID MyHullType::GetMainThrusterExteriorSound(void) const
{
return m_pHullData->mainThrusterExteriorSound;
}
SoundID MyHullType::GetManuveringThrusterInteriorSound(void) const
{
return m_pHullData->manuveringThrusterInteriorSound;
}
SoundID MyHullType::GetManuveringThrusterExteriorSound(void) const
{
return m_pHullData->manuveringThrusterExteriorSound;
}
const PartTypeListIGC* MyHullType::GetPreferredPartTypes(void) const
{
return m_pHullType->GetPreferredPartTypes();
}
IObject* MyHullType::GetIcon(void) const
{
return m_pHullType->GetIcon();
}
int MyHullType::GetLaunchSlots(void) const
{
return m_pHullType->GetLaunchSlots();
}
const Vector& MyHullType::GetLaunchPosition(int slotID) const
{
return m_pHullType->GetLaunchPosition(slotID);
}
const Vector& MyHullType::GetLaunchDirection(int slotID) const
{
return m_pHullType->GetLaunchDirection(slotID);
}
int MyHullType::GetLandSlots(void) const
{
return m_pHullType->GetLandSlots();
}
int MyHullType::GetLandPlanes(int slotID) const
{
return m_pHullType->GetLandPlanes(slotID);
}
const Vector& MyHullType::GetLandPosition(int slotID, int planeID) const
{
return m_pHullType->GetLandPosition(slotID, planeID);
}
const Vector& MyHullType::GetLandDirection(int slotID, int planeID) const
{
return m_pHullType->GetLandDirection(slotID, planeID);
}