//====================================================================== // // ShipObject_Components.cpp // copyright (c) 2004 Sony Online Entertainment // //====================================================================== #include "serverGame/FirstServerGame.h" #include "serverGame/ShipObject_Components.h" #include "UnicodeUtils.h" #include "serverGame/Chat.h" #include "serverGame/ContainerInterface.h" #include "serverGame/CreatureObject.h" #include "serverGame/MissileManager.h" #include "serverGame/PlayerObject.h" #include "serverGame/ResourceTypeObject.h" #include "serverGame/ServerObjectTemplate.h" #include "serverGame/ServerResourceClassObject.h" #include "serverGame/ServerUniverse.h" #include "serverGame/ServerWorld.h" #include "serverGame/ShipComponentDataEngine.h" #include "serverGame/ShipComponentDataManager.h" #include "serverScript/GameScriptObject.h" #include "serverScript/ScriptFunctionTable.h" #include "serverScript/ScriptParameters.h" #include "sharedFoundation/ConstCharCrcLowerString.h" #include "sharedFoundation/ConstCharCrcString.h" #include "sharedFoundation/Timer.h" #include "sharedGame/SharedStringIds.h" #include "sharedGame/ShipChassis.h" #include "sharedGame/ShipChassisSlot.h" #include "sharedGame/ShipChassisSlotType.h" #include "sharedGame/ShipComponentAttachmentManager.h" #include "sharedGame/ShipComponentData.h" #include "sharedGame/ShipComponentDescriptor.h" #include "sharedGame/ShipComponentFlags.h" #include "sharedGame/ShipComponentWeaponManager.h" #include "sharedGame/ShipTurretManager.h" #include "sharedLog/Log.h" #include "sharedObject/Appearance.h" #include "sharedObject/AppearanceTemplate.h" #include "sharedObject/AppearanceTemplateList.h" #include "sharedObject/Hardpoint.h" #include "sharedObject/NetworkIdManager.h" #include "sharedObject/ObjectTemplateList.h" #include "sharedObject/PortalProperty.h" #include "sharedObject/PortalPropertyTemplate.h" #include "sharedObject/VolumeContainer.h" // ====================================================================== namespace ShipObjectNamespace { ConstCharCrcString const s_turretPitchHardpoint("turretpitch1"); } using namespace ShipObjectNamespace; // ====================================================================== uint32 ShipObject::getChassisType () const { return m_chassisType.get (); } //---------------------------------------------------------------------- /** * Returns [0.0, 1.0] relating to the hitpoints of the chassis and all installed components * 1.0 == pristine, 0.0 == totally broken (though there are other rules to determine if a ship is flyable) */ float ShipObject::getOverallHealth() const { float total = 0.0f; int numComponents = 0; if(getMaximumChassisHitPoints() > 0.0) { total += getCurrentChassisHitPoints() / getMaximumChassisHitPoints(); ++numComponents; } for(int i = ShipChassisSlotType::SCST_first; i != ShipChassisSlotType::SCST_num_types; ++i) { if(isSlotInstalled(i)) { if(getComponentHitpointsMaximum(i) > 0.0f) { total += getComponentHitpointsCurrent(i) / getComponentHitpointsMaximum(i); ++numComponents; } } } if(numComponents <= 0) return 0.0f; else return clamp(0.0f, total / numComponents, 1.0f); } //---------------------------------------------------------------------- float ShipObject::getOverallHealthWithShieldsAndArmor() const { int numberObjectsToWeight = 0; float total = getOverallHealth(); ++numberObjectsToWeight; float const shieldHitpointsFrontMaximum = getShieldHitpointsFrontMaximum(); if (shieldHitpointsFrontMaximum != 0.0) { total += getShieldHitpointsFrontCurrent() / shieldHitpointsFrontMaximum; ++numberObjectsToWeight; } float const shieldHitpointsBackMaximum = getShieldHitpointsBackMaximum(); if (shieldHitpointsBackMaximum != 0.0) { total += getShieldHitpointsBackCurrent() / shieldHitpointsBackMaximum; ++numberObjectsToWeight; } float const componentArmorHitpointsMaximum0 = getComponentArmorHitpointsMaximum(ShipChassisSlotType::SCST_armor_0); if (componentArmorHitpointsMaximum0 != 0.0) { total += getComponentArmorHitpointsCurrent(ShipChassisSlotType::SCST_armor_0) / componentArmorHitpointsMaximum0; ++numberObjectsToWeight; } float const componentArmorHitpointsMaximum1 = getComponentArmorHitpointsMaximum(ShipChassisSlotType::SCST_armor_1); if (componentArmorHitpointsMaximum1 != 0.0) { total += getComponentArmorHitpointsCurrent(ShipChassisSlotType::SCST_armor_1) / componentArmorHitpointsMaximum1; ++numberObjectsToWeight; } return clamp(0.0f, total / static_cast(numberObjectsToWeight), 1.0f); } //---------------------------------------------------------------------- float ShipObject::getComponentArmorHitpointsMaximum (int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_componentArmorHitpointsMaximum.find (chassisSlot); if (it != m_componentArmorHitpointsMaximum.end ()) return (*it).second; return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getComponentArmorHitpointsCurrent (int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_componentArmorHitpointsCurrent.find (chassisSlot); if (it != m_componentArmorHitpointsCurrent.end ()) return (*it).second; return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getComponentEfficiencyGeneral (int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_componentEfficiencyGeneral.find (chassisSlot); if (it != m_componentEfficiencyGeneral.end ()) return (*it).second; return 1.0f; } //---------------------------------------------------------------------- float ShipObject::getComponentEfficiencyEnergy (int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_componentEfficiencyEnergy.find (chassisSlot); if (it != m_componentEfficiencyEnergy.end ()) return (*it).second; return 1.0f; } //---------------------------------------------------------------------- float ShipObject::getComponentEnergyMaintenanceRequirement (int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_componentEnergyMaintenanceRequirement.find (chassisSlot); if (it != m_componentEnergyMaintenanceRequirement.end ()) return (*it).second; return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getComponentMass (int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_componentMass.find (chassisSlot); if (it != m_componentMass.end ()) return (*it).second; return 0.0f; } //---------------------------------------------------------------------- uint32 ShipObject::getComponentCrc (int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_componentCrc.find (chassisSlot); if (it != m_componentCrc.end ()) return (*it).second; return 0; } //---------------------------------------------------------------------- float ShipObject::getComponentHitpointsCurrent (int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_componentHitpointsCurrent.find (chassisSlot); if (it != m_componentHitpointsCurrent.end ()) return (*it).second; return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getComponentHitpointsMaximum (int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_componentHitpointsMaximum.find (chassisSlot); if (it != m_componentHitpointsMaximum.end ()) return (*it).second; return 0.0f; } //---------------------------------------------------------------------- int ShipObject::getComponentFlags (int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_componentFlags.find (chassisSlot); if (it != m_componentFlags.end ()) return (*it).second; return 0; } //---------------------------------------------------------------------- Unicode::String const &ShipObject::getComponentName(int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_componentNames.find (chassisSlot); if (it != m_componentNames.end() && !(*it).second.empty()) return (*it).second; return Unicode::emptyString; } //---------------------------------------------------------------------- NetworkId const &ShipObject::getComponentCreator(int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_componentCreators.find (chassisSlot); if (it != m_componentCreators.end()) return (*it).second; return NetworkId::cms_invalid; } //---------------------------------------------------------------------- float ShipObject::getWeaponDamageMaximum (int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_weaponDamageMaximum.find (chassisSlot); if (it != m_weaponDamageMaximum.end ()) return (*it).second; return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getWeaponDamageMinimum (int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_weaponDamageMinimum.find (chassisSlot); if (it != m_weaponDamageMinimum.end ()) return (*it).second; return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getWeaponEffectivenessShields (int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_weaponEffectivenessShields.find (chassisSlot); if (it != m_weaponEffectivenessShields.end ()) return (*it).second; return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getWeaponEffectivenessArmor (int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_weaponEffectivenessArmor.find (chassisSlot); if (it != m_weaponEffectivenessArmor.end ()) return (*it).second; return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getWeaponEnergyPerShot (int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_weaponEnergyPerShot.find (chassisSlot); if (it != m_weaponEnergyPerShot.end ()) return (*it).second; return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getWeaponActualEnergyPerShot(int chassisSlot) const { float const weaponEfficiencyEnergy = std::max(0.1f, getComponentEfficiencyEnergy(chassisSlot)); return getWeaponEnergyPerShot(chassisSlot) / weaponEfficiencyEnergy; } //---------------------------------------------------------------------- float ShipObject::getWeaponRefireRate (int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_weaponRefireRate.find (chassisSlot); if (it != m_weaponRefireRate.end ()) return (*it).second; return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getWeaponActualRefireRate (int chassisSlot) const { if (!isSlotInstalled(chassisSlot)) return 0.0f; float const eff = clamp(0.1f, getWeaponEfficiencyRefireRate(chassisSlot), 10.0f); return getWeaponRefireRate(chassisSlot) / eff; } //---------------------------------------------------------------------- float ShipObject::getWeaponEfficiencyRefireRate (int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_weaponEfficiencyRefireRate.find (chassisSlot); if (it != m_weaponEfficiencyRefireRate.end ()) return (*it).second; return 1.0f; } //---------------------------------------------------------------------- int ShipObject::getWeaponAmmoCurrent(int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_weaponAmmoCurrent.find (chassisSlot); if (it != m_weaponAmmoCurrent.end ()) return (*it).second; return 0; } //---------------------------------------------------------------------- int ShipObject::getWeaponAmmoMaximum(int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_weaponAmmoMaximum.find (chassisSlot); if (it != m_weaponAmmoMaximum.end ()) return (*it).second; return 0; } //---------------------------------------------------------------------- uint32 ShipObject::getWeaponAmmoType(int chassisSlot) const { Archive::AutoDeltaMap::const_iterator const it = m_weaponAmmoType.find (chassisSlot); if (it != m_weaponAmmoType.end ()) return (*it).second; return 0; } //---------------------------------------------------------------------- float ShipObject::getShieldHitpointsFrontCurrent () const { if (isSlotInstalled (ShipChassisSlotType::SCST_shield_0)) return m_shieldHitpointsFrontCurrent.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getShieldHitpointsFrontMaximum () const { if (isSlotInstalled (ShipChassisSlotType::SCST_shield_0)) return m_shieldHitpointsFrontMaximum.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getShieldHitpointsBackCurrent () const { if (isSlotInstalled (ShipChassisSlotType::SCST_shield_0)) return m_shieldHitpointsBackCurrent.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getShieldHitpointsBackMaximum () const { if (isSlotInstalled (ShipChassisSlotType::SCST_shield_0)) return m_shieldHitpointsBackMaximum.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getShieldRechargeRate () const { if (isSlotInstalled (ShipChassisSlotType::SCST_shield_0)) return m_shieldRechargeRate.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getCapacitorEnergyCurrent () const { if (isSlotInstalled (ShipChassisSlotType::SCST_capacitor)) return m_capacitorEnergyCurrent.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getCapacitorEnergyMaximum () const { if (isSlotInstalled (ShipChassisSlotType::SCST_capacitor)) return m_capacitorEnergyMaximum.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getCapacitorEnergyEffectiveMaximum () const { if (isSlotInstalled (ShipChassisSlotType::SCST_capacitor) && isComponentFunctional(ShipChassisSlotType::SCST_capacitor)) return m_capacitorEnergyMaximum.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getCapacitorEnergyRechargeRate () const { if (isSlotInstalled (ShipChassisSlotType::SCST_capacitor)) return m_capacitorEnergyRechargeRate.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getEngineAccelerationRate () const { if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) return m_engineAccelerationRate.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getEngineDecelerationRate () const { if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) return m_engineDecelerationRate.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getEnginePitchAccelerationRate () const { if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) return m_enginePitchAccelerationRate.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getEngineYawAccelerationRate () const { if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) return m_engineYawAccelerationRate.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getEngineRollAccelerationRate () const { if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) return m_engineRollAccelerationRate.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getEnginePitchRateMaximum () const { if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) return m_enginePitchRateMaximum.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getEngineYawRateMaximum () const { if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) return m_engineYawRateMaximum.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getEngineRollRateMaximum () const { if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) return m_engineRollRateMaximum.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getEngineSpeedMaximum () const { if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) return m_engineSpeedMaximum.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getEngineSpeedRotationFactorMaximum() const { if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) return m_engineSpeedRotationFactorMaximum.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getEngineSpeedRotationFactorMinimum() const { if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) return m_engineSpeedRotationFactorMinimum.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getEngineSpeedRotationFactorOptimal() const { if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) return m_engineSpeedRotationFactorOptimal.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getReactorEnergyGenerationRate () const { if (isSlotInstalled (ShipChassisSlotType::SCST_reactor)) return m_reactorEnergyGenerationRate.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getBoosterEnergyCurrent () const { if (isSlotInstalled (ShipChassisSlotType::SCST_booster)) return m_boosterEnergyCurrent.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getBoosterEnergyMaximum () const { if (isSlotInstalled (ShipChassisSlotType::SCST_booster)) return m_boosterEnergyMaximum.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getBoosterEnergyRechargeRate () const { if (isSlotInstalled (ShipChassisSlotType::SCST_booster)) return m_boosterEnergyRechargeRate.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getBoosterEnergyConsumptionRate () const { if (isSlotInstalled (ShipChassisSlotType::SCST_booster)) return m_boosterEnergyConsumptionRate.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getBoosterAcceleration () const { if (isSlotInstalled (ShipChassisSlotType::SCST_booster)) return m_boosterAcceleration.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getBoosterSpeedMaximum () const { if (isSlotInstalled (ShipChassisSlotType::SCST_booster)) return m_boosterSpeedMaximum.get (); return 0.0f; } //---------------------------------------------------------------------- float ShipObject::getDroidInterfaceCommandSpeed () const { if (isSlotInstalled (ShipChassisSlotType::SCST_droid_interface)) return m_droidInterfaceCommandSpeed.get (); return 0.0f; } //---------------------------------------------------------------------- bool ShipObject::hasSlot (int chassisSlot) const { ShipChassis const * const shipChassis = ShipChassis::findShipChassisByCrc (getChassisType ()); return shipChassis && shipChassis->getSlot (static_cast(chassisSlot)); } //---------------------------------------------------------------------- bool ShipObject::setComponentArmorHitpointsMaximum (int chassisSlot, float componentArmorHitpointsMaximum) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentArmorHitpointsMaximum () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setComponentArmorHitpointsMaximum () called on slot [%d] with nothing installed.", chassisSlot)); return false; } m_componentArmorHitpointsMaximum.set (chassisSlot, componentArmorHitpointsMaximum); //-- force update of current hitpoints IGNORE_RETURN(setComponentArmorHitpointsCurrent (chassisSlot, getComponentArmorHitpointsCurrent (chassisSlot))); return true; } //---------------------------------------------------------------------- bool ShipObject::setComponentArmorHitpointsCurrent (int chassisSlot, float componentArmorHitpointsCurrent) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentArmorHitpointsCurrent () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setComponentArmorHitpointsCurrent () called on slot [%d] with nothing installed.", chassisSlot)); return false; } componentArmorHitpointsCurrent = std::min (getComponentArmorHitpointsMaximum (chassisSlot), componentArmorHitpointsCurrent); m_componentArmorHitpointsCurrent.set (chassisSlot, componentArmorHitpointsCurrent); return true; } //---------------------------------------------------------------------- bool ShipObject::setComponentEfficiencyGeneral (int chassisSlot, float componentEfficiencyGeneral) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentEfficiencyGeneral () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setComponentEfficiencyGeneral () called on slot [%d] with nothing installed.", chassisSlot)); return false; } componentEfficiencyGeneral = clamp (0.1f, componentEfficiencyGeneral, 10.0f); m_componentEfficiencyGeneral.set (chassisSlot, componentEfficiencyGeneral); return true; } //---------------------------------------------------------------------- bool ShipObject::setComponentEfficiencyEnergy (int chassisSlot, float componentEfficiencyEnergy) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentEfficiencyEnergy () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setComponentEfficiencyEnergy () called on slot [%d] with nothing installed.", chassisSlot)); return false; } componentEfficiencyEnergy = clamp (0.1f, componentEfficiencyEnergy, 10.0f); m_componentEfficiencyEnergy.set (chassisSlot, componentEfficiencyEnergy); return true; } //---------------------------------------------------------------------- bool ShipObject::setComponentEnergyMaintenanceRequirement (int chassisSlot, float componentEnergyMaintenanceRequirement) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentEnergyMaintenanceRequirement () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setComponentEnergyMaintenanceRequirement () called on slot [%d] with nothing installed.", chassisSlot)); return false; } m_componentEnergyMaintenanceRequirement.set (chassisSlot, componentEnergyMaintenanceRequirement); return true; } //---------------------------------------------------------------------- bool ShipObject::setComponentMass (int chassisSlot, float componentMass) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentMass () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setComponentMass () called on slot [%d] with nothing installed.", chassisSlot)); return false; } m_componentMass.set (chassisSlot, componentMass); internalSetChassisComponentMassCurrent(computeChassisComponentMassCurrent()); return true; } //---------------------------------------------------------------------- /** * Setting a component template crc to zero removes the component */ void ShipObject::setComponentCrc (int chassisSlot, uint32 componentCrc) { if (componentCrc == 0) { IGNORE_RETURN (m_componentArmorHitpointsMaximum.erase (chassisSlot)); IGNORE_RETURN (m_componentArmorHitpointsCurrent.erase (chassisSlot)); IGNORE_RETURN (m_componentEfficiencyGeneral.erase (chassisSlot)); IGNORE_RETURN (m_componentEfficiencyEnergy.erase (chassisSlot)); IGNORE_RETURN (m_componentEnergyMaintenanceRequirement.erase (chassisSlot)); IGNORE_RETURN (m_componentMass.erase (chassisSlot)); IGNORE_RETURN (m_componentCrc.erase (chassisSlot)); IGNORE_RETURN (m_componentCrcForClient.erase (chassisSlot)); IGNORE_RETURN (m_componentHitpointsCurrent.erase (chassisSlot)); IGNORE_RETURN (m_componentHitpointsMaximum.erase (chassisSlot)); IGNORE_RETURN (m_componentFlags.erase (chassisSlot)); IGNORE_RETURN (m_componentNames.erase (chassisSlot)); IGNORE_RETURN (m_weaponDamageMaximum.erase (chassisSlot)); IGNORE_RETURN (m_weaponDamageMinimum.erase (chassisSlot)); IGNORE_RETURN (m_weaponEffectivenessShields.erase (chassisSlot)); IGNORE_RETURN (m_weaponEffectivenessArmor.erase (chassisSlot)); IGNORE_RETURN (m_weaponEnergyPerShot.erase (chassisSlot)); IGNORE_RETURN (m_weaponRefireRate.erase (chassisSlot)); IGNORE_RETURN (m_componentCreators.erase (chassisSlot)); internalSetChassisComponentMassCurrent(computeChassisComponentMassCurrent()); } else { m_componentCrc.set (chassisSlot, componentCrc); m_componentCrcForClient.set (chassisSlot, componentCrc); //-- all components start out at low power so script gets the first power up pulse IGNORE_RETURN(setComponentLowPower (chassisSlot, true)); internalSetChassisComponentMassCurrent(computeChassisComponentMassCurrent()); } if (ShipChassisSlotType::isWeaponChassisSlot(static_cast(chassisSlot))) { // Cache the turret positions { int const weaponIndex = ShipChassisSlotType::getWeaponIndex(static_cast(chassisSlot)); if (ShipTurretManager::isTurret(getChassisType(), weaponIndex)) { m_turretWeaponIndices->setBit(weaponIndex); } else { m_turretWeaponIndices->clearBit(weaponIndex); } } // Cache for the fastest projectile weapon speed { m_fastestWeaponProjectileSpeed = 0.0f; for (int weaponIndex = 0; weaponIndex < ShipChassisSlotType::cms_numWeaponIndices; ++weaponIndex) { if (isProjectile(weaponIndex)) { m_fastestWeaponProjectileSpeed = std::max(m_fastestWeaponProjectileSpeed, getWeaponProjectileSpeed(weaponIndex)); } } } } } //---------------------------------------------------------------------- bool ShipObject::setComponentHitpointsCurrent (int chassisSlot, float componentHitpointsCurrent) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentHitpointsCurrent () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setComponentHitpointsCurrent () called on slot [%d] with nothing installed.", chassisSlot)); return false; } float const maxHp = getComponentHitpointsMaximum(chassisSlot); componentHitpointsCurrent = std::min (maxHp, componentHitpointsCurrent); m_componentHitpointsCurrent.set (chassisSlot, componentHitpointsCurrent); bool const isDemolished = isComponentDemolished(chassisSlot); if (componentHitpointsCurrent <= 0.0f && maxHp > 0.0f && !isDemolished) IGNORE_RETURN(setComponentDemolished(chassisSlot, true)); else if (isDemolished) IGNORE_RETURN(setComponentDemolished(chassisSlot, false)); return true; } //---------------------------------------------------------------------- bool ShipObject::setComponentHitpointsMaximum (int chassisSlot, float componentHitpointsMaximum) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentHitpointsMaximum () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setComponentHitpointsMaximum () called on slot [%d] with nothing installed.", chassisSlot)); return false; } m_componentHitpointsMaximum.set (chassisSlot, componentHitpointsMaximum); IGNORE_RETURN(setComponentHitpointsCurrent (chassisSlot, getComponentHitpointsCurrent (chassisSlot))); return true; } //---------------------------------------------------------------------- bool ShipObject::setComponentFlags (int chassisSlot, int componentFlags) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentFlags () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setComponentFlags () called on slot [%d] with nothing installed.", chassisSlot)); return false; } m_componentFlags.set (chassisSlot, componentFlags); return true; } //---------------------------------------------------------------------- bool ShipObject::setComponentName(int chassisSlot, Unicode::String const & componentName) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentName () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setComponentName () called on slot [%d] with nothing installed.", chassisSlot)); return false; } m_componentNames.set (chassisSlot, componentName); return true; } //---------------------------------------------------------------------- bool ShipObject::setComponentCreator(int chassisSlot, NetworkId const & componentCreator) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentName () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setComponentCreator () called on slot [%d] with nothing installed.", chassisSlot)); return false; } if (componentCreator != NetworkId::cms_invalid) m_componentCreators.set (chassisSlot, componentCreator); else m_componentCreators.erase(chassisSlot); return true; } //---------------------------------------------------------------------- bool ShipObject::setComponentDisabled (int chassisSlot, bool componentDisabled) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentDisabled () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setComponentDisabled () called on slot [%d] with nothing installed.", chassisSlot)); return false; } int const flags = getComponentFlags (chassisSlot); if (componentDisabled) { IGNORE_RETURN(setComponentFlags(chassisSlot, flags | static_cast(ShipComponentFlags::F_disabled))); IGNORE_RETURN(setComponentLowPower(chassisSlot, true)); IGNORE_RETURN(setComponentActive(chassisSlot, false)); } else { IGNORE_RETURN(setComponentFlags (chassisSlot, flags & ~static_cast(ShipComponentFlags::F_disabled))); IGNORE_RETURN(setComponentDisabledNeedsPower(chassisSlot, false)); } return true; } //---------------------------------------------------------------------- bool ShipObject::setComponentDisabledNeedsPower(int chassisSlot, bool componentDisabledNeedsPower) { FATAL(isInitialized() && !isAuthoritative(), ("ShipObject::setComponentDisabledNeedsPower() called on non-auth object.")); if (!isSlotInstalled(chassisSlot)) { WARNING(true, ("ShipObject::setComponentDisabledNeedsPower() called on slot [%d] with nothing installed.", chassisSlot)); return false; } int const flags = getComponentFlags(chassisSlot); if (componentDisabledNeedsPower) IGNORE_RETURN(setComponentFlags(chassisSlot, flags | static_cast(ShipComponentFlags::F_disabledNeedsPower))); else IGNORE_RETURN(setComponentFlags(chassisSlot, flags & ~static_cast(ShipComponentFlags::F_disabledNeedsPower))); return true; } //---------------------------------------------------------------------- bool ShipObject::setComponentLowPower (int chassisSlot, bool componentLowPower) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentLowPower () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setComponentLowPower () called on slot [%d] with nothing installed.", chassisSlot)); return false; } int const flags = getComponentFlags (chassisSlot); if (componentLowPower) IGNORE_RETURN(setComponentFlags (chassisSlot, flags | static_cast(ShipComponentFlags::F_lowPower))); else IGNORE_RETURN(setComponentFlags (chassisSlot, flags & ~static_cast(ShipComponentFlags::F_lowPower))); return true; } //---------------------------------------------------------------------- bool ShipObject::setComponentActive (int chassisSlot, bool componentActive) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentActive() called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setComponentActive() called on slot [%d] with nothing installed.", chassisSlot)); return false; } int const flags = getComponentFlags (chassisSlot); if (componentActive) IGNORE_RETURN(setComponentFlags (chassisSlot, flags | static_cast(ShipComponentFlags::F_active))); else IGNORE_RETURN(setComponentFlags (chassisSlot, flags & ~static_cast(ShipComponentFlags::F_active))); return true; } //---------------------------------------------------------------------- bool ShipObject::setComponentDemolished(int chassisSlot, bool const componentDemolished) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentDemolished() called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setComponentDemolished() called on slot [%d] with nothing installed.", chassisSlot)); return false; } int const flags = getComponentFlags (chassisSlot); if (componentDemolished) IGNORE_RETURN(setComponentFlags (chassisSlot, flags | static_cast(ShipComponentFlags::F_demolished))); else IGNORE_RETURN(setComponentFlags (chassisSlot, flags & ~static_cast(ShipComponentFlags::F_demolished))); return true; } //---------------------------------------------------------------------- bool ShipObject::setWeaponDamageMaximum (int chassisSlot, float weaponDamageMaximum) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponDamageMaximum () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setWeaponDamageMaximum () called on slot [%d] with nothing installed.", chassisSlot)); return false; } m_weaponDamageMaximum.set (chassisSlot, weaponDamageMaximum); return true; } //---------------------------------------------------------------------- bool ShipObject::setWeaponDamageMinimum (int chassisSlot, float weaponDamageMinimum) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponDamageMinimum () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setWeaponDamageMinimum () called on slot [%d] with nothing installed.", chassisSlot)); return false; } m_weaponDamageMinimum.set (chassisSlot, weaponDamageMinimum); return true; } //---------------------------------------------------------------------- bool ShipObject::setWeaponEffectivenessShields (int chassisSlot, float weaponEffectivenessShields) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponEffectivenessShields () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setWeaponEffectivenessShields () called on slot [%d] with nothing installed.", chassisSlot)); return false; } m_weaponEffectivenessShields.set (chassisSlot, weaponEffectivenessShields); return true; } //---------------------------------------------------------------------- bool ShipObject::setWeaponEffectivenessArmor (int chassisSlot, float weaponEffectivenessArmor) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponEffectivenessArmor () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setWeaponEffectivenessArmor () called on slot [%d] with nothing installed.", chassisSlot)); return false; } m_weaponEffectivenessArmor.set (chassisSlot, weaponEffectivenessArmor); return true; } //---------------------------------------------------------------------- bool ShipObject::setWeaponEnergyPerShot (int chassisSlot, float weaponEnergyPerShot) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponEnergyPerShot () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setWeaponEnergyPerShot () called on slot [%d] with nothing installed.", chassisSlot)); return false; } m_weaponEnergyPerShot.set (chassisSlot, weaponEnergyPerShot); return true; } //---------------------------------------------------------------------- bool ShipObject::setWeaponRefireRate (int chassisSlot, float weaponRefireRate) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponRefireRate () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setWeaponRefireRate () called on slot [%d] with nothing installed.", chassisSlot)); return false; } m_weaponRefireRate.set (chassisSlot, weaponRefireRate); return true; } //---------------------------------------------------------------------- bool ShipObject::setWeaponEfficiencyRefireRate (int chassisSlot, float weaponEfficiencyRefireRate) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponEfficiencyRefireRate () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setWeaponEfficiencyRefireRate () called on slot [%d] with nothing installed.", chassisSlot)); return false; } m_weaponEfficiencyRefireRate.set (chassisSlot, weaponEfficiencyRefireRate); return true; } // ---------------------------------------------------------------------- /** * Set a weapon's refire timer to have the specified percentage of its time * already elapsed. For example, 0.25 will prevent the weapon from firing * again until 75% of its regular refire time has elapsed. This setting * applies to the next shot only; future shots will use the regular refire rate. */ void ShipObject::setWeaponRefireTimerPercent(int weaponIndex, float refireTimerPercent) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponRefireTimerPercent () called on non-auth object.")); m_weaponRefireTimers[weaponIndex].setElapsedTime(refireTimerPercent * getWeaponActualRefireRate(static_cast(ShipChassisSlotType::SCST_weapon_first) + weaponIndex)); } //---------------------------------------------------------------------- bool ShipObject::setWeaponAmmoCurrent(int chassisSlot, int weaponAmmoCurrent) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponProjectileSpeed () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setWeaponAmmoCurrent () called on slot [%d] with nothing installed.", chassisSlot)); return false; } m_weaponAmmoCurrent.set (chassisSlot, weaponAmmoCurrent); return true; } //---------------------------------------------------------------------- bool ShipObject::setWeaponAmmoMaximum(int chassisSlot, int weaponAmmoMaximum) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponProjectileSpeed () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setWeaponAmmoMaximum () called on slot [%d] with nothing installed.", chassisSlot)); return false; } m_weaponAmmoMaximum.set (chassisSlot, weaponAmmoMaximum); return true; } //---------------------------------------------------------------------- bool ShipObject::setWeaponAmmoType(int chassisSlot, uint32 weaponAmmoType) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponProjectileSpeed () called on non-auth object.")); if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::setWeaponAmmoType () called on slot [%d] with nothing installed.", chassisSlot)); return false; } m_weaponAmmoType.set (chassisSlot, weaponAmmoType); return true; } //---------------------------------------------------------------------- bool ShipObject::setShieldHitpointsFrontCurrent (float shieldHitpointsCurrent) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setShieldHitpointsFrontCurrent () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_shield_0))) { WARNING (true, ("ShipObject::setShieldHitpointsFrontCurrent () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_shield_0))); return false; } shieldHitpointsCurrent = std::min (getShieldHitpointsFrontMaximum (), shieldHitpointsCurrent); m_shieldHitpointsFrontCurrent.set (shieldHitpointsCurrent); return true; } //---------------------------------------------------------------------- bool ShipObject::setShieldHitpointsFrontMaximum (float shieldHitpointsMaximum) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setShieldHitpointsFrontMaximum () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_shield_0))) { WARNING (true, ("ShipObject::setShieldHitpointsFrontMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_shield_0))); return false; } m_shieldHitpointsFrontMaximum.set (shieldHitpointsMaximum); IGNORE_RETURN(setShieldHitpointsFrontCurrent (getShieldHitpointsFrontCurrent ())); return true; } //---------------------------------------------------------------------- bool ShipObject::setShieldHitpointsBackCurrent (float shieldHitpointsCurrent) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setShieldHitpointsBackCurrent () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_shield_0))) { WARNING (true, ("ShipObject::setShieldHitpointsBackCurrent () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_shield_0))); return false; } shieldHitpointsCurrent = std::min (getShieldHitpointsBackMaximum (), shieldHitpointsCurrent); m_shieldHitpointsBackCurrent.set (shieldHitpointsCurrent); return true; } //---------------------------------------------------------------------- bool ShipObject::setShieldHitpointsBackMaximum (float shieldHitpointsMaximum) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setShieldHitpointsBackMaximum () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_shield_0))) { WARNING (true, ("ShipObject::setShieldHitpointsBackMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_shield_0))); return false; } m_shieldHitpointsBackMaximum.set (shieldHitpointsMaximum); IGNORE_RETURN(setShieldHitpointsBackCurrent (getShieldHitpointsBackCurrent ())); return true; } //---------------------------------------------------------------------- bool ShipObject::setShieldRechargeRate (float shieldRechargeRate) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setShieldRechargeRate () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_shield_0))) { WARNING (true, ("ShipObject::setShieldRechargeRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_shield_0))); return false; } m_shieldRechargeRate.set (shieldRechargeRate); return true; } //---------------------------------------------------------------------- bool ShipObject::setCapacitorEnergyCurrent (float capacitorEnergyCurrent) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setCapacitorEnergyCurrent () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_capacitor))) { WARNING (true, ("ShipObject::setCapacitorEnergyCurrent () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_capacitor))); return false; } float const capacitorEnergyMaximum = getCapacitorEnergyEffectiveMaximum () * getComponentEfficiencyGeneral(ShipChassisSlotType::SCST_capacitor); capacitorEnergyCurrent = std::min (capacitorEnergyMaximum, capacitorEnergyCurrent); m_capacitorEnergyCurrent = capacitorEnergyCurrent; return true; } //---------------------------------------------------------------------- bool ShipObject::setCapacitorEnergyMaximum (float capacitorEnergyMaximum) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setCapacitorEnergyMaximum () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_capacitor))) { WARNING (true, ("ShipObject::setCapacitorEnergyMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_capacitor))); return false; } m_capacitorEnergyMaximum = capacitorEnergyMaximum; IGNORE_RETURN(setCapacitorEnergyCurrent (getCapacitorEnergyCurrent ())); return true; } //---------------------------------------------------------------------- bool ShipObject::setCapacitorEnergyRechargeRate (float capacitorEnergyRechargeRate) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setCapacitorEnergyRechargeRate () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_capacitor))) { WARNING (true, ("ShipObject::setCapacitorEnergyRechargeRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_capacitor))); return false; } m_capacitorEnergyRechargeRate = capacitorEnergyRechargeRate; return true; } //---------------------------------------------------------------------- bool ShipObject::setEngineAccelerationRate (float engineAccelerationRate) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineAccelerationRate () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) { WARNING (true, ("ShipObject::setEngineAccelerationRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); return false; } m_engineAccelerationRate = engineAccelerationRate; return true; } //---------------------------------------------------------------------- bool ShipObject::setEngineDecelerationRate (float engineDecelerationRate) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineDecelerationRate () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) { WARNING (true, ("ShipObject::setEngineDecelerationRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); return false; } m_engineDecelerationRate = engineDecelerationRate; return true; } //---------------------------------------------------------------------- bool ShipObject::setEnginePitchAccelerationRate (float enginePitchAccelerationRate) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEnginePitchAccelerationRate () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) { WARNING (true, ("ShipObject::setEnginePitchAccelerationRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); return false; } m_enginePitchAccelerationRate = enginePitchAccelerationRate; return true; } //---------------------------------------------------------------------- bool ShipObject::setEngineYawAccelerationRate (float engineYawAccelerationRate) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineYawAccelerationRate () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) { WARNING (true, ("ShipObject::setEngineYawAccelerationRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); return false; } m_engineYawAccelerationRate = engineYawAccelerationRate; return true; } //---------------------------------------------------------------------- bool ShipObject::setEngineRollAccelerationRate (float engineRollAccelerationRate) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineRollAccelerationRate () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) { WARNING (true, ("ShipObject::setEngineRollAccelerationRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); return false; } m_engineRollAccelerationRate = engineRollAccelerationRate; return true; } //---------------------------------------------------------------------- bool ShipObject::setEnginePitchRateMaximum (float enginePitchRateMaximum) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEnginePitchRateMaximum () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) { WARNING (true, ("ShipObject::setEnginePitchRateMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); return false; } m_enginePitchRateMaximum = enginePitchRateMaximum; return true; } //---------------------------------------------------------------------- bool ShipObject::setEngineYawRateMaximum (float engineYawRateMaximum) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineYawRateMaximum () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) { WARNING (true, ("ShipObject::setEngineYawRateMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); return false; } m_engineYawRateMaximum = engineYawRateMaximum; return true; } //---------------------------------------------------------------------- bool ShipObject::setEngineRollRateMaximum (float engineRollRateMaximum) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineRollRateMaximum () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) { WARNING (true, ("ShipObject::setEngineRollRateMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); return false; } m_engineRollRateMaximum = engineRollRateMaximum; return true; } //---------------------------------------------------------------------- bool ShipObject::setEngineSpeedMaximum (float engineSpeedMaximum) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineSpeedMaximum () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) { WARNING (true, ("ShipObject::setEngineSpeedMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); return false; } m_engineSpeedMaximum = engineSpeedMaximum; return true; } //---------------------------------------------------------------------- bool ShipObject::setEngineSpeedRotationFactorMaximum(float engineSpeedRotationFactor) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineSpeedRotationFactorMaximum () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) { WARNING (true, ("ShipObject::setEngineSpeedRotationFactorMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); return false; } m_engineSpeedRotationFactorMaximum = engineSpeedRotationFactor; return true; } //---------------------------------------------------------------------- bool ShipObject::setEngineSpeedRotationFactorMinimum(float engineSpeedRotationFactorMin) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineSpeedRotationFactorMinimum() called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) { WARNING (true, ("ShipObject::setEngineSpeedRotationFactorMinimum() called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); return false; } m_engineSpeedRotationFactorMinimum = engineSpeedRotationFactorMin; return true; } //---------------------------------------------------------------------- bool ShipObject::setEngineSpeedRotationFactorOptimal(float engineSpeedRotationFactorOptimal) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineSpeedRotationFactorOptimal() called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) { WARNING (true, ("ShipObject::setEngineSpeedRotationFactorOptimal() called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); return false; } m_engineSpeedRotationFactorOptimal = engineSpeedRotationFactorOptimal; return true; } //---------------------------------------------------------------------- bool ShipObject::setReactorEnergyGenerationRate (float reactorEnergyGenerationRate) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setReactorEnergyGenerationRate () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_reactor))) { WARNING (true, ("ShipObject::setReactorEnergyGenerationRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_reactor))); return false; } m_reactorEnergyGenerationRate = reactorEnergyGenerationRate; return true; } //---------------------------------------------------------------------- bool ShipObject::setBoosterEnergyCurrent (float boosterEnergyCurrent) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setBoosterEnergyCurrent () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_booster))) { WARNING (true, ("ShipObject::setBoosterEnergyCurrent () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_booster))); return false; } boosterEnergyCurrent = std::min (getBoosterEnergyMaximum (), boosterEnergyCurrent); m_boosterEnergyCurrent = boosterEnergyCurrent; return true; } //---------------------------------------------------------------------- bool ShipObject::setBoosterEnergyMaximum (float boosterEnergyMaximum) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setBoosterEnergyMaximum () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_booster))) { WARNING (true, ("ShipObject::setBoosterEnergyMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_booster))); return false; } m_boosterEnergyMaximum = boosterEnergyMaximum; IGNORE_RETURN(setBoosterEnergyCurrent (getBoosterEnergyCurrent ())); return true; } //---------------------------------------------------------------------- bool ShipObject::setBoosterEnergyRechargeRate (float boosterEnergyRechargeRate) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setBoosterEnergyRechargeRate () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_booster))) { WARNING (true, ("ShipObject::setBoosterEnergyRechargeRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_booster))); return false; } m_boosterEnergyRechargeRate = boosterEnergyRechargeRate; return true; } //---------------------------------------------------------------------- bool ShipObject::setBoosterEnergyConsumptionRate (float boosterEnergyConsumptionRate) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setBoosterEnergyConsumptionRate () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_booster))) { WARNING (true, ("ShipObject::setBoosterEnergyConsumptionRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_booster))); return false; } m_boosterEnergyConsumptionRate = boosterEnergyConsumptionRate; return true; } //---------------------------------------------------------------------- bool ShipObject::setBoosterAcceleration (float boosterAcceleration) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setBoosterAcceleration () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_booster))) { WARNING (true, ("ShipObject::setBoosterAcceleration () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_booster))); return false; } m_boosterAcceleration = boosterAcceleration; return true; } //---------------------------------------------------------------------- bool ShipObject::setBoosterSpeedMaximum (float boosterSpeedMaximum) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setBoosterSpeedMaximum () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_booster))) { WARNING (true, ("ShipObject::setBoosterSpeedMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_booster))); return false; } m_boosterSpeedMaximum = boosterSpeedMaximum; return true; } //---------------------------------------------------------------------- bool ShipObject::setDroidInterfaceCommandSpeed (float droidInterfaceCommandSpeed) { FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setDroidInterfaceCommandSpeed () called on non-auth object.")); if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_droid_interface))) { WARNING (true, ("ShipObject::setDroidInterfaceCommandSpeed () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_droid_interface))); return false; } m_droidInterfaceCommandSpeed = droidInterfaceCommandSpeed; return true; } //---------------------------------------------------------------------- bool ShipObject::canInstallComponent (int chassisSlot, TangibleObject const & component) const { ShipComponentData const * const shipComponentData = ShipComponentDataManager::create (component); if (!shipComponentData) { WARNING (true, ("ShipObject::canInstallComponent failed for [%s] because a ShipComponentData could not be constructed.", component.getNetworkId ().getValueString ().c_str ())); return false; } if (chassisSlot < static_cast(ShipChassisSlotType::SCST_first) || chassisSlot >= static_cast(ShipChassisSlotType::SCST_num_types)) { WARNING (true, ("ShipObject::canInstallComponent failed for [%s] because a chassisSlot was invalid.", component.getNetworkId ().getValueString ().c_str ())); return false; } ShipChassis const * const shipChassis = ShipChassis::findShipChassisByCrc (getChassisType ()); if (shipChassis) { int effectiveCompatibilitySlot = chassisSlot; // weapon slots beyond 7 wrap back to slot 0 for the purposes of compatibility checking on captial ships if (isCapitalShip() && chassisSlot >= ShipChassisSlotType::SCST_num_explicit_types && chassisSlot <= ShipChassisSlotType::SCST_weapon_last) effectiveCompatibilitySlot = ShipChassisSlotType::SCST_weapon_first+((chassisSlot-ShipChassisSlotType::SCST_weapon_first)&7); ShipChassisSlot const * const slot = shipChassis->getSlot (static_cast(effectiveCompatibilitySlot)); if (slot != nullptr) { if (slot->canAcceptComponent (shipComponentData->getDescriptor ())) { //-- check for mass availability float const massAvailable = getChassisComponentMassMaximum() - getChassisComponentMassCurrent(); return massAvailable >= shipComponentData->m_mass; } } } return false; } //---------------------------------------------------------------------- /** * This function destroys the component */ bool ShipObject::installComponent (NetworkId const & installerId, int chassisSlot, TangibleObject & component) { if (!canInstallComponent (chassisSlot, component)) { WARNING (true, ("ShipObject::installComponent failed for [%s] because the component can't go here.", component.getNetworkId ().getValueString ().c_str ())); return false; } if (isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::installComponent failed for [%s] because the slot is occupied.", component.getNetworkId ().getValueString ().c_str ())); return false; } ShipComponentData const * const shipComponentData = ShipComponentDataManager::create (component); if (!shipComponentData) { WARNING (true, ("ShipObject::installComponent failed for [%s] because a ShipComponentData could not be constructed.", component.getNetworkId ().getValueString ().c_str ())); return false; } if(getScriptObject()) { ScriptParams p; p.addParam(installerId); p.addParam(component.getNetworkId ()); p.addParam(chassisSlot); if (getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_INSTALLING, p) == SCRIPT_OVERRIDE) return false; } shipComponentData->writeDataToShip (chassisSlot, *this); LOG( "CustomerService", ( "ShipComponents: %s (%s), [%s]: added to %s (%s) by %s", Unicode::wideToNarrow(component.getObjectName()).c_str(), component.getNetworkId().getValueString().c_str(), component.getObjectTemplateName(), Unicode::wideToNarrow(getObjectName()).c_str(), getNetworkId().getValueString().c_str(), PlayerObject::getAccountDescription(getOwnerId()).c_str())); IGNORE_RETURN (component.permanentlyDestroy (DeleteReasons::Consumed)); if(getScriptObject()) { ScriptParams p; p.addParam(installerId); p.addParam (chassisSlot); IGNORE_RETURN (getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_INSTALLED, p)); } return true; } //---------------------------------------------------------------------- void ShipObject::purgeComponent (int chassisSlot) { IGNORE_RETURN (internalUninstallComponent (NetworkId::cms_invalid, chassisSlot, nullptr)); } //---------------------------------------------------------------------- TangibleObject * ShipObject::internalUninstallComponent (NetworkId const & uninstallerId, int chassisSlot, ServerObject * containerTarget, bool allowOverload) { if (!isSlotInstalled (chassisSlot)) { WARNING (true, ("ShipObject::internalUninstallComponent failed... no component installed in slot")); return nullptr; } ShipComponentData * const shipComponentData = createShipComponentData (chassisSlot); if (shipComponentData == nullptr) { WARNING (true, ("ShipObject::internalUninstallComponent failed nullptr data")); delete shipComponentData; return nullptr; } if(getScriptObject()) { ScriptParams p; p.addParam(uninstallerId); p.addParam (chassisSlot); p.addParam (containerTarget ? containerTarget->getNetworkId () : NetworkId::cms_invalid); if (getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_UNINSTALLING, p) == SCRIPT_OVERRIDE) return nullptr; } TangibleObject * tangible = 0; if (containerTarget) { uint32 const objectTemplateCrc = shipComponentData->getDescriptor ().getObjectTemplateCrc (); ServerObject * obj = 0; if (allowOverload) { VolumeContainer * volContainer = ContainerInterface::getVolumeContainer(*containerTarget); if (volContainer == nullptr) return 0; int oldCapacity = volContainer->debugDoNotUseSetCapacity(-1); obj = ServerWorld::createNewObject(objectTemplateCrc, *containerTarget, true, true); volContainer->debugDoNotUseSetCapacity(oldCapacity); volContainer->recalculateVolume(); } else { obj = safe_cast(ServerWorld::createNewObject (objectTemplateCrc, *containerTarget, true)); } if (obj == nullptr) { WARNING (true, ("ShipObject::internalUninstallComponent failed for slot [%d] because ServerWorld could not create an object for [%d], or container is full", chassisSlot, objectTemplateCrc)); delete shipComponentData; return nullptr; } tangible = obj->asTangibleObject (); if (tangible == nullptr) { WARNING (true, ("ShipObject::internalUninstallComponent failed for slot [%d] because object template [%d] is not tangible", chassisSlot, objectTemplateCrc)); delete shipComponentData; IGNORE_RETURN (obj->permanentlyDestroy (DeleteReasons::SetupFailed)); return nullptr; } shipComponentData->writeDataToComponent (*tangible); LOG( "CustomerService", ( "ShipComponents: %s (%s), [%s]: removed from %s (%s) by %s", Unicode::wideToNarrow(tangible->getObjectName()).c_str(), tangible->getNetworkId().getValueString().c_str(), tangible->getObjectTemplateName(), Unicode::wideToNarrow(getObjectName()).c_str(), getNetworkId().getValueString().c_str(), PlayerObject::getAccountDescription(getOwnerId()).c_str())); } switch (chassisSlot) { case ShipChassisSlotType::SCST_reactor: IGNORE_RETURN(setReactorEnergyGenerationRate (0.0f)); break; case ShipChassisSlotType::SCST_engine: IGNORE_RETURN(setEngineAccelerationRate (0.0f)); IGNORE_RETURN(setEngineDecelerationRate (0.0f)); IGNORE_RETURN(setEnginePitchAccelerationRate (0.0f)); IGNORE_RETURN(setEngineYawAccelerationRate (0.0f)); IGNORE_RETURN(setEngineRollAccelerationRate (0.0f)); IGNORE_RETURN(setEnginePitchRateMaximum (0.0f)); IGNORE_RETURN(setEngineYawRateMaximum (0.0f)); IGNORE_RETURN(setEngineRollRateMaximum (0.0f)); IGNORE_RETURN(setEngineSpeedMaximum (0.0f)); break; case ShipChassisSlotType::SCST_capacitor: IGNORE_RETURN(setCapacitorEnergyCurrent (0.0f)); IGNORE_RETURN(setCapacitorEnergyMaximum (0.0f)); IGNORE_RETURN(setCapacitorEnergyRechargeRate (0.0f)); break; case ShipChassisSlotType::SCST_shield_0: IGNORE_RETURN(setShieldHitpointsFrontCurrent (0.0f)); IGNORE_RETURN(setShieldHitpointsFrontMaximum (0.0f)); IGNORE_RETURN(setShieldHitpointsBackCurrent (0.0f)); IGNORE_RETURN(setShieldHitpointsBackMaximum (0.0f)); IGNORE_RETURN(setShieldRechargeRate (0.0f)); break; case ShipChassisSlotType::SCST_booster: IGNORE_RETURN(setBoosterEnergyCurrent (0.0f)); IGNORE_RETURN(setBoosterEnergyMaximum (0.0f)); IGNORE_RETURN(setBoosterEnergyRechargeRate (0.0f)); IGNORE_RETURN(setBoosterEnergyConsumptionRate (0.0f)); IGNORE_RETURN(setBoosterAcceleration (0.0f)); IGNORE_RETURN(setBoosterSpeedMaximum (0.0f)); break; case ShipChassisSlotType::SCST_droid_interface: IGNORE_RETURN(setDroidInterfaceCommandSpeed (0.0f)); break; case ShipChassisSlotType::SCST_cargo_hold: { m_cargoHoldContents.clear(); setCargoHoldContentsCurrent(0); setCargoHoldContentsMaximum(0); } break; default: break; } setComponentCrc (chassisSlot, 0); delete shipComponentData; if(getScriptObject()) { ScriptParams p; p.addParam(uninstallerId); p.addParam (tangible ? tangible->getNetworkId () : NetworkId::cms_invalid); p.addParam (chassisSlot); p.addParam (containerTarget ? containerTarget->getNetworkId () : NetworkId::cms_invalid); IGNORE_RETURN (getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_UNINSTALLED, p)); } return tangible; } //---------------------------------------------------------------------- TangibleObject * ShipObject::uninstallComponent (NetworkId const & uninstallerId, int chassisSlot, ServerObject & containerTarget, bool allowOverload) { return internalUninstallComponent (uninstallerId, chassisSlot, &containerTarget, allowOverload); } //---------------------------------------------------------------------- bool ShipObject::installComponentFromData(int chassisSlot, ShipComponentData const & shipComponentData) { ShipChassis const * const shipChassis = ShipChassis::findShipChassisByCrc (getChassisType ()); if (shipChassis == nullptr) { DEBUG_WARNING (true, ("Ship [%s] chassis [%d] is invalid for installing component [%s]", getNetworkId().getValueString().c_str(), static_cast(getChassisType ()), shipComponentData.getDescriptor().getName().getString())); return false; } if (isSlotInstalled (chassisSlot)) { DEBUG_WARNING (true, ("Ship [%s] chassis [%s] slot [%s] is already filled, cannot install [%s]", getNetworkId().getValueString().c_str(), shipChassis->getName().getString(), ShipChassisSlotType::getNameFromType(static_cast(chassisSlot)).c_str(), shipComponentData.getDescriptor().getName().getString())); return false; } int effectiveCompatibilitySlot = chassisSlot; // weapon slots beyond 7 wrap back to slot 0 for the purposes of compatibility checking on captial ships if (isCapitalShip() && chassisSlot >= ShipChassisSlotType::SCST_num_explicit_types && chassisSlot <= ShipChassisSlotType::SCST_weapon_last) effectiveCompatibilitySlot = ShipChassisSlotType::SCST_weapon_first+((chassisSlot-ShipChassisSlotType::SCST_weapon_first)&7); ShipChassisSlot const * const slot = shipChassis->getSlot (static_cast(effectiveCompatibilitySlot)); if (slot == nullptr) { DEBUG_WARNING (true, ("Ship [%s] chassis [%s] does not support slot [%s] for installing component [%s]", getNetworkId().getValueString().c_str(), shipChassis->getName().getString(), ShipChassisSlotType::getNameFromType(static_cast(chassisSlot)).c_str(), shipComponentData.getDescriptor().getName().getString())); return false; } if (!slot->canAcceptComponent(shipComponentData.getDescriptor())) { //this chassis check, in the warning, is to suppress output related to the npe tutorial falcon instance, as it seems "special" std::string chassis = shipChassis->getName().getString(); DEBUG_WARNING ((chassis != "player_yt1300"), ("Component [%s], compat [%s] cannot be installed in ship [%s] chassis [%s], slot [%s], compats [%s].", shipComponentData.getDescriptor().getName().getString(), shipComponentData.getDescriptor().getCompatibility().getString(), getNetworkId().getValueString().c_str(), chassis.c_str(), ShipChassisSlotType::getNameFromType(static_cast(chassisSlot)).c_str(), slot->getCompatibilityString().c_str())); return false; } shipComponentData.writeDataToShip (chassisSlot, *this); return true; } //---------------------------------------------------------------------- bool ShipObject::pseudoInstallComponent(int chassisSlot, uint32 componentCrc) { ShipComponentDescriptor const * const shipComponentDescriptor = ShipComponentDescriptor::findShipComponentDescriptorByCrc (componentCrc); if (shipComponentDescriptor == nullptr) { WARNING (true, ("Invalid component name")); return false; } ShipComponentData * const shipComponentData = ShipComponentDataManager::create (*shipComponentDescriptor); if (shipComponentData == nullptr) { WARNING(true, ("ShipObject::pseudoInstallComponent invalid descriptor")); return false; } bool const retval = installComponentFromData(chassisSlot, *shipComponentData); delete shipComponentData; return retval; } //---------------------------------------------------------------------- ShipComponentData * ShipObject::createShipComponentData (int chassisSlot) const { ShipComponentDescriptor const * shipComponentDescriptor = nullptr; uint32 const componentCrc = getComponentCrc (chassisSlot); if (componentCrc) { shipComponentDescriptor = ShipComponentDescriptor::findShipComponentDescriptorByCrc (componentCrc); if (shipComponentDescriptor == nullptr) { WARNING (true, ("ShipObject::createShipComponentData failed for slot [%d] because component crc [%d] could not map to a component descriptor", chassisSlot, componentCrc)); return nullptr; } } else return nullptr; ShipComponentData * const shipComponentData = ShipComponentDataManager::create (*shipComponentDescriptor); if (shipComponentData == nullptr) { WARNING (true, ("ShipObject::createShipComponentData failed for slot [%d] ship Component data could not be constructed", chassisSlot)); delete(shipComponentData); return nullptr; } if (!shipComponentData->readDataFromShip (chassisSlot, *this)) WARNING (true, ("ShipObject::createShipComponentData failed for read data from the ship")); return shipComponentData; } //---------------------------------------------------------------------- bool ShipObject::isSlotInstalled (int chassisSlot) const { return getComponentCrc (chassisSlot) != 0; } //---------------------------------------------------------------------- bool ShipObject::isBoosterInstalled() const { return isSlotInstalled(ShipChassisSlotType::SCST_booster); } //---------------------------------------------------------------------- bool ShipObject::isBoosterActive() const { if (isBoosterInstalled()) { return isComponentActive(ShipChassisSlotType::SCST_booster); } return false; } // ---------------------------------------------------------------------- void ShipObject::setBoosterActive(bool const active) { if (isSlotInstalled(ShipChassisSlotType::SCST_booster)) IGNORE_RETURN(setComponentActive(ShipChassisSlotType::SCST_booster, active)); } //---------------------------------------------------------------------- float ShipObject::computeShipActualAccelerationRate () const { float rate = 0.0f; if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) { float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); rate = getEngineAccelerationRate () * efficiency; } if (isSlotInstalled (ShipChassisSlotType::SCST_booster) && isBoosterActive () && isComponentFunctional(ShipChassisSlotType::SCST_booster)) { float const boosterEfficiency = computeActualComponentEfficiencyGeneral (ShipChassisSlotType::SCST_booster); rate += getBoosterAcceleration () * boosterEfficiency; } //-- @todo: divide rate by mass rate = rate * m_movementPercent; return rate; } //---------------------------------------------------------------------- float ShipObject::computeShipActualDecelerationRate () const { float rate = 0.0f; float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) rate = getEngineDecelerationRate () * efficiency; else rate = getShipDataEngine().m_engineDecelerationRate; //-- @todo: divide rate by mass rate = rate * m_movementPercent; return rate; } //---------------------------------------------------------------------- float ShipObject::computeSpeedRotationFactor() const { //-- compute rotational factor float const engineSpeedRotationFactorBaseMax = getEngineSpeedRotationFactorMaximum(); float const engineSpeedRotationFactorBaseMin = getEngineSpeedRotationFactorMinimum(); float const engineSpeedRotationFactorOptimal = getEngineSpeedRotationFactorOptimal(); float const speedMax = getShipActualSpeedMaximum(); float const speedCur = getCurrentSpeed(); float const speedPercent = (speedMax > 0.0f) ? (speedCur / speedMax) : 0.0f; float engineSpeedRotationFactor = 1.0f; if (speedPercent < engineSpeedRotationFactorOptimal || engineSpeedRotationFactorOptimal >= 1.0f) { float const speedPercentToOptimal = speedPercent / engineSpeedRotationFactorOptimal; engineSpeedRotationFactor = linearInterpolate(engineSpeedRotationFactorBaseMin, 1.0f, speedPercentToOptimal); } else { float const speedPercentFromOptimal = (speedPercent - engineSpeedRotationFactorOptimal) / (1.0f - engineSpeedRotationFactorOptimal); engineSpeedRotationFactor = linearInterpolate(1.0f, engineSpeedRotationFactorBaseMax, speedPercentFromOptimal); } // snap to discreet values, to avoid constant change return floorf((engineSpeedRotationFactor * 10.f) + 0.5f) / 10.f; } //---------------------------------------------------------------------- float ShipObject::computeShipActualPitchAccelerationRate () const { //float rate = 0.0f; // //float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); // //if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) //{ // rate = getEnginePitchAccelerationRate () * efficiency; // // if (isComponentDisabled(ShipChassisSlotType::SCST_engine)) // { // //-- player ships are allowed to stop spinning // if (isPlayerShip()) // rate *= 0.5f; // else // rate = 0.0f; // } //} float rate = 0.0f; float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) rate = getEnginePitchAccelerationRate () * efficiency; else rate = getShipDataEngine().m_enginePitchAccelerationRate; //-- @todo: divide rate by rotational inertia return rate; } //---------------------------------------------------------------------- float ShipObject::computeShipActualYawAccelerationRate () const { //float rate = 0.0f; // //float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); // //if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) //{ // rate = getEngineYawAccelerationRate () * efficiency; // // if (isComponentDisabled(ShipChassisSlotType::SCST_engine)) // { // //-- player ships are allowed to stop spinning // if (isPlayerShip()) // rate *= 0.5f; // else // rate = 0.0f; // } //} float rate = 0.0f; float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) rate = getEngineYawAccelerationRate () * efficiency; else rate = getShipDataEngine().m_engineYawAccelerationRate; //-- @todo: divide rate by rotational inertia return rate; } //---------------------------------------------------------------------- float ShipObject::computeShipActualRollAccelerationRate () const { //float rate = 0.0f; // //float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); // //if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) //{ // rate = getEngineRollAccelerationRate () * efficiency; // // if (isComponentDisabled(ShipChassisSlotType::SCST_engine)) // { // //-- player ships are allowed to stop spinning // if (isPlayerShip()) // rate *= 0.5f; // else // rate = 0.0f; // } //} float rate = 0.0f; float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) rate = getEngineRollAccelerationRate () * efficiency; else rate = getShipDataEngine().m_engineRollAccelerationRate; //-- @todo: divide rate by rotational inertia return rate; } //---------------------------------------------------------------------- float ShipObject::computeShipActualPitchRateMaximum () const { //float rate = 0.0f; // //float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); // //if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) //{ // rate = getEnginePitchRateMaximum () * efficiency; // // if (isComponentDisabled(ShipChassisSlotType::SCST_engine)) // { // //-- player ships have zero max rotation rates so the ship will come to a stop // if (isPlayerShip()) // rate = 0.0f; // } //} float rate = 0.0f; float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) rate = getEnginePitchRateMaximum () * efficiency; rate *= computeSpeedRotationFactor(); return rate; } //---------------------------------------------------------------------- float ShipObject::computeShipActualYawRateMaximum () const { //float rate = 0.0f; // //float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); // //if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) //{ // rate = getEngineYawRateMaximum () * efficiency; // // if (isComponentDisabled(ShipChassisSlotType::SCST_engine)) // { // //-- player ships have zero max rotation rates so the ship will come to a stop // if (isPlayerShip()) // rate = 0.0f; // } //} float rate = 0.0f; float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) rate = getEngineYawRateMaximum () * efficiency; rate *= computeSpeedRotationFactor(); return rate; } //---------------------------------------------------------------------- float ShipObject::computeShipActualRollRateMaximum () const { //float rate = 0.0f; // //float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); // //if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) //{ // rate = getEngineRollRateMaximum () * efficiency; // // if (isComponentDisabled(ShipChassisSlotType::SCST_engine)) // { // //-- player ships have zero max rotation rates so the ship will come to a stop // if (isPlayerShip()) // rate = 0.0f; // } //} float rate = 0.0f; float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) rate = getEngineRollRateMaximum () * efficiency; return rate; } //---------------------------------------------------------------------- float ShipObject::computeShipActualSpeedMaximum () const { float rate = 0.0f; if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) { float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); rate = getEngineSpeedMaximum () * efficiency; } if (isSlotInstalled(ShipChassisSlotType::SCST_booster) && isBoosterActive() && isComponentFunctional(ShipChassisSlotType::SCST_booster)) rate += getBoosterSpeedMaximum () * computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_booster); if (hasWings() && hasCondition(TangibleObject::C_wingsOpened)) { ShipChassis const * const shipChassis = ShipChassis::findShipChassisByCrc(getChassisType()); if (nullptr != shipChassis) { float const wingOpenSpeedFactor = shipChassis->getWingOpenSpeedFactor(); rate *= wingOpenSpeedFactor; } } rate *= m_chassisSpeedMaximumModifier.get(); rate = std::min(512.0f, rate * m_movementPercent); return rate; } //---------------------------------------------------------------------- float ShipObject::getShipActualAccelerationRate () const { return m_shipActualAccelerationRate.get(); } //---------------------------------------------------------------------- float ShipObject::getShipActualDecelerationRate () const { return m_shipActualDecelerationRate.get(); } //---------------------------------------------------------------------- float ShipObject::getShipActualPitchAccelerationRate () const { return m_shipActualPitchAccelerationRate.get(); } //---------------------------------------------------------------------- float ShipObject::getShipActualYawAccelerationRate () const { return m_shipActualYawAccelerationRate.get(); } //---------------------------------------------------------------------- float ShipObject::getShipActualRollAccelerationRate () const { return m_shipActualRollAccelerationRate.get(); } //---------------------------------------------------------------------- float ShipObject::getShipActualPitchRateMaximum () const { return m_shipActualPitchRateMaximum.get(); } //---------------------------------------------------------------------- float ShipObject::getShipActualYawRateMaximum () const { return m_shipActualYawRateMaximum.get(); } //---------------------------------------------------------------------- float ShipObject::getShipActualRollRateMaximum () const { return m_shipActualRollRateMaximum.get(); } //---------------------------------------------------------------------- float ShipObject::getShipActualYprRateMaximum() const { return std::max(std::max(m_shipActualPitchRateMaximum.get(), m_shipActualYawRateMaximum.get()), m_shipActualRollRateMaximum.get()); } //---------------------------------------------------------------------- float ShipObject::getShipActualSpeedMaximum () const { return m_shipActualSpeedMaximum.get(); } //---------------------------------------------------------------------- bool ShipObject::isComponentDisabled (int chassisSlot) const { return (getComponentFlags (chassisSlot) & static_cast(ShipComponentFlags::F_disabled)) != 0; } //---------------------------------------------------------------------- bool ShipObject::isComponentDisabledNeedsPower(int chassisSlot) const { return (getComponentFlags (chassisSlot) & static_cast(ShipComponentFlags::F_disabledNeedsPower)) != 0; } //---------------------------------------------------------------------- bool ShipObject::isComponentLowPower (int chassisSlot) const { return (getComponentFlags (chassisSlot) & static_cast(ShipComponentFlags::F_lowPower)) != 0; } //---------------------------------------------------------------------- bool ShipObject::isComponentActive(int chassisSlot) const { return (getComponentFlags (chassisSlot) & static_cast(ShipComponentFlags::F_active)) != 0; } //---------------------------------------------------------------------- bool ShipObject::isComponentDemolished(int chassisSlot) const { return (getComponentFlags(chassisSlot) & ShipComponentFlags::F_demolished) != 0; } //---------------------------------------------------------------------- void ShipObject::handlePowerPulse (float timeElapsedSecs) { PROFILER_AUTO_BLOCK_DEFINE("ShipObject::handlePowerPulse"); DEBUG_FATAL (!isAuthoritative(), ("ShipObject::handlePowerPulse called on non-auth ship object")); //-- handle componentized power system ShipChassis const * const shipChassis = ShipChassis::findShipChassisByCrc (getChassisType ()); if (!shipChassis) return; CreatureObject * const pilot = getPilot(); float powerGenerated = 0.0f; if (isSlotInstalled (static_cast(ShipChassisSlotType::SCST_reactor)) && isComponentFunctional(ShipChassisSlotType::SCST_reactor)) { powerGenerated = getReactorEnergyGenerationRate () * computeActualComponentEfficiencyGeneral (static_cast(ShipChassisSlotType::SCST_reactor)) * timeElapsedSecs; powerGenerated += (powerGenerated * m_nebulaEffectReactor); powerGenerated = std::max (0.0f, powerGenerated); } //-- discharge the capacitor if it is disabled (because the power logic below is skipped for disabled components) if (isSlotInstalled(ShipChassisSlotType::SCST_capacitor) && !isComponentFunctional(ShipChassisSlotType::SCST_capacitor)) IGNORE_RETURN(setCapacitorEnergyCurrent(0.0f)); for (int i = static_cast(ShipChassisSlotType::SCST_first); i < static_cast(ShipChassisSlotType::SCST_num_types); ++i) { ShipChassisSlotType::Type const slotType = shipChassis->getSlotPowerPriority (i); if (slotType == ShipChassisSlotType::SCST_num_types || slotType == ShipChassisSlotType::SCST_reactor) continue; int const slotIndex = static_cast(slotType); if (!isSlotInstalled (slotIndex)) continue; if (isComponentDemolished(slotIndex)) continue; if (isComponentDisabled(slotIndex)) { if (!isComponentDisabledNeedsPower(slotIndex)) continue; } float const baseComponentEnergyRequired = getComponentEnergyMaintenanceRequirement (slotIndex) * timeElapsedSecs; float oo_componentEfficiencyEnergy = getComponentEfficiencyEnergy (slotIndex); if (oo_componentEfficiencyEnergy > 0.0f) oo_componentEfficiencyEnergy = RECIP (oo_componentEfficiencyEnergy); float const energyRequired = baseComponentEnergyRequired * oo_componentEfficiencyEnergy; //-- first consume the base energy requirement for the component float energyInsufficiencyPercent = 0.0f; //-- insufficient power if (energyRequired > powerGenerated) { if(getScriptObject()) { ScriptParams p; p.addParam (slotIndex); p.addParam (energyRequired); p.addParam (powerGenerated); IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_POWER_INSUFFICIENT, p)); //-- script has for some reason removed the component, stop processing it if (!isSlotInstalled(slotIndex)) continue; } //-- energy req cannot be zero energyInsufficiencyPercent = 1.0f - powerGenerated / energyRequired; IGNORE_RETURN(setComponentLowPower (slotIndex, true)); } //-- sufficient power else { if (isComponentLowPower (slotIndex)) { if(getScriptObject()) { ScriptParams p; p.addParam (slotIndex); p.addParam (energyRequired); IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_POWER_SUFFICIENT, p)); //-- script has for some reason removed the component, stop processing it if (!isSlotInstalled(slotIndex)) continue; } IGNORE_RETURN(setComponentLowPower (slotIndex, false)); } } powerGenerated = std::max (0.0f, powerGenerated - energyRequired); //-- if (isComponentDisabled(slotIndex)) continue; float const efficiencyGeneral = computeActualComponentEfficiencyGeneral(slotIndex); switch (slotType) { //-- //-- recharge or decay the shields //-- case ShipChassisSlotType::SCST_shield_0: { float const hpFrontCurrent = getShieldHitpointsFrontCurrent (); float const hpFrontMaximum = getShieldHitpointsFrontMaximum (); float const hpBackCurrent = getShieldHitpointsBackCurrent (); float const hpBackMaximum = getShieldHitpointsBackMaximum (); //-- recharge the shields if (!isComponentLowPower(slotIndex)) { float shieldRechargeRateHps = getShieldRechargeRate () * efficiencyGeneral * timeElapsedSecs; shieldRechargeRateHps += (shieldRechargeRateHps * m_nebulaEffectShields); if (shieldRechargeRateHps > 0.0f) { float const hpFrontNeeded = std::max (0.0f, std::min (hpFrontMaximum - hpFrontCurrent, shieldRechargeRateHps)); float const hpBackNeeded = std::max (0.0f, std::min (hpBackMaximum - hpBackCurrent, shieldRechargeRateHps)); if (hpFrontNeeded > 0.0f || hpBackNeeded > 0.0f) { if (hpFrontNeeded) IGNORE_RETURN(setShieldHitpointsFrontCurrent(hpFrontCurrent + hpFrontNeeded)); if (hpBackNeeded) IGNORE_RETURN(setShieldHitpointsBackCurrent(hpBackCurrent + hpBackNeeded)); } } } //-- decay the shields to some percentage else if (energyInsufficiencyPercent > 0.0f) { float const shieldDecayRateHps = std::max (1.0f, (getShieldRechargeRate () * timeElapsedSecs) * energyInsufficiencyPercent); float const minShieldsFront = (1.0f - energyInsufficiencyPercent) * getShieldHitpointsFrontMaximum(); float const minShieldsBack = (1.0f - energyInsufficiencyPercent) * getShieldHitpointsBackMaximum(); if (hpFrontCurrent > minShieldsFront) IGNORE_RETURN(setShieldHitpointsFrontCurrent(std::max(minShieldsFront, hpFrontCurrent - shieldDecayRateHps))); if (hpBackCurrent > minShieldsBack) IGNORE_RETURN(setShieldHitpointsBackCurrent(std::max(minShieldsFront, hpBackCurrent - shieldDecayRateHps))); } } break; //-- //-- recharge or decay the capacitor //-- case ShipChassisSlotType::SCST_capacitor: { float capacitorEnergyCurrent = getCapacitorEnergyCurrent (); float const capacitorEnergyMaximum = getCapacitorEnergyEffectiveMaximum () * getComponentEfficiencyGeneral(ShipChassisSlotType::SCST_capacitor); //-- the efficiency might cause the current charge to exceed the max if (capacitorEnergyCurrent > capacitorEnergyMaximum) { IGNORE_RETURN(setCapacitorEnergyCurrent (capacitorEnergyMaximum)); capacitorEnergyCurrent = getCapacitorEnergyCurrent (); } //-- recharge the capacitor if (!isComponentLowPower(slotIndex)) { float const rechargeRate = getCapacitorEnergyRechargeRate () * efficiencyGeneral * timeElapsedSecs; float const capacitorEnergyRechargeNeeded = std::min (capacitorEnergyMaximum - capacitorEnergyCurrent, rechargeRate); if (capacitorEnergyRechargeNeeded > 0.0f) { IGNORE_RETURN(setCapacitorEnergyCurrent (capacitorEnergyCurrent + capacitorEnergyRechargeNeeded)); } } //-- decay the capacitors to some percentage else if (energyInsufficiencyPercent > 0.0f) { float const decayRate = std::max (1.0f, (getCapacitorEnergyRechargeRate () * timeElapsedSecs) * energyInsufficiencyPercent); float const minLevel = (1.0f - energyInsufficiencyPercent) * getCapacitorEnergyEffectiveMaximum(); if (capacitorEnergyCurrent > minLevel) IGNORE_RETURN(setCapacitorEnergyCurrent (std::max(minLevel, capacitorEnergyCurrent - decayRate))); } } break; //-- //-- recharge or decay the booster //-- case ShipChassisSlotType::SCST_booster: { float boosterEnergyCurrent = getBoosterEnergyCurrent(); if (isBoosterActive()) { float const boosterEnergyUsed = (getBoosterEnergyConsumptionRate() * timeElapsedSecs) * oo_componentEfficiencyEnergy; IGNORE_RETURN(setBoosterEnergyCurrent(std::max(0.0f, boosterEnergyCurrent - boosterEnergyUsed))); boosterEnergyCurrent = getBoosterEnergyCurrent(); //-- when the booster runs out of energy, kill it if (boosterEnergyCurrent <= 0.0f) { IGNORE_RETURN(setComponentActive(ShipChassisSlotType::SCST_booster, false)); if (pilot != nullptr) Chat::sendSystemMessage(*pilot, SharedStringIds::booster_energy_depleted, Unicode::emptyString); restartBoosterTimer(); } break; } float const boosterEnergyMaximum = getBoosterEnergyMaximum (); //recharge the booster if (!isComponentLowPower(slotIndex)) { float const rechargeRate = getBoosterEnergyRechargeRate () * efficiencyGeneral * timeElapsedSecs; float const boosterEnergyRechargeNeeded = std::min (boosterEnergyMaximum - boosterEnergyCurrent, rechargeRate); if (boosterEnergyRechargeNeeded > 0.0f) { float const boosterEnergyRequired = boosterEnergyRechargeNeeded * oo_componentEfficiencyEnergy; IGNORE_RETURN(setBoosterEnergyCurrent (boosterEnergyCurrent + boosterEnergyRequired)); } } //-- decay the boosters to some percentage else if (energyInsufficiencyPercent > 0.0f) { float const decayRate = std::max (1.0f, (getBoosterEnergyRechargeRate () * timeElapsedSecs) * energyInsufficiencyPercent); float const minLevel = (1.0f - energyInsufficiencyPercent) * getBoosterEnergyMaximum(); if (boosterEnergyCurrent > minLevel) IGNORE_RETURN(setBoosterEnergyCurrent (std::max(minLevel, boosterEnergyCurrent - decayRate))); } } break; default: break; } //lint !e788 //switch cases not used } } //---------------------------------------------------------------------- int ShipObject::getProjectileIndexForWeapon(int const weaponIndex) const { if (weaponIndex < 0 || weaponIndex >= ShipChassisSlotType::cms_numWeaponIndices) return -1; ShipChassisSlotType::Type const weaponChassisSlotType = static_cast(weaponIndex + static_cast(ShipChassisSlotType::SCST_weapon_0)); uint32 const componentCrc = getComponentCrc(weaponChassisSlotType); if (componentCrc == 0) return -1; return ShipComponentWeaponManager::getProjectileIndex(componentCrc); } //---------------------------------------------------------------------- float ShipObject::getWeaponRange(int weaponIndex) const { if (weaponIndex < 0 || weaponIndex >= ShipChassisSlotType::cms_numWeaponIndices) return 0.0f; ShipChassisSlotType::Type const weaponChassisSlotType = static_cast(weaponIndex + static_cast(ShipChassisSlotType::SCST_weapon_0)); uint32 const componentCrc = getComponentCrc(weaponChassisSlotType); if (componentCrc == 0) return 0.0f; float range = 0.0f; if (ShipComponentWeaponManager::isMissile(componentCrc)) { int const missileTypeId = static_cast(getWeaponAmmoType(weaponChassisSlotType)); range = MissileManager::getInstance().getRangeByMissileType(missileTypeId); } else { range = ShipComponentWeaponManager::getRange(componentCrc); } return range; } //---------------------------------------------------------------------- float ShipObject::getWeaponProjectileSpeed(int weaponIndex) const { if (weaponIndex < 0 || weaponIndex >= ShipChassisSlotType::cms_numWeaponIndices) return 0.0f; ShipChassisSlotType::Type const weaponChassisSlotType = static_cast(weaponIndex + static_cast(ShipChassisSlotType::SCST_weapon_0)); uint32 const componentCrc = getComponentCrc(weaponChassisSlotType); if (componentCrc == 0) return 0.0f; float speed = 0.0f; if (ShipComponentWeaponManager::isMissile(componentCrc)) { int const missileTypeId = static_cast(getWeaponAmmoType(weaponChassisSlotType)); speed = MissileManager::getInstance().getSpeedByMissileType(missileTypeId); } else { speed = ShipComponentWeaponManager::getProjectileSpeed(componentCrc); } return speed; } //---------------------------------------------------------------------- float ShipObject::computeWeaponProjectileTimeToLive(int weaponIndex) const { if (weaponIndex < 0 || weaponIndex >= ShipChassisSlotType::cms_numWeaponIndices) return 0.0f; ShipChassisSlotType::Type const weaponChassisSlotType = static_cast(weaponIndex + static_cast(ShipChassisSlotType::SCST_weapon_0)); uint32 const componentCrc = getComponentCrc(weaponChassisSlotType); if (componentCrc == 0) return 0.0f; float timeToLive = 0.0f; if (ShipComponentWeaponManager::isMissile(componentCrc)) { int const missileTypeId = static_cast(getWeaponAmmoType(weaponChassisSlotType)); timeToLive = MissileManager::getInstance().getMaxTimeByMissileType(missileTypeId); } else { float const range = ShipComponentWeaponManager::getRange(componentCrc); float const projectileSpeed = ShipComponentWeaponManager::getProjectileSpeed(componentCrc); timeToLive = (projectileSpeed <= 0.0f) ? 0.0f : range / projectileSpeed; } return timeToLive; } //---------------------------------------------------------------------- float ShipObject::computeActualComponentEfficiencyGeneral(int chassisType) const { float efficiency = getComponentEfficiencyGeneral(chassisType); float nebulaEffect = 0.0f; switch (chassisType) { case ShipChassisSlotType::SCST_engine: nebulaEffect = m_nebulaEffectEngine; break; case ShipChassisSlotType::SCST_reactor: nebulaEffect = m_nebulaEffectReactor; break; case ShipChassisSlotType::SCST_shield_0: nebulaEffect = m_nebulaEffectShields; break; default: break; } efficiency = clamp(0.1f, efficiency + nebulaEffect, 10.0f); return efficiency; } //---------------------------------------------------------------------- void ShipObject::setSlotTargetable(ShipChassisSlotType::Type slot) { BitArray tmp(m_targetableSlotBitfield.get()); tmp.setBit(slot); m_targetableSlotBitfield = tmp; } //---------------------------------------------------------------------- void ShipObject::clearSlotTargetable(ShipChassisSlotType::Type slot) { BitArray tmp(m_targetableSlotBitfield.get()); tmp.clearBit(slot); m_targetableSlotBitfield = tmp; } //---------------------------------------------------------------------- bool ShipObject::getSlotTargetable(ShipChassisSlotType::Type slot) const { return m_targetableSlotBitfield.get().testBit(slot); } //---------------------------------------------------------------------- bool ShipObject::isValidTargetableSlot (ShipChassisSlotType::Type slot) const { if(getSlotTargetable(slot)) { if(isSlotInstalled(slot)) { if(isComponentFunctional(slot)) { return true; } } } return false; } //---------------------------------------------------------------------- void ShipObject::setPilotLookAtTargetSlot(ShipChassisSlotType::Type slot) { if(isAuthoritative() && isValidTargetableSlot(slot)) { m_pilotLookAtTargetSlot.set(slot); } } //---------------------------------------------------------------------- void ShipObject::setTurretTarget(int weaponIndex, CachedNetworkId const & target) { if (isAuthoritative()) { DEBUG_FATAL(!isTurret(weaponIndex), ("Assigning a target(%s) to a weaponIndex(%d) that is not a turret", target.getValueString().c_str(), weaponIndex)); if (!target.isValid()) IGNORE_RETURN(m_turretTargets.erase(weaponIndex)); else m_turretTargets[weaponIndex] = target; } } //---------------------------------------------------------------------- CachedNetworkId const & ShipObject::getTurretTarget(int weaponIndex) const { if (isAuthoritative()) { DEBUG_FATAL(!isTurret(weaponIndex), ("Requesting the target of an weaponIndex(%d) that is not a turret", weaponIndex)); std::map::const_iterator const it = m_turretTargets.find(weaponIndex); if (it != m_turretTargets.end()) return (*it).second; } return CachedNetworkId::cms_cachedInvalid; } //---------------------------------------------------------------------- Transform const ShipObject::getTurretTransform(int weaponIndex) const { int const chassisSlot = static_cast(ShipChassisSlotType::SCST_weapon_0) + weaponIndex; uint32 const componentCrc = getComponentCrc(chassisSlot); if (componentCrc != 0) { AppearanceTemplate const * exteriorAppearanceTemplate = 0; PortalProperty const * const portalProperty = getPortalProperty(); if (portalProperty) { char const * const exteriorAppearanceName = portalProperty->getPortalPropertyTemplate().getExteriorAppearanceName(); if (exteriorAppearanceName) exteriorAppearanceTemplate = AppearanceTemplateList::fetch(exteriorAppearanceName); } else { Appearance const * const appearance = getAppearance(); if (appearance) exteriorAppearanceTemplate = appearance->getAppearanceTemplate(); } if (exteriorAppearanceTemplate) { ShipComponentAttachmentManager::TemplateHardpointPairVector const &attachments = ShipComponentAttachmentManager::getAttachmentsForShip(getChassisType(), componentCrc, chassisSlot); if (!attachments.empty()) { ShipComponentAttachmentManager::TemplateHardpointPair const &templateHardpointPair = *attachments.begin(); int const turretYawHardpointIndex = exteriorAppearanceTemplate->getHardpointIndex(templateHardpointPair.second, true); WARNING(turretYawHardpointIndex == -1, ("Ship %s references hardpoint '%s' which could not be found.", getDebugInformation().c_str(), templateHardpointPair.second.getString())); if (turretYawHardpointIndex != -1) { Hardpoint const &turretYawHardpoint = exteriorAppearanceTemplate->getHardpoint(turretYawHardpointIndex); // we now need to find a weapon hardpoint on this attachment SharedObjectTemplate const * const objectTemplate = safe_cast(ObjectTemplateList::fetch(templateHardpointPair.first)); if (objectTemplate) { AppearanceTemplate const * const appearanceTemplate = AppearanceTemplateList::fetch(objectTemplate->getAppearanceFilename().c_str()); if (appearanceTemplate) { int const turretPitchHardpointIndex = appearanceTemplate->getHardpointIndex(s_turretPitchHardpoint, true); if (turretPitchHardpointIndex != -1) { Hardpoint const &turretPitchHardpoint = appearanceTemplate->getHardpoint(turretPitchHardpointIndex); return getTransform_o2p().rotateTranslate_l2p(turretYawHardpoint.getTransform().rotateTranslate_l2p(turretPitchHardpoint.getTransform())); } } } // we couldn't find a turret pitch hardpoint, so the turret yaw hardpoint is for the object which pitches also return getTransform_o2p().rotateTranslate_l2p(turretYawHardpoint.getTransform()); } } } } // we couldn't find an attachment hardpoint, so assume we fire forward from the ship center return getTransform_o2p(); } //---------------------------------------------------------------------- bool ShipObject::isMissile(int const weaponIndex) const { bool ismissile = false; if(weaponIndex >= 0 && weaponIndex < ShipChassisSlotType::cms_numWeaponIndices) { int const chassisSlot = static_cast(ShipChassisSlotType::SCST_weapon_first) + weaponIndex; uint32 const componentCrc = getComponentCrc(chassisSlot); if (componentCrc != 0) { ismissile = ShipComponentWeaponManager::isMissile(componentCrc); } } return ismissile; } //---------------------------------------------------------------------- bool ShipObject::isTurret(int const weaponIndex) const { DEBUG_FATAL(!ShipChassisSlotType::isWeaponIndex(weaponIndex), ("weaponIndex(%d) is out of range [0...%d]", weaponIndex, ShipChassisSlotType::cms_numWeaponIndices - 1)); return m_turretWeaponIndices->testBit(weaponIndex); } //---------------------------------------------------------------------- bool ShipObject::isCountermeasure(int const weaponIndex) const { ShipChassisSlotType::Type const shipChassisSlotType = static_cast(static_cast(ShipChassisSlotType::SCST_weapon_0) + weaponIndex); if (isSlotInstalled(shipChassisSlotType)) { uint32 const componentCrc = getComponentCrc(shipChassisSlotType); return ShipComponentWeaponManager::isCountermeasure(componentCrc); } return false; } //---------------------------------------------------------------------- bool ShipObject::isProjectile(int const weaponIndex) const { bool missile = isMissile(weaponIndex); bool turret = isTurret(weaponIndex); bool countermeasure = isCountermeasure(weaponIndex); return (!missile && !turret && !countermeasure); } //---------------------------------------------------------------------- float ShipObject::computeChassisComponentMassCurrent() const { float massCurrent = 0.0f; for (int chassisSlot = static_cast(ShipChassisSlotType::SCST_first); chassisSlot < static_cast(ShipChassisSlotType::SCST_num_types); ++chassisSlot) { if (!isSlotInstalled (chassisSlot)) continue; massCurrent += getComponentMass(chassisSlot); } return massCurrent; } //---------------------------------------------------------------------- float ShipObject::getChassisComponentMassMaximum() const { return m_chassisComponentMassMaximum.get(); } //---------------------------------------------------------------------- float ShipObject::getChassisComponentMassCurrent() const { return m_chassisComponentMassCurrent.get(); } //---------------------------------------------------------------------- void ShipObject::setChassisComponentMassMaximum(float massMaximum) { m_chassisComponentMassMaximum.set(massMaximum); } //---------------------------------------------------------------------- void ShipObject::internalSetChassisComponentMassCurrent(float massCurrent) { m_chassisComponentMassCurrent.set(massCurrent); } // ---------------------------------------------------------------------- /** * Check whether a turret can fire towards a particular location without * exceeding its rotation limits. */ bool ShipObject::canTurretFireTowardsLocation_p(int weaponIndex, Vector const & targetLocation_p) const { Transform turretTransform_o2p(getTurretTransform(weaponIndex)); uint32 const chassisCrc = getChassisType(); float const minYaw = ShipTurretManager::getTurretMinYaw(chassisCrc, weaponIndex); float const maxYaw = ShipTurretManager::getTurretMaxYaw(chassisCrc, weaponIndex); float const minPitch = ShipTurretManager::getTurretMinPitch(chassisCrc, weaponIndex); float const maxPitch = ShipTurretManager::getTurretMaxPitch(chassisCrc, weaponIndex); Vector const turretToTarget = turretTransform_o2p.rotateTranslate_p2l(targetLocation_p); float yaw=turretToTarget.theta(); float pitch=turretToTarget.phi(); // if yaw and pitch are limited for this turret, check that the desired yaw/pitch is within the range if ((maxYaw-minYaw)+0.001 < PI_TIMES_2) if (yaw > maxYaw || yaw < minYaw) return false; if ((maxPitch-minPitch)+0.001 < PI_TIMES_2) if (pitch > maxPitch || pitch < minPitch) return false; return true; } // ---------------------------------------------------------------------- /** * Given a position on the ship, figure out which targettable chassis slot covers * that position. Used to determine which component a projectile hit. */ int ShipObject::findTargetChassisSlotByPosition(Vector const & position_o) const { DEBUG_FATAL(!isCapitalShip(),("Programmer bug: findChassisSlotByPosition() should only be called on capital ships")); AppearanceTemplate const * exteriorAppearanceTemplate = 0; PortalProperty const * const portalProperty = getPortalProperty(); if (portalProperty) { char const * const exteriorAppearanceName = portalProperty->getPortalPropertyTemplate().getExteriorAppearanceName(); if (exteriorAppearanceName) exteriorAppearanceTemplate = AppearanceTemplateList::fetch(exteriorAppearanceName); } else { Appearance const * const appearance = getAppearance(); if (appearance) exteriorAppearanceTemplate = appearance->getAppearanceTemplate(); } NOT_NULL(exteriorAppearanceTemplate); if (!exteriorAppearanceTemplate) //lint !e774 only always false in debug mode return ShipChassisSlotType::SCST_invalid; ShipChassisSlotType::Type closestSlot = ShipChassisSlotType::SCST_invalid; float closestDistance = 0.0f; for (int chassisSlotIterator = static_cast(ShipChassisSlotType::SCST_first); chassisSlotIterator != static_cast(ShipChassisSlotType::SCST_num_types); ++chassisSlotIterator) { ShipChassisSlotType::Type chassisSlot = static_cast(chassisSlotIterator); uint32 const componentCrc = getComponentCrc(chassisSlot); //DEBUG_REPORT_LOG(componentCrc != 0 && !getSlotTargetable(chassisSlot),("Skipping slot %i because it is not targettable\n",chassisSlot)); if (componentCrc != 0 && getSlotTargetable(chassisSlot)) { float hitRange = ShipComponentAttachmentManager::getComponentHitRange(getChassisType(), componentCrc, chassisSlot); { // First look at regular attachments ShipComponentAttachmentManager::TemplateHardpointPairVector const &attachments = ShipComponentAttachmentManager::getAttachmentsForShip(getChassisType(), componentCrc, chassisSlot); for (ShipComponentAttachmentManager::TemplateHardpointPairVector::const_iterator i=attachments.begin(); i!=attachments.end(); ++i) { ShipComponentAttachmentManager::TemplateHardpointPair const &templateHardpointPair = *i; int const hardpointIndex = exteriorAppearanceTemplate->getHardpointIndex(templateHardpointPair.second, true); WARNING(hardpointIndex == -1, ("Ship %s references hardpoint '%s' which could not be found.", getDebugInformation().c_str(), templateHardpointPair.second.getString())); if (hardpointIndex != -1) { Hardpoint const & hardpoint = exteriorAppearanceTemplate->getHardpoint(hardpointIndex); Transform const & transform_o = hardpoint.getTransform(); float const distanceSquared = (position_o - transform_o.getPosition_p()).magnitudeSquared(); if (distanceSquared < sqr(hitRange) && ((closestSlot == ShipChassisSlotType::SCST_invalid) || (distanceSquared < closestDistance))) { closestSlot = chassisSlot; closestDistance = distanceSquared; } } } } { // Second look at "extra" hardpoints (hardpoints that exist for the sake of targeting only ShipComponentAttachmentManager::HardpointVector const &extraHardpoints = ShipComponentAttachmentManager::getExtraHardpointsForComponent(getChassisType(), componentCrc, chassisSlot); for (ShipComponentAttachmentManager::HardpointVector::const_iterator i=extraHardpoints.begin(); i!=extraHardpoints.end(); ++i) { int const hardpointIndex = exteriorAppearanceTemplate->getHardpointIndex(*i, true); WARNING(hardpointIndex == -1, ("Ship %s references hardpoint '%s' which could not be found.", getDebugInformation().c_str(), (*i).getString())); if (hardpointIndex != -1) { Hardpoint const & hardpoint = exteriorAppearanceTemplate->getHardpoint(hardpointIndex); Transform const & transform_o = hardpoint.getTransform(); float const distanceSquared = (position_o - transform_o.getPosition_p()).magnitudeSquared(); if (distanceSquared < sqr(hitRange) && ((closestSlot == ShipChassisSlotType::SCST_invalid) || (distanceSquared < closestDistance))) { closestSlot = chassisSlot; closestDistance = distanceSquared; } } } } } } return closestSlot; } // ---------------------------------------------------------------------- void ShipObject::findTransformsForComponent(int const chassisSlot, std::vector & transforms) const { transforms.clear(); AppearanceTemplate const * const exteriorAppearanceTemplate = getExteriorAppearance(); if (!exteriorAppearanceTemplate) return; uint32 const componentCrc = getComponentCrc(chassisSlot); { // First look at regular attachments ShipComponentAttachmentManager::TemplateHardpointPairVector const &attachments = ShipComponentAttachmentManager::getAttachmentsForShip(getChassisType(), componentCrc, chassisSlot); for (ShipComponentAttachmentManager::TemplateHardpointPairVector::const_iterator i=attachments.begin(); i!=attachments.end(); ++i) { ShipComponentAttachmentManager::TemplateHardpointPair const &templateHardpointPair = *i; int const hardpointIndex = exteriorAppearanceTemplate->getHardpointIndex(templateHardpointPair.second, true); WARNING(hardpointIndex == -1, ("Ship %s references hardpoint '%s' which could not be found.", getDebugInformation().c_str(), templateHardpointPair.second.getString())); if (hardpointIndex != -1) { Hardpoint const & hardpoint = exteriorAppearanceTemplate->getHardpoint(hardpointIndex); Transform const & transform_o = hardpoint.getTransform(); transforms.push_back(transform_o); } } } { // Second look at "extra" hardpoints (hardpoints that exist for the sake of targeting only ShipComponentAttachmentManager::HardpointVector const &extraHardpoints = ShipComponentAttachmentManager::getExtraHardpointsForComponent(getChassisType(), componentCrc, chassisSlot); for (ShipComponentAttachmentManager::HardpointVector::const_iterator i=extraHardpoints.begin(); i!=extraHardpoints.end(); ++i) { int const hardpointIndex = exteriorAppearanceTemplate->getHardpointIndex(*i, true); WARNING(hardpointIndex == -1, ("Ship %s references hardpoint '%s' which could not be found.", getDebugInformation().c_str(), (*i).getString())); if (hardpointIndex != -1) { Hardpoint const & hardpoint = exteriorAppearanceTemplate->getHardpoint(hardpointIndex); Transform const & transform_o = hardpoint.getTransform(); transforms.push_back(transform_o); } } } } // ---------------------------------------------------------------------- AppearanceTemplate const * ShipObject::getExteriorAppearance() const { AppearanceTemplate const * exteriorAppearanceTemplate = 0; PortalProperty const * const portalProperty = getPortalProperty(); if (portalProperty) { char const * const exteriorAppearanceName = portalProperty->getPortalPropertyTemplate().getExteriorAppearanceName(); if (exteriorAppearanceName) exteriorAppearanceTemplate = AppearanceTemplateList::fetch(exteriorAppearanceName); } else { Appearance const * const appearance = getAppearance(); if (appearance) exteriorAppearanceTemplate = appearance->getAppearanceTemplate(); } NOT_NULL(exteriorAppearanceTemplate); return exteriorAppearanceTemplate; } // ---------------------------------------------------------------------- float ShipObject::getFastestWeaponProjectileSpeed() const { return m_fastestWeaponProjectileSpeed; } //---------------------------------------------------------------------- int ShipObject::getCargoHoldContentsMaximum() const { return m_cargoHoldContentsMaximum.get(); } //---------------------------------------------------------------------- bool ShipObject::setCargoHoldContentsMaximum(int contents) { if (isSlotInstalled(static_cast(ShipChassisSlotType::SCST_cargo_hold))) { m_cargoHoldContentsMaximum = contents; setCargoHoldContentsCurrent(getCargoHoldContentsCurrent()); return true; } return false; } //---------------------------------------------------------------------- int ShipObject::getCargoHoldContentsCurrent() const { return m_cargoHoldContentsCurrent.get(); } //---------------------------------------------------------------------- bool ShipObject::setCargoHoldContentsCurrent(int contents) { if (isSlotInstalled(static_cast(ShipChassisSlotType::SCST_cargo_hold))) { int const maximum = getCargoHoldContentsMaximum(); m_cargoHoldContentsCurrent = std::min(contents, maximum); return true; } return false; } //---------------------------------------------------------------------- ShipObject::NetworkIdIntMap const & ShipObject::getCargoHoldContents() const { return m_cargoHoldContents.getMap(); } //---------------------------------------------------------------------- void ShipObject::setCargoHoldContents(NetworkIdIntMap const & contents) { if (isSlotInstalled(static_cast(ShipChassisSlotType::SCST_cargo_hold))) { m_cargoHoldContents.clear(); NetworkIdIntMap::const_iterator const end = contents.end(); for (NetworkIdIntMap::const_iterator it = contents.begin(); it != end; ++it) { m_cargoHoldContents.insert(it->first, it->second); } setCargoHoldContentsCurrent(computeCargoHoldContentsCurrent()); } } //---------------------------------------------------------------------- void ShipObject::setCargoHoldContent(NetworkId const & resourceTypeId, int amount) { if (isSlotInstalled(static_cast(ShipChassisSlotType::SCST_cargo_hold))) { if (amount <= 0) { m_cargoHoldContents.erase(resourceTypeId); m_cargoHoldContentsResourceTypeInfo.erase(resourceTypeId); } else { ResourceTypeObject const * const resourceTypeObject = ServerUniverse::getInstance().getResourceTypeById(resourceTypeId); if (nullptr == ServerUniverse::getInstance().getResourceTypeById(resourceTypeId)) { WARNING(true, ("ShipObject::setCargoHoldContent invalid resource type [%s]", resourceTypeId.getValueString().c_str())); return; } bool alreadyHasThisResource = getCargoHoldContent(resourceTypeId) > 0; if (!alreadyHasThisResource) { m_cargoHoldContentsResourceTypeInfo.set( resourceTypeId, ResourceTypeInfoPair(Unicode::narrowToWide(resourceTypeObject->getResourceName()), resourceTypeObject->getParentClass().getResourceClassName())); } m_cargoHoldContents.set(resourceTypeId, amount); } setCargoHoldContentsCurrent(computeCargoHoldContentsCurrent()); } } //---------------------------------------------------------------------- int ShipObject::getCargoHoldContent(NetworkId const & resourceTypeId) const { if (isSlotInstalled(static_cast(ShipChassisSlotType::SCST_cargo_hold))) { NetworkIdIntMap::const_iterator const it = m_cargoHoldContents.find(resourceTypeId); if (it != m_cargoHoldContents.end()) { return (*it).second; } } return 0; } //---------------------------------------------------------------------- int ShipObject::computeCargoHoldContentsCurrent() const { int total = 0; NetworkIdIntMap::const_iterator const end = m_cargoHoldContents.end(); for (NetworkIdIntMap::const_iterator it = m_cargoHoldContents.begin(); it != end; ++it) { total += (*it).second; } return total; } //======================================================================