From bff6ff3add3af9d742b33d7cf58db1fe560fd57c Mon Sep 17 00:00:00 2001 From: Roy Falk Date: Thu, 15 Aug 2024 06:57:26 +0300 Subject: [PATCH] Lib Component - connect core components (#871) * Add Component, Reactor, EConsumer and EContainer classes Add unit tests. Remove UnitCsvFactory reliance on VSFileSystem for better separation of concerns. Game doesn't build because unit tests require VSFileSystem and that pulls in half the game with it. As this is imported from the original lib component branch by file, some stuff here is for future commits. * Fix error C7555 in CICD on windows use of designated initializers requires at least '/std:c++20' * Fix bug - Implement Downgrade in Component Reverse order of visibility in EnergyConsumer. Make visibility modifiers explicit in EnergyContainer and Reactor. * Connect reactor, capacitor and ftl_capacitor to engine. * Fix multiplication warnings --- engine/src/cmd/armed.cpp | 15 +- engine/src/cmd/armed.h | 1 + engine/src/cmd/basecomputer.cpp | 7 + engine/src/cmd/carrier.cpp | 27 ++-- engine/src/cmd/carrier.h | 1 + engine/src/cmd/cloak.cpp | 9 +- engine/src/cmd/cloak.h | 5 +- engine/src/cmd/energetic.cpp | 177 +++++++++++---------- engine/src/cmd/energetic.h | 19 +-- engine/src/cmd/intelligent.cpp | 5 +- engine/src/cmd/intelligent.h | 1 + engine/src/cmd/jump_capable.cpp | 19 +-- engine/src/cmd/mount.cpp | 6 +- engine/src/cmd/movable.cpp | 63 ++++---- engine/src/cmd/planet.cpp | 2 +- engine/src/cmd/unit_csv.cpp | 38 +++-- engine/src/cmd/unit_generic.cpp | 56 +++---- engine/src/cmd/unit_generic.h | 12 ++ engine/src/cmd/unit_util_generic.cpp | 29 ++++ engine/src/cmd/upgradeable_unit.cpp | 110 +++++++++++++ engine/src/cmd/upgradeable_unit.h | 37 +++++ engine/src/components/component.cpp | 15 ++ engine/src/components/component.h | 3 +- engine/src/components/energy_container.cpp | 7 + engine/src/components/energy_container.h | 3 + engine/src/components/reactor.cpp | 15 +- engine/src/components/reactor.h | 5 +- 27 files changed, 466 insertions(+), 221 deletions(-) diff --git a/engine/src/cmd/armed.cpp b/engine/src/cmd/armed.cpp index 40f99bb2b6..eb0e0edf50 100644 --- a/engine/src/cmd/armed.cpp +++ b/engine/src/cmd/armed.cpp @@ -37,6 +37,7 @@ #include "unit_util.h" #include "vs_logging.h" #include "resource/resource.h" +#include "vega_cast_utils.h" #include @@ -250,14 +251,14 @@ void Armed::Fire(unsigned int weapon_type_bitmask, bool listen_to_owner) { //&& ( (ROLES::EVERYTHING_ELSE&weapon_type_bitmask&i->type->role_bits) || i->type->role_bits == 0 ) ((locked_on && missile_and_want_to_fire_missiles) || gun_and_want_to_fire_guns); if ((*i).type->type == WEAPON_TYPE::BEAM) { - if ((*i).type->energy_rate * simulation_atom_var > unit->energy) { + if ((*i).type->energy_rate * static_cast(simulation_atom_var) > unit->energy.Level()) { //NOT ONLY IN non-networking mode : anyway, the server will tell everyone including us to stop if not already done (*i).UnFire(); continue; } } else //Only in non-networking mode - if (i->type->energy_rate > unit->energy) { + if (i->type->energy_rate > unit->energy.Level()) { if (!want_to_fire) { i->UnFire(); } @@ -277,11 +278,11 @@ void Armed::Fire(unsigned int weapon_type_bitmask, bool listen_to_owner) { if (i->type->type == WEAPON_TYPE::BEAM) { if (i->ref.gun) { if ((!i->ref.gun->Dissolved()) || i->ref.gun->Ready()) { - unit->energy -= i->type->energy_rate * simulation_atom_var; + unit->energy.Deplete(true, i->type->energy_rate * static_cast(simulation_atom_var)); } } } else if (i->type->isMissile()) { // FIXME other than beams, only missiles are processed here? - unit->energy -= i->type->energy_rate; + unit->energy.Deplete(true, i->type->energy_rate); } //IF WE REFRESH ENERGY FROM SERVER : Think to send the energy update to the firing client with ACK TO fireRequest //fire only 1 missile at a time @@ -333,7 +334,7 @@ void Armed::LockTarget(bool myboo) { } QVector Armed::PositionITTS(const QVector &absposit, Vector velocity, float speed, bool steady_itts) const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); if (speed == FLT_MAX) { return unit->Position(); } @@ -412,7 +413,7 @@ void Armed::setAverageGunSpeed() { } bool Armed::TargetLocked(const Unit *checktarget) const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); if (!unit->computer.radar.locked) { return false; } @@ -449,7 +450,7 @@ void Armed::ToggleWeapon(bool missile, bool forward) { } float Armed::TrackingGuns(bool &missilelock) { - const Unit *unit = static_cast(this); + Unit *unit = vega_dynamic_cast_ptr(this); float trackingcone = 0; missilelock = false; for (int i = 0; i < getNumMounts(); ++i) { diff --git a/engine/src/cmd/armed.h b/engine/src/cmd/armed.h index 56f57af709..e7d6054ffa 100644 --- a/engine/src/cmd/armed.h +++ b/engine/src/cmd/armed.h @@ -49,6 +49,7 @@ class Armed { public: Armed(); + virtual ~Armed() = default; //Fires all active guns that are or arent Missiles //if bitmask is (1<<31) then fire off autotracking of that type; diff --git a/engine/src/cmd/basecomputer.cpp b/engine/src/cmd/basecomputer.cpp index 52f82ad4bc..138547e734 100644 --- a/engine/src/cmd/basecomputer.cpp +++ b/engine/src/cmd/basecomputer.cpp @@ -3656,6 +3656,7 @@ void BaseComputer::SellUpgradeOperation::selectMount(void) { } //Check, and verify user wants Sell Upgrade transaction. Returns true if more input is required. +// Only applies to mounts! bool BaseComputer::SellUpgradeOperation::checkTransaction(void) { Unit *playerUnit = m_parent.m_player.GetUnit(); if (!playerUnit) { @@ -3675,6 +3676,7 @@ bool BaseComputer::SellUpgradeOperation::checkTransaction(void) { } //Finish the transaction. +// Only applies to mounts! void BaseComputer::SellUpgradeOperation::concludeTransaction(void) { Unit *playerUnit = m_parent.m_player.GetUnit(); Unit *baseUnit = m_parent.m_base.GetUnit(); @@ -3750,7 +3752,12 @@ bool BaseComputer::sellUpgrade(const EventCommandId &command, Control *control) Unit *baseUnit = m_base.GetUnit(); if (baseUnit && playerUnit) { playerUnit->SellCargo(item->GetName(), quantity, _Universe->AccessCockpit()->credits, sold, baseUnit); + + // Old system UnitUtil::RecomputeUnitUpgrades(playerUnit); + + // New system + UpgradeOperationResult result = playerUnit->UpgradeUnit(item->GetName(), false, true); refresh(); } return true; diff --git a/engine/src/cmd/carrier.cpp b/engine/src/cmd/carrier.cpp index 47c509a191..540cd3d29a 100644 --- a/engine/src/cmd/carrier.cpp +++ b/engine/src/cmd/carrier.cpp @@ -34,6 +34,7 @@ #include "missile.h" #include "vs_random.h" #include "vs_logging.h" +#include "vega_cast_utils.h" #include "json.h" @@ -494,12 +495,12 @@ bool cargoIsUpgrade(const Cargo &c) { } float Carrier::getHiddenCargoVolume() const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); return unit->HiddenCargoVolume; } bool Carrier::CanAddCargo(const Cargo &carg) const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); //Always can, in this case (this accounts for some odd precision issues) if ((carg.quantity == 0) || (carg.GetVolume() == 0)) { @@ -523,17 +524,17 @@ bool Carrier::CanAddCargo(const Cargo &carg) const { //The cargo volume of this ship when empty. Max cargo volume. float Carrier::getEmptyCargoVolume(void) const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); return unit->CargoVolume; } float Carrier::getEmptyUpgradeVolume(void) const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); return unit->UpgradeVolume; } float Carrier::getCargoVolume(void) const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); float result = 0.0; for (unsigned int i = 0; i < unit->cargo.size(); ++i) { if (!cargoIsUpgrade(unit->cargo[i])) { @@ -567,7 +568,7 @@ float Carrier::PriceCargo(const std::string &s) { } float Carrier::getUpgradeVolume(void) const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); float result = 0.0; for (unsigned int i = 0; i < unit->cargo.size(); ++i) { if (cargoIsUpgrade(unit->cargo[i])) { @@ -583,7 +584,7 @@ Cargo &Carrier::GetCargo(unsigned int i) { } const Cargo &Carrier::GetCargo(unsigned int i) const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); return unit->cargo[i]; } @@ -609,7 +610,7 @@ void Carrier::GetSortedCargoCat(const std::string &cat, size_t &begin, size_t &e // The game also crashed due to endless loop. // I returned the code and now it works and I don't know why. Cargo *Carrier::GetCargo(const std::string &s, unsigned int &i) { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); if (unit->GetCargo(s, i)) { return &GetCargo(i); } @@ -617,7 +618,7 @@ Cargo *Carrier::GetCargo(const std::string &s, unsigned int &i) { } const Cargo *Carrier::GetCargo(const std::string &s, unsigned int &i) const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); static Hashtable index_cache_table; Unit *mpl = getMasterPartList(); @@ -670,12 +671,12 @@ const Cargo *Carrier::GetCargo(const std::string &s, unsigned int &i) const { } unsigned int Carrier::numCargo() const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); return unit->cargo.size(); } std::string Carrier::GetManifest(unsigned int i, Unit *scanningUnit, const Vector &oldspd) const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); ///FIXME somehow mangle string string mangled = unit->cargo[i].name; @@ -700,7 +701,7 @@ std::string Carrier::GetManifest(unsigned int i, Unit *scanningUnit, const Vecto } bool Carrier::SellCargo(unsigned int i, int quantity, float &creds, Cargo &carg, Unit *buyer) { - const Unit *unit = static_cast(this); + Unit *unit = vega_dynamic_cast_ptr(this); if (i < 0 || i >= unit->cargo.size() || !buyer->CanAddCargo(unit->cargo[i]) || unit->getMass() < unit->cargo[i].GetMass()) { @@ -721,7 +722,7 @@ bool Carrier::SellCargo(unsigned int i, int quantity, float &creds, Cargo &carg, } bool Carrier::SellCargo(const std::string &s, int quantity, float &creds, Cargo &carg, Unit *buyer) { - const Unit *unit = static_cast(this); + Unit *unit = vega_dynamic_cast_ptr(this); Cargo tmp; tmp.name = s; diff --git a/engine/src/cmd/carrier.h b/engine/src/cmd/carrier.h index e334e5d56e..6fa662f888 100644 --- a/engine/src/cmd/carrier.h +++ b/engine/src/cmd/carrier.h @@ -40,6 +40,7 @@ class Carrier { std::vector cargo; Carrier(); + virtual ~Carrier() = default; void SortCargo(); static std::string cargoSerializer(const struct XMLType &input, void *mythis); diff --git a/engine/src/cmd/cloak.cpp b/engine/src/cmd/cloak.cpp index 7f20ef5c86..f74cc0c2f6 100644 --- a/engine/src/cmd/cloak.cpp +++ b/engine/src/cmd/cloak.cpp @@ -26,6 +26,7 @@ #include "unit_csv_factory.h" #include "vegastrike.h" #include "configuration/configuration.h" +#include "unit_generic.h" Cloak::Cloak() { @@ -63,7 +64,7 @@ void Cloak::Save(std::map& unit) unit["Cloak_Glass"] = std::to_string(glass); } -void Cloak::Update(Energetic *energetic) +void Cloak::Update(Unit *unit) { // Unit is not capable of cloaking or damaged or just not cloaking if(status == CloakingStatus::disabled || @@ -74,7 +75,7 @@ void Cloak::Update(Energetic *energetic) // Use warp power for cloaking (SPEC capacitor) const static bool warp_energy_for_cloak = configuration()->warp_config.use_warp_energy_for_cloak; - double available_energy = warp_energy_for_cloak ? energetic->warpenergy : energetic->energy.Value(); + double available_energy = warp_energy_for_cloak ? unit->ftl_energy.Level() : unit->energy.Level(); // Insufficient energy to cloak ship @@ -83,9 +84,9 @@ void Cloak::Update(Energetic *energetic) } else { // Subtract the energy used if (warp_energy_for_cloak) { - energetic->warpenergy -= (simulation_atom_var * energy); + unit->ftl_energy.Deplete(true, simulation_atom_var * energy); } else { - energetic->energy -= (simulation_atom_var * energy); + unit->energy.Deplete(true, simulation_atom_var * energy); } } diff --git a/engine/src/cmd/cloak.h b/engine/src/cmd/cloak.h index 967145d279..2a63e76b44 100644 --- a/engine/src/cmd/cloak.h +++ b/engine/src/cmd/cloak.h @@ -31,6 +31,9 @@ #include "energetic.h" #include "damageable_layer.h" +// TODO: remove dependency on unit +class Unit; + enum class CloakingStatus { disabled, damaged, @@ -67,7 +70,7 @@ class Cloak Cloak(std::string unit_key); void Save(std::map& unit); - void Update(Energetic *energetic); + void Update(Unit *unit); void Toggle(); // Toggle cloak on/off bool Capable() const { diff --git a/engine/src/cmd/energetic.cpp b/engine/src/cmd/energetic.cpp index 2f0a4091df..4f94ebca12 100644 --- a/engine/src/cmd/energetic.cpp +++ b/engine/src/cmd/energetic.cpp @@ -31,6 +31,7 @@ #include "unit_generic.h" #include "universe.h" #include "resource/resource.h" +#include "vega_cast_utils.h" #include @@ -38,13 +39,10 @@ * ships, space installations, missiles, drones, etc. */ -Energetic::Energetic() : energy(0, 0), - recharge(0), - maxwarpenergy(0), - warpenergy(0), +Energetic::Energetic() : constrained_charge_to_shields(0.0f), sufficient_energy_to_recharge_shields(true), - fuel(0), + //fuel(0), afterburnenergy(0), afterburntype(0) { jump.warpDriveRating = 0; @@ -55,21 +53,22 @@ Energetic::Energetic() : energy(0, 0), jump.damage = 0; } -void Energetic::decreaseWarpEnergy(bool insys, float time) { +void Energetic::decreaseWarpEnergy(bool insys, double time) { + Unit *unit = vega_dynamic_cast_ptr(this); + if (configuration()->fuel.fuel_equals_warp) { - this->warpenergy = this->fuel; - } - this->warpenergy -= (insys ? jump.insysenergy / configuration()->warp_config.bleed_factor : jump.energy) * time; - if (this->warpenergy < 0) { - this->warpenergy = 0; + unit->ftl_energy.SetLevel(unit->fuel.Level()); } + + unit->ftl_energy.Deplete(true, (insys ? jump.insysenergy / configuration()->warp_config.bleed_factor : jump.energy) * time); + if (configuration()->fuel.fuel_equals_warp) { - this->fuel = this->warpenergy; + unit->fuel.SetLevel(unit->ftl_energy.Level()); } } void Energetic::DecreaseWarpEnergyInWarp() { - Unit *unit = static_cast(this); + Unit *unit = vega_dynamic_cast_ptr(this); const bool in_warp = unit->graphicOptions.InWarp; @@ -80,8 +79,8 @@ void Energetic::DecreaseWarpEnergyInWarp() { //FIXME FIXME FIXME // Roy Falk - fix what? float bleed = jump.insysenergy / configuration()->warp_config.bleed_factor * simulation_atom_var; - if (warpenergy > bleed) { - warpenergy -= bleed; + if (unit->ftl_energy.Level() > bleed) { + unit->ftl_energy.Deplete(true, bleed); } else { unit->graphicOptions.InWarp = 0; unit->graphicOptions.WarpRamping = 1; @@ -89,24 +88,27 @@ void Energetic::DecreaseWarpEnergyInWarp() { } float Energetic::energyData() const { + const Unit *unit = vega_dynamic_cast_ptr(this); float capacitance = const_cast(this)->totalShieldEnergyCapacitance(); if (configuration()->physics_config.max_shield_lowers_capacitance) { - if (energy.MaxValue() <= capacitance) { + if (unit->energy.MaxLevel() <= capacitance) { return 0; } - return (energy) / (energy.MaxValue() - capacitance); + return (unit->energy.Level()) / (unit->energy.MaxLevel() - capacitance); } else { - return energy.Percent(); + return unit->energy.Percent(); } } float Energetic::energyRechargeData() const { - return recharge; + const Unit *unit = vega_dynamic_cast_ptr(this); + return unit->reactor.Capacity(); } float Energetic::fuelData() const { - return fuel; + const Unit *unit = vega_dynamic_cast_ptr(this); + return unit->fuel.Level(); } float Energetic::getFuelUsage(bool afterburner) { @@ -123,14 +125,15 @@ float Energetic::getFuelUsage(bool afterburner) { */ // TODO: this is still an ugly hack void Energetic::WCWarpIsFuelHack(bool transfer_warp_to_fuel) { + Unit *unit = vega_dynamic_cast_ptr(this); if (!configuration()->fuel.fuel_equals_warp) { return; } if (transfer_warp_to_fuel) { - fuel = warpenergy; + unit->fuel.SetLevel(unit->ftl_energy.Level()); } else { - warpenergy = fuel; + unit->ftl_energy.SetLevel(unit->fuel.Level()); } } @@ -148,59 +151,60 @@ float Energetic::ExpendMomentaryFuelUsage(float magnitude) { * @param quantity - requested quantity to use * @return - actual quantity used */ -float Energetic::ExpendFuel(float quantity) { - fuel -= configuration()->fuel.normal_fuel_usage * quantity; - - if (fuel < 0) { - quantity += fuel; - fuel = 0; - } - - return quantity; +float Energetic::ExpendFuel(double quantity) { + Unit *unit = vega_dynamic_cast_ptr(this); + return quantity * unit->fuel.Deplete(true, configuration()->fuel.normal_fuel_usage * quantity); } float Energetic::getWarpEnergy() const { - return warpenergy; + const Unit *unit = vega_dynamic_cast_ptr(this); + return unit->ftl_energy.Level(); } -void Energetic::increaseWarpEnergy(bool insys, float time) { +void Energetic::increaseWarpEnergy(bool insys, double time) { + Unit *unit = vega_dynamic_cast_ptr(this); if (configuration()->fuel.fuel_equals_warp) { - this->warpenergy = this->fuel; - } - this->warpenergy += (insys ? jump.insysenergy : jump.energy) * time; - if (this->warpenergy > this->maxwarpenergy) { - this->warpenergy = this->maxwarpenergy; + unit->ftl_energy.SetLevel(unit->fuel.Level()); } + + unit->ftl_energy.Charge((insys ? jump.insysenergy : jump.energy) * time); + if (configuration()->fuel.fuel_equals_warp) { - this->fuel = this->warpenergy; + unit->fuel.SetLevel(unit->ftl_energy.Level()); } } float Energetic::maxEnergyData() const { - return energy.MaxValue(); + const Unit *unit = vega_dynamic_cast_ptr(this); + return unit->energy.MaxLevel(); } void Energetic::rechargeEnergy() { - if ((!configuration()->fuel.reactor_uses_fuel) || (fuel > 0)) { - energy += recharge * simulation_atom_var; + Unit *unit = vega_dynamic_cast_ptr(this); + if ((!configuration()->fuel.reactor_uses_fuel) || (!unit->fuel.Depleted())) { + unit->energy.Charge(unit->reactor.Capacity() * simulation_atom_var); } } bool Energetic::refillWarpEnergy() { + Unit *unit = vega_dynamic_cast_ptr(this); if (configuration()->fuel.fuel_equals_warp) { - this->warpenergy = this->fuel; - } - float tmp = this->maxwarpenergy; - if (tmp < this->jump.energy) { - tmp = this->jump.energy; + unit->ftl_energy.SetLevel(unit->fuel.Level()); } - if (tmp > this->warpenergy) { - this->warpenergy = tmp; + + // TODO: move this elsewhere. It should be evaluated every time. + if (unit->ftl_energy.MaxLevel() < this->jump.energy) { + unit->ftl_energy.SetCapacity(this->jump.energy, false); + } + + if(unit->ftl_energy.Level() < unit->ftl_energy.MaxLevel()) { + unit->ftl_energy.Refill(); if (configuration()->fuel.fuel_equals_warp) { - this->fuel = this->warpenergy; + unit->fuel.SetLevel(unit->ftl_energy.Level()); } return true; } + return false; } @@ -209,30 +213,31 @@ void Energetic::setAfterburnerEnergy(float aft) { } void Energetic::setEnergyRecharge(float enrech) { - recharge = enrech; + Unit *unit = vega_dynamic_cast_ptr(this); + unit->reactor.SetCapacity(enrech); } -void Energetic::setFuel(float f) { - fuel = f; -} float Energetic::warpCapData() const { - return maxwarpenergy; + const Unit *unit = vega_dynamic_cast_ptr(this); + return unit->ftl_energy.MaxLevel(); } float Energetic::warpEnergyData() const { - if (maxwarpenergy > 0) { - return ((float) warpenergy) / ((float) maxwarpenergy); + const Unit *unit = vega_dynamic_cast_ptr(this); + if (unit->ftl_energy.MaxLevel() > 0) { + return unit->ftl_energy.Percent(); } + if (jump.energy > 0) { - return ((float) warpenergy) / ((float) jump.energy); + return ((float) unit->ftl_energy.Level()) / ((float) jump.energy); } return 0.0f; } // Basically max or current shield x 0.2 float Energetic::totalShieldEnergyCapacitance() { - Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); DamageableLayer *shield = unit->shield; float total_max_shield_value = shield->TotalMaxLayerValue(); @@ -260,28 +265,26 @@ void Energetic::ExpendEnergy(const bool player_ship) { } void Energetic::ExpendEnergy(float usage) { + Unit *unit = vega_dynamic_cast_ptr(this); // Operator overloaded to prevent negative usage - energy -= usage; + unit->energy.Deplete(true, usage); } // The original code was a continuation of the comment above and simply unclear. // I replaced it with a very simple model. void Energetic::ExpendFuel() { + Unit *unit = vega_dynamic_cast_ptr(this); + if (!configuration()->fuel.reactor_uses_fuel) { return; } - const float fuel_usage = configuration()->fuel.fmec_exit_velocity_inverse * recharge * simulation_atom_var; - fuel = std::max(0.0f, fuel - fuel_usage); - - if (!FINITE(fuel)) { - VS_LOG(error, "Fuel is nan C"); - fuel = 0; - } + const float fuel_usage = configuration()->fuel.fmec_exit_velocity_inverse * unit->reactor.Capacity() * simulation_atom_var; + unit->fuel.Deplete(true, fuel_usage); } void Energetic::MaintainECM() { - Unit *unit = static_cast(this); + Unit *unit = vega_dynamic_cast_ptr(this); if (!unit->computer.ecmactive) { return; @@ -292,7 +295,7 @@ void Energetic::MaintainECM() { } void Energetic::MaintainShields() { - Unit *unit = static_cast(this); + Unit *unit = vega_dynamic_cast_ptr(this); const bool in_warp = unit->graphicOptions.InWarp; const int shield_facets = unit->shield->number_of_facets; @@ -312,13 +315,13 @@ void Energetic::MaintainShields() { efficiency / configuration()->physics_config.shield_energy_capacitance * shield_facets * configuration()->physics_config.shield_maintenance_charge * simulation_atom_var; - sufficient_energy_to_recharge_shields = shield_maintenance > energy; + sufficient_energy_to_recharge_shields = shield_maintenance > unit->energy.Level(); ExpendEnergy(shield_maintenance); } void Energetic::ExpendEnergyToRechargeShields() { - Unit *unit = static_cast(this); + Unit *unit = vega_dynamic_cast_ptr(this); const bool in_warp = unit->graphicOptions.InWarp; @@ -331,26 +334,28 @@ void Energetic::ExpendEnergyToRechargeShields() { return; } - float current_shield_value = unit->shield->TotalLayerValue(); - float max_shield_value = unit->shield->TotalMaxLayerValue(); - float regeneration = unit->shield->GetRegeneration(); - float maximum_charge = std::min(max_shield_value - current_shield_value, regeneration); + double current_shield_value = unit->shield->TotalLayerValue(); + double max_shield_value = unit->shield->TotalMaxLayerValue(); + double regeneration = unit->shield->GetRegeneration(); + double maximum_charge = std::min(max_shield_value - current_shield_value, regeneration); // Here we store the actual charge we'll use in RegenShields constrained_charge_to_shields = maximum_charge; sufficient_energy_to_recharge_shields = (constrained_charge_to_shields > 0); - float actual_charge = std::min(maximum_charge, energy.Value()); - float energy_required_to_charge = actual_charge * VSDPercent() * + double actual_charge = std::min(maximum_charge, unit->energy.Level()); + double energy_required_to_charge = actual_charge * VSDPercent() * simulation_atom_var; - ExpendEnergy(energy_required_to_charge); + ExpendEnergy((float)energy_required_to_charge); } void Energetic::RechargeWarpCapacitors(const bool player_ship) { + Unit *unit = vega_dynamic_cast_ptr(this); + // Will try to keep the percentage of warp and normal capacitors equal - const float transfer_capacity = 0.005f; - const float capacitor_percent = energy / energy.MaxValue(); - const float warp_capacitor_percent = warpenergy / maxwarpenergy; - const float warp_multiplier = WarpEnergyMultiplier(player_ship); + const double transfer_capacity = 0.005f; + const double capacitor_percent = unit->energy.Percent(); + const double warp_capacitor_percent = unit->ftl_energy.Percent(); + const double warp_multiplier = WarpEnergyMultiplier(player_ship); if (warp_capacitor_percent >= 1.0f || warp_capacitor_percent > capacitor_percent || @@ -358,11 +363,11 @@ void Energetic::RechargeWarpCapacitors(const bool player_ship) { return; } - const float previous_energy = energy.Value(); - ExpendEnergy(energy.MaxValue() * transfer_capacity); + const double previous_energy = unit->energy.Level(); + ExpendEnergy((float)(unit->energy.MaxLevel() * transfer_capacity)); - const float actual_energy = previous_energy - energy.Value(); - warpenergy = std::min(maxwarpenergy, warpenergy + actual_energy * warp_multiplier); + const double actual_energy = previous_energy - unit->energy.Level(); + unit->ftl_energy.SetLevel(std::min(unit->ftl_energy.MaxLevel(), unit->ftl_energy.Level() + actual_energy * warp_multiplier)); } float Energetic::WarpEnergyMultiplier(const bool player_ship) { diff --git a/engine/src/cmd/energetic.h b/engine/src/cmd/energetic.h index dcb2e71044..e951a735dc 100644 --- a/engine/src/cmd/energetic.h +++ b/engine/src/cmd/energetic.h @@ -31,8 +31,9 @@ class Energetic { public: Energetic(); + virtual ~Energetic() = default; - void decreaseWarpEnergy(bool insys, float time); + void decreaseWarpEnergy(bool insys, double time); void DecreaseWarpEnergyInWarp(); float energyData() const; @@ -43,14 +44,14 @@ class Energetic { static float getFuelUsage(bool afterburner); void WCWarpIsFuelHack(bool transfer_warp_to_fuel); float ExpendMomentaryFuelUsage(float magnitude); - float ExpendFuel(float quantity); + float ExpendFuel(double quantity); void ExpendEnergy(const bool player_ship); void ExpendEnergy(float usage); void ExpendEnergyToRechargeShields(); void ExpendFuel(); float getWarpEnergy() const; - void increaseWarpEnergy(bool insys, float time); + void increaseWarpEnergy(bool insys, double time); float maxEnergyData() const; @@ -63,7 +64,6 @@ class Energetic { void setAfterburnerEnergy(float aft); void setEnergyRecharge(float enrech); - void setFuel(float f); float totalShieldEnergyCapacitance(); @@ -86,21 +86,10 @@ class Energetic { } jump{}; - //current energy - Resource energy; - //how much the energy recharges per second - float recharge; - - //maximum energy - float maxwarpenergy; //short fix - //current energy - float warpenergy; //short fix float constrained_charge_to_shields; bool sufficient_energy_to_recharge_shields; - //fuel of this unit - float fuel; float afterburnenergy; //short fix int afterburntype; //0--energy, 1--fuel //-1 means it is off. -2 means it doesn't exist. otherwise it's engaged to destination (positive number) diff --git a/engine/src/cmd/intelligent.cpp b/engine/src/cmd/intelligent.cpp index 439bc89809..bd46fc79ee 100644 --- a/engine/src/cmd/intelligent.cpp +++ b/engine/src/cmd/intelligent.cpp @@ -42,6 +42,7 @@ #include "gfx/mesh.h" #include "ai/turretai.h" #include "collide2/CSopcodecollider.h" +#include "vega_cast_utils.h" #include @@ -220,13 +221,13 @@ string Intelligent::getFullAIDescription() { } float Intelligent::getRelation(const Unit *targ) const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); return unit->pilot->GetEffectiveRelationship(unit, targ); } double Intelligent::getMinDis(const QVector &pnt) const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); float minsofar = 1e+10; float tmpvar; diff --git a/engine/src/cmd/intelligent.h b/engine/src/cmd/intelligent.h index bbef78e1ee..1e2ae3c665 100644 --- a/engine/src/cmd/intelligent.h +++ b/engine/src/cmd/intelligent.h @@ -35,6 +35,7 @@ class Order; class Intelligent { public: Intelligent(); + virtual ~Intelligent() = default; public: class csOPCODECollider *getCollideTree(const Vector &scale = Vector(1, diff --git a/engine/src/cmd/jump_capable.cpp b/engine/src/cmd/jump_capable.cpp index 571b470fb7..f0b815a33d 100644 --- a/engine/src/cmd/jump_capable.cpp +++ b/engine/src/cmd/jump_capable.cpp @@ -32,6 +32,7 @@ #include "gfx/warptrail.h" #include "vsfilesystem.h" #include "vs_exit.h" +#include "vega_cast_utils.h" // TODO: once implementation is refactored, deal with this too extern QVector RealPosition(const Unit *un); @@ -138,7 +139,7 @@ bool JumpCapable::AutoPilotToErrorMessage(const Unit *target, return AutoPilotToErrorMessage(targ, ignore_energy_requirements, failuremessage, recursive_level); } } - if (unit->warpenergy < unit->jump.insysenergy) { + if (unit->ftl_energy.Level() < unit->jump.insysenergy) { if (!ignore_energy_requirements) { return false; } @@ -270,7 +271,7 @@ bool JumpCapable::AutoPilotToErrorMessage(const Unit *target, failuremessage = configuration()->graphics_config.hud.already_near_message; return false; } - unit->warpenergy -= totpercent * unit->jump.insysenergy; + unit->ftl_energy.Deplete(true, static_cast(totpercent) * unit->jump.insysenergy); if (unsafe == false && totpercent == 0) { end = endne; } @@ -386,7 +387,7 @@ bool JumpCapable::AutoPilotToErrorMessage(const Unit *target, float JumpCapable::CalculateNearestWarpUnit(float minmultiplier, Unit **nearest_unit, bool count_negative_warp_units) const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); static float smallwarphack = XMLSupport::parse_float(vs_config->getVariable("physics", "minwarpeffectsize", "100")); static float bigwarphack = @@ -479,7 +480,7 @@ float JumpCapable::CalculateNearestWarpUnit(float minmultiplier, } float JumpCapable::CourseDeviation(const Vector &OriginalCourse, const Vector &FinalCourse) const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); if (unit->ViewComputerData().max_ab_speed() > .001) { return (OriginalCourse - (FinalCourse)).Magnitude() / unit->ViewComputerData().max_ab_speed(); } else { @@ -495,12 +496,12 @@ void JumpCapable::DeactivateJumpDrive() { } const std::vector &JumpCapable::GetDestinations() const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); return unit->pImage->destination; } const Energetic::UnitJump &JumpCapable::GetJumpStatus() const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); return unit->jump; } @@ -520,7 +521,7 @@ StarSystem *JumpCapable::getStarSystem() { } const StarSystem *JumpCapable::getStarSystem() const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); if (activeStarSystem) { return activeStarSystem; } else { @@ -535,7 +536,7 @@ const StarSystem *JumpCapable::getStarSystem() const { } Vector JumpCapable::GetWarpRefVelocity() const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); //Velocity Vector VelocityRef(0, 0, 0); @@ -555,7 +556,7 @@ Vector JumpCapable::GetWarpRefVelocity() const { } Vector JumpCapable::GetWarpVelocity() const { - const Unit *unit = static_cast(this); + const Unit *unit = vega_dynamic_cast_ptr(this); if (unit->graphicOptions.WarpFieldStrength == 1.0) { // Short circuit, most ships won't be at warp, so it simplifies math a lot diff --git a/engine/src/cmd/mount.cpp b/engine/src/cmd/mount.cpp index 860d3816d9..1fc446e494 100644 --- a/engine/src/cmd/mount.cpp +++ b/engine/src/cmd/mount.cpp @@ -253,7 +253,7 @@ bool Mount::PhysicsAlignedFire(Unit *caller, if (type->type == WEAPON_TYPE::BEAM || type->isMissile()) { //Missiles and beams set to processed. processed = PROCESSED; - } else if (ref.refire < type->Refire() || type->energy_rate > caller->energy) { + } else if (ref.refire < type->Refire() || type->energy_rate > caller->energy.Level()) { //Wait until refire has expired and reactor has produced enough energy for the next bolt. return true; } //Not ready to refire yet. But don't stop firing. @@ -299,7 +299,7 @@ bool Mount::PhysicsAlignedFire(Unit *caller, } break; case WEAPON_TYPE::BOLT: - caller->energy -= type->energy_rate; + caller->energy.Deplete(true, type->energy_rate); hint[Unit::UNIT_BOLT] = Bolt(type, mat, velocity, @@ -308,7 +308,7 @@ bool Mount::PhysicsAlignedFire(Unit *caller, break; case WEAPON_TYPE::BALL: { - caller->energy -= type->energy_rate; + caller->energy.Deplete(true, type->energy_rate); hint[Unit::UNIT_BOLT] = BoltDrawManager::GetInstance().AddBall(type, mat, velocity, owner, hint[Unit::UNIT_BOLT]); break; diff --git a/engine/src/cmd/movable.cpp b/engine/src/cmd/movable.cpp index 5c1dce7cb8..c737134ef9 100644 --- a/engine/src/cmd/movable.cpp +++ b/engine/src/cmd/movable.cpp @@ -561,7 +561,7 @@ Vector Movable::ClampVelocity(const Vector &velocity, const bool afterburn) { Unit *unit = static_cast(this); float fuelclamp = (energetic->fuelData() <= 0) ? configuration()->fuel.no_fuel_thrust : 1; - float abfuelclamp = (energetic->fuelData() <= 0 || (energetic->energy < unit->afterburnenergy * simulation_atom_var)) ? configuration()->fuel.no_fuel_afterburn : 1; + float abfuelclamp = (energetic->fuelData() <= 0 || (unit->energy.Level() < unit->afterburnenergy * static_cast(simulation_atom_var))) ? configuration()->fuel.no_fuel_afterburn : 1; float limit = afterburn ? (abfuelclamp * (unit->computer.max_ab_speed() @@ -613,28 +613,29 @@ Vector Movable::MaxThrust(const Vector &amt1) { //CMD_FLYBYWIRE depends on new version of Clampthrust... don't change without resolving it // TODO: refactor soon. Especially access to the fuel variable Vector Movable::ClampThrust(const Vector &amt1, bool afterburn) { - Unit *unit = static_cast(this); + Unit *unit = vega_dynamic_cast_ptr(this); const bool WCfuelhack = configuration()->fuel.fuel_equals_warp; const bool finegrainedFuelEfficiency = configuration()->fuel.variable_fuel_consumption; if (WCfuelhack) { - if (unit->fuel > unit->warpenergy) { - unit->fuel = unit->warpenergy; + // TODO: just don't use fuel in WC + if (unit->fuel.Level() > unit->ftl_energy.Level()) { + unit->fuel.SetLevel(unit->ftl_energy.Level()); } - if (unit->fuel < unit->warpenergy) { - unit->warpenergy = unit->fuel; + if (unit->fuel.Level() < unit->ftl_energy.Level()) { + unit->ftl_energy.SetLevel(unit->fuel.Level()); } } float instantenergy = unit->afterburnenergy * simulation_atom_var; - if ((unit->afterburntype == 0) && unit->energy < instantenergy) { + if ((unit->afterburntype == 0) && unit->energy.Level() < instantenergy) { afterburn = false; } - if ((unit->afterburntype == 1) && unit->fuel < 0) { - unit->fuel = 0; + if ((unit->afterburntype == 1) && unit->fuel.Level() < 0) { + unit->fuel.Zero(); afterburn = false; } - if ((unit->afterburntype == 2) && unit->warpenergy < 0) { - unit->warpenergy = 0; + if ((unit->afterburntype == 2) && unit->ftl_energy.Level() < 0) { + unit->ftl_energy.SetCapacity(0); afterburn = false; } if (3 == unit->afterburntype) { //no afterburner -- we should really make these types an enum :-/ @@ -642,8 +643,8 @@ Vector Movable::ClampThrust(const Vector &amt1, bool afterburn) { } Vector Res = amt1; - float fuelclamp = (unit->fuel <= 0) ? configuration()->fuel.no_fuel_thrust : 1; - float abfuelclamp = (unit->fuel <= 0) ? configuration()->fuel.no_fuel_afterburn : 1; + float fuelclamp = (unit->fuel.Level() <= 0) ? configuration()->fuel.no_fuel_thrust : 1; + float abfuelclamp = (unit->fuel.Level() <= 0) ? configuration()->fuel.no_fuel_afterburn : 1; if (fabs(amt1.i) > fabs(fuelclamp * limits.lateral)) { Res.i = copysign(fuelclamp * limits.lateral, amt1.i); } @@ -666,45 +667,45 @@ Vector Movable::ClampThrust(const Vector &amt1, bool afterburn) { if (unit->afterburntype == 2) { //Energy-consuming afterburner //HACK this forces the reaction to be Li-6+Li-6 fusion with efficiency governed by the getFuelUsage function - unit->warpenergy -= unit->afterburnenergy * Energetic::getFuelUsage(afterburn) * simulation_atom_var * Res.Magnitude() - * FMEC_exit_vel_inverse - / Lithium6constant; + unit->ftl_energy.Deplete(true, unit->afterburnenergy * Energetic::getFuelUsage(afterburn) * simulation_atom_var * Res.Magnitude() + * FMEC_exit_vel_inverse / Lithium6constant); } if (3 == unit->afterburntype || unit->afterburntype == 1) { //fuel-burning overdrive - uses afterburner efficiency. In NO_AFTERBURNER case, "afterburn" will always be false, so can reuse code. //HACK this forces the reaction to be Li-6+Li-6 fusion with efficiency governed by the getFuelUsage function - unit->fuel -= + unit->fuel.Deplete(true, ((afterburn && finegrainedFuelEfficiency) ? unit->afterburnenergy : Energetic::getFuelUsage(afterburn)) * simulation_atom_var * Res.Magnitude() - * FMEC_exit_vel_inverse / Lithium6constant; + * FMEC_exit_vel_inverse / Lithium6constant); #ifndef __APPLE__ - if (ISNAN(unit->fuel)) { + if (ISNAN(unit->fuel.Level())) { VS_LOG(error, "Fuel is NAN A"); - unit->fuel = 0; + unit->fuel.Zero(); } #endif } if (unit->afterburntype == 0) { //fuel-burning afterburner - uses default efficiency - appears to check for available energy? FIXME //HACK this forces the reaction to be Li-6+Li-6 fusion with efficiency governed by the getFuelUsage function - unit->fuel -= unit->getFuelUsage(false) * simulation_atom_var * Res.Magnitude() * FMEC_exit_vel_inverse / Lithium6constant; + unit->fuel.Deplete(true, unit->getFuelUsage(false) * simulation_atom_var * Res.Magnitude() * FMEC_exit_vel_inverse / Lithium6constant); #ifndef __APPLE__ - if (ISNAN(unit->fuel)) { + if (ISNAN(unit->fuel.Level())) { VS_LOG(error, "Fuel is NAN B"); - unit->fuel = 0; + unit->fuel.Zero(); } #endif } if ((afterburn) && (unit->afterburntype == 0)) { - unit->energy -= instantenergy; + unit->energy.Deplete(true, instantenergy); } if (WCfuelhack) { - if (unit->fuel > unit->warpenergy) { - unit->fuel = unit->warpenergy; + // TODO: just don't use fuel in WC + if (unit->fuel.Level() > unit->ftl_energy.Level()) { + unit->fuel.SetLevel(unit->ftl_energy.Level()); } - if (unit->fuel < unit->warpenergy) { - unit->warpenergy = unit->fuel; + if (unit->fuel.Level() < unit->ftl_energy.Level()) { + unit->ftl_energy.SetLevel(unit->fuel.Level()); } } return Res; @@ -771,13 +772,13 @@ void Movable::Thrust(const Vector &amt1, bool afterburn) { Unit *unit = static_cast(this); if (unit->afterburntype == 0) { - afterburn = afterburn && unit->energy > unit->afterburnenergy * simulation_atom_var; + afterburn = afterburn && unit->energy.Level() > unit->afterburnenergy * static_cast(simulation_atom_var); } //SIMULATION_ATOM; ? if (unit->afterburntype == 1) { - afterburn = afterburn && unit->fuel > 0; + afterburn = afterburn && unit->fuel.Level() > 0; } if (unit->afterburntype == 2) { - afterburn = afterburn && unit->warpenergy > 0; + afterburn = afterburn && unit->ftl_energy.Level() > 0; } diff --git a/engine/src/cmd/planet.cpp b/engine/src/cmd/planet.cpp index 717b79caf7..519410fc74 100644 --- a/engine/src/cmd/planet.cpp +++ b/engine/src/cmd/planet.cpp @@ -462,7 +462,7 @@ void Planet::InitPlanet(QVector x, VSSprite *tmp = pImage->pHudImage; pImage->pHudImage = un->GetImageInformation().pHudImage; un->GetImageInformation().pHudImage = tmp; - maxwarpenergy = un->warpCapData(); + ftl_energy.SetCapacity(un->warpCapData()); if (smartplanets) { SubUnits.prepend(un); un->SetRecursiveOwner(this); diff --git a/engine/src/cmd/unit_csv.cpp b/engine/src/cmd/unit_csv.cpp index cfad4830b1..307629808c 100644 --- a/engine/src/cmd/unit_csv.cpp +++ b/engine/src/cmd/unit_csv.cpp @@ -731,7 +731,7 @@ void Unit::LoadRow(std::string unit_identifier, string modification, bool saved_ pImage->CockpitCenter.k = UnitCSVFactory::GetVariable(unit_key, "CockpitZ", 0.0f) * xml.unitscale; Mass = UnitCSVFactory::GetVariable(unit_key, "Mass", 1.0f); Momentofinertia = UnitCSVFactory::GetVariable(unit_key, "Moment_Of_Inertia", 1.0f); - fuel = UnitCSVFactory::GetVariable(unit_key, "Fuel_Capacity", 0.0f); + // Hull float temp_hull = UnitCSVFactory::GetVariable(unit_key, "Hull", 0.0f); @@ -809,16 +809,29 @@ void Unit::LoadRow(std::string unit_identifier, string modification, bool saved_ // End shield section + // Energy + // TODO: The following code has a bug. + // It will set the max of the component as the current value loaded from the + // CSV. If the component is damaged, this will be lower than the original value. + fuel.SetCapacity(UnitCSVFactory::GetVariable(unit_key, "Fuel_Capacity", 0.0), true); + energy.SetCapacity(UnitCSVFactory::GetVariable(unit_key, "Primary_Capacitor", 0.0), true); + ftl_energy.SetCapacity(UnitCSVFactory::GetVariable(unit_key, "Warp_Capacitor", 0.0), true); + reactor.SetCapacity(UnitCSVFactory::GetVariable(unit_key, "Reactor_Recharge", 0.0)); + + const bool WCfuelhack = configuration()->fuel.fuel_equals_warp; + + //this is required to make sure we don't trigger the "globally out of fuel" if we use all warp charges -- save some afterburner for later!!! + if (WCfuelhack) { + ftl_energy.SetCapacity(ftl_energy.MaxLevel() + jump.energy * 0.1f); + fuel.SetCapacity(ftl_energy.MaxLevel()); + } - const bool WCfuelhack = configuration()->fuel.fuel_equals_warp; - maxwarpenergy = warpenergy = UnitCSVFactory::GetVariable(unit_key, "Warp_Capacitor", 0.0f); + // End Energy graphicOptions.MinWarpMultiplier = UnitCSVFactory::GetVariable(unit_key, "Warp_Min_Multiplier", 1.0f); graphicOptions.MaxWarpMultiplier = UnitCSVFactory::GetVariable(unit_key, "Warp_Max_Multiplier", 1.0f); - double capacitor = UnitCSVFactory::GetVariable(unit_key, "Primary_Capacitor", 0.0f); - energy = Resource(capacitor, 0.0f, capacitor); - recharge = UnitCSVFactory::GetVariable(unit_key, "Reactor_Recharge", 0.0f); + jump.drive = UnitCSVFactory::GetVariable(unit_key, "Jump_Drive_Present", false) ? -1 : -2; jump.delay = UnitCSVFactory::GetVariable(unit_key, "Jump_Drive_Delay", 0); forcejump = UnitCSVFactory::GetVariable(unit_key, "Wormhole", false); @@ -828,10 +841,7 @@ void Unit::LoadRow(std::string unit_identifier, string modification, bool saved_ ? true : false) ? 1 : 0; jump.energy = UnitCSVFactory::GetVariable(unit_key, "Outsystem_Jump_Cost", 0.0f); jump.insysenergy = UnitCSVFactory::GetVariable(unit_key, "Warp_Usage_Cost", 0.0f); - if (WCfuelhack) { - fuel = warpenergy = warpenergy + jump.energy - * 0.1f; - } //this is required to make sure we don't trigger the "globally out of fuel" if we use all warp charges -- save some afterburner for later!!! + afterburnenergy = UnitCSVFactory::GetVariable(unit_key, "Afterburner_Usage_Cost", 32767.0f); afterburntype = UnitCSVFactory::GetVariable(unit_key, "Afterburner_Type", @@ -1262,7 +1272,7 @@ string Unit::WriteUnitString() { } unit["Mass"] = tos(Mass); unit["Moment_Of_Inertia"] = tos(Momentofinertia); - unit["Fuel_Capacity"] = tos(fuel); + unit["Fuel_Capacity"] = tos(fuel.Level()); unit["Hull"] = tos(GetHullLayer().facets[0].health); unit["Spec_Interdiction"] = tos(specInterdiction); @@ -1327,11 +1337,11 @@ string Unit::WriteUnitString() { unit["Shield_Leak"] = tos(0); //tos( shield.leak/100.0 ); unit["Shield_Efficiency"] = tos(1); //tos( shield.efficiency ); unit["Shield_Recharge"] = tos(shield->GetRegeneration()); //tos( shield.recharge ); - unit["Warp_Capacitor"] = tos(maxwarpenergy); + unit["Warp_Capacitor"] = tos(ftl_energy.Level()); unit["Warp_Min_Multiplier"] = tos(graphicOptions.MinWarpMultiplier); unit["Warp_Max_Multiplier"] = tos(graphicOptions.MaxWarpMultiplier); - unit["Primary_Capacitor"] = tos(energy.MaxValue()); - unit["Reactor_Recharge"] = tos(recharge); + unit["Primary_Capacitor"] = tos(energy.Level()); + unit["Reactor_Recharge"] = tos(reactor.Capacity()); unit["Jump_Drive_Present"] = tos(jump.drive >= -1); unit["Jump_Drive_Delay"] = tos(jump.delay); unit["Wormhole"] = tos(forcejump != 0); diff --git a/engine/src/cmd/unit_generic.cpp b/engine/src/cmd/unit_generic.cpp index 23c6d462a3..73ed76c7a0 100644 --- a/engine/src/cmd/unit_generic.cpp +++ b/engine/src/cmd/unit_generic.cpp @@ -1019,7 +1019,7 @@ bool Unit::jumpReactToCollision(Unit *smalle) { //we have a drive if ((!SPEC_interference && (smalle->GetJumpStatus().drive >= 0 && //we have power - (smalle->warpenergy >= smalle->GetJumpStatus().energy + (smalle->ftl_energy.Level() >= smalle->GetJumpStatus().energy //or we're being cheap || (ai_jump_cheat && cp == nullptr) ))) @@ -1046,9 +1046,9 @@ bool Unit::jumpReactToCollision(Unit *smalle) { return false; } if ((!SPEC_interference && (GetJumpStatus().drive >= 0 - && (warpenergy >= GetJumpStatus().energy || (ai_jump_cheat && cp == NULL)) + && (ftl_energy.Level() >= GetJumpStatus().energy || (ai_jump_cheat && cp == NULL)) )) || smalle->forcejump) { - warpenergy -= GetJumpStatus().energy; + ftl_energy.Deplete(false, GetJumpStatus().energy); DeactivateJumpDrive(); Unit *jumppoint = smalle; @@ -1131,6 +1131,7 @@ Unit *findUnitInStarsystem(const void *unitDoNotDereference) { //NUMGAUGES has been moved to pImages.h in UnitImages void Unit::DamageRandSys(float dam, const Vector &vec, float randnum, float degrees) { + // TODO: take actual damage into account when damaging components. float deg = fabs(180 * atan2(vec.i, vec.k) / M_PI); randnum = rand01(); const float inv_min_dam = 1.0F - configuration()->physics_config.min_damage; @@ -1274,11 +1275,11 @@ void Unit::DamageRandSys(float dam, const Vector &vec, float randnum, float degr static float cargo_damage_prob = upgradevolume_damage_prob - XMLSupport::parse_float(vs_config->getVariable("physics", "cargo_damage_prob", "1")); if (randnum >= fuel_damage_prob) { - fuel *= dam; + fuel.Damage(); } else if (randnum >= warpenergy_damage_prob) { - warpenergy *= dam; + ftl_energy.Damage(); } else if (randnum >= ab_damage_prob) { - this->afterburnenergy += ((1 - dam) * recharge); + this->afterburnenergy += ((1 - dam) * reactor.Capacity()); } else if (randnum >= cargovolume_damage_prob) { CargoVolume *= dam; } else if (randnum >= upgradevolume_damage_prob) { @@ -1329,12 +1330,14 @@ void Unit::DamageRandSys(float dam, const Vector &vec, float randnum, float degr } else if (randnum >= .7) { // TODO: lib_damage shield.recharge *= dam; } else if (randnum >= .5) { - static float mindam = + /*static float mindam = XMLSupport::parse_float(vs_config->getVariable("physics", "min_recharge_shot_damage", "0.5")); if (dam < mindam) { dam = mindam; } - this->recharge *= dam; + this->recharge *= dam;*/ + // TODO: do the above + reactor.Damage(); } else if (randnum >= .2) { static float mindam = XMLSupport::parse_float(vs_config->getVariable("physics", "min_maxenergy_shot_damage", "0.2")); @@ -2856,6 +2859,15 @@ bool Unit::UpAndDownGrade(const Unit *up, const Unit *downgradelimit, bool force_change_on_nothing, bool gen_downgrade_list) { + // New Code + UpgradeOperationResult result = UpgradeUnit(up->name, !downgrade, touchme); + if(result.upgradeable) { + percentage = result.percent; + return result.success; + } + + + // Old Code percentage = 0; static bool @@ -2996,9 +3008,9 @@ bool Unit::UpAndDownGrade(const Unit *up, if (!csv_cell_null_check || force_change_on_nothing || cell_has_recursive_data(upgrade_name, up->faction, "Warp_Capacitor|Warp_Usage_Cost")) { - if (!csv_cell_null_check || force_change_on_nothing + /*if (!csv_cell_null_check || force_change_on_nothing || cell_has_recursive_data(upgrade_name, up->faction, "Warp_Capacitor")) - STDUPGRADE(maxwarpenergy, up->maxwarpenergy, templ->maxwarpenergy, 0); + STDUPGRADE(maxwarpenergy, up->maxwarpenergy, templ->maxwarpenergy, 0);*/ if (!csv_cell_null_check || force_change_on_nothing || cell_has_recursive_data(upgrade_name, up->faction, "Warp_Usage_Cost")) STDUPGRADE(jump.insysenergy, up->jump.insysenergy, templ->jump.insysenergy, 0); @@ -3061,9 +3073,9 @@ bool Unit::UpAndDownGrade(const Unit *up, hull->facets[0].max_health = hull->facets[0].health; } - if (!csv_cell_null_check || force_change_on_nothing + /*if (!csv_cell_null_check || force_change_on_nothing || cell_has_recursive_data(upgrade_name, up->faction, "Reactor_Recharge")) - STDUPGRADE(recharge, up->recharge, templ->recharge, 0); + STDUPGRADE(recharge, up->recharge, templ->recharge, 0);*/ static bool unittable = XMLSupport::parse_bool(vs_config->getVariable("physics", "UnitTable", "false")); //Uncommon fields (capacities... rates... etc...) if (!csv_cell_null_check || force_change_on_nothing @@ -3091,12 +3103,12 @@ bool Unit::UpAndDownGrade(const Unit *up, if (!csv_cell_null_check || force_change_on_nothing || cell_has_recursive_data(upgrade_name, up->faction, "ECM_Rating")) STDUPGRADE(ecm, up->ecm, templ->ecm, 0); //ecm is unsigned --chuck_starchaser - if (!csv_cell_null_check || force_change_on_nothing + /*if (!csv_cell_null_check || force_change_on_nothing || cell_has_recursive_data(upgrade_name, up->faction, "Primary_Capacitor")) { temporary_upgrade_float_variable = static_cast(energy.MaxValue()); STDUPGRADE(temporary_upgrade_float_variable, up->energy.MaxValue(), templ->energy.MaxValue(), 0); energy.SetMaxValue(temporary_upgrade_float_variable); - } + }*/ } //Maneuvering stuff if (!csv_cell_null_check || force_change_on_nothing @@ -3127,9 +3139,9 @@ bool Unit::UpAndDownGrade(const Unit *up, if (!csv_cell_null_check || force_change_on_nothing || cell_has_recursive_data(upgrade_name, up->faction, "Afterburner_Accel")) STDUPGRADE(limits.afterburn, tlimits_afterburn, templ->limits.afterburn, 0); - if (!csv_cell_null_check || force_change_on_nothing + /*if (!csv_cell_null_check || force_change_on_nothing || cell_has_recursive_data(upgrade_name, up->faction, "Fuel_Capacity")) - STDUPGRADE(fuel, up->fuel, templ->fuel, 0); + STDUPGRADE(fuel, up->fuel, templ->fuel, 0);*/ if (!csv_cell_null_check || force_change_on_nothing || cell_has_recursive_data(upgrade_name, up->faction, "Default_Speed_Governor")) STDUPGRADE(computer.max_combat_speed, tmax_speed, templ->computer.max_combat_speed, 0); @@ -3607,12 +3619,6 @@ int Unit::RepairUpgrade() { if (shield.recharge > maxrecharge->shield.recharge) shield.recharge = maxrecharge->shield.recharge; }*/ - if (up->energy.MaxValue() == energy.MaxValue() && up->recharge > recharge) { - recharge = up->recharge; - if (recharge > maxrecharge->recharge) { - recharge = maxrecharge->recharge; - } - } } } } @@ -4336,10 +4342,6 @@ void Unit::UpdatePhysics3(const Transformation &trans, Unit *superunit) { ActTurn(); - if (fuel < 0) { - fuel = 0; - } - static CloakingStatus previous_status = cloak.status; cloak.Update(this); @@ -4567,7 +4569,7 @@ void Unit::UpdatePhysics3(const Transformation &trans, trackingcone, hint)) { const WeaponInfo *typ = mounts[i].type; - energy += typ->energy_rate * (typ->type == WEAPON_TYPE::BEAM ? simulation_atom_var : 1); + energy.Charge(static_cast(typ->energy_rate) * (typ->type == WEAPON_TYPE::BEAM ? simulation_atom_var : 1)); } } else if (mounts[i].processed == Mount::UNFIRED || mounts[i].ref.refire > 2 * mounts[i].type->Refire()) { mounts[i].processed = Mount::UNFIRED; diff --git a/engine/src/cmd/unit_generic.h b/engine/src/cmd/unit_generic.h index 568f03dec1..7894a672ae 100644 --- a/engine/src/cmd/unit_generic.h +++ b/engine/src/cmd/unit_generic.h @@ -83,6 +83,10 @@ void UncheckUnit( class Unit*un ); #include "cargo_color.h" +// Components +#include "components/energy_container.h" +#include "components/reactor.h" + extern char *GetUnitDir(const char *filename); Unit *getMasterPartList(); @@ -146,6 +150,14 @@ class Unit : public Armed, public Audible, public Drawable, public Damageable, p StringPool::Reference csvRow; public: + // Components + EnergyContainer fuel = EnergyContainer(EnergyType::Fuel); + EnergyContainer energy = EnergyContainer(EnergyType::Energy); + EnergyContainer ftl_energy = EnergyContainer(EnergyType::FTL); + + // TODO: move this to a single constructor?! + Reactor reactor = Reactor(&fuel, &energy, &ftl_energy); + Cloak cloak; /// Radar and related systems diff --git a/engine/src/cmd/unit_util_generic.cpp b/engine/src/cmd/unit_util_generic.cpp index 8a1057ac72..b508b2bfc0 100644 --- a/engine/src/cmd/unit_util_generic.cpp +++ b/engine/src/cmd/unit_util_generic.cpp @@ -42,6 +42,9 @@ #include "universe.h" #include "vs_logging.h" #include "weapon_info.h" +#include "unit_csv_factory.h" + +#include #include "cmd/script/pythonmission.h" #ifndef NO_GFX @@ -894,6 +897,32 @@ float PercentOperational(Unit *un, std::string name, std::string category, bool if (!un) { return 0; } + + // New Code + // TODO: Make actually return percent damaged + + // name is unit_key with stripped suffix. Need to add it again + // TODO: check for prefixes: add_ mult_ + std::string unit_key = name; + if(!boost::algorithm::ends_with(unit_key, "__upgrades")) { + unit_key = name + "__upgrades"; + } + + const std::string upgrade_category = UnitCSVFactory::GetVariable(unit_key, "Upgrade_Type", std::string()); + if(upgrade_category == "Reactor") { + return un->reactor.Damaged() ? 0.5 : 1.0; + } + + if(upgrade_category == "Capacitor") { + return un->reactor.Damaged() ? 0.5 : 1.0; + } + + if(upgrade_category == "FTL_Capacitor") { + return un->reactor.Damaged() ? 0.5 : 1.0; + } + + + // Old Code if (category.find(DamagedCategory) == 0) { return 0.0f; } diff --git a/engine/src/cmd/upgradeable_unit.cpp b/engine/src/cmd/upgradeable_unit.cpp index 210b3fceb4..4888be8b5e 100644 --- a/engine/src/cmd/upgradeable_unit.cpp +++ b/engine/src/cmd/upgradeable_unit.cpp @@ -39,6 +39,7 @@ #include "weapon_info.h" #include "vega_cast_utils.h" #include "vs_logging.h" +#include "unit_csv_factory.h" std::vector ParseUnitUpgrades(const std::string &upgrades) { if(upgrades.size() == 0) { @@ -86,6 +87,115 @@ UpgradeableUnit::UpgradeableUnit() extern int GetModeFromName(const char *input_buffer); +UpgradeType GetUpgradeType(const std::string upgrade_key) { + std::string upgrade_type_string = UnitCSVFactory::GetVariable(upgrade_key, "Upgrade_Type", std::string()); + std::string upgrade_name = UnitCSVFactory::GetVariable(upgrade_key, "Name", std::string()); + + if(upgrade_type_string.empty()) return UpgradeType::None; + + if(upgrade_type_string == "Armor") { + return UpgradeType::Armor; + } + //if(upgrade_type_string == "Hull") return UpgradeType::Hull; + if(upgrade_type_string == "Shield") { + return UpgradeType::Shield; + } + + if(upgrade_type_string == "Reactor") { + return UpgradeType::Reactor; + } + + if(upgrade_type_string == "FTL_Capacitor") { + return UpgradeType::FTL_Capacitor; + } + + if(upgrade_type_string == "Capacitor") { + return UpgradeType::Capacitor; + } + + if(upgrade_type_string == "Jump_Drive") { + return UpgradeType::Jump_Drive; + } + + if(upgrade_type_string == "Afterburner") { + return UpgradeType::Afterburner; + } + + return UpgradeType::None; +} + +UpgradeOperationResult UpgradeableUnit::UpgradeUnit(const std::string upgrade_name, + bool upgrade, bool apply) { + Unit* unit = vega_dynamic_cast_ptr(this); + const std::string upgrade_key = upgrade_name + UPGRADES_SUFFIX; + const UpgradeType upgrade_type = GetUpgradeType(upgrade_key); + + UpgradeOperationResult result; + + switch(upgrade_type) { + /*case UpgradeType::Armor: + result.upgradeable = true; + result.success = unit->armor->CanWillUpDowngrade(upgrade_key, upgrade, apply); + break; + case UpgradeType::Shield: + result.upgradeable = true; + result.success = unit->shield->CanWillUpDowngrade(upgrade_key, upgrade, apply); + break;*/ + + case UpgradeType::Capacitor: + result.upgradeable = true; + result.success = unit->energy.CanWillUpDowngrade(upgrade_key, upgrade, apply); + break; + case UpgradeType::FTL_Capacitor: + result.upgradeable = true; + result.success = unit->ftl_energy.CanWillUpDowngrade(upgrade_key, upgrade, apply); + break; + case UpgradeType::Reactor: + result.upgradeable = true; + result.success = unit->reactor.CanWillUpDowngrade(upgrade_key, upgrade, apply); + break; + + /*case UpgradeType::Afterburner: + result.upgradeable = true; + result.success = unit->afterburner.CanWillUpDowngrade(upgrade_key, upgrade, apply); + std::cout << "Afterburner upgraded successfully\n"; + break; + case UpgradeType::Drive: + result.upgradeable = true; + result.success = unit->armor->CanWillUpDowngrade(upgrade_key, upgrade, apply); + break; + case UpgradeType::Jump_Drive: + result.upgradeable = true; + result.success = unit->jump_drive.CanWillUpDowngrade(upgrade_key, upgrade, apply); + break; + + case UpgradeType::Cloak: + result.upgradeable = true; + result.success = unit->cloak.CanWillUpDowngrade(upgrade_key, upgrade, apply); + break; + /*case UpgradeType::ECM: + result.upgradeable = true; + result.success = unit->ecm.CanWillUpDowngrade(upgrade_key, upgrade, apply); + break; + case UpgradeType::Radar: + result.upgradeable = true; + result.success = unit->radar.CanWillUpDowngrade(upgrade_key, upgrade, apply); + break;*/ + + /*case UpgradeType::Repair_Droid: + result.upgradeable = true; + result.success = unit->repair_droid.CanWillUpDowngrade(upgrade_key, upgrade, apply); + break;*/ + + default: + //std::cout << "Unhandled type for " << upgrade_name << std::endl; + break; + } + + return result; +} + + // TODO: remove unit parameter void UpgradeableUnit::UpgradeUnit(const std::string &upgrades) { const std::string delimiter = ";"; diff --git a/engine/src/cmd/upgradeable_unit.h b/engine/src/cmd/upgradeable_unit.h index 609e1db248..e640f02781 100644 --- a/engine/src/cmd/upgradeable_unit.h +++ b/engine/src/cmd/upgradeable_unit.h @@ -32,6 +32,41 @@ class Unit; class Mount; +const std::string UPGRADES_SUFFIX = "__upgrades"; + +// A struct to hold all results of the upgrade operation +struct UpgradeOperationResult { + double percent = 0.0; // Old part percent operational + bool success = false; // Can we upgrade/downgrade + bool upgradeable = false; // Temp variable. Until we map all types. +}; + +enum class UpgradeType { + None, + + Armor, + //Hull, // Can't upgrade the hull right now + Shield, + + Capacitor, + FTL_Capacitor, + Reactor, + + Afterburner, + Drive, + Jump_Drive, + + Cloak, + ECM, + Radar, + + Repair_Droid + + // TODO: all the rest of the upgrades, shady or not... +}; + +UpgradeType GetUpgradeType(const std::string upgrade_key); + // TODO: make this into a subclass of unit later class UpgradeableUnit @@ -39,6 +74,8 @@ class UpgradeableUnit public: UpgradeableUnit(); virtual ~UpgradeableUnit() {} + UpgradeOperationResult UpgradeUnit(const std::string upgrade_name, + bool upgrade, bool apply); void UpgradeUnit(const std::string &upgrades); bool UpgradeMounts(const Unit *up, int subunitoffset, diff --git a/engine/src/components/component.cpp b/engine/src/components/component.cpp index 54b9364098..2861b026ce 100644 --- a/engine/src/components/component.cpp +++ b/engine/src/components/component.cpp @@ -28,6 +28,10 @@ #include "component.h" #include "unit_csv_factory.h" +const std::string NAME = "Name"; +const std::string MASS = "Mass"; +const std::string VOLUME = "Volume"; + Component::Component(double mass, double volume, bool integral): unit_key(""), upgrade_name(""), @@ -73,6 +77,17 @@ bool Component::Downgrade() { return true; } +bool Component::Upgrade(const std::string upgrade_key) { + this->upgrade_key = upgrade_key; + upgrade_name = UnitCSVFactory::GetVariable(upgrade_key, NAME, std::string()); + + mass = UnitCSVFactory::GetVariable(upgrade_key, MASS, 0.0); + // TODO: volume currently not in units.json. need to merge with items list + volume = UnitCSVFactory::GetVariable(upgrade_key, VOLUME, 0.0); + + return true; +} + void Component::SetIntegral(bool integral) { this->integral = integral; } \ No newline at end of file diff --git a/engine/src/components/component.h b/engine/src/components/component.h index 28b17f32f1..7539578b71 100644 --- a/engine/src/components/component.h +++ b/engine/src/components/component.h @@ -79,9 +79,10 @@ class Component virtual bool CanUpgrade(const std::string upgrade_key) const = 0; - virtual bool Upgrade(const std::string upgrade_key) = 0; + virtual bool Upgrade(const std::string upgrade_key); virtual void Damage() = 0; + virtual void DamageByPercent(double percent) = 0; virtual void Repair() = 0; virtual bool Damaged() const = 0; diff --git a/engine/src/components/energy_container.cpp b/engine/src/components/energy_container.cpp index b3c692a903..e786c46f06 100644 --- a/engine/src/components/energy_container.cpp +++ b/engine/src/components/energy_container.cpp @@ -73,6 +73,9 @@ void EnergyContainer::SetCapacity(const double capacity, bool refill) { } double EnergyContainer::Level() const { return level.Value(); } +void EnergyContainer::SetLevel(double new_level) { + level = new_level; +} double EnergyContainer::MaxLevel() const { return level.MaxValue(); } double EnergyContainer::Percent() const { if(level.MaxValue() == 0.0) { @@ -185,6 +188,10 @@ void EnergyContainer::Damage() { level.RandomDamage(); } +void EnergyContainer::DamageByPercent(double percent) { + level.DamageByPercent(percent); +} + void EnergyContainer::Repair() { level.RepairFully(); } diff --git a/engine/src/components/energy_container.h b/engine/src/components/energy_container.h index db5008451d..39b65ed7a6 100644 --- a/engine/src/components/energy_container.h +++ b/engine/src/components/energy_container.h @@ -67,6 +67,7 @@ class EnergyContainer: public Component void SetCapacity(const double capacity, bool refill = true); double Level() const; + void SetLevel(double new_level); double MaxLevel() const; double Percent() const; void Refill(); @@ -89,6 +90,8 @@ class EnergyContainer: public Component virtual bool Upgrade(const std::string upgrade_name); virtual void Damage(); + virtual void DamageByPercent(double percent); + virtual void Repair(); virtual bool Damaged() const; diff --git a/engine/src/components/reactor.cpp b/engine/src/components/reactor.cpp index fe2ea5bd5a..aee793a724 100644 --- a/engine/src/components/reactor.cpp +++ b/engine/src/components/reactor.cpp @@ -73,6 +73,7 @@ bool Reactor::Downgrade() { return false; } + Component::Downgrade(); capacity.SetMaxValue(0.0); atom_capacity = 0.0; SetConsumption(0.0); @@ -80,19 +81,18 @@ bool Reactor::Downgrade() { return true; } -bool Reactor::CanUpgrade(const std::string upgrade_name) const { +bool Reactor::CanUpgrade(const std::string upgrade_key) const { return !Damaged(); } -bool Reactor::Upgrade(const std::string upgrade_name) { +bool Reactor::Upgrade(const std::string upgrade_key) { if(!CanUpgrade(upgrade_key)) { return false; } - this->upgrade_key = upgrade_key; - this->upgrade_name = upgrade_name; + Component::Upgrade(upgrade_key); - capacity = UnitCSVFactory::GetVariable(upgrade_name, REACTOR_RECHARGE, 0.0f); + capacity.SetMaxValue(UnitCSVFactory::GetVariable(upgrade_key, REACTOR_RECHARGE, 0.0)); atom_capacity = capacity * simulation_atom_var; SetConsumption(capacity * conversion_ratio); @@ -104,6 +104,11 @@ void Reactor::Damage() { atom_capacity = capacity.Value() * simulation_atom_var; } +void Reactor::DamageByPercent(double percent) { + capacity.DamageByPercent(percent); + atom_capacity = capacity.Value() * simulation_atom_var; +} + void Reactor::Repair() { capacity.RepairFully(); atom_capacity = capacity.Value() * simulation_atom_var; diff --git a/engine/src/components/reactor.h b/engine/src/components/reactor.h index 2176021ab4..34b7980664 100644 --- a/engine/src/components/reactor.h +++ b/engine/src/components/reactor.h @@ -62,11 +62,12 @@ class Reactor: public Component, public EnergyConsumer virtual bool Downgrade(); - virtual bool CanUpgrade(const std::string upgrade_name) const; + virtual bool CanUpgrade(const std::string upgrade_key) const; - virtual bool Upgrade(const std::string upgrade_name); + virtual bool Upgrade(const std::string upgrade_key); virtual void Damage(); + virtual void DamageByPercent(double percent); virtual void Repair(); virtual bool Damaged() const;