naev 0.10.4
ship.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <limits.h>
11#include "physfsrwops.h"
12#include "SDL_image.h"
13
14#include "naev.h"
17#include "ship.h"
18
19#include "array.h"
20#include "colour.h"
21#include "conf.h"
22#include "log.h"
23#include "ndata.h"
24#include "nfile.h"
25#include "nstring.h"
26#include "nxml.h"
27#include "shipstats.h"
28#include "slots.h"
29#include "toolkit.h"
30#include "unistd.h"
31
32#define XML_SHIP "ship"
34#define SHIP_ENGINE "_engine"
35#define SHIP_TARGET "_target"
36#define SHIP_COMM "_comm"
38#define VIEW_WIDTH 300
39#define VIEW_HEIGHT 300
41#define BUTTON_WIDTH 80
42#define BUTTON_HEIGHT 30
44#define STATS_DESC_MAX 256
46static Ship* ship_stack = NULL;
48/*
49 * Prototypes
50 */
51static int ship_loadGFX( Ship *temp, const char *buf, int sx, int sy, int engine );
52static int ship_loadPLG( Ship *temp, const char *buf, int size_hint );
53static int ship_parse( Ship *temp, const char *filename );
54static void ship_freeSlot( ShipOutfitSlot* s );
55
59static int ship_cmp( const void *p1, const void *p2 )
60{
61 const Ship *s1, *s2;
62 s1 = (const Ship*) p1;
63 s2 = (const Ship*) p2;
64 return strcmp( s1->name, s2->name );
65}
66
73const Ship* ship_get( const char* name )
74{
75 const Ship *s = ship_getW( name );
76 if (s==NULL)
77 WARN(_("Ship %s does not exist"), name);
78 return s;
79}
80
87const Ship* ship_getW( const char* name )
88{
89 const Ship s = {.name = (char*)name };
90 return bsearch( &s, ship_stack, array_size(ship_stack), sizeof(Ship), ship_cmp );
91}
92
96const char *ship_existsCase( const char* name )
97{
98 for (int i=0; i<array_size(ship_stack); i++)
99 if (strcasecmp(name,ship_stack[i].name)==0)
100 return ship_stack[i].name;
101 return NULL;
102}
103
107const Ship* ship_getAll (void)
108{
109 return ship_stack;
110}
111
115int ship_compareTech( const void *arg1, const void *arg2 )
116{
117 const Ship *s1, *s2;
118
119 /* Get ships. */
120 s1 = * (const Ship**) arg1;
121 s2 = * (const Ship**) arg2;
122
123 /* Compare requirements. */
124 if ((s1->condstr!=NULL) && (s2->condstr==NULL))
125 return -1;
126 else if ((s2->condstr!=NULL) && (s1->condstr==NULL))
127 return +1;
128
129 /* Compare class. */
130 if (s1->class < s2->class)
131 return +1;
132 else if (s1->class > s2->class)
133 return -1;
134
135 /* Compare price. */
136 if (s1->price < s2->price)
137 return +1;
138 else if (s1->price > s2->price)
139 return -1;
140
141 /* Same. */
142 return strcmp( s1->name, s2->name );
143}
144
151const char* ship_class( const Ship* s )
152{
153 return ship_classToString( s->class );
154}
155
162const char* ship_classDisplay( const Ship* s )
163{
164 if (s->class_display)
165 return s->class_display;
166 return ship_class( s );
167}
168
175const char *ship_classToString( ShipClass class )
176{
177 switch (class) {
178 case SHIP_CLASS_NULL:
179 return "NULL";
180 /* Civilian. */
181 case SHIP_CLASS_YACHT:
182 return N_("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");
191 /* Military. */
192 case SHIP_CLASS_SCOUT:
193 return N_("Scout");
194 case SHIP_CLASS_INTERCEPTOR:
195 return N_("Interceptor");
196 case SHIP_CLASS_FIGHTER:
197 return N_("Fighter");
198 case SHIP_CLASS_BOMBER:
199 return N_("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");
210 /* Unknown. */
211 default:
212 return N_("Unknown");
213 }
214}
215
216#define STRTOSHIP( x, y ) if (strcmp(str,x)==0) return y
222ShipClass ship_classFromString( const char* str )
223{
224 if (str==NULL)
225 return SHIP_CLASS_NULL;
226 /* Civilian */
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 );
232
233 /* Military */
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 );
243
244 /* Unknown */
245 return SHIP_CLASS_NULL;
246}
247#undef STRTOSHIP
248
252credits_t ship_basePrice( const Ship* s )
253{
254 return s->price;
255}
256
260credits_t ship_buyPrice( const Ship* s )
261{
262 /* Get base price. */
263 credits_t price = ship_basePrice(s);
264
265 for (int i=0; i<array_size(s->outfit_structure); i++) {
266 const Outfit *o = s->outfit_structure[i].data;
267 if (o != NULL)
268 price += o->price;
269 }
270 for (int i=0; i<array_size(s->outfit_utility); i++) {
271 const Outfit *o = s->outfit_utility[i].data;
272 if (o != NULL)
273 price += o->price;
274 }
275 for (int i=0; i<array_size(s->outfit_weapon); i++) {
276 const Outfit *o = s->outfit_weapon[i].data;
277 if (o != NULL)
278 price += o->price;
279 }
280
281 return price;
282}
283
290{
291 if (s->gfx_comm != NULL)
292 return gl_newImage( s->gfx_comm, 0 );
293 return NULL;
294}
295
302int ship_size( const Ship *s )
303{
304 switch (s->class) {
305 case SHIP_CLASS_YACHT:
306 case SHIP_CLASS_SCOUT:
307 case SHIP_CLASS_INTERCEPTOR:
308 return 1;
309
310 case SHIP_CLASS_COURIER:
311 case SHIP_CLASS_FIGHTER:
312 case SHIP_CLASS_BOMBER:
313 return 2;
314
315 case SHIP_CLASS_FREIGHTER:
316 case SHIP_CLASS_CORVETTE:
317 return 3;
318
319 case SHIP_CLASS_DESTROYER:
320 case SHIP_CLASS_ARMOURED_TRANSPORT:
321 return 4;
322
323 case SHIP_CLASS_BULK_FREIGHTER:
324 case SHIP_CLASS_CRUISER:
325 return 5;
326
327 case SHIP_CLASS_BATTLESHIP:
328 case SHIP_CLASS_CARRIER:
329 return 6;
330
331 default:
332 return -1;
333 }
334}
335
339static int ship_genTargetGFX( Ship *temp, SDL_Surface *surface, int sx, int sy )
340{
341 SDL_Surface *gfx, *gfx_store;
342 int x, y, sw, sh;
343 SDL_Rect rtemp, dstrect;
344 char buf[PATH_MAX];
345
346 /* Get sprite size. */
347 sw = temp->gfx_space->w / sx;
348 sh = temp->gfx_space->h / sy;
349
350 /* Create the surface. */
351 SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE);
352
353 /* create the temp POT surface */
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 );
358
359 if (gfx == NULL) {
360 WARN( _("Unable to create ship '%s' targeting surface."), temp->name );
361 return -1;
362 }
363
364 /* Copy over for target. */
365 gl_getSpriteFromDir( &x, &y, temp->gfx_space, M_PI* 5./4. );
366 rtemp.x = sw * x;
367 rtemp.y = sh * y;
368 rtemp.w = sw;
369 rtemp.h = sh;
370 dstrect.x = 0;
371 dstrect.y = 0;
372 dstrect.w = rtemp.w;
373 dstrect.h = rtemp.h;
374 SDL_BlitSurface( surface, &rtemp, gfx, &dstrect );
375
376 /* Copy over for store. */
377 dstrect.x = (SHIP_TARGET_W - sw) / 2;
378 dstrect.y = (SHIP_TARGET_H - sh) / 2;
379 dstrect.w = rtemp.w;
380 dstrect.h = rtemp.h;
381 SDL_BlitSurface( surface, &rtemp, gfx_store, &dstrect );
382
383 /* Load the store surface. */
384 snprintf( buf, sizeof(buf), "%s_gfx_store", temp->name );
385 temp->gfx_store = gl_loadImagePad( buf, gfx_store, OPENGL_TEX_VFLIP, SHIP_TARGET_W, SHIP_TARGET_H, 1, 1, 1 );
386
387 /* Load the surface. */
388 snprintf( buf, sizeof(buf), "%s_gfx_target", temp->name );
389 temp->gfx_target = gl_loadImagePad( buf, gfx, OPENGL_TEX_VFLIP, sw, sh, 1, 1, 1 );
390
391 return 0;
392}
393
402static int ship_loadSpaceImage( Ship *temp, char *str, int sx, int sy )
403{
404 SDL_RWops *rw;
405 SDL_Surface *surface;
406 int ret;
407
408 /* Load the space sprite. */
409 rw = PHYSFSRWOPS_openRead( str );
410 if (rw==NULL) {
411 WARN(_("Unable to open '%s' for reading!"), str);
412 return -1;
413 }
414 surface = IMG_Load_RW( rw, 0 );
415
416 /* Load the texture. */
417 /* Don't try to be smart here and avoid loading the transparency map or
418 * we'll hit issues with collisions. */
419 /*
420 if (temp->polygon != NULL)
421 temp->gfx_space = gl_loadImagePad( str, surface,
422 OPENGL_TEX_MIPMAPS | OPENGL_TEX_VFLIP,
423 surface->w, surface->h, sx, sy, 0 );
424 else
425 */
426 temp->gfx_space = gl_loadImagePadTrans( str, surface, rw,
427 OPENGL_TEX_MAPTRANS | OPENGL_TEX_MIPMAPS | OPENGL_TEX_VFLIP,
428 surface->w, surface->h, sx, sy, 0 );
429
430 /* Create the target graphic. */
431 ret = ship_genTargetGFX( temp, surface, sx, sy );
432 if (ret != 0)
433 return ret;
434
435 /* Free stuff. */
436 SDL_RWclose( rw );
437 SDL_FreeSurface( surface );
438
439 /* Calculate mount angle. */
440 temp->mangle = 2.*M_PI;
441 temp->mangle /= temp->gfx_space->sx * temp->gfx_space->sy;
442 return 0;
443}
444
453static int ship_loadEngineImage( Ship *temp, char *str, int sx, int sy )
454{
455 temp->gfx_engine = gl_newSprite( str, sx, sy, OPENGL_TEX_MIPMAPS );
456 return (temp->gfx_engine != NULL);
457}
458
468static int ship_loadGFX( Ship *temp, const char *buf, int sx, int sy, int engine )
469{
470 char str[PATH_MAX], *ext, *base, *delim;
471
472 /* Get base path. */
473 delim = strchr( buf, '_' );
474 base = delim==NULL ? strdup( buf ) : strndup( buf, delim-buf );
475
476 /* Load the 3d model */
477 snprintf(str, sizeof(str), SHIP_3DGFX_PATH"%s/%s/%s.obj", base, buf, buf);
478 if (PHYSFS_exists(str)) {
479 temp->gfx_3d = object_loadFromFile(str);
480 }
481
482 /* Load the space sprite. */
483 ext = ".webp";
484 snprintf( str, sizeof(str), SHIP_GFX_PATH"%s/%s%s", base, buf, ext );
485 if (!PHYSFS_exists(str)) {
486 ext = ".png";
487 snprintf( str, sizeof(str), SHIP_GFX_PATH"%s/%s%s", base, buf, ext );
488 }
489 ship_loadSpaceImage( temp, str, sx, sy );
490
491 /* Load the engine sprite .*/
492 if (engine) {
493 snprintf( str, sizeof(str), SHIP_GFX_PATH"%s/%s"SHIP_ENGINE"%s", base, buf, ext );
494 ship_loadEngineImage( temp, str, sx, sy );
495 if (temp->gfx_engine == NULL)
496 WARN(_("Ship '%s' does not have an engine sprite (%s)."), temp->name, str );
497 }
498
499 /* Get the comm graphic for future loading. */
500 asprintf( &temp->gfx_comm, SHIP_GFX_PATH"%s/%s"SHIP_COMM"%s", base, buf, ext );
501 free( base );
502
503 return 0;
504}
505
513static int ship_loadPLG( Ship *temp, const char *buf, int size_hint )
514{
515 char file[PATH_MAX];
516 CollPoly *polygon;
517 xmlDocPtr doc;
518 xmlNodePtr node;
519
520 snprintf( file, sizeof(file), "%s%s.xml", SHIP_POLYGON_PATH, buf );
521
522 /* See if the file does exist. */
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);
528 return 0;
529 }
530
531 /* Load the XML. */
532 doc = xml_parsePhysFS( file );
533 if (doc == NULL)
534 return 0;
535
536 node = doc->xmlChildrenNode; /* First polygon node */
537 if (node == NULL) {
538 xmlFreeDoc(doc);
539 WARN(_("Malformed %s file: does not contain elements"), file);
540 return 0;
541 }
542
543 do { /* load the polygon data */
544 if (xml_isNode(node,"polygons")) {
545 xmlNodePtr cur = node->children;
546 temp->polygon = array_create_size( CollPoly, size_hint );
547 do {
548 if (xml_isNode(cur,"polygon")) {
549 polygon = &array_grow( &temp->polygon );
550 LoadPolygon( polygon, cur );
551 }
552 } while (xml_nextNode(cur));
553 }
554 } while (xml_nextNode(node));
555
556 xmlFreeDoc(doc);
557 return 0;
558}
559
569static int ship_parseSlot( Ship *temp, ShipOutfitSlot *slot, OutfitSlotType type, xmlNodePtr node )
570{
571 OutfitSlotSize base_size;
572 char *buf;
573
574 /* Initialize. */
575 memset( slot, 0, sizeof(ShipOutfitSlot) );
576 /* Parse size. */
577 xmlr_attr_strd( node, "size", buf );
578 if (buf != NULL)
579 base_size = outfit_toSlotSize( buf );
580 else {
581 WARN(_("Ship '%s' has undefined slot size, setting to '%s'"),temp->name, "Small");
582 base_size = OUTFIT_SLOT_SIZE_LIGHT;
583 }
584 free(buf);
585
586 /* Get mount point for weapons. */
587 if (type == OUTFIT_SLOT_WEAPON) {
588 xmlr_attr_float( node, "x", slot->mount.x );
589 xmlr_attr_float( node, "y", slot->mount.y );
590 /* Since we measure in pixels, we have to modify it so it
591 * doesn't get corrected by the ortho correction. */
592 slot->mount.y *= M_SQRT2;
593 xmlr_attr_float( node, "h", slot->mount.h );
594 }
595
596 /* Parse property. */
597 xmlr_attr_strd( node, "prop", buf );
598 if (buf != NULL) {
599 slot->slot.spid = sp_get( buf );
600 slot->exclusive = sp_exclusive( slot->slot.spid );
601 slot->required = sp_required( slot->slot.spid );
602 slot->locked = sp_locked( slot->slot.spid );
603 free( buf );
604 }
605 //TODO: consider inserting those two parse blocks below inside the parse block above
606
607 /* Parse exclusive flag, default false. */
608 xmlr_attr_int_def( node, "exclusive", slot->exclusive, slot->exclusive );
609 /* TODO: decide if exclusive should even belong in ShipOutfitSlot,
610 * remove this hack, and fix slot->exclusive to slot->slot.exclusive
611 * in it's two previous occurrences, meaning three lines above and 12
612 * lines above */
613 /* hack */
614 slot->slot.exclusive = slot->exclusive;
615
616 /* Parse required flag, default false. */
617 xmlr_attr_int_def( node, "required", slot->required, slot->required );
618
619 /* Parse locked flag, default false. */
620 xmlr_attr_int_def( node, "locked", slot->locked, slot->locked );
621
622 /* Name if applicable. */
623 xmlr_attr_strd( node, "name", slot->name );
624
625 /* Parse default outfit. */
626 buf = xml_get(node);
627 if (buf != NULL) {
628 const Outfit *o = outfit_get( buf );
629 if (o == NULL)
630 WARN( _("Ship '%s' has default outfit '%s' which does not exist."), temp->name, buf );
631 slot->data = o;
632 }
633
634 /* Set stuff. */
635 slot->slot.size = base_size;
636 slot->slot.type = type;
637
638 /* Required slots need a default outfit. */
639 if (slot->required && (slot->data == NULL))
640 WARN(_("Ship '%s' has required slot without a default outfit."), temp->name);
641
642 return 0;
643}
644
652static int ship_parse( Ship *temp, const char *filename )
653{
654 xmlNodePtr parent, node;
655 xmlDocPtr doc;
656 int sx, sy;
657 char str[PATH_MAX];
658 int noengine;
659 ShipStatList *ll;
660 ShipTrailEmitter trail;
661
662 /* Load the XML. */
663 doc = xml_parsePhysFS( filename );
664 if (doc == NULL)
665 return -1;
666
667 parent = doc->xmlChildrenNode; /* First ship node */
668 if (parent == NULL) {
669 xmlFreeDoc(doc);
670 WARN(_("Malformed %s file: does not contain elements"), filename);
671 return -1;
672 }
673
674 /* Clear memory. */
675 memset( temp, 0, sizeof(Ship) );
676
677 /* Defaults. */
678 ss_statsInit( &temp->stats_array );
679 temp->dt_default = 1.;
680
681 /* Get name. */
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 );
685
686 /* Default offsets for the engine. */
687 temp->trail_emitters = NULL;
688
689 /* Load the rest of the data. */
690 node = parent->xmlChildrenNode;
691 do { /* load all the data */
692
693 /* Only handle nodes. */
694 xml_onlyNodes(node);
695
696 if (xml_isNode(node,"class")) {
697 xmlr_attr_strd( node, "display", temp->class_display );
698 temp->class = ship_classFromString( xml_get(node) );
699 continue;
700 }
701 if (xml_isNode(node,"GFX")) {
702 /* Get base graphic name. */
703 char *buf = xml_get(node);
704 if (buf==NULL) {
705 WARN(_("Ship '%s': GFX element is NULL"), temp->name);
706 continue;
707 }
708
709 /* Get size. */
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 );
713
714 xmlr_attr_int(node, "noengine", noengine );
715
716 /* Load the polygon. */
717 ship_loadPLG( temp, buf, sx*sy );
718
719 /* Load the graphics. */
720 ship_loadGFX( temp, buf, sx, sy, !noengine );
721
722 /* Validity check: there must be 1 polygon per sprite. */
723 if ((temp->polygon != NULL) && array_size(temp->polygon) != sx*sy) {
724 WARN(_("Ship '%s': the number of collision polygons is wrong.\n \
725 npolygon = %i and sx*sy = %i"),
726 temp->name, array_size(temp->polygon), sx*sy);
727 }
728
729 continue;
730 }
731
732 if (xml_isNode(node,"gfx_space")) {
733 /* Get path */
734 char *buf = xml_get(node);
735 if (buf==NULL) {
736 WARN(_("Ship '%s': gfx_space element is NULL"), temp->name);
737 continue;
738 }
739 snprintf( str, sizeof(str), GFX_PATH"%s", buf );
740
741 /* Get sprite size. */
742 xmlr_attr_int_def( node, "sx", sx, 8 );
743 xmlr_attr_int_def( node, "sy", sy, 8 );
744
745 /* Load the graphics. */
746 ship_loadSpaceImage( temp, str, sx, sy );
747
748 continue;
749 }
750
751 if (xml_isNode(node,"gfx_engine")) {
752 /* Get path */
753 char *buf = xml_get(node);
754 if (buf==NULL) {
755 WARN(_("Ship '%s': gfx_engine element is NULL"), temp->name);
756 continue;
757 }
758 snprintf( str, sizeof(str), GFX_PATH"%s", buf );
759
760 /* Get sprite size. */
761 xmlr_attr_int_def( node, "sx", sx, 8 );
762 xmlr_attr_int_def( node, "sy", sy, 8 );
763
764 /* Load the graphics. */
765 ship_loadEngineImage( temp, str, sx, sy );
766
767 continue;
768 }
769
770 if (xml_isNode(node,"gfx_comm")) {
771 /* Get path */
772 char *buf = xml_get(node);
773 if (buf==NULL) {
774 WARN(_("Ship '%s': gfx_comm element is NULL"), temp->name);
775 continue;
776 }
777 snprintf( str, sizeof(str), GFX_PATH"%s", buf );
778 temp->gfx_comm = strdup(str);
779 continue;
780 }
781 if (xml_isNode(node,"gfx_overlays")) {
782 xmlNodePtr cur = node->children;
784 do {
785 xml_onlyNodes(cur);
786 if (xml_isNode(cur,"gfx_overlay"))
788 xml_parseTexture( cur, OVERLAY_GFX_PATH"%s", 1, 1, OPENGL_TEX_MIPMAPS ) );
789 } while (xml_nextNode(cur));
790 continue;
791 }
792
793 xmlr_strd(node,"GUI",temp->gui);
794 if (xml_isNode(node,"sound")) {
795 xmlr_attr_float_def( node, "pitch", temp->engine_pitch, 1. );
796 temp->sound = sound_get( xml_get(node) );
797 continue;
798 }
799 xmlr_strd(node,"base_type",temp->base_type);
800 xmlr_float(node,"time_mod",temp->dt_default);
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);
806 xmlr_strd(node,"description",temp->description);
807 xmlr_int(node,"points",temp->points);
808 xmlr_int(node,"rarity",temp->rarity);
809
810 if (xml_isNode(node,"flags")) {
811 xmlNodePtr cur = node->children;
812 do {
813 xml_onlyNodes(cur);
814 if (xml_isNode(cur,"noplayer")) {
815 ship_setFlag( temp, SHIP_NOPLAYER );
816 continue;
817 }
818 if (xml_isNode(cur,"noescort")) {
819 ship_setFlag( temp, SHIP_NOESCORT );
820 continue;
821 }
822 if (xml_isNode(cur,"unique")) {
823 ship_setFlag( temp, SHIP_UNIQUE );
824 continue;
825 }
826 WARN(_("Ship '%s' has unknown flags node '%s'."), temp->name, cur->name);
827 } while (xml_nextNode(cur));
828 continue;
829 }
830
831 if (xml_isNode(node,"trail_generator")) {
832 char *buf;
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 );
837 if (temp->trail_emitters == NULL) {
839 }
840 buf = xml_get(node);
841 if (buf == NULL)
842 buf = "default";
843 trail.trail_spec = trailSpec_get( buf );
844 if (trail.trail_spec != NULL)
845 array_push_back( &temp->trail_emitters, trail );
846 continue;
847 }
848
849 if (xml_isNode(node,"movement")) {
850 xmlNodePtr cur = node->children;
851 do {
852 xml_onlyNodes(cur);
853 xmlr_float(cur,"thrust",temp->thrust);
854 xmlr_float(cur,"turn",temp->turn);
855 xmlr_float(cur,"speed",temp->speed);
856 /* All the xmlr_ stuff have continue cases. */
857 WARN(_("Ship '%s' has unknown movement node '%s'."), temp->name, cur->name);
858 } while (xml_nextNode(cur));
859 continue;
860 }
861 if (xml_isNode(node,"health")) {
862 xmlNodePtr cur = node->children;
863 do {
864 xml_onlyNodes(cur);
865 xmlr_float(cur,"absorb",temp->dmg_absorb);
866 xmlr_float(cur,"armour",temp->armour);
867 xmlr_float(cur,"armour_regen",temp->armour_regen);
868 xmlr_float(cur,"shield",temp->shield);
869 xmlr_float(cur,"shield_regen",temp->shield_regen);
870 xmlr_float(cur,"energy",temp->energy);
871 xmlr_float(cur,"energy_regen",temp->energy_regen);
872 /* All the xmlr_ stuff have continue cases. */
873 WARN(_("Ship '%s' has unknown health node '%s'."), temp->name, cur->name);
874 } while (xml_nextNode(cur));
875 continue;
876 }
877 if (xml_isNode(node,"characteristics")) {
878 xmlNodePtr cur = node->children;
879 do {
880 xml_onlyNodes(cur);
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);
885 xmlr_int(cur,"fuel_consumption",temp->fuel_consumption);
886 xmlr_float(cur,"cargo",temp->cap_cargo);
887 /* All the xmlr_ stuff have continue cases. */
888 WARN(_("Ship '%s' has unknown characteristic node '%s'."), temp->name, cur->name);
889 } while (xml_nextNode(cur));
890 continue;
891 }
892 if (xml_isNode(node,"slots")) {
893 /* Allocate the space. */
897
898 /* Initialize the mounts. */
899 xmlNodePtr cur = node->children;
900 do {
901 xml_onlyNodes(cur);
902 if (xml_isNode(cur,"structure"))
903 ship_parseSlot( temp, &array_grow(&temp->outfit_structure), OUTFIT_SLOT_STRUCTURE, cur );
904 else if (xml_isNode(cur,"utility"))
905 ship_parseSlot( temp, &array_grow(&temp->outfit_utility), OUTFIT_SLOT_UTILITY, cur );
906 else if (xml_isNode(cur,"weapon"))
907 ship_parseSlot( temp, &array_grow(&temp->outfit_weapon), OUTFIT_SLOT_WEAPON, cur );
908 else
909 WARN(_("Ship '%s' has unknown slot node '%s'."), temp->name, cur->name);
910 } while (xml_nextNode(cur));
913 array_shrink( &temp->outfit_weapon );
914 continue;
915 }
916
917 /* Parse ship stats. */
918 if (xml_isNode(node,"stats")) {
919 xmlNodePtr cur = node->children;
920 do {
921 xml_onlyNodes(cur);
922 ll = ss_listFromXML( cur );
923 if (ll != NULL) {
924 ll->next = temp->stats;
925 temp->stats = ll;
926 continue;
927 }
928 WARN(_("Ship '%s' has unknown stat '%s'."), temp->name, cur->name);
929 } while (xml_nextNode(cur));
930
931 /* Load array. */
932 ss_statsInit( &temp->stats_array );
933 ss_statsModFromList( &temp->stats_array, temp->stats );
934
935 /* Create description. */
936 if (temp->stats != NULL) {
937 int i;
938 temp->desc_stats = malloc( STATS_DESC_MAX );
939 i = ss_statsListDesc( temp->stats, temp->desc_stats, STATS_DESC_MAX, 0 );
940 if (i <= 0) {
941 free( temp->desc_stats );
942 temp->desc_stats = NULL;
943 }
944 }
945
946 continue;
947 }
948
949 /* Parse tags. */
950 if (xml_isNode(node, "tags")) {
951 xmlNodePtr cur = node->children;
952 temp->tags = array_create( char* );
953 do {
954 xml_onlyNodes(cur);
955 if (xml_isNode(cur, "tag")) {
956 char *tmp = xml_get(cur);
957 if (tmp != NULL)
958 array_push_back( &temp->tags, strdup(tmp) );
959 continue;
960 }
961 WARN(_("Ship '%s' has unknown node in tags '%s'."), temp->name, cur->name );
962 } while (xml_nextNode(cur));
963 continue;
964 }
965
966 /* Used by on-valid and NSH utils, no in-game meaning. */
967 if (xml_isNode(node,"mission"))
968 continue;
969
970 DEBUG(_("Ship '%s' has unknown node '%s'."), temp->name, node->name);
971 } while (xml_nextNode(node));
972
973 /* Post processing. */
974 temp->dmg_absorb /= 100.;
975 temp->turn *= M_PI / 180.; /* Convert to rad. */
976
977 /* Check license. */
978 if (temp->license && !outfit_licenseExists(temp->license))
979 WARN(_("Ship '%s' has inexistent license requirement '%s'!"), temp->name, temp->license);
980
981 /* ship validator */
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");
985 MELEMENT((temp->gfx_space==NULL) || (temp->gfx_comm==NULL),"GFX");
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");
990 MELEMENT(temp->dt_default<=0.,"time_mod");
991 MELEMENT(temp->fabricator==NULL,"fabricator");
992 MELEMENT(temp->description==NULL,"description");
993 MELEMENT(temp->armour==0.,"armour");
994 MELEMENT((temp->cond!=NULL) && (temp->condstr==NULL), "condstr");
995 MELEMENT((temp->cond==NULL) && (temp->condstr!=NULL), "cond");
996 /*MELEMENT(temp->thrust==0.,"thrust");
997 MELEMENT(temp->turn==0.,"turn");
998 MELEMENT(temp->speed==0.,"speed");
999 MELEMENT(temp->shield==0.,"shield");
1000 MELEMENT(temp->shield_regen==0.,"shield_regen");
1001 MELEMENT(temp->energy==0.,"energy");
1002 MELEMENT(temp->energy_regen==0.,"energy_regen");
1003 MELEMENT(temp->fuel==0.,"fuel");*/
1004 MELEMENT(temp->crew==0,"crew");
1005 MELEMENT(temp->mass==0.,"mass");
1006 MELEMENT(temp->fuel_consumption==0,"fuel_consumption");
1007 /*MELEMENT(temp->cap_cargo==0,"cargo");
1008 MELEMENT(temp->cpu==0.,"cpu");*/
1009#undef MELEMENT
1010
1011 xmlFreeDoc(doc);
1012
1013 return 0;
1014}
1015
1021int ships_load (void)
1022{
1023 char **ship_files;
1024 int nfiles;
1025 Uint32 time = SDL_GetTicks();
1026
1027 /* Validity. */
1028 ss_check();
1029
1030 ship_files = ndata_listRecursive( SHIP_DATA_PATH );
1031 nfiles = array_size( ship_files );
1032
1033 /* Initialize stack if needed. */
1034 if (ship_stack == NULL)
1036
1037 for (int i=0; i<nfiles; i++) {
1038 if (ndata_matchExt( ship_files[i], "xml" )) {
1039 /* Load the ship. */
1040 Ship s;
1041 int ret = ship_parse( &s, ship_files[i] );
1042 if (ret == 0)
1044
1045 /* Render if necessary. */
1047 }
1048
1049 /* Clean up. */
1050 free( ship_files[i] );
1051 }
1052 qsort( ship_stack, array_size(ship_stack), sizeof(Ship), ship_cmp );
1053
1054 /* Shrink stack. */
1056 if (conf.devmode) {
1057 time = SDL_GetTicks() - time;
1058 DEBUG( n_( "Loaded %d Ship in %.3f s", "Loaded %d Ships in %.3f s", array_size(ship_stack) ), array_size(ship_stack), time/1000. );
1059 }
1060 else
1061 DEBUG( n_( "Loaded %d Ship", "Loaded %d Ships", array_size(ship_stack) ), array_size(ship_stack) );
1062
1063 /* Clean up. */
1064 array_free( ship_files );
1065
1066 return 0;
1067}
1068
1072void ships_free (void)
1073{
1074 for (int i=0; i < array_size(ship_stack); i++) {
1075 Ship *s = &ship_stack[i];
1076
1077 /* Free stored strings. */
1078 free(s->name);
1079 free(s->class_display);
1080 free(s->description);
1081 free(s->gui);
1082 free(s->base_type);
1083 free(s->fabricator);
1084 free(s->license);
1085 free(s->cond);
1086 free(s->condstr);
1087 free(s->desc_stats);
1088
1089 /* Free outfits. */
1090 for (int j=0; j<array_size(s->outfit_structure); j++)
1091 ship_freeSlot( &s->outfit_structure[j] );
1092 for (int j=0; j<array_size(s->outfit_utility); j++)
1093 ship_freeSlot( &s->outfit_utility[j] );
1094 for (int j=0; j<array_size(s->outfit_weapon); j++)
1095 ship_freeSlot( &s->outfit_weapon[j] );
1099
1100 ss_free( s->stats );
1101
1102 /* Free graphics. */
1103 object_free(s->gfx_3d);
1108 free(s->gfx_comm);
1109 for (int j=0; j<array_size(s->gfx_overlays); j++)
1112
1113 /* Free collision polygons. */
1114 for (int j=0; j<array_size(s->polygon); j++) {
1115 free(s->polygon[j].x);
1116 free(s->polygon[j].y);
1117 }
1118
1120 array_free(s->polygon);
1121
1122 /* Free tags. */
1123 for (int j=0; j<array_size(s->tags); j++)
1124 free(s->tags[j]);
1125 array_free(s->tags);
1126 }
1127
1129 ship_stack = NULL;
1130}
1131
1132static void ship_freeSlot( ShipOutfitSlot* s )
1133{
1134 outfit_freeSlot( &s->slot );
1135 free( s->name );
1136}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition: array.h:158
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
Definition: array.h:102
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition: array.h:168
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition: array.h:119
#define array_shrink(ptr_array)
Shrinks memory to fit only ‘size’ elements.
Definition: array.h:149
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition: array.h:129
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition: array.h:93
void LoadPolygon(CollPoly *polygon, xmlNodePtr node)
Loads a polygon from an xml node.
Definition: collision.c:32
void naev_renderLoadscreen(void)
Renders the loadscreen if necessary.
Definition: naev.c:549
Header file with generic functions and naev-specifics.
#define PATH_MAX
Definition: naev.h:50
int ndata_matchExt(const char *path, const char *ext)
Sees if a file matches an extension.
Definition: ndata.c:366
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
Definition: ndata.c:232
static char buf[NEWS_MAX_LENGTH]
Definition: news.c:45
int asprintf(char **strp, const char *fmt,...)
Like sprintf(), but it allocates a large-enough string and returns the pointer in the first argument....
Definition: nstring.c:161
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,...
Definition: nstring.c:94
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.
Definition: nxml.c:29
xmlDocPtr xml_parsePhysFS(const char *filename)
Analogous to xmlParseMemory/xmlParseFile.
Definition: nxml.c:75
void object_free(Object *object)
Frees memory reserved for the object.
Definition: object.c:358
Object * object_loadFromFile(const char *filename)
Loads object.
Definition: object.c:225
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.
Definition: opengl_tex.c:684
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.
Definition: opengl_tex.c:444
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.
Definition: opengl_tex.c:331
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
Definition: opengl_tex.c:570
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.
Definition: opengl_tex.c:857
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition: opengl_tex.c:755
const Outfit * outfit_get(const char *name)
Gets an outfit by name.
Definition: outfit.c:118
OutfitSlotSize outfit_toSlotSize(const char *s)
Gets the outfit slot size from a human readable string.
Definition: outfit.c:411
int outfit_licenseExists(const char *name)
Checks to see if a license exists.
Definition: outfit.c:2748
void outfit_freeSlot(OutfitSlot *s)
Frees an outfit slot.
Definition: outfit.c:1047
int ship_size(const Ship *s)
Gets the size of the ship.
Definition: ship.c:302
ShipClass ship_classFromString(const char *str)
Gets the machine ship class identifier from a human readable string.
Definition: ship.c:222
static int ship_parseSlot(Ship *temp, ShipOutfitSlot *slot, OutfitSlotType type, xmlNodePtr node)
Parses a slot for a ship.
Definition: ship.c:569
static Ship * ship_stack
Definition: ship.c:46
const char * ship_class(const Ship *s)
Gets the ship's class name in human readable form.
Definition: ship.c:151
const char * ship_classDisplay(const Ship *s)
Gets the ship's display class in human readable form.
Definition: ship.c:162
credits_t ship_basePrice(const Ship *s)
Gets the ship's base price (no outfits).
Definition: ship.c:252
credits_t ship_buyPrice(const Ship *s)
The ship buy price, includes default outfits.
Definition: ship.c:260
const Ship * ship_getW(const char *name)
Gets a ship based on its name without warning.
Definition: ship.c:87
#define SHIP_ENGINE
Definition: ship.c:34
int ships_load(void)
Loads all the ships in the data files.
Definition: ship.c:1021
static int ship_loadEngineImage(Ship *temp, char *str, int sx, int sy)
Loads the space graphics for a ship from an image.
Definition: ship.c:453
static int ship_cmp(const void *p1, const void *p2)
Compares two ship pointers for qsort.
Definition: ship.c:59
const Ship * ship_getAll(void)
Gets the array (array.h) of all ships.
Definition: ship.c:107
static int ship_loadSpaceImage(Ship *temp, char *str, int sx, int sy)
Loads the space graphics for a ship from an image.
Definition: ship.c:402
void ships_free(void)
Frees all the ships.
Definition: ship.c:1072
static int ship_loadGFX(Ship *temp, const char *buf, int sx, int sy, int engine)
Loads the graphics for a ship.
Definition: ship.c:468
int ship_compareTech(const void *arg1, const void *arg2)
Comparison function for qsort().
Definition: ship.c:115
const char * ship_classToString(ShipClass class)
Gets the ship class name in human readable form.
Definition: ship.c:175
#define STATS_DESC_MAX
Definition: ship.c:44
#define SHIP_COMM
Definition: ship.c:36
static int ship_parse(Ship *temp, const char *filename)
Extracts the in-game ship from an XML node.
Definition: ship.c:652
glTexture * ship_loadCommGFX(const Ship *s)
Loads the ship's comm graphic.
Definition: ship.c:289
static int ship_loadPLG(Ship *temp, const char *buf, int size_hint)
Loads the collision polygon for a ship.
Definition: ship.c:513
const Ship * ship_get(const char *name)
Gets a ship based on its name.
Definition: ship.c:73
static int ship_genTargetGFX(Ship *temp, SDL_Surface *surface, int sx, int sy)
Generates a target graphic for a ship.
Definition: ship.c:339
const char * ship_existsCase(const char *name)
Checks to see if an ship exists matching name (case insensitive).
Definition: ship.c:96
int ss_statsListDesc(const ShipStatList *ll, char *buf, int len, int newline)
Writes the ship statistics description.
Definition: shipstats.c:699
void ss_free(ShipStatList *ll)
Frees a list of ship stats.
Definition: shipstats.c:807
int ss_statsModFromList(ShipStats *stats, const ShipStatList *list)
Updates a stat structure from a stat list.
Definition: shipstats.c:543
int ss_statsInit(ShipStats *stats)
Initializes a stat structure.
Definition: shipstats.c:347
int ss_check(void)
Checks for validity.
Definition: shipstats.c:331
ShipStatList * ss_listFromXML(xmlNodePtr node)
Creates a shipstat list element from an xml node.
Definition: shipstats.c:209
int sp_locked(unsigned int spid)
Gets whether or not a slot property is locked.
Definition: slots.c:190
unsigned int sp_get(const char *name)
Gets the id of a slot property.
Definition: slots.c:124
int sp_required(unsigned int spid)
Gets whether or not a slot property is required.
Definition: slots.c:170
int sp_exclusive(unsigned int spid)
Gets whether or not a slot property is exclusive.
Definition: slots.c:180
int sound_get(const char *name)
Gets the buffer to sound of name.
Definition: sound.c:764
const TrailSpec * trailSpec_get(const char *name)
Gets a trail spec by name.
Definition: spfx.c:1268
Represents a polygon used for collision detection.
Definition: collision.h:13
float * x
Definition: collision.h:14
float * y
Definition: collision.h:15
OutfitSlotSize size
Definition: outfit.h:105
int exclusive
Definition: outfit.h:103
unsigned int spid
Definition: outfit.h:102
OutfitSlotType type
Definition: outfit.h:104
A ship outfit, depends radically on the type.
Definition: outfit.h:304
credits_t price
Definition: outfit.h:322
int devmode
Definition: conf.h:158
double x
Definition: ship.h:62
double y
Definition: ship.h:63
double h
Definition: ship.h:64
Ship outfit slot.
Definition: ship.h:70
int exclusive
Definition: ship.h:73
int required
Definition: ship.h:74
const Outfit * data
Definition: ship.h:76
char * name
Definition: ship.h:72
ShipMount mount
Definition: ship.h:77
OutfitSlot slot
Definition: ship.h:71
int locked
Definition: ship.h:75
Represents relative ship statistics as a linked list.
Definition: shipstats.h:167
struct ShipStatList_ * next
Definition: shipstats.h:168
Ship trail emitter.
Definition: ship.h:83
double y_engine
Definition: ship.h:85
const TrailSpec * trail_spec
Definition: ship.h:88
double h_engine
Definition: ship.h:86
double x_engine
Definition: ship.h:84
unsigned int always_under
Definition: ship.h:87
Represents a space ship.
Definition: ship.h:94
double shield_regen
Definition: ship.h:129
double dt_default
Definition: ship.h:123
double cap_cargo
Definition: ship.h:122
glTexture * gfx_space
Definition: ship.h:137
ShipStats stats_array
Definition: ship.h:166
char * license
Definition: ship.h:105
double gfx_3d_scale
Definition: ship.h:136
char * name
Definition: ship.h:95
double thrust
Definition: ship.h:112
int sound
Definition: ship.h:152
int fuel
Definition: ship.h:120
char * fabricator
Definition: ship.h:108
char * description
Definition: ship.h:109
char * base_type
Definition: ship.h:96
char * class_display
Definition: ship.h:98
credits_t price
Definition: ship.h:104
double energy_regen
Definition: ship.h:131
double armour
Definition: ship.h:126
int fuel_consumption
Definition: ship.h:121
double armour_regen
Definition: ship.h:127
glTexture * gfx_target
Definition: ship.h:139
CollPoly * polygon
Definition: ship.h:146
int crew
Definition: ship.h:117
ShipStatList * stats
Definition: ship.h:165
double dmg_absorb
Definition: ship.h:132
double engine_pitch
Definition: ship.h:153
char * condstr
Definition: ship.h:107
char * cond
Definition: ship.h:106
int points
Definition: ship.h:99
double cpu
Definition: ship.h:119
double mangle
Definition: ship.h:161
double speed
Definition: ship.h:114
ShipOutfitSlot * outfit_utility
Definition: ship.h:157
double turn
Definition: ship.h:113
char * desc_stats
Definition: ship.h:164
char ** tags
Definition: ship.h:169
int rarity
Definition: ship.h:100
glTexture * gfx_engine
Definition: ship.h:138
ShipOutfitSlot * outfit_weapon
Definition: ship.h:158
Object * gfx_3d
Definition: ship.h:135
glTexture * gfx_store
Definition: ship.h:140
double energy
Definition: ship.h:130
char * gfx_comm
Definition: ship.h:141
ShipTrailEmitter * trail_emitters
Definition: ship.h:143
char * gui
Definition: ship.h:149
glTexture ** gfx_overlays
Definition: ship.h:142
double shield
Definition: ship.h:128
ShipClass class
Definition: ship.h:97
double mass
Definition: ship.h:118
ShipOutfitSlot * outfit_structure
Definition: ship.h:156
Abstraction for rendering sprite sheets.
Definition: opengl_tex.h:34
double w
Definition: opengl_tex.h:38
double sx
Definition: opengl_tex.h:42
double sy
Definition: opengl_tex.h:43
double h
Definition: opengl_tex.h:39