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(); }
bool Ship::CanHyperspaceTo(const SystemPath *dest, int &outFuelRequired, double &outDurationSecs, enum HyperjumpStatus *outStatus) { Equip::Type t = m_equipment.Get(Equip::SLOT_ENGINE); Equip::Type fuelType = GetHyperdriveFuelType(); int hyperclass = EquipType::types[t].pval; int fuel = m_equipment.Count(Equip::SLOT_CARGO, fuelType); outFuelRequired = 0; if (hyperclass == 0) { if (outStatus) *outStatus = HYPERJUMP_NO_DRIVE; return false; } if (Pi::currentSystem && Pi::currentSystem->GetPath().IsSameSystem(*dest)) { if (outStatus) *outStatus = HYPERJUMP_CURRENT_SYSTEM; return false; } float dist = distance_to_system(dest); this->CalcStats(); outFuelRequired = int(ceil(hyperclass*hyperclass*dist / m_stats.hyperspace_range_max)); double m_totalmass = m_stats.total_mass; if (outFuelRequired > hyperclass*hyperclass) outFuelRequired = hyperclass*hyperclass; if (outFuelRequired < 1) outFuelRequired = 1; if (dist > m_stats.hyperspace_range_max) { outFuelRequired = 0; if (outStatus) *outStatus = HYPERJUMP_OUT_OF_RANGE; return false; } else if (fuel < outFuelRequired) { if (outStatus) *outStatus = HYPERJUMP_INSUFFICIENT_FUEL; return false; } else { // Old comments: // take at most a week. why a week? because a week is a // fundamental physical unit in the same sense that the planck length // is, and so it is very probable that future hyperspace // technologies will involve travelling a week through time. // Now mass has more of an effect on the time taken, this is mainly // for gameplay considerations for courier missions and the like. outDurationSecs = ((dist * dist * 0.5) / (m_stats.hyperspace_range_max * hyperclass)) * (60.0 * 60.0 * 24.0 * sqrt(m_totalmass)); //float hours = outDurationSecs * 0.0002778; //printf("%f LY in %f hours OR %d seconds \n", dist, hours, outDurationSecs); //printf("%d seconds\n", outDurationSecs); if (outFuelRequired <= fuel) { if (outStatus) *outStatus = HYPERJUMP_OK; return true; } else { if (outStatus) *outStatus = HYPERJUMP_INSUFFICIENT_FUEL; return false; } } }
void Ship::UseHyperspaceFuel(const SystemPath *dest) { int fuel_cost; Equip::Type fuelType = GetHyperdriveFuelType(); double dur; bool hscheck = CanHyperspaceTo(dest, fuel_cost, dur); assert(hscheck); m_equipment.Remove(fuelType, fuel_cost); if (fuelType == Equip::MILITARY_FUEL) { m_equipment.Add(Equip::RADIOACTIVES, fuel_cost); } }
Ship::HyperjumpStatus Ship::GetHyperspaceDetails(const SystemPath &dest, int &outFuelRequired, double &outDurationSecs) { assert(dest.HasValidSystem()); outFuelRequired = 0; outDurationSecs = 0.0; UpdateStats(); if (GetFlightState() == HYPERSPACE) return HYPERJUMP_DRIVE_ACTIVE; Equip::Type t = m_equipment.Get(Equip::SLOT_ENGINE); Equip::Type fuelType = GetHyperdriveFuelType(); int hyperclass = Equip::types[t].pval; int fuel = m_equipment.Count(Equip::SLOT_CARGO, fuelType); if (hyperclass == 0) return HYPERJUMP_NO_DRIVE; StarSystem *s = Pi::game->GetSpace()->GetStarSystem().Get(); if (s && s->GetPath().IsSameSystem(dest)) return HYPERJUMP_CURRENT_SYSTEM; float dist = distance_to_system(dest); outFuelRequired = Pi::CalcHyperspaceFuelOut(hyperclass, dist, m_stats.hyperspace_range_max); double m_totalmass = GetMass()/1000; if (dist > m_stats.hyperspace_range_max) { outFuelRequired = 0; return HYPERJUMP_OUT_OF_RANGE; } else if (fuel < outFuelRequired) { return HYPERJUMP_INSUFFICIENT_FUEL; } else { outDurationSecs = Pi::CalcHyperspaceDuration(hyperclass, m_totalmass, dist); if (outFuelRequired <= fuel) { return HYPERJUMP_OK; } else { return HYPERJUMP_INSUFFICIENT_FUEL; } } }
void Ship::UpdateEquipStats() { const ShipType &stype = GetShipType(); m_stats.max_capacity = stype.capacity; m_stats.used_capacity = 0; m_stats.used_cargo = 0; for (int i=0; i<Equip::SLOT_MAX; i++) { for (int j=0; j<stype.equipSlotCapacity[i]; j++) { Equip::Type t = m_equipment.Get(Equip::Slot(i), j); if (t) m_stats.used_capacity += Equip::types[t].mass; if (Equip::Slot(i) == Equip::SLOT_CARGO) m_stats.used_cargo += Equip::types[t].mass; } } m_stats.free_capacity = m_stats.max_capacity - m_stats.used_capacity; m_stats.total_mass = m_stats.used_capacity + stype.hullMass; m_stats.shield_mass = TONS_HULL_PER_SHIELD * float(m_equipment.Count(Equip::SLOT_SHIELD, Equip::SHIELD_GENERATOR)); UpdateMass(); UpdateFuelStats(); Equip::Type fuelType = GetHyperdriveFuelType(); if (stype.equipSlotCapacity[Equip::SLOT_ENGINE]) { Equip::Type t = m_equipment.Get(Equip::SLOT_ENGINE); int hyperclass = Equip::types[t].pval; if (!hyperclass) { // no drive m_stats.hyperspace_range = m_stats.hyperspace_range_max = 0; } else { m_stats.hyperspace_range_max = Pi::CalcHyperspaceRangeMax(hyperclass, GetMass()/1000); m_stats.hyperspace_range = Pi::CalcHyperspaceRange(hyperclass, GetMass()/1000, m_equipment.Count(Equip::SLOT_CARGO, fuelType)); } } else { m_stats.hyperspace_range = m_stats.hyperspace_range_max = 0; } }
const shipstats_t *Ship::CalcStats() { const ShipType &stype = GetShipType(); m_stats.max_capacity = stype.capacity; m_stats.used_capacity = 0; m_stats.used_cargo = 0; Equip::Type fuelType = GetHyperdriveFuelType(); for (int i=0; i<Equip::SLOT_MAX; i++) { for (int j=0; j<stype.equipSlotCapacity[i]; j++) { Equip::Type t = m_equipment.Get(Equip::Slot(i), j); if (t) m_stats.used_capacity += EquipType::types[t].mass; if (Equip::Slot(i) == Equip::SLOT_CARGO) m_stats.used_cargo += EquipType::types[t].mass; } } m_stats.free_capacity = m_stats.max_capacity - m_stats.used_capacity; m_stats.total_mass = m_stats.used_capacity + stype.hullMass; m_stats.shield_mass = TONS_HULL_PER_SHIELD * float(m_equipment.Count(Equip::SLOT_SHIELD, Equip::SHIELD_GENERATOR)); if (stype.equipSlotCapacity[Equip::SLOT_ENGINE]) { Equip::Type t = m_equipment.Get(Equip::SLOT_ENGINE); int hyperclass = EquipType::types[t].pval; if (!hyperclass) { // no drive m_stats.hyperspace_range = m_stats.hyperspace_range_max = 0; } else { // for the sake of hyperspace range, we count ships mass as 60% of original. m_stats.hyperspace_range_max = Pi::CalcHyperspaceRange(hyperclass, m_stats.total_mass); m_stats.hyperspace_range = std::min(m_stats.hyperspace_range_max, m_stats.hyperspace_range_max * m_equipment.Count(Equip::SLOT_CARGO, fuelType) / (hyperclass * hyperclass)); } } else { m_stats.hyperspace_range = m_stats.hyperspace_range_max = 0; } return &m_stats; }