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() {