diff --git a/engine/src/cmd/armed.cpp b/engine/src/cmd/armed.cpp index 40f99bb2b..338b08201 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 * 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 * 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 56f57af70..e7d6054ff 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 52f82ad4b..138547e73 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 47c509a19..540cd3d29 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 e334e5d56..6fa662f88 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 7f20ef5c8..f74cc0c2f 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 967145d27..2a63e76b4 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 2f0a4091d..993801144 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; @@ -56,20 +54,21 @@ Energetic::Energetic() : energy(0, 0), } void Energetic::decreaseWarpEnergy(bool insys, float 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()); } } @@ -149,58 +152,59 @@ float Energetic::ExpendMomentaryFuelUsage(float magnitude) { * @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; + 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) { + 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 dcb2e7104..671ba97a0 100644 --- a/engine/src/cmd/energetic.h +++ b/engine/src/cmd/energetic.h @@ -31,6 +31,7 @@ class Energetic { public: Energetic(); + virtual ~Energetic() = default; void decreaseWarpEnergy(bool insys, float time); void DecreaseWarpEnergyInWarp(); @@ -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 439bc8980..bd46fc79e 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 bbef78e1e..1e2ae3c66 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 571b470fb..956ae27ae 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, 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 860d3816d..1fc446e49 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 5c1dce7cb..8d814f756 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 * 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 * 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 717b79caf..519410fc7 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 cfad4830b..307629808 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 23c6d462a..badba83c1 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(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 568f03dec..7894a672a 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 8a1057ac7..b508b2bfc 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 210b3fceb..4888be8b5 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 609e1db24..e640f0278 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 54b936409..2861b026c 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 28b17f32f..7539578b7 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 b3c692a90..e786c46f0 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 db5008451..39b65ed7a 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 fe2ea5bd5..aee793a72 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 2176021ab..34b798066 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;