void Ship::StaticUpdate(const float timeStep) { // do player sounds before dead check, so they also turn off if (IsType(Object::PLAYER)) DoThrusterSounds(); if (IsDead()) return; if (m_controller) m_controller->StaticUpdate(timeStep); if (GetHullTemperature() > 1.0) Explode(); UpdateAlertState(); /* FUEL SCOOPING!!!!!!!!! */ int capacity = 0; Properties().Get("fuel_scoop_cap", capacity); if (m_flightState == FLYING && capacity > 0) { Body *astro = GetFrame()->GetBody(); if (astro && astro->IsType(Object::PLANET)) { Planet *p = static_cast<Planet*>(astro); if (p->GetSystemBody()->IsScoopable()) { double dist = GetPosition().Length(); double pressure, density; p->GetAtmosphericState(dist, &pressure, &density); double speed = GetVelocity().Length(); vector3d vdir = GetVelocity().Normalized(); vector3d pdir = -GetOrient().VectorZ(); double dot = vdir.Dot(pdir); if ((m_stats.free_capacity) && (dot > 0.95) && (speed > 2000.0) && (density > 1.0)) { double rate = speed*density*0.00000333f*double(capacity); if (Pi::rng.Double() < rate) { lua_State *l = Lua::manager->GetLuaState(); pi_lua_import(l, "Equipment"); LuaTable hydrogen = LuaTable(l, -1).Sub("cargo").Sub("hydrogen"); LuaObject<Ship>::CallMethod(this, "AddEquip", hydrogen); UpdateEquipStats(); if (this->IsType(Object::PLAYER)) { Pi::game->log->Add(stringf(Lang::FUEL_SCOOP_ACTIVE_N_TONNES_H_COLLECTED, formatarg("quantity", LuaObject<Ship>::CallMethod<int>(this, "CountEquip", hydrogen)))); } lua_pop(l, 3); } } } } } // Cargo bay life support capacity = 0; Properties().Get("cargo_life_support_cap", capacity); if (!capacity) { // Hull is pressure-sealed, it just doesn't provide // temperature regulation and breathable atmosphere // kill stuff roughly every 5 seconds if ((!m_dockedWith) && (5.0*Pi::rng.Double() < timeStep)) { std::string t(Pi::rng.Int32(2) ? "live_animals" : "slaves"); lua_State *l = Lua::manager->GetLuaState(); pi_lua_import(l, "Equipment"); LuaTable cargo = LuaTable(l, -1).Sub("cargo"); if (LuaObject<Ship>::CallMethod<int>(this, "RemoveEquip", cargo.Sub(t))) { LuaObject<Ship>::CallMethod<int>(this, "AddEquip", cargo.Sub("fertilizer")); if (this->IsType(Object::PLAYER)) { Pi::game->log->Add(Lang::CARGO_BAY_LIFE_SUPPORT_LOST); } lua_pop(l, 4); } else lua_pop(l, 3); } } if (m_flightState == FLYING) m_launchLockTimeout -= timeStep; if (m_launchLockTimeout < 0) m_launchLockTimeout = 0; if (m_flightState == JUMPING || m_flightState == HYPERSPACE) m_launchLockTimeout = 0; // lasers for (int i=0; i<ShipType::GUNMOUNT_MAX; i++) { m_gun[i].recharge -= timeStep; float rateCooling = 0.01f; float cooler = 1.0f; Properties().Get("laser_cooler_cap", cooler); rateCooling *= cooler; m_gun[i].temperature -= rateCooling*timeStep; if (m_gun[i].temperature < 0.0f) m_gun[i].temperature = 0; if (m_gun[i].recharge < 0.0f) m_gun[i].recharge = 0; if (!m_gun[i].state) continue; if (m_gun[i].recharge > 0.0f) continue; if (m_gun[i].temperature > 1.0) continue; FireWeapon(i); } if (m_ecmRecharge > 0.0f) { m_ecmRecharge = std::max(0.0f, m_ecmRecharge - timeStep); } if (m_shieldCooldown > 0.0f) { m_shieldCooldown = std::max(0.0f, m_shieldCooldown - timeStep); } if (m_stats.shield_mass_left < m_stats.shield_mass) { // 250 second recharge float recharge_rate = 0.004f; float booster = 1.0f; Properties().Get("shield_energy_booster_cap", booster); recharge_rate *= booster; m_stats.shield_mass_left = Clamp(m_stats.shield_mass_left + m_stats.shield_mass * recharge_rate * timeStep, 0.0f, m_stats.shield_mass); Properties().Set("shieldMassLeft", m_stats.shield_mass_left); } if (m_wheelTransition) { m_wheelState += m_wheelTransition*0.3f*timeStep; m_wheelState = Clamp(m_wheelState, 0.0f, 1.0f); if (is_equal_exact(m_wheelState, 0.0f) || is_equal_exact(m_wheelState, 1.0f)) m_wheelTransition = 0; } if (m_testLanded) TestLanded(); capacity = 0; Properties().Get("hull_autorepair_cap", capacity); if (capacity) { m_stats.hull_mass_left = std::min(m_stats.hull_mass_left + 0.1f*timeStep, float(m_type->hullMass)); Properties().Set("hullMassLeft", m_stats.hull_mass_left); Properties().Set("hullPercent", 100.0f * (m_stats.hull_mass_left / float(m_type->hullMass))); } // After calling StartHyperspaceTo this Ship must not spawn objects // holding references to it (eg missiles), as StartHyperspaceTo // removes the ship from Space::bodies and so the missile will not // have references to this cleared by NotifyRemoved() if (m_hyperspace.now) { m_hyperspace.now = false; EnterHyperspace(); } if (m_hyperspace.countdown > 0.0f) { // Check the Lua function bool abort = false; lua_State * l = m_hyperspace.checks.GetLua(); if (l) { m_hyperspace.checks.PushCopyToStack(); if (lua_isfunction(l, -1)) { lua_call(l, 0, 1); abort = !lua_toboolean(l, -1); lua_pop(l, 1); } } if (abort) { AbortHyperjump(); } else { m_hyperspace.countdown = m_hyperspace.countdown - timeStep; if (!abort && m_hyperspace.countdown <= 0.0f) { m_hyperspace.countdown = 0; m_hyperspace.now = true; SetFlightState(JUMPING); // We have to fire it here, because the event isn't actually fired until // after the whole physics update, which means the flight state on next // step would be HYPERSPACE, thus breaking quite a few things. LuaEvent::Queue("onLeaveSystem", this); } } } //Add smoke trails for missiles on thruster state static double s_timeAccum = 0.0; s_timeAccum += timeStep; if (m_type->tag == ShipType::TAG_MISSILE && !is_equal_exact(m_thrusters.LengthSqr(), 0.0) && (s_timeAccum > 4 || 0.1*Pi::rng.Double() < timeStep)) { s_timeAccum = 0.0; const vector3d pos = GetOrient() * vector3d(0, 0 , 5); const float speed = std::min(10.0*GetVelocity().Length()*std::max(1.0,fabs(m_thrusters.z)),100.0); SfxManager::AddThrustSmoke(this, speed, pos); } }
void Ship::StaticUpdate(const float timeStep) { // do player sounds before dead check, so they also turn off if (IsType(Object::PLAYER)) DoThrusterSounds(); if (IsDead()) return; if (m_controller) m_controller->StaticUpdate(timeStep); if (GetHullTemperature() > 1.0) Explode(); UpdateAlertState(); /* FUEL SCOOPING!!!!!!!!! */ if ((m_flightState == FLYING) && (m_equipment.Get(Equip::SLOT_FUELSCOOP) != Equip::NONE)) { Body *astro = GetFrame()->GetBody(); if (astro && astro->IsType(Object::PLANET)) { Planet *p = static_cast<Planet*>(astro); if (p->GetSystemBody()->IsScoopable()) { double dist = GetPosition().Length(); double pressure, density; p->GetAtmosphericState(dist, &pressure, &density); double speed = GetVelocity().Length(); vector3d vdir = GetVelocity().Normalized(); vector3d pdir = -GetOrient().VectorZ(); double dot = vdir.Dot(pdir); if ((m_stats.free_capacity) && (dot > 0.95) && (speed > 2000.0) && (density > 1.0)) { double rate = speed*density*0.00001f; if (Pi::rng.Double() < rate) { m_equipment.Add(Equip::HYDROGEN); UpdateEquipStats(); if (this->IsType(Object::PLAYER)) { Pi::Message(stringf(Lang::FUEL_SCOOP_ACTIVE_N_TONNES_H_COLLECTED, formatarg("quantity", m_equipment.Count(Equip::SLOT_CARGO, Equip::HYDROGEN)))); } } } } } } // Cargo bay life support if (m_equipment.Get(Equip::SLOT_CARGOLIFESUPPORT) != Equip::CARGO_LIFE_SUPPORT) { // Hull is pressure-sealed, it just doesn't provide // temperature regulation and breathable atmosphere // kill stuff roughly every 5 seconds if ((!m_dockedWith) && (5.0*Pi::rng.Double() < timeStep)) { Equip::Type t = (Pi::rng.Int32(2) ? Equip::LIVE_ANIMALS : Equip::SLAVES); if (m_equipment.Remove(t, 1)) { m_equipment.Add(Equip::FERTILIZER); if (this->IsType(Object::PLAYER)) { Pi::Message(Lang::CARGO_BAY_LIFE_SUPPORT_LOST); } } } } if (m_flightState == FLYING) m_launchLockTimeout -= timeStep; if (m_launchLockTimeout < 0) m_launchLockTimeout = 0; // lasers for (int i=0; i<ShipType::GUNMOUNT_MAX; i++) { m_gunRecharge[i] -= timeStep; float rateCooling = 0.01f; if (m_equipment.Get(Equip::SLOT_LASERCOOLER) != Equip::NONE) { rateCooling *= float(Equip::types[ m_equipment.Get(Equip::SLOT_LASERCOOLER) ].pval); } m_gunTemperature[i] -= rateCooling*timeStep; if (m_gunTemperature[i] < 0.0f) m_gunTemperature[i] = 0; if (m_gunRecharge[i] < 0.0f) m_gunRecharge[i] = 0; if (!m_gunState[i]) continue; if (m_gunRecharge[i] > 0.0f) continue; if (m_gunTemperature[i] > 1.0) continue; FireWeapon(i); } if (m_ecmRecharge > 0.0f) { m_ecmRecharge = std::max(0.0f, m_ecmRecharge - timeStep); } if (m_stats.shield_mass_left < m_stats.shield_mass) { // 250 second recharge float recharge_rate = 0.004f; if (m_equipment.Get(Equip::SLOT_ENERGYBOOSTER) != Equip::NONE) { recharge_rate *= float(Equip::types[ m_equipment.Get(Equip::SLOT_ENERGYBOOSTER) ].pval); } m_stats.shield_mass_left += m_stats.shield_mass * recharge_rate * timeStep; } m_stats.shield_mass_left = Clamp(m_stats.shield_mass_left, 0.0f, m_stats.shield_mass); if (m_wheelTransition) { m_wheelState += m_wheelTransition*0.3f*timeStep; m_wheelState = Clamp(m_wheelState, 0.0f, 1.0f); if (is_equal_exact(m_wheelState, 0.0f) || is_equal_exact(m_wheelState, 1.0f)) m_wheelTransition = 0; } if (m_testLanded) TestLanded(); if (m_equipment.Get(Equip::SLOT_HULLAUTOREPAIR) == Equip::HULL_AUTOREPAIR) { const ShipType &stype = GetShipType(); m_stats.hull_mass_left = std::min(m_stats.hull_mass_left + 0.1f*timeStep, float(stype.hullMass)); } // After calling StartHyperspaceTo this Ship must not spawn objects // holding references to it (eg missiles), as StartHyperspaceTo // removes the ship from Space::bodies and so the missile will not // have references to this cleared by NotifyRemoved() if (m_hyperspace.countdown > 0.0f) { m_hyperspace.countdown = m_hyperspace.countdown - timeStep; if (m_hyperspace.countdown <= 0.0f) { m_hyperspace.countdown = 0; m_hyperspace.now = true; } } if (m_hyperspace.now) { m_hyperspace.now = false; EnterHyperspace(); } }