diff --git a/dat/outfit.xml b/dat/outfit.xml index c4d047a..4d5d2ba 100644 --- a/dat/outfit.xml +++ b/dat/outfit.xml @@ -391,4 +391,17 @@ <cargo>-15</cargo> </specific> </outfit> +<outfit name="Star Map"> +<general> +<max>1</max> +<tech>4</tech> +<mass>0</mass> +<price>7000</price> +<description>A Star Map will give you details about all systems up to 2 jumps away. It's a great way to discover parts of the universe.</description> +<gfx_store>map</gfx_store> +</general> +<specific type="map"> +<radius>2</radius> +</specific> +</outfit> </Outfits> diff --git a/gfx/outfit/store/map.png b/gfx/outfit/store/map.png new file mode 100644 index 0000000..3fb936a Binary files /dev/null and b/gfx/outfit/store/map.png differ diff --git a/src/llua.c b/src/llua.c index 441a345..89fc5b7 100644 --- a/src/llua.c +++ b/src/llua.c @@ -191,7 +191,7 @@ static int space_jumpDist(lua_State* L) { else goal = cur_system->name; - s = map_getJumpPath(&jumps, start, goal); + s = map_getJumpPath(&jumps, start, goal, 1); free(s); lua_pushnumber(L, jumps); diff --git a/src/map.c b/src/map.c index 074b5ee..36ed00c 100644 --- a/src/map.c +++ b/src/map.c @@ -282,7 +282,7 @@ static void map_mouse(SDL_Event* event, double mx, double my) { if(map_path) free(map_path); map_path = map_getJumpPath(&map_npath, - cur_system->name, sys->name); + cur_system->name, sys->name, 0); if(map_npath == 0) hyperspace_target = -1; @@ -540,7 +540,7 @@ static void A_freeList(SysNode* first) { free(p); } -StarSystem** map_getJumpPath(int* njumps, char* sysstart, char* sysend) { +StarSystem** map_getJumpPath(int* njumps, char* sysstart, char* sysend, int ignore_known) { int i, cost; StarSystem* sys, *ssys, *esys, **res; @@ -556,7 +556,7 @@ StarSystem** map_getJumpPath(int* njumps, char* sysstart, char* sysend) { esys = system_get(sysend); /* End. */ /* System target must be known. */ - if(!sys_isKnown(esys)) { + if(!ignore_known && !sys_isKnown(esys)) { if(space_sysReachable(esys)) { /* Can we still reach it? */ res = malloc(sizeof(StarSystem*)); (*njumps) = 1; @@ -582,7 +582,7 @@ StarSystem** map_getJumpPath(int* njumps, char* sysstart, char* sysend) { for(i = 0; i < cur->sys->njumps; i++) { sys = &systems_stack[cur->sys->jumps[i]]; - if(!sys_isKnown(sys)) continue; + if(!ignore_known && !sys_isKnown(sys)) continue; neighbour = A_newNode(sys, NULL); @@ -617,4 +617,44 @@ StarSystem** map_getJumpPath(int* njumps, char* sysstart, char* sysend) { return res; } +/* Marks maps around a radius of current system as known. */ +int map_map(char* targ_sys, int r) { + int i, dep; + StarSystem* sys, *jsys; + SysNode* closed, *open, *cur, *neighbour; + + A_gc = NULL; + open = closed = NULL; + + if(targ_sys == NULL) sys = cur_system; + else sys = system_get(targ_sys); + sys_setFlag(sys, SYSTEM_KNOWN); + open = A_newNode(sys, NULL); + open->r = 0; + + while((cur = A_lowest(open)) != NULL) { + /* Mark system as known and go to next. */ + sys = cur->sys; + dep = cur->r; + sys_setFlag(sys, SYSTEM_KNOWN); + open = A_rm(open, sys); + closed = A_add(closed, cur); + + /* Check it's jumps. */ + for(i = 0; i < sys->njumps; i++) { + jsys = &systems_stack[cur->sys->jumps[i]]; + + /* System has already been parsed or is too deep. */ + if((A_in(closed, jsys) != NULL) || (dep+1 > r)) + continue; + + /* Create new node and such. */ + neighbour = A_newNode(jsys, NULL); + neighbour->r = dep+1; + open = A_add(open, neighbour); + } + } + A_freeList(A_gc); + return 0; +} diff --git a/src/map.h b/src/map.h index 3520f6b..93983f6 100644 --- a/src/map.h +++ b/src/map.h @@ -9,5 +9,6 @@ void map_clear(void); void map_jump(void); /* Manipulate universe stuff. */ -StarSystem** map_getJumpPath(int* njumps, char* sysstart, char* sysend); +StarSystem** map_getJumpPath(int* njumps, char* sysstart, char* sysend, int ignore_known); +int map_map(char* targ_sys, int r); diff --git a/src/outfit.c b/src/outfit.c index 8b294a3..84d8225 100644 --- a/src/outfit.c +++ b/src/outfit.c @@ -35,6 +35,7 @@ static void outfit_parseSLauncher(Outfit* tmp, const xmlNodePtr parent); static void outfit_parseSAmmo(Outfit* tmp, const xmlNodePtr parent); static void outfit_parseSMod(Outfit* tmp, const xmlNodePtr parent); static void outfit_parseSAfterburner(Outfit* tmp, const xmlNodePtr parent); +static void outfit_parseSMap(Outfit* tmp, const xmlNodePtr parent); /* Return an outfit. */ Outfit* outfit_get(const char* name) { @@ -128,6 +129,10 @@ int outfit_isAfterburner(const Outfit* o) { return (o->type == OUTFIT_TYPE_AFTERBURNER); } +int outfit_isMap(const Outfit* o) { + return(o->type == OUTFIT_TYPE_MAP); +} + /* Get the outfit graphics. */ glTexture* outfit_gfx(const Outfit* o) { if(outfit_isWeapon(o)) return o->u.blt.gfx_space; @@ -189,7 +194,8 @@ const char* outfit_typename[] = { "Bolt Turret", "Beam Turret", "Ship Modification", - "Afterburner" + "Afterburner", + "Map" }; const char* outfit_getType(const Outfit* o) { @@ -204,17 +210,19 @@ const char* outfit_typenamebroad[] = { "Ammo", "Turret", "Modification", - "Afterburner" + "Afterburner", + "Map" }; const char* outfit_getTypeBroad(const Outfit* o) { int i = 0; - if(outfit_isWeapon(o)) i = 1; - else if(outfit_isLauncher(o)) i = 2; - else if(outfit_isAmmo(o)) i = 3; - else if(outfit_isTurret(o)) i = 4; - else if(outfit_isMod(o)) i = 5; - else if(outfit_isAfterburner(o)) i = 6; + if(outfit_isWeapon(o)) i = 1; + else if(outfit_isLauncher(o)) i = 2; + else if(outfit_isAmmo(o)) i = 3; + else if(outfit_isTurret(o)) i = 4; + else if(outfit_isMod(o)) i = 5; + else if(outfit_isAfterburner(o)) i = 6; + else if(outfit_isMap(o)) i = 7; return outfit_typenamebroad[i]; } @@ -250,6 +258,7 @@ static OutfitType outfit_strToOutfitType(char* buf) { O_CMP("turret beam", OUTFIT_TYPE_TURRET_BEAM); O_CMP("modification", OUTFIT_TYPE_MODIFICATION); O_CMP("afterburner", OUTFIT_TYPE_AFTERBURNER); + O_CMP("map", OUTFIT_TYPE_MAP); WARN("Invalid outfit type '%s'", buf); return OUTFIT_TYPE_NULL; @@ -421,6 +430,16 @@ static void outfit_parseSAfterburner(Outfit* tmp, const xmlNodePtr parent) { } while((node = node->next)); } +static void outfit_parseSMap(Outfit* tmp, const xmlNodePtr parent) { + xmlNodePtr node; + node = parent->children; + + do { + if(xml_isNode(node, "radius")) + tmp->u.map.radius = xml_getInt(node); + } while(xml_nextNode(node)); +} + /* Parse and return Outfits from parent node. */ static Outfit* outfit_parse(const xmlNodePtr parent) { Outfit* tmp = CALLOC_L(Outfit); @@ -479,6 +498,8 @@ static Outfit* outfit_parse(const xmlNodePtr parent) { outfit_parseSMod(tmp, node); else if(outfit_isAfterburner(tmp)) outfit_parseSAfterburner(tmp, node); + else if(outfit_isMap(tmp)) + outfit_parseSMap(tmp, node); } } while((node = node->next)); #define MELEMENT(o,s) if(o) WARN("Outfit '%s' missing '"s"' element", tmp->name) diff --git a/src/outfit.h b/src/outfit.h index 1c20f70..33952cf 100644 --- a/src/outfit.h +++ b/src/outfit.h @@ -24,7 +24,8 @@ typedef enum OutfitType_ { OUTFIT_TYPE_TURRET_BOLT, OUTFIT_TYPE_TURRET_BEAM, OUTFIT_TYPE_MODIFICATION, - OUTFIT_TYPE_AFTERBURNER + OUTFIT_TYPE_AFTERBURNER, + OUTFIT_TYPE_MAP } OutfitType; typedef enum DamageType_ { @@ -112,6 +113,9 @@ typedef struct Outfit_ { double speed_perc, speed_abs; /* Percent and absolute speed bonus. */ double energy; /* Energy used while active. */ } afb; + struct { /* Map. */ + double radius; /* Amount of systems to add */ + } map; } u; } Outfit; @@ -129,6 +133,7 @@ int outfit_isAmmo(const Outfit* o); int outfit_isTurret(const Outfit* o); int outfit_isMod(const Outfit* o); int outfit_isAfterburner(const Outfit* o); +int outfit_isMap(const Outfit* o); const char* outfit_getType(const Outfit* o); const char* outfit_getTypeBroad(const Outfit* o); diff --git a/src/pilot.c b/src/pilot.c index a55fc96..2c84215 100644 --- a/src/pilot.c +++ b/src/pilot.c @@ -10,6 +10,7 @@ #include "spfx.h" #include "rng.h" #include "hook.h" +#include "map.h" #include "pilot.h" #define XML_ID "Fleets" /* XML section identifier. */ @@ -533,6 +534,12 @@ int pilot_addOutfit(Pilot* pilot, Outfit* outfit, int quantity) { q = quantity; + /* Special case if it's a map. */ + if(outfit_isMap(outfit)) { + map_map(NULL, outfit->u.map.radius); + return 1; /* Must return 1 for paying purposes. */ + } + /* Does outfit already exist? */ for(i = 0; i < pilot->noutfits; i++) if(strcmp(outfit->name, pilot->outfits[i].outfit->name)==0) {