27#include "nlua_faction.h"
30#include "nlua_shiplog.h"
37#include "player_fleet.h"
41#define XML_MISSION_TAG "mission"
65static int mission_meetConditionals(
const MissionData *misn );
67 const Spob *pnt,
const StarSystem *sys );
106 WARN(_(
"Mission '%s' not found in stack"), name);
146 if (misn->
chunk == LUA_NOREF) {
147 WARN(_(
"Trying to initialize mission '%s' that has no loaded Lua chunk!"), misn->
name);
152 memset( mission, 0,
sizeof(
Mission) );
153 mission->
env = LUA_NOREF;
160 mission->
data = misn;
163 mission->
desc = strdup(_(
"No description."));
167 mission->
env = nlua_newEnv();
173 nlua_setenv(naevL, mission->
env,
"mem");
177 WARN(_(
"Error loading mission file: %s\n"
179 "Most likely Lua file has improper syntax, please check"),
187 int ret = misn_run( mission,
"create");
208 return misn_run( mission,
"accept" );
234static int mission_meetConditionals(
const MissionData *misn )
238 pcre2_match_data *match_data = pcre2_match_data_create_from_pattern( misn->
avail.
chapter_re, NULL );
240 pcre2_match_data_free( match_data );
243 case PCRE2_ERROR_NOMATCH:
246 WARN(_(
"Matching error %d"), rc );
255 if (mis_isFlag(misn,MISSION_UNIQUE) &&
264 WARN(_(
"Conditional for mission '%s' failed to run"), misn->
name);
289 const Spob *pnt,
const StarSystem *sys )
299 else if (spob_isFlag(pnt, SPOB_NOMISNSPAWN))
310 return !mission_meetConditionals( misn );
321void missions_run( MissionAvailability loc,
int faction,
const Spob *pnt,
const StarSystem *sys )
341 if (RNGF() < chance) {
395 return mission_meetConditionals( mdat );
398const char *mission_availabilityStr( MissionAvailability loc )
401 case MIS_AVAIL_UNSET:
405 case MIS_AVAIL_COMPUTER:
411 case MIS_AVAIL_ENTER:
423 case SYSMARKER_COMPUTER:
428 case SPOBMARKER_COMPUTER:
430 case SPOBMARKER_HIGH:
431 case SPOBMARKER_PLOT:
434 WARN(_(
"Unknown marker type."));
439MissionMarkerType mission_markerTypeSpobToSystem( MissionMarkerType t )
442 case SYSMARKER_COMPUTER:
447 case SPOBMARKER_COMPUTER:
448 return SYSMARKER_COMPUTER;
450 return SYSMARKER_LOW;
451 case SPOBMARKER_HIGH:
452 return SYSMARKER_HIGH;
453 case SPOBMARKER_PLOT:
454 return SYSMARKER_PLOT;
456 WARN(_(
"Unknown marker type."));
461MissionMarkerType mission_markerTypeSystemToSpob( MissionMarkerType t )
464 case SYSMARKER_COMPUTER:
465 return SPOBMARKER_COMPUTER;
467 return SPOBMARKER_LOW;
469 return SPOBMARKER_HIGH;
471 return SPOBMARKER_PLOT;
472 case SPOBMARKER_COMPUTER:
474 case SPOBMARKER_HIGH:
475 case SPOBMARKER_PLOT:
478 WARN(_(
"Unknown marker type."));
483void mission_toLuaTable( lua_State *L ,
const MissionData *m )
487 lua_pushstring(L, m->
name);
488 lua_setfield(L,-2,
"name");
490 lua_pushboolean(L,mis_isFlag(m,MISSION_UNIQUE));
491 lua_setfield(L,-2,
"unique");
495 lua_pushboolean(L,1);
496 lua_setfield(L,-2,m->
tags[j]);
498 lua_setfield(L,-2,
"tags");
501const char **mission_loadFailed (
void)
512 MissionMarkerType type;
516 xmlr_attr_int_def( node,
"id",
id, -1 );
517 xmlr_attr_int_def( node,
"type", type, -1 );
520 case SYSMARKER_COMPUTER:
526 WARN( _(
"Mission Marker to system '%s' does not exist"), xml_get( node ) );
530 case SPOBMARKER_COMPUTER:
532 case SPOBMARKER_HIGH:
533 case SPOBMARKER_PLOT:
536 WARN( _(
"Mission Marker to spob '%s' does not exist"), xml_get( node ) );
541 WARN(_(
"Unknown marker type."));
569 marker->
objid = objid;
605 StarSystem *firstsys = NULL;
618 case SYSMARKER_COMPUTER:
624 case SPOBMARKER_COMPUTER:
626 case SPOBMARKER_HIGH:
627 case SPOBMARKER_PLOT:
631 WARN(_(
"Marked spob '%s' is not in any system!"), pnt->
name);
637 WARN(_(
"Unknown marker type."));
642 sys_setFlag( sys, SYSTEM_CMARKED );
666 case SYSMARKER_COMPUTER:
672 case SPOBMARKER_COMPUTER:
674 case SPOBMARKER_HIGH:
675 case SPOBMARKER_PLOT:
679 WARN(_(
"Marked spob '%s' is not in any system!"), pnt->
name);
685 WARN(_(
"Unknown marker type."));
703 if (misn->
cargo == NULL)
720 if (misn->
cargo[i] == cargo_id)
724 DEBUG(_(
"Mission '%s' attempting to unlink nonexistent cargo %d."),
725 misn->
title, cargo_id);
752 WARN(_(
"Failed to remove mission cargo '%d' for mission '%s'."), misn->
cargo[i], misn->
title);
757 osd_destroy(misn->
osd);
763 if (misn->
env != LUA_NOREF)
764 nlua_freeEnv(misn->
env);
782 memset( misn, 0,
sizeof(
Mission) );
783 misn->
env = LUA_NOREF;
827 if (mission->
chunk != LUA_NOREF)
828 luaL_unref( naevL, LUA_REGISTRYINDEX, mission->
chunk );
834 free(mission->
tags[i]);
892 if ((m1->
npc != NULL) && (m2->
npc != NULL))
893 return strcmp( m1->
npc, m2->
npc );
896 if ((m1->
title != NULL) && (m2->
title != NULL))
915 const Spob *pnt,
const StarSystem *sys, MissionAvailability loc )
938 for (
int j=0; j<rep; j++) {
953 tmp = realloc( tmp,
sizeof(
Mission) * alloced );
981 if (strcasecmp( loc,
"None" ) == 0)
982 return MIS_AVAIL_NONE;
983 else if (strcasecmp( loc,
"Computer" ) == 0)
984 return MIS_AVAIL_COMPUTER;
985 else if (strcasecmp( loc,
"Bar" ) == 0)
986 return MIS_AVAIL_BAR;
987 else if (strcasecmp( loc,
"Land" ) == 0)
988 return MIS_AVAIL_LAND;
989 else if (strcasecmp( loc,
"Enter" ) == 0)
990 return MIS_AVAIL_ENTER;
1010 temp->
chunk = LUA_NOREF;
1016 xmlr_attr_strd(parent,
"name",temp->
name);
1017 if (temp->
name == NULL)
1018 WARN( _(
"Mission in %s has invalid or no name"), MISSION_DATA_PATH );
1020 node = parent->xmlChildrenNode;
1024 xml_onlyNodes(node);
1026 if (xml_isNode(node,
"unique")) {
1027 mis_setFlag(temp,MISSION_UNIQUE);
1030 if (xml_isNode(node,
"location")) {
1033 WARN(_(
"Mission '%s' has unknown location '%s'!"), temp->
name, xml_get(node) );
1037 xmlr_strd(node,
"spob",temp->
avail.
spob);
1040 if (xml_isNode(node,
"faction")) {
1046 xmlr_strd(node,
"cond",temp->
avail.
cond);
1047 xmlr_strd(node,
"done",temp->
avail.
done);
1050 if (xml_isNode(node,
"tags")) {
1051 xmlNodePtr cur = node->children;
1055 if (xml_isNode(cur,
"tag")) {
1056 const char *tmp = xml_get(cur);
1061 WARN(_(
"Mission '%s' has unknown node in tags '%s'."), temp->
name, cur->name );
1062 }
while (xml_nextNode(cur));
1065 else if (xml_isNode(node,
"notes"))
continue;
1067 WARN(_(
"Unknown node '%s' in mission '%s'"),node->name,temp->
name);
1068 }
while (xml_nextNode(node));
1074 WARN(_(
"Mission '%s' failed to compile Lua conditional!"), temp->
name);
1080 PCRE2_SIZE erroroffset;
1081 temp->
avail.
chapter_re = pcre2_compile( (PCRE2_SPTR)temp->
avail.
chapter, PCRE2_ZERO_TERMINATED, 0, &errornumber, &erroroffset, NULL );
1083 PCRE2_UCHAR buffer[256];
1084 pcre2_get_error_message( errornumber, buffer,
sizeof(buffer) );
1085 WARN(_(
"Mission '%s' chapter PCRE2 compilation failed at offset %d: %s"), temp->
name, (
int)erroroffset, buffer );
1089#define MELEMENT(o,s) \
1090 if (o) WARN( _("Mission '%s' missing/invalid '%s' element"), temp->name, s)
1091 MELEMENT(temp->
avail.
loc==MIS_AVAIL_UNSET,
"location");
1112 return strcmp( ma->
name, mb->
name );
1123 Uint32 time = SDL_GetTicks();
1125 char **mission_files;
1130 for (
int i=0; i <
array_size( mission_files ); i++) {
1132 free( mission_files[i] );
1142 WARN(_(
"Duplicate event '%s'!"), md->
name);
1151 time = SDL_GetTicks() - time;
1173 const char *pos, *start_pos;
1177 if (filebuf == NULL) {
1178 WARN(_(
"Unable to read data from '%s'"), file);
1187 pos =
strnstr( filebuf,
"</mission>", bufsize );
1189 pos =
strnstr( filebuf,
"function create", bufsize );
1190 if ((pos != NULL) && !strncmp(pos,
"--common",bufsize))
1191 WARN(_(
"Mission '%s' has create function but no XML header!"), file);
1197 start_pos =
strnstr( filebuf,
"<?xml ", bufsize );
1198 pos =
strnstr( filebuf,
"--]]", bufsize );
1199 if (pos == NULL || start_pos == NULL) {
1200 WARN(_(
"Mission file '%s' has missing XML header!"), file);
1205 doc = xmlParseMemory( start_pos, pos-start_pos);
1207 WARN(_(
"Unable to parse document XML header for Mission '%s'"), file);
1211 node = doc->xmlChildrenNode;
1213 ERR( _(
"Malformed XML header for '%s' mission: missing root element '%s'"), file,
XML_MISSION_TAG );
1220 temp->
lua = filebuf;
1224 if (temp->
chunk != LUA_NOREF) {
1225 luaL_unref( naevL, LUA_REGISTRYINDEX, temp->
chunk );
1226 temp->
chunk = LUA_NOREF;
1230 int ret = luaL_loadbuffer(naevL, temp->
lua, strlen(temp->
lua), temp->
name );
1231 if (ret == LUA_ERRSYNTAX)
1232 WARN(_(
"Mission Lua '%s' syntax error: %s"), file, lua_tostring(naevL,-1) );
1234 temp->
chunk = luaL_ref( naevL, LUA_REGISTRYINDEX );
1291 xmlw_startElem(writer,
"temporary_cargo");
1296 xmlw_startElem(writer,
"cargo");
1298 xmlw_endElem(writer);
1300 xmlw_endElem(writer);
1303 xmlw_startElem(writer,
"missions");
1309 xmlw_startElem(writer,
"mission");
1312 xmlw_attr(writer,
"data",
"%s",misn->
data->
name);
1313 xmlw_attr(writer,
"id",
"%u",misn->
id);
1315 xmlw_elem(writer,
"title",
"%s",misn->
title);
1316 xmlw_elem(writer,
"desc",
"%s",misn->
desc);
1317 xmlw_elem(writer,
"reward",
"%s",misn->
reward);
1318 xmlw_elem(writer,
"reward_value",
"%"CREDITS_PRI,misn->
reward_value);
1321 xmlw_startElem( writer,
"markers" );
1324 xmlw_startElem(writer,
"marker");
1325 xmlw_attr(writer,
"id",
"%d",m->
id);
1326 xmlw_attr(writer,
"type",
"%d",m->
type);
1328 xmlw_endElem(writer);
1330 xmlw_endElem( writer );
1333 xmlw_startElem(writer,
"cargos");
1335 xmlw_elem(writer,
"cargo",
"%u", misn->
cargo[j]);
1336 xmlw_endElem(writer);
1339 if (misn->
osd > 0) {
1341 char **items = osd_getItems(misn->
osd);
1343 xmlw_startElem(writer,
"osd");
1346 xmlw_attr(writer,
"title",
"%s",osd_getTitle(misn->
osd));
1347 xmlw_attr(writer,
"nitems",
"%d",
array_size(items));
1348 xmlw_attr(writer,
"active",
"%d",osd_getActive(misn->
osd));
1349 xmlw_attr(writer,
"hidden",
"%d",osd_getHide(misn->
osd));
1350 priority = osd_getPriority(misn->
osd);
1352 xmlw_attr(writer,
"priority",
"%d",osd_getPriority(misn->
osd));
1356 xmlw_elem(writer,
"msg",
"%s",items[j]);
1358 xmlw_endElem(writer);
1362 xmlw_startElem(writer,
"claims");
1364 xmlw_endElem(writer);
1367 xmlw_startElem(writer,
"lua");
1369 xmlw_endElem(writer);
1371 xmlw_endElem(writer);
1373 xmlw_endElem(writer);
1387 xmlw_attr( writer,
"name",
"%s",
c->name );
1388 xmlw_attr( writer,
"description",
"%s",
c->description );
1389 for (
int j=0; j <
array_size(
c->illegalto ); j++)
1390 xmlw_elem( writer,
"illegalto",
"%s",
faction_name(
c->illegalto[ j ] ) );
1405 node = parent->xmlChildrenNode;
1407 xml_onlyNodes(node);
1410 if (xml_isNode(node,
"temporary_cargo") || xml_isNode(node,
"mission_cargo")) {
1411 xmlNodePtr cur = node->xmlChildrenNode;
1414 if (xml_isNode( cur,
"cargo" ))
1416 }
while (xml_nextNode( cur ));
1419 }
while (xml_nextNode( node ));
1436 xmlr_attr_strd( cur,
"name", name );
1437 if ( name == NULL ) {
1438 WARN( _(
"Mission cargo without name!" ) );
1448 xmlr_attr_strd( cur,
"description", desc );
1449 if ( desc == NULL ) {
1450 WARN( _(
"Mission temporary cargo '%s' missing description!" ), name );
1457 ccur = cur->xmlChildrenNode;
1459 xml_onlyNodes( ccur );
1460 if ( xml_isNode( ccur,
"illegalto" ) ) {
1464 }
while ( xml_nextNode( ccur ) );
1485 node = parent->xmlChildrenNode;
1487 xml_onlyNodes(node);
1488 if (xml_isNode(node,
"missions")) {
1493 }
while (xml_nextNode(node));
1519 node = parent->xmlChildrenNode;
1521 if (xml_isNode(node,
"mission")) {
1524 int misn_failed = 0;
1528 xmlr_attr_strd(node,
"data", buf);
1531 WARN(_(
"Mission '%s' from saved game not found in game - ignoring."), buf);
1538 WARN(_(
"Mission '%s' from saved game failed to load properly - ignoring."), buf);
1548 xmlr_attr_int(node,
"id", misn->
id);
1550 cur = node->xmlChildrenNode;
1552 xmlr_strd(cur,
"title",misn->
title);
1553 xmlr_strd(cur,
"desc",misn->
desc);
1554 xmlr_strd(cur,
"reward",misn->
reward);
1558 if (xml_isNode(cur,
"markers")) {
1559 xmlNodePtr nest = cur->xmlChildrenNode;
1561 if (xml_isNode(nest,
"marker"))
1563 }
while (xml_nextNode(nest));
1567 if (xml_isNode(cur,
"cargos")) {
1568 xmlNodePtr nest = cur->xmlChildrenNode;
1570 if (xml_isNode(nest,
"cargo"))
1572 }
while (xml_nextNode(nest));
1576 if (xml_isNode(cur,
"osd")) {
1577 int hidden, priority;
1580 xmlr_attr_int_def( cur,
"nitems", nitems, -1 );
1583 xmlr_attr_strd(cur,
"title",title);
1584 items = malloc( nitems *
sizeof(
char*) );
1585 nest = cur->xmlChildrenNode;
1587 if (xml_isNode(nest,
"msg")) {
1589 WARN(_(
"Inconsistency with 'nitems' in save file."));
1592 items[i] = xml_get(nest);
1595 }
while (xml_nextNode(nest));
1598 xmlr_attr_int_def( cur,
"priority", priority, data->avail.priority );
1601 misn->
osd = osd_create( title, nitems, items, priority );
1606 xmlr_attr_int_def( cur,
"active", active, -1 );
1608 osd_active( misn->
osd, active );
1610 xmlr_attr_int_def( cur,
"hidden", hidden, 0 );
1611 osd_setHide( misn->
osd, hidden );
1615 if (xml_isNode(cur,
"claims"))
1618 if (xml_isNode(cur,
"lua")) {
1622 WARN(_(
"Mission '%s' from saved game failed to unpersist Lua properly - ignoring."), data->name);
1627 }
while (xml_nextNode(cur));
1637 }
while (xml_nextNode(node));
1642int mission_reload(
const char *name )
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
#define array_end(array)
Returns a pointer to the end of the reserved memory space.
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
#define array_shrink(ptr_array)
Shrinks memory to fit only ‘size’ elements.
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
#define array_begin(array)
Returns a pointer to the beginning of the reserved memory space.
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
void claim_destroy(Claim_t *claim)
Destroys a system claim.
void claim_activate(Claim_t *claim)
Activates a claim on a system.
Claim_t * claim_xmlLoad(xmlNodePtr parent)
Loads a claim.
int claim_xmlSave(xmlTextWriterPtr writer, const Claim_t *claim)
Saves all the systems in a claim in XML.
Commodity * commodity_newTemp(const char *name, const char *desc)
Creates a new temporary commodity.
Commodity * commodity_getW(const char *name)
Gets a commodity by name without warning.
int commodity_tempIllegalto(Commodity *com, int faction)
Makes a temporary commodity illegal to something.
int cond_compile(const char *cond)
Compiles a conditional statement that can then be used as a reference.
const char * faction_name(int f)
Gets a factions "real" (internal) name.
int faction_get(const char *name)
Gets a faction ID by name.
void hook_rmMisnParent(unsigned int parent)
Removes all hooks belonging to parent mission.
int mission_accept(Mission *mission)
Small wrapper for misn_run.
int missions_saveTempCommodity(xmlTextWriterPtr writer, const Commodity *c)
Saves a temporary commodity's defintion into the current node.
Mission ** player_missions
static int mission_markerLoad(Mission *misn, xmlNodePtr node)
Loads a mission marker from xml.
const StarSystem * mission_getSystemMarker(const Mission *misn)
Gets the first system that has been marked by a mission.
Mission * missions_genList(int *n, int faction, const Spob *pnt, const StarSystem *sys, MissionAvailability loc)
Generates a mission list. This runs create() so won't work with all missions.
void mission_cleanup(Mission *misn)
Cleans up a mission.
int mission_addMarker(Mission *misn, int id, int objid, MissionMarkerType type)
Adds a system marker to a mission.
const StarSystem * mission_sysComputerMark(const Mission *misn)
Marks the system of the computer mission to reflect where it will head to.
const MissionData * mission_getFromName(const char *name)
Gets mission data from a name.
void missions_free(void)
Frees all the mission data.
int mission_alreadyRunning(const MissionData *misn)
Checks to see if mission is already running.
static const char * mission_markerTarget(const MissionMarker *m)
Gets the name of the mission marker target.
static int mission_matchFaction(const MissionData *misn, int faction)
Checks to see if a mission matches the faction requirements.
int mission_linkCargo(Mission *misn, unsigned int cargo_id)
Links cargo to the mission for posterior cleanup.
void missions_activateClaims(void)
Activates mission claims.
void mission_sysMark(void)
Marks all active systems that need marking.
void missions_run(MissionAvailability loc, int faction, const Spob *pnt, const StarSystem *sys)
Runs missions matching location, all Lua side and one-shot.
static MissionData * mission_stack
int missions_loadActive(xmlNodePtr parent)
Loads the player's active missions from a save.
static int mission_parseFile(const char *file, MissionData *temp)
Parses a single mission.
static int mission_parseXML(MissionData *temp, const xmlNodePtr parent)
Parses a node of a mission.
static int missions_parseActive(xmlNodePtr parent)
Parses the actual individual mission nodes.
static char ** player_missions_failed
void mission_shift(int pos)
Puts the specified mission at the end of the player_missions array.
int missions_load(void)
Loads all the mission data.
static int missions_cmp(const void *a, const void *b)
Ordering function for missions.
Commodity * missions_loadTempCommodity(xmlNodePtr cur)
Loads a temporary commodity.
static int mission_meetReq(const MissionData *misn, int faction, const Spob *pnt, const StarSystem *sys)
Checks to see if a mission meets the requirements.
int mission_start(const char *name, unsigned int *id)
Starts a mission.
int mission_getID(const char *name)
Gets id from mission name.
int missions_saveActive(xmlTextWriterPtr writer)
Saves the player's active missions.
static int mission_compare(const void *arg1, const void *arg2)
Compares to missions to see which has more priority.
static unsigned int mission_genID(void)
Generates a new id for the mission.
static unsigned int mission_id
static void mission_freeData(MissionData *mission)
Frees MissionData.
static int mission_location(const char *loc)
Gets location based on a human readable string.
static int mission_init(Mission *mission, const MissionData *misn, int genid, int create, unsigned int *id)
Initializes a mission.
int mission_unlinkCargo(Mission *misn, unsigned int cargo_id)
Unlinks cargo from the mission, removes it from the player.
const MissionData * mission_list(void)
Returns all the missions.
int missions_loadCommodity(xmlNodePtr parent)
Loads the player's special mission commodities.
int mission_test(const char *name)
Tests the conditionals of a mission.
void missions_cleanup(void)
Cleans up all the player's active missions.
const MissionData * mission_get(int id)
Gets a MissionData based on ID.
int naev_isQuit(void)
Get if Naev is trying to quit.
Header file with generic functions and naev-specifics.
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
int misn_loadLibs(nlua_env env)
Registers all the mission libraries.
void npc_patchMission(Mission *misn)
Patches a new mission bar npc into the bar system.
int npc_rm_parentMission(unsigned int mid)
Removes all the npc belonging to a mission.
char * strnstr(const char *haystack, const char *needle, size_t size)
A bounded version of strstr. Conforms to BSD semantics.
int nxml_persistLua(nlua_env env, xmlTextWriterPtr writer)
Persists all the nxml Lua data.
int nxml_unpersistLua(nlua_env env, xmlNodePtr parent)
Unpersists Lua data into a table named "mem".
void gl_freeTexture(glTexture *texture)
Frees a texture.
int pilot_rmMissionCargo(Pilot *pilot, unsigned int cargo_id, int jettison)
Removes special mission cargo based on id.
int player_missionAlreadyDone(int id)
Checks to see if player has already completed a mission.
PilotCommodity * pfleet_cargoList(void)
Gets a list of all the cargo in the fleet.
Spob * spob_get(const char *spobname)
Gets a spob based on its name.
StarSystem * system_getIndex(int id)
Get the system by its index.
int spob_index(const Spob *p)
Gets the ID of a spob.
StarSystem * system_get(const char *sysname)
Get the system from its name.
const char * spob_getSystem(const char *spobname)
Get the name of a system from a spobname.
int space_addMarker(int objid, MissionMarkerType type)
Adds a marker to a system.
void space_clearMarkers(void)
Clears all system markers.
Spob * spob_getIndex(int ind)
Gets spob by index.
void space_clearComputerMarkers(void)
Clears all the system computer markers.
int system_index(const StarSystem *sys)
Gets the index of a star system.
Represents an active mission.
Stores a pilot commodity.
const Commodity * commodity
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...