diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 45ff7d4d9..63f3fb91d 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -165,6 +165,7 @@ IF (UNIX) ${Vega_Strike_SOURCE_DIR}/src/cmd ${Vega_Strike_SOURCE_DIR}/src/damage ${Vega_Strike_SOURCE_DIR}/src/resource + ${Vega_Strike_SOURCE_DIR}/src/components ${Vega_Strike_BINARY_DIR} ${Vega_Strike_BINARY_DIR}/src /usr/include/harfbuzz/ @@ -175,6 +176,7 @@ ELSE () ${Vega_Strike_SOURCE_DIR}/src/cmd ${Vega_Strike_SOURCE_DIR}/src/damage ${Vega_Strike_SOURCE_DIR}/src/resource + ${Vega_Strike_SOURCE_DIR}/src/components ${Vega_Strike_BINARY_DIR} ${Vega_Strike_BINARY_DIR}/src ) @@ -714,6 +716,14 @@ SET(LIBRESOURCE src/cmd/json.cpp ) +SET(LIBCOMPONENT + src/components/component.cpp + + src/components/energy_consumer.cpp + src/components/energy_container.cpp + src/components/reactor.cpp + ) + SET(LIBGUI_SOURCES src/gui/button.cpp src/gui/control.cpp @@ -1123,6 +1133,7 @@ ADD_LIBRARY(vegastrike-engine_com ${LIBCONFIG} ${LIBDAMAGE} ${LIBRESOURCE} + ${LIBCOMPONENT} ${LIBAI_SOURCES} ${LIBCMD_SOURCES} ${LIBNET_SOURCES} @@ -1709,12 +1720,15 @@ IF (USE_GTEST) src/resource/tests/manifest_tests.cpp src/resource/tests/random_tests.cpp src/exit_unit_tests.cpp + src/components/tests/energy_container_tests.cpp + src/components/tests/balancing_tests.cpp ) ADD_LIBRARY(vegastrike-testing ${LIBCONFIG} ${LIBDAMAGE} ${LIBRESOURCE} + ${LIBCOMPONENT} ${LIBCMD_SOURCES} ${LIBVS_LOGGING} ) diff --git a/engine/src/cmd/unit_csv_factory.cpp b/engine/src/cmd/unit_csv_factory.cpp index 03be6f4b4..0f0951c39 100644 --- a/engine/src/cmd/unit_csv_factory.cpp +++ b/engine/src/cmd/unit_csv_factory.cpp @@ -93,9 +93,8 @@ std::vector ProcessLine(std::string &line) { return cells; } -void UnitCSVFactory::ParseCSV(VSFileSystem::VSFile &file, bool saved_game) { +void UnitCSVFactory::ParseCSV(std::string data, std::string root, bool saved_game) { std::vector columns; - std::string data = file.ReadFull(); std::string delimiter = "\n"; size_t pos = 0; std::string token; @@ -124,7 +123,7 @@ void UnitCSVFactory::ParseCSV(VSFileSystem::VSFile &file, bool saved_game) { } // Add root - unit_attributes["root"] = file.GetRoot(); + unit_attributes["root"] = root; std::string key = (saved_game ? "player_ship" : line[0]); @@ -151,3 +150,8 @@ std::string GetUnitKeyFromNameAndFaction(const std::string unit_name, const std: return std::string(); } + +void UnitCSVFactory::LoadUnit(std::string key, + std::map unit_map) { + UnitCSVFactory::units[key] = unit_map; +} \ No newline at end of file diff --git a/engine/src/cmd/unit_csv_factory.h b/engine/src/cmd/unit_csv_factory.h index 3d6b87c8b..62c0e46de 100644 --- a/engine/src/cmd/unit_csv_factory.h +++ b/engine/src/cmd/unit_csv_factory.h @@ -59,6 +59,8 @@ const std::string keys[] = {"Key", "Directory", "Name", "STATUS", "Object_Type", "Explosion", "Num_Animation_Stages", "Upgrade_Storage_Volume", "Heat_Sink_Rating", "Shield_Efficiency", "Num_Chunks", "Chunk_0", "Collide_Subunits", "Spec_Interdiction", "Tractorability", + // For component upgrade + "Upgrade_Type", "Facets", // These values are not in units.csv! There are probably more but I stopped mapping. // TODO: map all missing values using the commented out code below! "FaceCamera", "Unit_Role", "Attack_Preference", "Hidden_Hold_Volume", "Equipment_Space"}; @@ -102,7 +104,7 @@ class UnitCSVFactory { friend class UnitJSONFactory; friend class UnitOptimizeFactory; public: - static void ParseCSV(VSFileSystem::VSFile &file, bool saved_game); + static void ParseCSV(std::string data, std::string root, bool saved_game); template static inline T GetVariable(std::string unit_key, std::string const &attribute_key, T default_value) = delete; @@ -124,6 +126,9 @@ class UnitCSVFactory { static std::map GetUnit(std::string key) { return UnitCSVFactory::units[key]; } + + static void LoadUnit(std::string key, + std::map unit_map); }; // Template Specialization diff --git a/engine/src/cmd/unit_generic.cpp b/engine/src/cmd/unit_generic.cpp index 3c0498b1d..23c6d462a 100644 --- a/engine/src/cmd/unit_generic.cpp +++ b/engine/src/cmd/unit_generic.cpp @@ -454,7 +454,8 @@ void Unit::Init(const char *filename, VSFile unitTab; VSError taberr = unitTab.OpenReadOnly(filepath + ".csv", UnitSaveFile); if (taberr <= Ok) { - UnitCSVFactory::ParseCSV(unitTab, true); + std::string data = unitTab.ReadFull(); + UnitCSVFactory::ParseCSV(data, unitTab.GetRoot(), true); unitTab.Close(); saved_game = true; } diff --git a/engine/src/components/component.cpp b/engine/src/components/component.cpp new file mode 100644 index 000000000..54b936409 --- /dev/null +++ b/engine/src/components/component.cpp @@ -0,0 +1,78 @@ +/* + * component.cpp + * + * Copyright (c) 2001-2002 Daniel Horn + * Copyright (c) 2002-2019 pyramid3d and other Vega Strike Contributors + * Copyright (c) 2019-2023 Stephen G. Tuggy, Benjamen R. Meyer, Roy Falk and other Vega Strike Contributors + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +// -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- + +#include "component.h" +#include "unit_csv_factory.h" + +Component::Component(double mass, double volume, bool integral): + unit_key(""), + upgrade_name(""), + mass(mass), volume(volume), + integral(integral) {} + + +void Component::Load(std::string upgrade_key, std::string unit_key) { + this->unit_key = unit_key; + upgrade_name = UnitCSVFactory::GetVariable(upgrade_key, "Name", std::string()); + this->upgrade_key = upgrade_key; + + mass = UnitCSVFactory::GetVariable(upgrade_key, "Mass", 0.0); + // TODO: volume = UnitCSVFactory::GetVariable(upgrade_key, "Volume", 0.0); + // TODO: bool integral = false; +} + +// TODO: convert to std::pair +bool Component::CanWillUpDowngrade(const std::string upgrade_key, + bool upgrade, bool apply) { + if(upgrade) { + if(apply) { + return Upgrade(upgrade_key); + } else { + return CanUpgrade(upgrade_key); + } + } else { + if(apply) { + return Downgrade(); + } else { + return CanDowngrade(); + } + } +} + +bool Component::Downgrade() { + upgrade_name = std::string(); + upgrade_key = std::string(); + + mass = 0.0; + 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 new file mode 100644 index 000000000..28b17f32f --- /dev/null +++ b/engine/src/components/component.h @@ -0,0 +1,92 @@ +/* + * component.h + * + * Copyright (c) 2001-2002 Daniel Horn + * Copyright (c) 2002-2019 pyramid3d and other Vega Strike Contributors + * Copyright (c) 2019-2023 Stephen G. Tuggy, Benjamen R. Meyer, Roy Falk and other Vega Strike Contributors + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +// -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- + +#ifndef COMPONENT_H +#define COMPONENT_H + +#include +#include + +/** + * LibComponent is currently tightly coupled to LibDamage and + * other various libraries in VegaStrike engine. + * Consider decoupling and subclassing every component in it. + */ + +class Unit; + +// TODO: add complete list +enum class ComponentType { + Hull, + Armor, + Shield, + Drive +}; + +class Component +{ +protected: + std::string unit_key; // Areus.blank + std::string upgrade_name; // Isometal Armor + std::string upgrade_key; // armor03__upgrades + + double mass = 0; + double volume = 0; + + bool integral = false; // Part of the ship. Can't be upgraded/downgraded +public: + Component(double mass, + double volume, bool integral); + + // Load from units dictionary + virtual void Load(std::string upgrade_key, std::string unit_key); + + virtual void SaveToCSV(std::map& unit) const = 0; + + virtual std::string Describe() const = 0; // Describe component in base_computer + + // Handle the four cases of CanUpgrade/Upgrade/CanDowngrade/Downgrade + bool CanWillUpDowngrade(const std::string upgrade_key, + bool upgrade, bool apply); + + virtual bool CanDowngrade() const = 0; + + virtual bool Downgrade(); + + virtual bool CanUpgrade(const std::string upgrade_key) const = 0; + + virtual bool Upgrade(const std::string upgrade_key) = 0; + + virtual void Damage() = 0; + virtual void Repair() = 0; + + virtual bool Damaged() const = 0; + virtual bool Installed() const = 0; + + void SetIntegral(bool integral); +}; +#endif // COMPONENT_H diff --git a/engine/src/components/energy_consumer.cpp b/engine/src/components/energy_consumer.cpp new file mode 100644 index 000000000..8fd618acd --- /dev/null +++ b/engine/src/components/energy_consumer.cpp @@ -0,0 +1,68 @@ +/* + * energy_consumer.cpp + * + * Copyright (c) 2001-2002 Daniel Horn + * Copyright (c) 2002-2019 pyramid3d and other Vega Strike Contributors + * Copyright (c) 2019-2023 Stephen G. Tuggy, Benjamen R. Meyer, Roy Falk and other Vega Strike Contributors + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +// -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- + +#include "energy_consumer.h" + +double EnergyConsumer::simulation_atom_var = 0.1; + +EnergyConsumer::EnergyConsumer(EnergyContainer *source, + bool partial, + double consumption): + source(source), + partial(partial), + consumption(consumption), + atom_consumption(consumption * simulation_atom_var) {} + + +double EnergyConsumer::Consume() { + if(!source) { + return 0.0; + } + + return source->Deplete(partial, atom_consumption); +} + +double EnergyConsumer::GetConsumption() const { + return consumption; +} + +double EnergyConsumer::GetAtomConsumption() const { + return atom_consumption; +} + +void EnergyConsumer::SetConsumption(double consumption) { + this->consumption = consumption; + atom_consumption = consumption * simulation_atom_var; +} + +void EnergyConsumer::SetSource(EnergyContainer* source) { + this->source = source; +} + +void EnergyConsumer::ZeroSource() { + source->Zero(); +} \ No newline at end of file diff --git a/engine/src/components/energy_consumer.h b/engine/src/components/energy_consumer.h new file mode 100644 index 000000000..cc1eee109 --- /dev/null +++ b/engine/src/components/energy_consumer.h @@ -0,0 +1,54 @@ +/* + * energy_consumer.h + * + * Copyright (c) 2001-2002 Daniel Horn + * Copyright (c) 2002-2019 pyramid3d and other Vega Strike Contributors + * Copyright (c) 2019-2023 Stephen G. Tuggy, Benjamen R. Meyer, Roy Falk and other Vega Strike Contributors + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +// -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- + +#ifndef ENERGYCONSUMER_H +#define ENERGYCONSUMER_H + +#include "energy_container.h" + +class EnergyConsumer { +protected: + double consumption; // Directly converted to atomic. Mostly for book keeping. + double atom_consumption; // consumption per 0.1 seconds. + + static double simulation_atom_var; + +private: + EnergyContainer *source; + bool partial; // Can power consumer with less energy than requested +public: + EnergyConsumer(EnergyContainer *source, bool partial, double consumption = 0.0); + double Consume(); + double GetConsumption() const; + double GetAtomConsumption() const; + void SetConsumption(double consumption); + void SetSource(EnergyContainer* source); + void ZeroSource(); + +}; + +#endif // ENERGYCONSUMER_H diff --git a/engine/src/components/energy_container.cpp b/engine/src/components/energy_container.cpp new file mode 100644 index 000000000..b3c692a90 --- /dev/null +++ b/engine/src/components/energy_container.cpp @@ -0,0 +1,199 @@ +/* + * energy_container.cpp + * + * Copyright (c) 2001-2002 Daniel Horn + * Copyright (c) 2002-2019 pyramid3d and other Vega Strike Contributors + * Copyright (c) 2019-2023 Stephen G. Tuggy, Benjamen R. Meyer, Roy Falk and other Vega Strike Contributors + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +// -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- + +#include "energy_container.h" +#include "unit_csv_factory.h" + +#include + +const std::string FUEL_CAPACITY = "Fuel_Capacity"; +const std::string CAPACITOR = "Warp_Capacitor"; +const std::string FTL_CAPACITOR = "Primary_Capacitor"; + +EnergyContainer::EnergyContainer(EnergyType type): + Component(0.0, 0.0, false), + type(type), + level(Resource(0.0,0.0,0.0)) {} + + +// Return value - any surplus charge +double EnergyContainer::Charge(const double quantity) { + double old_level = level.Value(); + level += quantity; + + return quantity - level.Value() + old_level; +} + +double EnergyContainer::Deplete(bool partial, const double quantity) { + // Check we have enough energy to fully charge the consumer + if(!partial && quantity > level.Value()) { + return 0.0; + } + + double old_level = level.Value(); + level -= quantity; + double actual_usage = old_level - level.Value(); + return actual_usage / quantity; +} + +bool EnergyContainer::Depleted() const { + return (level.Value() < 0.0001); +} + +void EnergyContainer::SetCapacity(const double capacity, bool refill) { + if(refill) { + level = Resource(capacity,0,capacity); + } else { + level = Resource(0,0,capacity); + } +} + +double EnergyContainer::Level() const { return level.Value(); } +double EnergyContainer::MaxLevel() const { return level.MaxValue(); } +double EnergyContainer::Percent() const { + if(level.MaxValue() == 0.0) { + return 0.0; + } + + return level.Value()/level.MaxValue(); +} + +void EnergyContainer::Zero() { level = 0; } + + +void EnergyContainer::Refill() { + level.SetToMax(); +} + + +// Component Functions +void EnergyContainer::Load(std::string upgrade_key, std::string unit_key) { + // Component + upgrade_key = ""; + + // TODO: nice to have - ship mass goes down as fuel depleted + mass = 0; + volume = 0; + + double capacity = 0.0; + + switch(type) { + case EnergyType::Fuel: + upgrade_name = "Fuel"; + capacity = UnitCSVFactory::GetVariable(unit_key, FUEL_CAPACITY, 1.0); + break; + + case EnergyType::Energy: + upgrade_name = "Capacitor"; + capacity = UnitCSVFactory::GetVariable(unit_key, CAPACITOR, 1.0); + break; + + case EnergyType::FTL: + upgrade_name = "FTL_Capacitor"; + capacity = UnitCSVFactory::GetVariable(unit_key, FTL_CAPACITOR, 1.0); + break; + + case EnergyType::None: + break; + } + + SetCapacity(capacity); +} + +void EnergyContainer::SaveToCSV(std::map& unit) const { + unit[FUEL_CAPACITY] = std::to_string(MaxLevel()); +} + +std::string EnergyContainer::Describe() const { + return std::string(); +} + +bool EnergyContainer::CanDowngrade() const { + return !Damaged(); +} + +bool EnergyContainer::Downgrade() { + if(!CanDowngrade()) { + return false; + } + + level.SetMaxValue(0.0); + return true; +} + +bool EnergyContainer::CanUpgrade(const std::string upgrade_key) const { + return !Damaged(); +} + +bool EnergyContainer::Upgrade(const std::string upgrade_key) { + if(!CanUpgrade(upgrade_key)) { + return false; + } + + this->upgrade_key = upgrade_key; + upgrade_name = UnitCSVFactory::GetVariable(upgrade_key, "Name", std::string()); + + double capacity = 0.0; + + switch(type) { + case EnergyType::Fuel: + capacity = UnitCSVFactory::GetVariable(upgrade_key, FUEL_CAPACITY, 1.0); + break; + + case EnergyType::Energy: + capacity = UnitCSVFactory::GetVariable(upgrade_key, CAPACITOR, 1.0); + break; + + case EnergyType::FTL: + capacity = UnitCSVFactory::GetVariable(upgrade_key, FTL_CAPACITOR, 1.0); + break; + + case EnergyType::None: + break; + } + + SetCapacity(capacity); + return true; +} + + +void EnergyContainer::Damage() { + level.RandomDamage(); +} + +void EnergyContainer::Repair() { + level.RepairFully(); +} + +bool EnergyContainer::Damaged() const { + return level.Damaged(); +} + + +bool EnergyContainer::Installed() const { + return level > 0.0; +} \ No newline at end of file diff --git a/engine/src/components/energy_container.h b/engine/src/components/energy_container.h new file mode 100644 index 000000000..db5008451 --- /dev/null +++ b/engine/src/components/energy_container.h @@ -0,0 +1,98 @@ +/* + * energy_container.h + * + * Copyright (c) 2001-2002 Daniel Horn + * Copyright (c) 2002-2019 pyramid3d and other Vega Strike Contributors + * Copyright (c) 2019-2023 Stephen G. Tuggy, Benjamen R. Meyer, Roy Falk and other Vega Strike Contributors + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +// -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- + +#ifndef ENERGYCONTAINER_H +#define ENERGYCONTAINER_H + +#include +#include + +#include "resource/resource.h" +#include "component.h" + +/* Discussion of FTL - yes, it isn't really faster. However, +* it would be easier for a new developer or someone from WC +* to figure what it means. +*/ +enum class EnergyType { + Fuel, // 1 + Energy, // 0 Capacitor + FTL, // 2 FTL + None // 3 Free Energy +}; + + +/** + * @brief The EnergyContainer class models the fuel cell, capacitor and SPEC capacitor + */ +class EnergyContainer: public Component +{ +private: + EnergyType type; + Resource level; + +public: + EnergyContainer(EnergyType type); + + // Return value - any surplus charge + double Charge(const double quantity); + + // Partial - can power consumer with less energy than requested + double Deplete(bool partial, const double quantity); + bool Depleted() const; + + void SetCapacity(const double capacity, bool refill = true); + double Level() const; + double MaxLevel() const; + double Percent() const; + void Refill(); + + void Zero(); + + // Component + virtual void Load(std::string upgrade_key, std::string unit_key); + + virtual void SaveToCSV(std::map& unit) const; + + virtual std::string Describe() const; // Describe component in base_computer + + virtual bool CanDowngrade() const; + + virtual bool Downgrade(); + + virtual bool CanUpgrade(const std::string upgrade_name) const; + + virtual bool Upgrade(const std::string upgrade_name); + + virtual void Damage(); + virtual void Repair(); + + virtual bool Damaged() const; + virtual bool Installed() const; +}; + +#endif // ENERGYCONTAINER_H diff --git a/engine/src/components/reactor.cpp b/engine/src/components/reactor.cpp new file mode 100644 index 000000000..fe2ea5bd5 --- /dev/null +++ b/engine/src/components/reactor.cpp @@ -0,0 +1,145 @@ +/* + * reactor.cpp + * + * Copyright (c) 2001-2002 Daniel Horn + * Copyright (c) 2002-2019 pyramid3d and other Vega Strike Contributors + * Copyright (c) 2019-2023 Stephen G. Tuggy, Benjamen R. Meyer, Roy Falk and other Vega Strike Contributors + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +// -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- + +#include "reactor.h" + +#include "unit_csv_factory.h" + +#include + +const std::string REACTOR_RECHARGE = "Reactor_Recharge"; + + + +Reactor::Reactor(EnergyContainer *source, + EnergyContainer *energy, + EnergyContainer *ftl_energy, + double conversion_ratio): + Component(0.0, 0.0, false), + EnergyConsumer(source, false), + capacity(0.0, 0.0, 0.0), + atom_capacity(0.0), + conversion_ratio(conversion_ratio), + energy(energy), + ftl_energy(ftl_energy) { +} + + +void Reactor::Load(std::string upgrade_key, std::string unit_key) { + capacity = UnitCSVFactory::GetVariable(unit_key, REACTOR_RECHARGE, 0.0f); + atom_capacity = capacity * simulation_atom_var; + SetConsumption(capacity * conversion_ratio); +} + +void Reactor::SaveToCSV(std::map& unit) const { + // TODO: This won't record damage to recharge + unit[REACTOR_RECHARGE] = std::to_string(capacity.MaxValue()); +} + +std::string Reactor::Describe() const { + return std::string(); +} + +bool Reactor::CanDowngrade() const { + return !Damaged(); +} + +bool Reactor::Downgrade() { + if(!CanDowngrade()) { + return false; + } + + capacity.SetMaxValue(0.0); + atom_capacity = 0.0; + SetConsumption(0.0); + + return true; +} + +bool Reactor::CanUpgrade(const std::string upgrade_name) const { + return !Damaged(); +} + +bool Reactor::Upgrade(const std::string upgrade_name) { + if(!CanUpgrade(upgrade_key)) { + return false; + } + + this->upgrade_key = upgrade_key; + this->upgrade_name = upgrade_name; + + capacity = UnitCSVFactory::GetVariable(upgrade_name, REACTOR_RECHARGE, 0.0f); + atom_capacity = capacity * simulation_atom_var; + SetConsumption(capacity * conversion_ratio); + + return true; +} + +void Reactor::Damage() { + capacity.RandomDamage(); + atom_capacity = capacity.Value() * simulation_atom_var; +} + +void Reactor::Repair() { + capacity.RepairFully(); + atom_capacity = capacity.Value() * simulation_atom_var; +} + +bool Reactor::Damaged() const { + return capacity.Damaged(); +} + +bool Reactor::Installed() const { + return capacity.MaxValue() > 0; +} + +void Reactor::Generate() { + double power = Consume(); + + // Zero out fuel if power is 0 + if(power < 0.0001) { + ZeroSource(); + return; + } + + double surplus = energy->Charge(atom_capacity * power); + surplus = ftl_energy->Charge(atom_capacity * surplus); +} + +double Reactor::Capacity() const { + return capacity.Value(); +} + +double Reactor::MaxCapacity() const { + return capacity.MaxValue(); +} + +void Reactor::SetCapacity(double capacity) { + this->capacity.SetMaxValue(capacity); + atom_capacity = capacity * simulation_atom_var; + SetConsumption(capacity * conversion_ratio); +} \ No newline at end of file diff --git a/engine/src/components/reactor.h b/engine/src/components/reactor.h new file mode 100644 index 000000000..2176021ab --- /dev/null +++ b/engine/src/components/reactor.h @@ -0,0 +1,81 @@ +/* + * reactor.h + * + * Copyright (c) 2001-2002 Daniel Horn + * Copyright (c) 2002-2019 pyramid3d and other Vega Strike Contributors + * Copyright (c) 2019-2023 Stephen G. Tuggy, Benjamen R. Meyer, Roy Falk and other Vega Strike Contributors + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +// -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- + +#ifndef REACTOR_H +#define REACTOR_H + +#include "component.h" +#include "energy_container.h" +#include "energy_consumer.h" +#include "resource/resource.h" + +class EnergyManager; + +class Reactor: public Component, public EnergyConsumer +{ +private: + Resource capacity; // Capacity per second + double atom_capacity; // Capacity per atom + const double conversion_ratio; // Used to calculate fuel consumption + + EnergyContainer *energy; + EnergyContainer *ftl_energy; + +public: + Reactor(EnergyContainer *source, + EnergyContainer *energy, + EnergyContainer *ftl_energy, + double conversion_ratio = 0.0001); // < 0.01 or very short flight + + + virtual void Load(std::string upgrade_key, std::string unit_key); + + virtual void SaveToCSV(std::map& unit) const; + + virtual std::string Describe() const; // Describe component in base_computer + + virtual bool CanDowngrade() const; + + virtual bool Downgrade(); + + virtual bool CanUpgrade(const std::string upgrade_name) const; + + virtual bool Upgrade(const std::string upgrade_name); + + virtual void Damage(); + virtual void Repair(); + + virtual bool Damaged() const; + virtual bool Installed() const; + + void Generate(); + double Capacity() const; + double MaxCapacity() const; + void SetCapacity(double capacity); +}; + +#endif // REACTOR_H diff --git a/engine/src/components/tests/balancing_tests.cpp b/engine/src/components/tests/balancing_tests.cpp new file mode 100644 index 000000000..081ab49f7 --- /dev/null +++ b/engine/src/components/tests/balancing_tests.cpp @@ -0,0 +1,176 @@ +#include + +#include "energy_container.h" +#include "reactor.h" + +double simulation_atom_var = 0.1; + +bool fairlyEqual(double a, double b); + +struct EnergySetup { + double capacity; + double fuel_capacity; + double energy_capacity; + double ftl_capacity; + + EnergySetup(double capacity, double fuel_capacity, + double energy_capacity, + double ftl_capacity): + capacity(capacity), fuel_capacity(fuel_capacity), + energy_capacity(energy_capacity), ftl_capacity(ftl_capacity) {} +}; + + +double reactor_capacity = 15; + +double fuel_capacity = 3.51; // Robin +double energy_capacity = 100.0; // capacitor 1 +double spec_capacity = 200.0; // spec capacitor 1 + +double mass = 48; + +// Consumers +// Fuel +double reactor_usage_factor = 0.001; +double drive = 1; +double afterburner = 3; + +// Energy +double shield_recharge = 4; +double lifeSupport = 1; +double radar = 1; +double shieldRegen = 1; +double shieldMaintenance = 1; +double ECM = 10; +double Cloak = 10; + +// SPEC +double SPECDrive = 1; +double JumpDrive = 1; + +struct EnergyManager { + EnergyContainer fuel; + EnergyContainer energy; + EnergyContainer ftl_energy; + Reactor reactor; + + EnergyManager(EnergySetup setup, + double simulation_atom_var): + fuel(EnergyType::Fuel), energy(EnergyType::Energy), + ftl_energy(EnergyType::FTL), + reactor(&fuel, &energy, &ftl_energy) { + fuel.SetCapacity(setup.fuel_capacity); + energy.SetCapacity(setup.energy_capacity); + ftl_energy.SetCapacity(setup.ftl_capacity); + reactor.SetCapacity(setup.capacity); + } + + void Print(int counter) { + std::cout << counter << " R: " << reactor.Capacity() << + " F: " << fuel.Level() << + " E: " << energy.Level() << + " S: " << ftl_energy.Level() << std::endl; + } +}; + +struct FuelBurnResult { + double residue; + int iterations; + int seconds; + + FuelBurnResult(double residue, int iterations, int seconds): + residue(residue), iterations(iterations), seconds(seconds) {} +}; + +FuelBurnResult fuelBurn(EnergyManager& manager, + std::vector& consumers, + int seconds, + int print_every_n = 1000) { + int run_time = seconds / simulation_atom_var; + + manager.Print(-1); + EXPECT_FALSE(manager.fuel.Depleted()); + EXPECT_FALSE(manager.energy.Depleted()); + EXPECT_FALSE(manager.ftl_energy.Depleted()); + + int i = 0; + for(;i consumers = {}; + + FuelBurnResult result = fuelBurn(manager, consumers, seconds, 1000); + std::cout << "Reactor consumption: " << manager.reactor.GetAtomConsumption() << std::endl; + + std::cout << "NoFuelBurn percent left: " << result.residue * 100 << std::endl; + + // 1 / (sim_atom_var (0.1) * conversion_ration (0.001)) + EXPECT_GT(result.iterations, 99900); + EXPECT_LT(result.iterations, 100900); +} + +// This tests a fighter ship with level 1 equipment and steady 15MJ energy consumption +// Ship flies for 22 minutes +TEST(FuelBurn, RobinNaive_1) { + EnergySetup setup = {15.0, 3.51, 100.0, 200.0}; + EnergyManager manager = EnergyManager(setup, simulation_atom_var); + std::vector consumers = { + EnergyConsumer(&manager.fuel, false, 0.001), // Drive + EnergyConsumer(&manager.fuel, false, 0.001 * 3 * .05), // Afterburner, Drive consumption x 3 but 5% of flight time + EnergyConsumer(&manager.energy, false, 15.0) // General consumer at 15 per second + }; + + int seconds = 60 * 60; // 60 minutes gameplay + + FuelBurnResult result = fuelBurn(manager, consumers, seconds, 1000); + EXPECT_GT(result.iterations, 12000); // More than 10 minutes + + std::cout << "RobinNaive_1 NoFuelBurn percent left: " << result.residue * 100 << std::endl; + //EXPECT_EQ(0,1); // use these to see detailed prints +} + +// This tests a fighter ship with level 1 equipment and steady 40MJ energy consumption +// Ship flies for 10 minutes +TEST(FuelBurn, RobinNaive_2) { + EnergySetup setup = {44.0, 3.51, 300.0, 200.0}; + EnergyManager manager = EnergyManager(setup, simulation_atom_var); + std::vector consumers = { + EnergyConsumer(&manager.fuel, false, 0.001), // Drive + EnergyConsumer(&manager.fuel, false, 0.001 * 3 * .05), // Afterburner, Drive consumption x 3 but 5% of flight time + EnergyConsumer(&manager.energy, false, 40) // General consumer at 40 per second + }; + + int seconds = 60 * 60; // 60 minutes gameplay + + FuelBurnResult result = fuelBurn(manager, consumers, seconds, 1000); + EXPECT_GT(result.iterations, 6000); // More than 10 minutes + + std::cout << "NaiveFuelBurn_2 percent left: " << result.residue * 100 << std::endl; + //EXPECT_EQ(0,1); // use these to see detailed prints +} \ No newline at end of file diff --git a/engine/src/components/tests/energy_container_tests.cpp b/engine/src/components/tests/energy_container_tests.cpp new file mode 100644 index 000000000..d5bed7838 --- /dev/null +++ b/engine/src/components/tests/energy_container_tests.cpp @@ -0,0 +1,30 @@ +#include + +#include "energy_container.h" +#include "energy_consumer.h" + +void printContainer(EnergyContainer& container) { + std::cout << "Max Level: " << container.MaxLevel(); + std::cout << " Level: " << container.Level(); + std::cout << " Percent: " << container.Percent() << std::endl; +} + +TEST(EnergyContainer, Sanity) { + EnergyContainer container = EnergyContainer(EnergyType::Energy); + EXPECT_EQ(container.Level(), 0.0); + container.SetCapacity(10.0, true); + + printContainer(container); + + EnergyConsumer consumer = EnergyConsumer(&container, + false, + 1.0); + + + int i=0; + while(!container.Depleted() && i < 100) { + consumer.Consume(); + printContainer(container); + i++; + } +} \ No newline at end of file diff --git a/engine/src/universe.cpp b/engine/src/universe.cpp index ceb935368..c753a1a8b 100644 --- a/engine/src/universe.cpp +++ b/engine/src/universe.cpp @@ -287,7 +287,8 @@ void InitUnitTables() { VSFileSystem::VSFile csvFile; VSFileSystem::VSError err = csvFile.OpenReadOnly("units.csv", VSFileSystem::UnitFile); if (err <= VSFileSystem::Ok) { - UnitCSVFactory::ParseCSV(csvFile, true); + std::string data = csvFile.ReadFull(); + UnitCSVFactory::ParseCSV(data, csvFile.GetRoot(), true); } else { std::cerr << "Unable to open units file. Aborting.\n"; abort();