diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index d38bd30f0d..ea6f8bc342 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -708,7 +708,10 @@ SET(LIBRESOURCE src/resource/resource.cpp src/resource/store.cpp src/resource/product.cpp -) + src/resource/cargo.cpp + src/resource/manifest.cpp + src/cmd/json.cpp + ) SET(LIBGUI_SOURCES src/gui/button.cpp @@ -853,7 +856,6 @@ ENDIF() SET(LIBCMD_SOURCES src/cmd/alphacurve.cpp - src/cmd/cargo.cpp src/cmd/carrier.cpp src/cmd/collection.cpp src/cmd/collide_map.cpp @@ -871,7 +873,6 @@ SET(LIBCMD_SOURCES src/cmd/unit_csv_factory.cpp src/cmd/unit_json_factory.cpp src/cmd/unit_optimize_factory.cpp - src/cmd/json.cpp src/cmd/unit_functions_generic.cpp src/cmd/unit_generic.cpp src/cmd/upgradeable_unit.cpp @@ -1702,6 +1703,7 @@ IF (USE_GTEST) src/damage/tests/object_tests.cpp src/resource/tests/buy_sell.cpp src/resource/tests/resource_test.cpp + src/resource/tests/manifest_tests.cpp src/exit_unit_tests.cpp ) diff --git a/engine/src/cmd/basecomputer.h b/engine/src/cmd/basecomputer.h index d64bdff48d..37b8eb0b8b 100644 --- a/engine/src/cmd/basecomputer.h +++ b/engine/src/cmd/basecomputer.h @@ -29,6 +29,7 @@ #include "gui/windowcontroller.h" #include "cmd/unit_generic.h" #include "gui/simplepicker.h" +#include "cargo_color.h" //The BaseComputer class displays an interactive screen that supports a //number of functions in a base. diff --git a/engine/src/cmd/cargo_color.h b/engine/src/cmd/cargo_color.h new file mode 100644 index 0000000000..77edc3764d --- /dev/null +++ b/engine/src/cmd/cargo_color.h @@ -0,0 +1,43 @@ +/** + * cargo_color.h + * + * Copyright (c) 2001-2002 Daniel Horn + * Copyright (c) 2002-2019 pyramid3d and other Vega Strike Contributors + * Copyright (c) 2019-2021 Stephen G. Tuggy, and other Vega Strike Contributors + * Copyright (C) 2022-2023 Stephen G. Tuggy, Benjamen R. Meyer + * + * 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 . + */ +#ifndef VEGA_STRIKE_ENGINE_CMD_CARGO_COLOR_H +#define VEGA_STRIKE_ENGINE_CMD_CARGO_COLOR_H + +#include "gfxlib_struct.h" +#include "cargo.h" + +// TODO: remove this. That's what std::pair is for. +// A stupid struct that is only for grouping 2 different types of variables together in one return value +class CargoColor { +public: + Cargo cargo; + GFXColor color; + + CargoColor() : cargo(), color(1, 1, 1, 1) { + } +}; + +#endif //VEGA_STRIKE_ENGINE_CMD_CARGO_COLOR_H diff --git a/engine/src/cmd/carrier.cpp b/engine/src/cmd/carrier.cpp index e1be6243bd..47c509a191 100644 --- a/engine/src/cmd/carrier.cpp +++ b/engine/src/cmd/carrier.cpp @@ -41,7 +41,6 @@ extern int SelectDockPort(Unit *, Unit *parent); extern void SwitchUnits(Unit *, Unit *); extern void abletodock(int dock); -extern void UpdateMasterPartList(Unit *ret); // Replace with std:sto* here and at unit_csv.cpp static double stof(const string &inp, double def = 0) { @@ -544,58 +543,7 @@ float Carrier::getCargoVolume(void) const { return result; } -// TODO: get rid of this helper function and others like it. -extern std::string getJSONValue(const json::jobject& object, const std::string &key, const std::string &default_value); -Unit *Carrier::makeMasterPartList() { - unsigned int i; - Unit *ret = new Unit(); - ret->name = "master_part_list"; - - //vs_config->getVariable("data", "master_part_list", "master_part_list"); - static std::string json_filenames[] = { - "master_part_list.json", - "master_ship_list.json", - "master_component_list.json", - "master_asteroid_list.json", - }; - - for(const std::string& json_filename : json_filenames) { - std::ifstream ifs(json_filename, std::ifstream::in); - std::stringstream buffer; - buffer << ifs.rdbuf(); - - const std::string json_text = buffer.str(); - - std::vector parts = json::parsing::parse_array(json_text.c_str()); - for (const std::string &part_text : parts) { - json::jobject part = json::jobject::parse(part_text); - Cargo carg; - - carg.name = getJSONValue(part, "file", ""); - carg.SetCategory(getJSONValue(part, "categoryname", "")); - carg.SetVolume(std::stof(getJSONValue(part, "volume", ""))); - carg.SetMass(std::stof(getJSONValue(part, "mass", ""))); - carg.quantity = 1; - carg.price = std::stoi(getJSONValue(part, "price", "")); - carg.SetDescription(getJSONValue(part, "description", "")); - ret->cargo.push_back(carg); - } - } - - - UpdateMasterPartList(ret); - if (!ret->GetCargo("Pilot", i)) { //required items - ret->AddCargo(Cargo("Pilot", "Contraband", 800, 1, .01, 1, 1.0, 1.0), true); - } - if (!ret->GetCargo("Hitchhiker", i)) { - ret->AddCargo(Cargo("Hitchhiker", "Passengers", 42, 1, .01, 5.0, 1.0, 1.0), true); - } - if (!ret->GetCargo("Slaves", i)) { - ret->AddCargo(Cargo("Slaves", "Contraband", 800, 1, .01, 1, 1, 1), true); - } - return ret; -} float Carrier::PriceCargo(const std::string &s) { Unit *unit = static_cast(this); diff --git a/engine/src/cmd/carrier.h b/engine/src/cmd/carrier.h index 7cd35de844..e334e5d56e 100644 --- a/engine/src/cmd/carrier.h +++ b/engine/src/cmd/carrier.h @@ -26,9 +26,13 @@ #ifndef VEGA_STRIKE_ENGINE_CMD_CARRIER_H #define VEGA_STRIKE_ENGINE_CMD_CARRIER_H -#include "cargo.h" +#include "resource/cargo.h" +#include "gfx/vec.h" #include +#include + +class Unit; // A unit (ship) that carries cargo class Carrier { @@ -39,7 +43,6 @@ class Carrier { void SortCargo(); static std::string cargoSerializer(const struct XMLType &input, void *mythis); - static Unit *makeMasterPartList(); bool CanAddCargo(const Cargo &carg) const; void AddCargo(const Cargo &carg, bool sort = true); int RemoveCargo(unsigned int i, int quantity, bool eraseZero = true); diff --git a/engine/src/cmd/script/script_call_unit_generic.cpp b/engine/src/cmd/script/script_call_unit_generic.cpp index abf7094832..be0566267f 100644 --- a/engine/src/cmd/script/script_call_unit_generic.cpp +++ b/engine/src/cmd/script/script_call_unit_generic.cpp @@ -68,9 +68,10 @@ #include "star_system.h" #include "universe.h" #include "vs_logging.h" +#include "manifest.h" extern const vector &ParseDestinations(const string &value); -extern Unit &GetUnitMasterPartList(); + extern bool PlanetHasLights(Unit *un); #if 0 @@ -243,57 +244,34 @@ varInst *Mission::call_unit(missionNode *node, int mode) { varInst *vireturn = NULL; vireturn = call_olist_new(node, mode); if (mode == SCRIPT_RUN) { - Cargo *ret = NULL; - Unit *mpl = &GetUnitMasterPartList(); - unsigned int max = mpl->numCargo(); - if (!category.empty()) { - size_t Begin, End; - mpl->GetSortedCargoCat(category, Begin, End); - if (Begin < End) { - unsigned int i = Begin + (rand() % (End - Begin)); - ret = &mpl->GetCargo(i); - } - } else { - if (mpl->numCargo()) { - for (unsigned int i = 0; i < 500; i++) { - ret = &mpl->GetCargo(rand() % max); - if (ret->GetName().find("mission") == string::npos) { - break; - } - } - } else { - ret = new Cargo(); //mem leak--won't happen - } - } - if (ret) { - ret->SetQuantity(quantity); - viret = newVarInst(VI_IN_OBJECT); - viret->type = VAR_OBJECT; - viret->objectname = "string"; - viret->object = ret->GetNameAddress(); - ((olist_t *) vireturn->object)->push_back(viret); - viret = newVarInst(VI_IN_OBJECT); - viret->type = VAR_OBJECT; - viret->objectname = "string"; - viret->object = const_cast(&ret->GetCategory()); - ((olist_t *) vireturn->object)->push_back(viret); - viret = newVarInst(VI_IN_OBJECT); - viret->type = VAR_FLOAT; - viret->float_val = ret->GetPrice(); - ((olist_t *) vireturn->object)->push_back(viret); - viret = newVarInst(VI_IN_OBJECT); - viret->type = VAR_INT; - viret->int_val = quantity; - ((olist_t *) vireturn->object)->push_back(viret); - viret = newVarInst(VI_IN_OBJECT); - viret->type = VAR_FLOAT; - viret->float_val = ret->GetMass(); - ((olist_t *) vireturn->object)->push_back(viret); - viret = newVarInst(VI_IN_OBJECT); - viret->type = VAR_FLOAT; - viret->float_val = ret->GetVolume(); - ((olist_t *) vireturn->object)->push_back(viret); - } + Cargo c = Manifest::MPL().GetRandomCargoFromCategory(category, quantity); + + viret = newVarInst(VI_IN_OBJECT); + viret->type = VAR_OBJECT; + viret->objectname = "string"; + viret->object = c.GetNameAddress(); + ((olist_t *) vireturn->object)->push_back(viret); + viret = newVarInst(VI_IN_OBJECT); + viret->type = VAR_OBJECT; + viret->objectname = "string"; + viret->object = const_cast(&c.GetCategory()); + ((olist_t *) vireturn->object)->push_back(viret); + viret = newVarInst(VI_IN_OBJECT); + viret->type = VAR_FLOAT; + viret->float_val = c.GetPrice(); + ((olist_t *) vireturn->object)->push_back(viret); + viret = newVarInst(VI_IN_OBJECT); + viret->type = VAR_INT; + viret->int_val = quantity; + ((olist_t *) vireturn->object)->push_back(viret); + viret = newVarInst(VI_IN_OBJECT); + viret->type = VAR_FLOAT; + viret->float_val = c.GetMass(); + ((olist_t *) vireturn->object)->push_back(viret); + viret = newVarInst(VI_IN_OBJECT); + viret->type = VAR_FLOAT; + viret->float_val = c.GetVolume(); + ((olist_t *) vireturn->object)->push_back(viret); } debug(3, node, mode, "unit getRandCargo: "); printVarInst(3, vireturn); diff --git a/engine/src/cmd/unit_csv.cpp b/engine/src/cmd/unit_csv.cpp index 91d28caa76..ad6496e888 100644 --- a/engine/src/cmd/unit_csv.cpp +++ b/engine/src/cmd/unit_csv.cpp @@ -1424,41 +1424,7 @@ string Unit::WriteUnitString() { return writeCSV(unit); } -void UpdateMasterPartList(Unit *ret) { - for (unsigned int i = 0; i < _Universe->numPlayers(); ++i) { - Cockpit *cp = _Universe->AccessCockpit(i); - std::vector *addedcargoname = &cp->savegame->getMissionStringData("master_part_list_content"); - std::vector *addedcargocat = &cp->savegame->getMissionStringData("master_part_list_category"); - std::vector *addedcargovol = &cp->savegame->getMissionStringData("master_part_list_volume"); - std::vector *addedcargoprice = &cp->savegame->getMissionStringData("master_part_list_price"); - std::vector *addedcargomass = &cp->savegame->getMissionStringData("master_part_list_mass"); - std::vector *addedcargodesc = &cp->savegame->getMissionStringData("master_part_list_description"); - for (unsigned int j = 0; j < addedcargoname->size(); ++j) { - Cargo carg; - carg.SetName((*addedcargoname)[j]); - carg.SetCategory((j < addedcargocat->size() ? (*addedcargocat)[j] : std::string("Uncategorized"))); - carg.SetVolume((j < addedcargovol->size() ? XMLSupport::parse_float((*addedcargovol)[j]) : 1.0)); - carg.SetPrice((j < addedcargoprice->size() ? XMLSupport::parse_float((*addedcargoprice)[j]) : 0.0)); - carg.SetMass((j < addedcargomass->size() ? XMLSupport::parse_float((*addedcargomass)[j]) : .01)); - carg.SetDescription( - (j < addedcargodesc->size() ? (*addedcargodesc)[j] : std::string("No Description Added"))); - carg.SetQuantity(1); - ret->cargo.push_back(carg); - } - } - std::sort(ret->cargo.begin(), ret->cargo.end()); - { - Cargo last_cargo; - for (int i = ret->numCargo() - 1; i >= 0; --i) { - if (ret->GetCargo(i).GetName() == last_cargo.GetName() - && ret->GetCargo(i).GetCategory() == last_cargo.GetCategory()) { - ret->RemoveCargo(i, ret->GetCargo(i).GetQuantity(), true); - } else { - last_cargo = ret->GetCargo(i); - } - } - } -} + diff --git a/engine/src/cmd/unit_generic.cpp b/engine/src/cmd/unit_generic.cpp index 1365c74a73..14dfa67c83 100644 --- a/engine/src/cmd/unit_generic.cpp +++ b/engine/src/cmd/unit_generic.cpp @@ -77,6 +77,8 @@ #include "resource/resource.h" #include "base_util.h" #include "unit_csv_factory.h" +#include "savegame.h" +#include "manifest.h" #include #include @@ -96,22 +98,21 @@ using std::endl; using std::list; -std::string getMasterPartListUnitName() { - return configuration()->data_config.master_part_list; -} -Unit *_masterPartList = nullptr; +// This is a left over kludge because I don't want to mess with python interfaces yet. +// TODO: remove Unit *getMasterPartList() { - if (_masterPartList == nullptr) { - static bool making = true; - if (making) { - making = false; - _masterPartList = Unit::makeMasterPartList(); - making = true; + static Unit ret; + + if(ret.cargo.empty()) { + ret.name = "master_part_list"; + for(const Cargo& c : Manifest::MPL().getItems()) { + ret.AddCargo(c); } + } - return _masterPartList; + return &ret; } using namespace XMLSupport; @@ -2039,7 +2040,6 @@ void Unit::PerformDockingOperations() { std::set arrested_list_do_not_dereference; -void UpdateMasterPartList(Unit *); int Unit::ForceDock(Unit *utdw, unsigned int whichdockport) { if (utdw->pImage->dockingports.size() <= whichdockport) { @@ -2062,7 +2062,7 @@ int Unit::ForceDock(Unit *utdw, unsigned int whichdockport) { if (this == _Universe->AccessCockpit()->GetParent()) { this->RestoreGodliness(); } - UpdateMasterPartList(UniverseUtil::GetMasterPartList()); + unsigned int cockpit = UnitUtil::isPlayerStarship(this); static float MinimumCapacityToRefuelOnLand = diff --git a/engine/src/cmd/unit_generic.h b/engine/src/cmd/unit_generic.h index 75aec3451f..00cb85b922 100644 --- a/engine/src/cmd/unit_generic.h +++ b/engine/src/cmd/unit_generic.h @@ -80,6 +80,8 @@ void UncheckUnit( class Unit*un ); #include "configuration/configuration.h" #include "configuration/game_config.h" +#include "cargo_color.h" + extern char *GetUnitDir(const char *filename); Unit *getMasterPartList(); diff --git a/engine/src/cmd/weapon_factory.cpp b/engine/src/cmd/weapon_factory.cpp index 3a00ae1f99..123f606b23 100644 --- a/engine/src/cmd/weapon_factory.cpp +++ b/engine/src/cmd/weapon_factory.cpp @@ -87,7 +87,8 @@ WeaponFactory::WeaponFactory(std::string filename) { } } -std::string getJSONValue(const json::jobject& object, const std::string &key, const std::string &default_value) { +// TODO: dup in MPL. Remove +static std::string getJSONValue(const json::jobject& object, const std::string &key, const std::string &default_value) { if(object.has_key(key)) { std::string value = object.get(key); value = value.substr(1, value.size() - 2); @@ -97,7 +98,7 @@ std::string getJSONValue(const json::jobject& object, const std::string &key, co return default_value; } -float getJSONValue(const json::jobject& object, const std::string &key, const float &default_value) { +static float getJSONValue(const json::jobject& object, const std::string &key, const float &default_value) { if(object.has_key(key)) { try { return std::stof(object.get(key)); diff --git a/engine/src/main.cpp b/engine/src/main.cpp index 8f805464a2..12b96fd2f3 100644 --- a/engine/src/main.cpp +++ b/engine/src/main.cpp @@ -349,6 +349,10 @@ int main(int argc, char *argv[]) { //might overwrite the default mission with the command line InitUnitTables(); + + // Initialise the master parts list before first use. + Manifest::MPL(); + #ifdef HAVE_PYTHON Python::init(); diff --git a/engine/src/cmd/cargo.cpp b/engine/src/resource/cargo.cpp similarity index 98% rename from engine/src/cmd/cargo.cpp rename to engine/src/resource/cargo.cpp index 5f690a03a0..46709e537e 100644 --- a/engine/src/cmd/cargo.cpp +++ b/engine/src/resource/cargo.cpp @@ -27,9 +27,8 @@ #include "cargo.h" -#include "unit_generic.h" -Cargo::Cargo() { +Cargo::Cargo(): Product() { mass = 0; volume = 0; mission = false; diff --git a/engine/src/cmd/cargo.h b/engine/src/resource/cargo.h similarity index 86% rename from engine/src/cmd/cargo.h rename to engine/src/resource/cargo.h index 626fe94bff..73a5237da6 100644 --- a/engine/src/cmd/cargo.h +++ b/engine/src/resource/cargo.h @@ -23,11 +23,9 @@ * You should have received a copy of the GNU General Public License * along with Vega Strike. If not, see . */ -#ifndef VEGA_STRIKE_ENGINE_CMD_CARGO_H -#define VEGA_STRIKE_ENGINE_CMD_CARGO_H +#ifndef VEGA_STRIKE_ENGINE_RESOURCE_CARGO_H +#define VEGA_STRIKE_ENGINE_RESOURCE_CARGO_H -#include "SharedPool.h" -#include "gfxlib_struct.h" #include "product.h" #include @@ -44,6 +42,7 @@ class Cargo : public Product { float functionality; float max_functionality; + friend class Manifest; public: Cargo(); Cargo(std::string name, std::string category, float price, int quantity, float mass, float volume, @@ -83,15 +82,4 @@ class Cargo : public Product { int reduce() { quantity--; return quantity; } }; -// A stupid struct that is only for grouping 2 different types of variables together in one return value -// Must come after Cargo for obvious reasons -class CargoColor { -public: - Cargo cargo; - GFXColor color; - - CargoColor() : cargo(), color(1, 1, 1, 1) { - } -}; - -#endif //VEGA_STRIKE_ENGINE_CMD_CARGO_H +#endif //VEGA_STRIKE_ENGINE_RESOURCE_CARGO_H diff --git a/engine/src/resource/manifest.cpp b/engine/src/resource/manifest.cpp new file mode 100644 index 0000000000..73bee5bdd2 --- /dev/null +++ b/engine/src/resource/manifest.cpp @@ -0,0 +1,170 @@ +/* + * manifest.cpp + * + * Copyright (C) 2001-2023 Daniel Horn, Benjaman Meyer, Roy Falk, Stephen G. Tuggy, + * 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 3 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 . + */ + +#include "manifest.h" + +#include +#include +#include +#include +#include + +//#include "xml_support.h" // TODO: replace this later +#include "json.h" + + +// TODO: get rid of this helper function and others like it. +static std::string getJSONValue(const json::jobject& object, const std::string &key, const std::string &default_value) { + if(object.has_key(key)) { + std::string value = object.get(key); + value = value.substr(1, value.size() - 2); + return value; + } + + return default_value; +} + +static float getJSONValue(const json::jobject& object, const std::string &key, const float &default_value) { + if(object.has_key(key)) { + try { + return std::stof(object.get(key)); + } catch(...) {} + try { + return std::stoi(object.get(key)); + } catch(...) {} + } + + return default_value; +} + + +Manifest::Manifest() { + _items = std::vector(); +} + +Manifest::Manifest(std::string category) { + Manifest& mpl = Manifest::MPL(); + + auto predicate = [&category](Cargo c) {return c.GetCategory() == category;}; + std::copy_if(mpl._items.begin(), mpl._items.end(), + std::back_inserter(_items), predicate); +} + +// Called by MPL if it is empty +Manifest::Manifest(int dummy) { + _items = std::vector(); + + // TODO: get this from some configuration maybe?!? + static std::string json_filenames[] = { + "master_part_list.json", + "master_ship_list.json", + "master_component_list.json", + "master_asteroid_list.json", + }; + + for(const std::string& json_filename : json_filenames) { + std::ifstream ifs(json_filename, std::ifstream::in); + std::stringstream buffer; + buffer << ifs.rdbuf(); + + const std::string json_text = buffer.str(); + + std::vector parts = json::parsing::parse_array(json_text.c_str()); + for (const std::string &part_text : parts) { + json::jobject part = json::jobject::parse(part_text); + + std::string name = getJSONValue(part, "file", ""); + std::string category = getJSONValue(part, "categoryname", ""); + + Cargo cargo = Cargo(name, + category, + std::stoi(getJSONValue(part, "price", "")), // Price + 1, // Quantity + std::stof(getJSONValue(part, "mass", "")), // Mass + std::stof(getJSONValue(part, "volume", ""))); // Volume + cargo.SetDescription(getJSONValue(part, "description", "")); // Description + _items.push_back(cargo); + } + } +} + +Manifest& Manifest::MPL() { + static Manifest mpl = Manifest(1); + + return mpl; +} + +Cargo Manifest::GetRandomCargo(int quantity) { + // TODO: Need to figure a better solution here + if(_items.empty()) { + return Cargo(); + } + + std::random_device dev; + std::mt19937 rng(dev()); + std::uniform_int_distribution int_dist(0,_items.size()-1); + + int index = int_dist(rng); // TODO: test this gets all items + Cargo c = _items[index]; + c.SetQuantity(quantity); + return c; +} + + + +Cargo Manifest::GetRandomCargoFromCategory(std::string category, int quantity) { + Manifest manifest = GetCategoryManifest(category); + + // If category is empty, return randomly from MPL itself. + if(manifest._items.empty()) { + manifest = GetMissionManifest(); + if(manifest._items.empty()) { + return GetRandomCargo(quantity); + } + } + + return manifest.GetRandomCargo(quantity); +} + +Manifest Manifest::GetCategoryManifest(std::string category) { + Manifest manifest; + + std::copy_if(_items.begin(), _items.end(), back_inserter(manifest._items), + [category](Cargo c) { + return c.GetCategory() == category; + }); + + return manifest; +} + +Manifest Manifest::GetMissionManifest() { + Manifest manifest; + + std::copy_if(_items.begin(), _items.end(), back_inserter(manifest._items), + [](Cargo c) { + return c.name.find("mission") != std::string::npos; + }); + + return manifest; +} diff --git a/engine/src/resource/manifest.h b/engine/src/resource/manifest.h new file mode 100644 index 0000000000..71d65aeced --- /dev/null +++ b/engine/src/resource/manifest.h @@ -0,0 +1,60 @@ +/* + * manifest.h + * + * Copyright (C) 2001-2023 Daniel Horn, Benjaman Meyer, Roy Falk, Stephen G. Tuggy, + * 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 3 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 . + */ + +#ifndef MANIFEST_H +#define MANIFEST_H + +#include +#include + +#include "cargo.h" + +/** + * A manifest is a list of items in a cargo hold. + * The master part list is a special, singleton instance holding all items + * in the game. It is read only (const). Its short is MPL. + **/ +class Manifest { + std::vector _items; + + Manifest(int dummy); // Create the MPL singleton. +public: + Manifest(); + Manifest(std::string category); // Create a subset of the MPL for a category + + static Manifest& MPL(); // Get the master part list singleton + Cargo GetRandomCargo(int quantity = 0); + Cargo GetRandomCargoFromCategory(std::string category, int quantity = 0); + Manifest GetCategoryManifest(std::string category); + Manifest GetMissionManifest(); + + std::vector getItems() { return _items; } + bool empty() { return _items.empty(); } + int size() { return _items.size(); } +}; + + + + +#endif //MANIFEST_H diff --git a/engine/src/resource/tests/manifest_tests.cpp b/engine/src/resource/tests/manifest_tests.cpp new file mode 100644 index 0000000000..a1a742e8b3 --- /dev/null +++ b/engine/src/resource/tests/manifest_tests.cpp @@ -0,0 +1,75 @@ +/* + * manifest.cpp + * + * Copyright (C) 2001-2023 Daniel Horn, Benjaman Meyer, Roy Falk, Stephen G. Tuggy, + * 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 3 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 . + */ + + +#include +#include +#include +#include + +#include "manifest.h" + + +TEST(Manifest, Random) { + int size = 5; + + std::random_device dev; + std::mt19937 rng(dev()); + std::uniform_int_distribution int_dist(0,size-1); + + for(int i=0;i<1000;i++) { + int index = int_dist(rng); + + EXPECT_GE(index,0); + EXPECT_LT(index,size); + } +} + + +TEST(Manifest, MPL) { + // TODO: reenable once we figure out how to find out the data folder location + + /*boost::filesystem::path full_path(boost::filesystem::current_path()); + std::cerr << "Current path is : " << full_path << std::endl; + std::string path = boost::filesystem::current_path().c_str(); + path = path + "/../data/"; + + boost::filesystem::current_path(path); + + Manifest mpl = Manifest::MPL(); + + std::cerr << "MPL Size" << mpl.size() << std::endl << std::flush; + + EXPECT_GT(mpl.size(), 100); + + Manifest food = mpl.GetCategoryManifest("Natural_Products/Food/Confed"); + + EXPECT_EQ(food.size(), 4); + + Cargo c = mpl.GetRandomCargoFromCategory("Natural_Products/Food/Confed"); + + std::cout << c.GetName() << std::endl; + + EXPECT_GT(c.GetName().size(), 0);*/ +} \ No newline at end of file diff --git a/engine/src/universe_util.h b/engine/src/universe_util.h index 97d9e29731..6a32bc011b 100644 --- a/engine/src/universe_util.h +++ b/engine/src/universe_util.h @@ -27,6 +27,7 @@ #include "cmd/collection.h" #include "gfx/vec.h" #include "cmd/unit_util.h" +#include "manifest.h" #include #include @@ -359,9 +360,6 @@ Unit *launch(std::string name_string, QVector pos, std::string sqadlogo); -///this gets a random cargo type (useful for cargo missions) from either any category if category is '' or else from a specific category 'Contraband' comes to mind! -Cargo getRandCargo(int quantity, std::string category); - ///this gets the current game time since last start in seconds //float GetGameTime(); diff --git a/engine/src/universe_util_generic.cpp b/engine/src/universe_util_generic.cpp index bd0f0916c9..6f3aa23764 100644 --- a/engine/src/universe_util_generic.cpp +++ b/engine/src/universe_util_generic.cpp @@ -51,6 +51,7 @@ #include "cmd/unit_collide.h" #include "cmd/unit_find.h" #include "unit_csv_factory.h" +#include "manifest.h" #include "python/init.h" #include @@ -202,36 +203,8 @@ namespace UniverseUtil { return tmp; } - Cargo getRandCargo(int quantity, string category) { - Cargo *ret = NULL; - Unit *mpl = &GetUnitMasterPartList(); - unsigned int max = mpl->numCargo(); - if (!category.empty()) { - size_t Begin, End; - mpl->GetSortedCargoCat(category, Begin, End); - if (Begin < End) { - unsigned int i = Begin + (rand() % (End - Begin)); - ret = &mpl->GetCargo(i); - } else { - VS_LOG(info, (boost::format("Cargo category %1% not found") % category)); - } - } else if (mpl->numCargo()) { - for (unsigned int i = 0; i < 500; ++i) { - ret = &mpl->GetCargo(rand() % max); - if (ret->GetName().find("mission") == string::npos) { - break; - } - } - } - if (ret) { - Cargo tempret = *ret; - tempret.SetQuantity(quantity); - return tempret; //uses copy - } else { - Cargo newret; - newret.SetQuantity(0); - return newret; - } + Cargo getRandCargo(int quantity, std::string category) { + return Manifest::MPL().GetRandomCargoFromCategory(category, quantity); } float GetGameTime() {