11#include "physfsrwops.h"
32#define XML_SHIP "ship"
34#define SHIP_ENGINE "_engine"
35#define SHIP_TARGET "_target"
36#define SHIP_COMM "_comm"
39#define VIEW_HEIGHT 300
41#define BUTTON_WIDTH 80
42#define BUTTON_HEIGHT 30
44#define STATS_DESC_MAX 256
51static int ship_loadGFX(
Ship *temp,
const char *buf,
int sx,
int sy,
int engine );
59static int ship_cmp(
const void *p1,
const void *p2 )
62 s1 = (
const Ship*) p1;
63 s2 = (
const Ship*) p2;
77 WARN(_(
"Ship %s does not exist"), name);
89 const Ship s = {.
name = (
char*)name };
120 s1 = * (
const Ship**) arg1;
121 s2 = * (
const Ship**) arg2;
142 return strcmp( s1->
name, s2->
name );
178 case SHIP_CLASS_NULL:
181 case SHIP_CLASS_YACHT:
183 case SHIP_CLASS_COURIER:
184 return N_(
"Courier");
185 case SHIP_CLASS_FREIGHTER:
186 return N_(
"Freighter");
187 case SHIP_CLASS_ARMOURED_TRANSPORT:
188 return N_(
"Armoured Transport");
189 case SHIP_CLASS_BULK_FREIGHTER:
190 return N_(
"Bulk Freighter");
192 case SHIP_CLASS_SCOUT:
194 case SHIP_CLASS_INTERCEPTOR:
195 return N_(
"Interceptor");
196 case SHIP_CLASS_FIGHTER:
197 return N_(
"Fighter");
198 case SHIP_CLASS_BOMBER:
200 case SHIP_CLASS_CORVETTE:
201 return N_(
"Corvette");
202 case SHIP_CLASS_DESTROYER:
203 return N_(
"Destroyer");
204 case SHIP_CLASS_CRUISER:
205 return N_(
"Cruiser");
206 case SHIP_CLASS_BATTLESHIP:
207 return N_(
"Battleship");
208 case SHIP_CLASS_CARRIER:
209 return N_(
"Carrier");
212 return N_(
"Unknown");
216#define STRTOSHIP( x, y ) if (strcmp(str,x)==0) return y
225 return SHIP_CLASS_NULL;
227 STRTOSHIP(
"Yacht", SHIP_CLASS_YACHT );
228 STRTOSHIP(
"Courier", SHIP_CLASS_COURIER );
229 STRTOSHIP(
"Freighter", SHIP_CLASS_FREIGHTER );
230 STRTOSHIP(
"Armoured Transport", SHIP_CLASS_ARMOURED_TRANSPORT );
231 STRTOSHIP(
"Bulk Freighter", SHIP_CLASS_BULK_FREIGHTER );
234 STRTOSHIP(
"Scout", SHIP_CLASS_SCOUT );
235 STRTOSHIP(
"Interceptor", SHIP_CLASS_INTERCEPTOR );
236 STRTOSHIP(
"Fighter", SHIP_CLASS_FIGHTER );
237 STRTOSHIP(
"Bomber", SHIP_CLASS_BOMBER );
238 STRTOSHIP(
"Corvette", SHIP_CLASS_CORVETTE );
239 STRTOSHIP(
"Destroyer", SHIP_CLASS_DESTROYER );
240 STRTOSHIP(
"Cruiser", SHIP_CLASS_CRUISER );
241 STRTOSHIP(
"Battleship", SHIP_CLASS_BATTLESHIP);
242 STRTOSHIP(
"Carrier", SHIP_CLASS_CARRIER );
245 return SHIP_CLASS_NULL;
305 case SHIP_CLASS_YACHT:
306 case SHIP_CLASS_SCOUT:
307 case SHIP_CLASS_INTERCEPTOR:
310 case SHIP_CLASS_COURIER:
311 case SHIP_CLASS_FIGHTER:
312 case SHIP_CLASS_BOMBER:
315 case SHIP_CLASS_FREIGHTER:
316 case SHIP_CLASS_CORVETTE:
319 case SHIP_CLASS_DESTROYER:
320 case SHIP_CLASS_ARMOURED_TRANSPORT:
323 case SHIP_CLASS_BULK_FREIGHTER:
324 case SHIP_CLASS_CRUISER:
327 case SHIP_CLASS_BATTLESHIP:
328 case SHIP_CLASS_CARRIER:
341 SDL_Surface *gfx, *gfx_store;
343 SDL_Rect rtemp, dstrect;
351 SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE);
354 gfx = SDL_CreateRGBSurface( 0, sw, sh,
355 surface->format->BytesPerPixel*8, RGBAMASK );
356 gfx_store = SDL_CreateRGBSurface( 0, SHIP_TARGET_W, SHIP_TARGET_H,
357 surface->format->BytesPerPixel*8, RGBAMASK );
360 WARN( _(
"Unable to create ship '%s' targeting surface."), temp->
name );
374 SDL_BlitSurface( surface, &rtemp, gfx, &dstrect );
377 dstrect.x = (SHIP_TARGET_W - sw) / 2;
378 dstrect.y = (SHIP_TARGET_H - sh) / 2;
381 SDL_BlitSurface( surface, &rtemp, gfx_store, &dstrect );
384 snprintf( buf,
sizeof(buf),
"%s_gfx_store", temp->
name );
388 snprintf( buf,
sizeof(buf),
"%s_gfx_target", temp->
name );
405 SDL_Surface *surface;
409 rw = PHYSFSRWOPS_openRead( str );
411 WARN(_(
"Unable to open '%s' for reading!"), str);
414 surface = IMG_Load_RW( rw, 0 );
427 OPENGL_TEX_MAPTRANS | OPENGL_TEX_MIPMAPS | OPENGL_TEX_VFLIP,
428 surface->w, surface->h, sx, sy, 0 );
437 SDL_FreeSurface( surface );
470 char str[
PATH_MAX], *ext, *base, *delim;
473 delim = strchr( buf,
'_' );
474 base = delim==NULL ? strdup( buf ) :
strndup( buf, delim-buf );
477 snprintf(str,
sizeof(str), SHIP_3DGFX_PATH
"%s/%s/%s.obj", base, buf, buf);
478 if (PHYSFS_exists(str)) {
484 snprintf( str,
sizeof(str), SHIP_GFX_PATH
"%s/%s%s", base, buf, ext );
485 if (!PHYSFS_exists(str)) {
487 snprintf( str,
sizeof(str), SHIP_GFX_PATH
"%s/%s%s", base, buf, ext );
493 snprintf( str,
sizeof(str), SHIP_GFX_PATH
"%s/%s"SHIP_ENGINE"%s", base, buf, ext );
496 WARN(_(
"Ship '%s' does not have an engine sprite (%s)."), temp->
name, str );
520 snprintf( file,
sizeof(file),
"%s%s.xml", SHIP_POLYGON_PATH, buf );
523 if (!PHYSFS_exists(file)) {
524 WARN(_(
"%s xml collision polygon does not exist!\n \
525 Please use the script 'polygon_from_sprite.py' if sprites are used,\n \
526 And 'polygonSTL.py' if 3D model is used in game.\n \
527 These files can be found in Naev's artwork repo."), file);
536 node = doc->xmlChildrenNode;
539 WARN(_(
"Malformed %s file: does not contain elements"), file);
544 if (xml_isNode(node,
"polygons")) {
545 xmlNodePtr cur = node->children;
548 if (xml_isNode(cur,
"polygon")) {
552 }
while (xml_nextNode(cur));
554 }
while (xml_nextNode(node));
571 OutfitSlotSize base_size;
577 xmlr_attr_strd( node,
"size", buf );
581 WARN(_(
"Ship '%s' has undefined slot size, setting to '%s'"),temp->
name,
"Small");
582 base_size = OUTFIT_SLOT_SIZE_LIGHT;
587 if (type == OUTFIT_SLOT_WEAPON) {
588 xmlr_attr_float( node,
"x", slot->
mount.
x );
589 xmlr_attr_float( node,
"y", slot->
mount.
y );
593 xmlr_attr_float( node,
"h", slot->
mount.
h );
597 xmlr_attr_strd( node,
"prop", buf );
620 xmlr_attr_int_def( node,
"locked", slot->
locked, slot->
locked );
623 xmlr_attr_strd( node,
"name", slot->
name );
630 WARN( _(
"Ship '%s' has default outfit '%s' which does not exist."), temp->
name, buf );
640 WARN(_(
"Ship '%s' has required slot without a default outfit."), temp->
name);
654 xmlNodePtr parent, node;
667 parent = doc->xmlChildrenNode;
668 if (parent == NULL) {
670 WARN(_(
"Malformed %s file: does not contain elements"), filename);
675 memset( temp, 0,
sizeof(
Ship) );
682 xmlr_attr_strd( parent,
"name", temp->
name );
683 if (temp->
name == NULL)
684 WARN( _(
"Ship in %s has invalid or no name"), SHIP_DATA_PATH );
690 node = parent->xmlChildrenNode;
696 if (xml_isNode(node,
"class")) {
701 if (xml_isNode(node,
"GFX")) {
703 char *buf = xml_get(node);
705 WARN(_(
"Ship '%s': GFX element is NULL"), temp->
name);
710 xmlr_attr_float_def(node,
"size", temp->
gfx_3d_scale, 1);
711 xmlr_attr_int_def( node,
"sx", sx, 8 );
712 xmlr_attr_int_def( node,
"sy", sy, 8 );
714 xmlr_attr_int(node,
"noengine", noengine );
724 WARN(_(
"Ship '%s': the number of collision polygons is wrong.\n \
725 npolygon = %i and sx*sy = %i"),
732 if (xml_isNode(node,
"gfx_space")) {
734 char *buf = xml_get(node);
736 WARN(_(
"Ship '%s': gfx_space element is NULL"), temp->
name);
739 snprintf( str,
sizeof(str), GFX_PATH
"%s", buf );
742 xmlr_attr_int_def( node,
"sx", sx, 8 );
743 xmlr_attr_int_def( node,
"sy", sy, 8 );
751 if (xml_isNode(node,
"gfx_engine")) {
753 char *buf = xml_get(node);
755 WARN(_(
"Ship '%s': gfx_engine element is NULL"), temp->
name);
758 snprintf( str,
sizeof(str), GFX_PATH
"%s", buf );
761 xmlr_attr_int_def( node,
"sx", sx, 8 );
762 xmlr_attr_int_def( node,
"sy", sy, 8 );
770 if (xml_isNode(node,
"gfx_comm")) {
772 char *buf = xml_get(node);
774 WARN(_(
"Ship '%s': gfx_comm element is NULL"), temp->
name);
777 snprintf( str,
sizeof(str), GFX_PATH
"%s", buf );
781 if (xml_isNode(node,
"gfx_overlays")) {
782 xmlNodePtr cur = node->children;
786 if (xml_isNode(cur,
"gfx_overlay"))
789 }
while (xml_nextNode(cur));
793 xmlr_strd(node,
"GUI",temp->
gui);
794 if (xml_isNode(node,
"sound")) {
795 xmlr_attr_float_def( node,
"pitch", temp->
engine_pitch, 1. );
799 xmlr_strd(node,
"base_type",temp->
base_type);
801 xmlr_long(node,
"price",temp->
price);
802 xmlr_strd(node,
"license",temp->
license);
803 xmlr_strd(node,
"cond",temp->
cond);
804 xmlr_strd(node,
"condstr",temp->
condstr);
805 xmlr_strd(node,
"fabricator",temp->
fabricator);
807 xmlr_int(node,
"points",temp->
points);
808 xmlr_int(node,
"rarity",temp->
rarity);
810 if (xml_isNode(node,
"flags")) {
811 xmlNodePtr cur = node->children;
814 if (xml_isNode(cur,
"noplayer")) {
815 ship_setFlag( temp, SHIP_NOPLAYER );
818 if (xml_isNode(cur,
"noescort")) {
819 ship_setFlag( temp, SHIP_NOESCORT );
822 if (xml_isNode(cur,
"unique")) {
823 ship_setFlag( temp, SHIP_UNIQUE );
826 WARN(_(
"Ship '%s' has unknown flags node '%s'."), temp->
name, cur->name);
827 }
while (xml_nextNode(cur));
831 if (xml_isNode(node,
"trail_generator")) {
833 xmlr_attr_float( node,
"x", trail.
x_engine );
834 xmlr_attr_float( node,
"y", trail.
y_engine );
835 xmlr_attr_float( node,
"h", trail.
h_engine );
836 xmlr_attr_int_def( node,
"always_under", trail.
always_under, 0 );
849 if (xml_isNode(node,
"movement")) {
850 xmlNodePtr cur = node->children;
853 xmlr_float(cur,
"thrust",temp->
thrust);
854 xmlr_float(cur,
"turn",temp->
turn);
855 xmlr_float(cur,
"speed",temp->
speed);
857 WARN(_(
"Ship '%s' has unknown movement node '%s'."), temp->
name, cur->name);
858 }
while (xml_nextNode(cur));
861 if (xml_isNode(node,
"health")) {
862 xmlNodePtr cur = node->children;
866 xmlr_float(cur,
"armour",temp->
armour);
868 xmlr_float(cur,
"shield",temp->
shield);
870 xmlr_float(cur,
"energy",temp->
energy);
873 WARN(_(
"Ship '%s' has unknown health node '%s'."), temp->
name, cur->name);
874 }
while (xml_nextNode(cur));
877 if (xml_isNode(node,
"characteristics")) {
878 xmlNodePtr cur = node->children;
881 xmlr_int(cur,
"crew",temp->
crew);
882 xmlr_float(cur,
"mass",temp->
mass);
883 xmlr_float(cur,
"cpu",temp->
cpu);
884 xmlr_int(cur,
"fuel",temp->
fuel);
888 WARN(_(
"Ship '%s' has unknown characteristic node '%s'."), temp->
name, cur->name);
889 }
while (xml_nextNode(cur));
892 if (xml_isNode(node,
"slots")) {
899 xmlNodePtr cur = node->children;
902 if (xml_isNode(cur,
"structure"))
904 else if (xml_isNode(cur,
"utility"))
906 else if (xml_isNode(cur,
"weapon"))
909 WARN(_(
"Ship '%s' has unknown slot node '%s'."), temp->
name, cur->name);
910 }
while (xml_nextNode(cur));
918 if (xml_isNode(node,
"stats")) {
919 xmlNodePtr cur = node->children;
928 WARN(_(
"Ship '%s' has unknown stat '%s'."), temp->
name, cur->name);
929 }
while (xml_nextNode(cur));
936 if (temp->
stats != NULL) {
950 if (xml_isNode(node,
"tags")) {
951 xmlNodePtr cur = node->children;
955 if (xml_isNode(cur,
"tag")) {
956 char *tmp = xml_get(cur);
961 WARN(_(
"Ship '%s' has unknown node in tags '%s'."), temp->
name, cur->name );
962 }
while (xml_nextNode(cur));
967 if (xml_isNode(node,
"mission"))
970 DEBUG(_(
"Ship '%s' has unknown node '%s'."), temp->
name, node->name);
971 }
while (xml_nextNode(node));
975 temp->
turn *= M_PI / 180.;
979 WARN(_(
"Ship '%s' has inexistent license requirement '%s'!"), temp->
name, temp->
license);
982#define MELEMENT(o,s) if (o) WARN( _("Ship '%s' missing '%s' element"), temp->name, s)
983 MELEMENT(temp->
name==NULL,
"name");
984 MELEMENT(temp->
base_type==NULL,
"base_type");
986 MELEMENT(temp->
gui==NULL,
"GUI");
987 MELEMENT(temp->
class==SHIP_CLASS_NULL,
"class");
988 MELEMENT(temp->
points==0,
"points");
989 MELEMENT(temp->
price==0,
"price");
991 MELEMENT(temp->
fabricator==NULL,
"fabricator");
993 MELEMENT(temp->
armour==0.,
"armour");
994 MELEMENT((temp->
cond!=NULL) && (temp->
condstr==NULL),
"condstr");
995 MELEMENT((temp->
cond==NULL) && (temp->
condstr!=NULL),
"cond");
1004 MELEMENT(temp->
crew==0,
"crew");
1005 MELEMENT(temp->
mass==0.,
"mass");
1025 Uint32 time = SDL_GetTicks();
1037 for (
int i=0; i<nfiles; i++) {
1050 free( ship_files[i] );
1057 time = SDL_GetTicks() - time;
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
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_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
void LoadPolygon(CollPoly *polygon, xmlNodePtr node)
Loads a polygon from an xml node.
void naev_renderLoadscreen(void)
Renders the loadscreen if necessary.
Header file with generic functions and naev-specifics.
int ndata_matchExt(const char *path, const char *ext)
Sees if a file matches an extension.
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
static char buf[NEWS_MAX_LENGTH]
int asprintf(char **strp, const char *fmt,...)
Like sprintf(), but it allocates a large-enough string and returns the pointer in the first argument....
char * strndup(const char *s, size_t n)
Return a pointer to a new string, which is a duplicate of the string s (or, if necessary,...
glTexture * xml_parseTexture(xmlNodePtr node, const char *path, int defsx, int defsy, const unsigned int flags)
Parses a texture handling the sx and sy elements.
xmlDocPtr xml_parsePhysFS(const char *filename)
Analogous to xmlParseMemory/xmlParseFile.
void object_free(Object *object)
Frees memory reserved for the object.
Object * object_loadFromFile(const char *filename)
Loads object.
glTexture * gl_newSprite(const char *path, const int sx, const int sy, const unsigned int flags)
Loads the texture immediately, but also sets it as a sprite.
glTexture * gl_loadImagePad(const char *name, SDL_Surface *surface, unsigned int flags, int w, int h, int sx, int sy, int freesur)
Loads the already padded SDL_Surface to a glTexture.
glTexture * gl_loadImagePadTrans(const char *name, SDL_Surface *surface, SDL_RWops *rw, unsigned int flags, int w, int h, int sx, int sy, int freesur)
Wrapper for gl_loadImagePad that includes transparency mapping.
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
void gl_getSpriteFromDir(int *x, int *y, const glTexture *t, const double dir)
Sets x and y to be the appropriate sprite for glTexture using dir.
void gl_freeTexture(glTexture *texture)
Frees a texture.
const Outfit * outfit_get(const char *name)
Gets an outfit by name.
OutfitSlotSize outfit_toSlotSize(const char *s)
Gets the outfit slot size from a human readable string.
int outfit_licenseExists(const char *name)
Checks to see if a license exists.
void outfit_freeSlot(OutfitSlot *s)
Frees an outfit slot.
int ship_size(const Ship *s)
Gets the size of the ship.
ShipClass ship_classFromString(const char *str)
Gets the machine ship class identifier from a human readable string.
static int ship_parseSlot(Ship *temp, ShipOutfitSlot *slot, OutfitSlotType type, xmlNodePtr node)
Parses a slot for a ship.
const char * ship_class(const Ship *s)
Gets the ship's class name in human readable form.
const char * ship_classDisplay(const Ship *s)
Gets the ship's display class in human readable form.
credits_t ship_basePrice(const Ship *s)
Gets the ship's base price (no outfits).
credits_t ship_buyPrice(const Ship *s)
The ship buy price, includes default outfits.
const Ship * ship_getW(const char *name)
Gets a ship based on its name without warning.
int ships_load(void)
Loads all the ships in the data files.
static int ship_loadEngineImage(Ship *temp, char *str, int sx, int sy)
Loads the space graphics for a ship from an image.
static int ship_cmp(const void *p1, const void *p2)
Compares two ship pointers for qsort.
const Ship * ship_getAll(void)
Gets the array (array.h) of all ships.
static int ship_loadSpaceImage(Ship *temp, char *str, int sx, int sy)
Loads the space graphics for a ship from an image.
void ships_free(void)
Frees all the ships.
static int ship_loadGFX(Ship *temp, const char *buf, int sx, int sy, int engine)
Loads the graphics for a ship.
int ship_compareTech(const void *arg1, const void *arg2)
Comparison function for qsort().
const char * ship_classToString(ShipClass class)
Gets the ship class name in human readable form.
static int ship_parse(Ship *temp, const char *filename)
Extracts the in-game ship from an XML node.
glTexture * ship_loadCommGFX(const Ship *s)
Loads the ship's comm graphic.
static int ship_loadPLG(Ship *temp, const char *buf, int size_hint)
Loads the collision polygon for a ship.
const Ship * ship_get(const char *name)
Gets a ship based on its name.
static int ship_genTargetGFX(Ship *temp, SDL_Surface *surface, int sx, int sy)
Generates a target graphic for a ship.
const char * ship_existsCase(const char *name)
Checks to see if an ship exists matching name (case insensitive).
int ss_statsListDesc(const ShipStatList *ll, char *buf, int len, int newline)
Writes the ship statistics description.
void ss_free(ShipStatList *ll)
Frees a list of ship stats.
int ss_statsModFromList(ShipStats *stats, const ShipStatList *list)
Updates a stat structure from a stat list.
int ss_statsInit(ShipStats *stats)
Initializes a stat structure.
int ss_check(void)
Checks for validity.
ShipStatList * ss_listFromXML(xmlNodePtr node)
Creates a shipstat list element from an xml node.
int sp_locked(unsigned int spid)
Gets whether or not a slot property is locked.
unsigned int sp_get(const char *name)
Gets the id of a slot property.
int sp_required(unsigned int spid)
Gets whether or not a slot property is required.
int sp_exclusive(unsigned int spid)
Gets whether or not a slot property is exclusive.
int sound_get(const char *name)
Gets the buffer to sound of name.
const TrailSpec * trailSpec_get(const char *name)
Gets a trail spec by name.
Represents a polygon used for collision detection.
A ship outfit, depends radically on the type.
Represents relative ship statistics as a linked list.
struct ShipStatList_ * next
const TrailSpec * trail_spec
unsigned int always_under
ShipOutfitSlot * outfit_utility
ShipOutfitSlot * outfit_weapon
ShipTrailEmitter * trail_emitters
glTexture ** gfx_overlays
ShipOutfitSlot * outfit_structure
Abstraction for rendering sprite sheets.