void Ship::TestLanded() { m_testLanded = false; if (m_launchLockTimeout > 0.0f) return; if (m_wheelState < 1.0f) return; if (GetFrame()->GetBody()->IsType(Object::PLANET)) { double speed = GetVelocity().Length(); vector3d up = GetPosition().Normalized(); const double planetRadius = static_cast<Planet*>(GetFrame()->GetBody())->GetTerrainHeight(up); if (speed < MAX_LANDING_SPEED) { // check player is sortof sensibly oriented for landing if (GetOrient().VectorY().Dot(up) > 0.99) { // position at zero altitude SetPosition(up * (planetRadius - GetAabb().min.y)); // position facing in roughly the same direction vector3d right = up.Cross(GetOrient().VectorZ()).Normalized(); SetOrient(matrix3x3d::FromVectors(right, up)); SetVelocity(vector3d(0, 0, 0)); SetAngVelocity(vector3d(0, 0, 0)); ClearThrusterState(); SetFlightState(LANDED); Sound::BodyMakeNoise(this, "Rough_Landing", 1.0f); LuaEvent::Queue("onShipLanded", this, GetFrame()->GetBody()); onLanded.emit(); } } } }
void Ship::EnterHyperspace() { assert(GetFlightState() != Ship::HYPERSPACE); const SystemPath dest = GetHyperspaceDest(); int fuel_cost; Ship::HyperjumpStatus status = CheckHyperspaceTo(dest, fuel_cost, m_hyperspace.duration); if (status != HYPERJUMP_OK) { // XXX something has changed (fuel loss, mass change, whatever). // could report it to the player but better would be to cancel the // countdown before this is reached. either way do something return; } Equip::Type fuelType = GetHyperdriveFuelType(); m_equipment.Remove(fuelType, fuel_cost); if (fuelType == Equip::MILITARY_FUEL) { m_equipment.Add(Equip::RADIOACTIVES, fuel_cost); } UpdateEquipStats(); LuaEvent::Queue("onLeaveSystem", this); SetFlightState(Ship::HYPERSPACE); // virtual call, do class-specific things OnEnterHyperspace(); }
void Ship::EnterHyperspace() { assert(GetFlightState() != Ship::HYPERSPACE); // Is it still a good idea, with the onLeaveSystem moved elsewhere? Ship::HyperjumpStatus status = CheckHyperjumpCapability(); if (status != HYPERJUMP_OK && status != HYPERJUMP_INITIATED) { if (m_flightState == JUMPING) SetFlightState(FLYING); return; } // Clear ships cached list of nearby bodies so we don't try to access them. m_nearbyBodies.clear(); SetFlightState(Ship::HYPERSPACE); // virtual call, do class-specific things OnEnterHyperspace(); }
void Ship::EnterSystem() { assert(GetFlightState() == Ship::HYPERSPACE); // virtual call, do class-specific things OnEnterSystem(); SetFlightState(Ship::FLYING); LuaEvent::Queue("onEnterSystem", this); }
void Ship::Blastoff() { if (m_flightState != LANDED) return; vector3d up = GetPosition().Normalized(); assert(GetFrame()->GetBody()->IsType(Object::PLANET)); const double planetRadius = 2.0 + static_cast<Planet*>(GetFrame()->GetBody())->GetTerrainHeight(up); SetVelocity(vector3d(0, 0, 0)); SetAngVelocity(vector3d(0, 0, 0)); SetFlightState(FLYING); SetPosition(up*planetRadius - GetAabb().min.y*up); SetThrusterState(1, 1.0); // thrust upwards LuaEvent::Queue("onShipTakeOff", this, GetFrame()->GetBody()); }
void Ship::SetLandedOn(Planet *p, float latitude, float longitude) { m_wheelTransition = 0; m_wheelState = 1.0f; Frame* f = p->GetFrame()->GetRotFrame(); SetFrame(f); vector3d up = vector3d(cos(latitude)*sin(longitude), sin(latitude), cos(latitude)*cos(longitude)); const double planetRadius = p->GetTerrainHeight(up); SetPosition(up * (planetRadius - GetAabb().min.y)); vector3d right = up.Cross(vector3d(0,0,1)).Normalized(); SetOrient(matrix3x3d::FromVectors(right, up)); SetVelocity(vector3d(0, 0, 0)); SetAngVelocity(vector3d(0, 0, 0)); ClearThrusterState(); SetFlightState(LANDED); LuaEvent::Queue("onShipLanded", this, p); onLanded.emit(); }
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); } }