naev 0.10.4
player.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <stdlib.h>
11#include "physfs.h"
12
13#include "naev.h"
16#include "player.h"
17
18#include "ai.h"
19#include "camera.h"
20#include "claim.h"
21#include "comm.h"
22#include "conf.h"
23#include "dialogue.h"
24#include "difficulty.h"
25#include "economy.h"
26#include "equipment.h"
27#include "escort.h"
28#include "event.h"
29#include "font.h"
30#include "gui.h"
31#include "gui_omsg.h"
32#include "hook.h"
33#include "info.h"
34#include "input.h"
35#include "intro.h"
36#include "land.h"
37#include "land_outfits.h"
38#include "load.h"
39#include "log.h"
40#include "map.h"
41#include "map_overlay.h"
42#include "menu.h"
43#include "mission.h"
44#include "music.h"
45#include "ndata.h"
46#include "news.h"
47#include "nfile.h"
48#include "nlua_misn.h"
49#include "nlua_outfit.h"
50#include "nlua_ship.h"
51#include "nlua_var.h"
52#include "nstring.h"
53#include "ntime.h"
54#include "nxml.h"
55#include "opengl.h"
56#include "pause.h"
57#include "pilot.h"
58#include "player_gui.h"
59#include "player_fleet.h"
60#include "player_inventory.h"
61#include "rng.h"
62#include "shiplog.h"
63#include "sound.h"
64#include "space.h"
65#include "spfx.h"
66#include "start.h"
67#include "toolkit.h"
68#include "unidiff.h"
69
70/*
71 * Player stuff
72 */
74static const Ship* player_ship = NULL;
75static credits_t player_creds = 0;
76static credits_t player_payback = 0;
77static int player_ran_updater = 0;
78static char *player_message_noland = NULL;
80/*
81 * Licenses.
82 */
83static char **player_licenses = NULL;
85/*
86 * Default radar resolution.
87 */
88#define RADAR_RES_DEFAULT 50.
90/*
91 * player sounds.
92 */
93static int player_engine_group = -1;
94static int player_hyper_group = -1;
95static int player_gui_group = -1;
96int snd_target = -1;
97int snd_jump = -1;
98int snd_nav = -1;
99int snd_hail = -1;
100/* Hyperspace sounds. */
101int snd_hypPowUp = -1;
102int snd_hypEng = -1;
105int snd_hypJump = -1;
106static int player_lastEngineSound = -1;
107static int player_hailCounter = 0;
108static double player_hailTimer = 0.;
110/*
111 * Player pilot stack (ships they have) and outfit (outfits they have) stacks (array.h)
112 */
116/*
117 * player global properties
118 */
119/* used in input.c */
120double player_left = 0.;
121double player_right = 0.;
122double player_acc = 0.;
123/* for death and such */
124static double player_timer = 0.;
126/*
127 * unique mission and event stack.
128 */
129static int* missions_done = NULL;
130static int* events_done = NULL;
132/*
133 * prototypes
134 */
135/*
136 * internal
137 */
138static void player_checkHail (void);
139/* creation */
140static void player_newSetup();
141static int player_newMake (void);
142static PlayerShip_t* player_newShipMake( const char* name );
143/* sound */
144static void player_initSound (void);
145/* save/load */
146static int player_saveEscorts( xmlTextWriterPtr writer );
147static int player_saveShipSlot( xmlTextWriterPtr writer, const PilotOutfitSlot *slot, int i );
148static int player_saveShip( xmlTextWriterPtr writer, PlayerShip_t *pship );
149static int player_saveMetadata( xmlTextWriterPtr writer );
150static Spob* player_parse( xmlNodePtr parent );
151static int player_parseDoneMissions( xmlNodePtr parent );
152static int player_parseDoneEvents( xmlNodePtr parent );
153static int player_parseLicenses( xmlNodePtr parent );
154static int player_parseInventory( xmlNodePtr parent );
155static void player_parseShipSlot( xmlNodePtr node, Pilot *ship, PilotOutfitSlot *slot );
156static int player_parseShip( xmlNodePtr parent, int is_player );
157static int player_parseEscorts( xmlNodePtr parent );
158static int player_parseMetadata( xmlNodePtr parent );
159static void player_addOutfitToPilot( Pilot* pilot, const Outfit* outfit, PilotOutfitSlot *s );
160static int player_runUpdaterScript( const char* type, const char* name, int q );
161static const Outfit* player_tryGetOutfit( const char* name, int q );
162static const Ship* player_tryGetShip( const char* name );
163static void player_tryAddLicense( const char* name );
164/* Render. */
165static void player_renderStealthUnderlay( double dt );
166static void player_renderStealthOverlay( double dt );
167static void player_renderAimHelper( double dt );
168/* Misc. */
169static int player_filterSuitableSpob( Spob *p );
170static void player_spobOutOfRangeMsg (void);
171static int player_outfitCompare( const void *arg1, const void *arg2 );
172static int player_thinkMouseFly(void);
173static int preemption = 0; /* Hyperspace target/untarget preemption. */
174
175/*
176 * externed
177 */
178int player_save( xmlTextWriterPtr writer ); /* save.c */
179Spob* player_load( xmlNodePtr parent ); /* save.c */
180
184int player_init (void)
185{
186 if (player_stack==NULL)
188 if (player_outfits==NULL)
191 memset( &player, 0, sizeof(PlayerShip_t) );
192 return 0;
193}
194
198static void player_newSetup()
199{
200 double x, y;
201
202 /* Setup sound */
204
205 /* Clean up player stuff if we'll be recreating. */
207
208 /* Set up GUI. */
211
212 /* Sane time defaults. */
213 player.last_played = time(NULL);
216 player.chapter = strdup( start_chapter() );
217
218 /* For pretty background. */
220 space_init( start_system(), 1 );
221 start_position( &x, &y );
222
223 cam_setTargetPos( x, y, 0 );
224 cam_setZoom( conf.zoom_far );
225
226 /* Clear the init message for new game. */
228}
229
238void player_new (void)
239{
240 /* Set up new player. */
242
243 /* Some meta-data. */
244 player.date_created = time(NULL);
245
246 /* Get the name. */
247 player.name = dialogue_input( _("Player Name"), 1, 60,
248 _("Please write your name:") );
249
250 /* Player cancelled dialogue. */
251 if (player.name == NULL) {
252 menu_main();
253 return;
254 }
255
256 load_refresh();
257 if (array_size( load_getList( player.name ) ) > 0) {
258 int r = dialogue_YesNo(_("Overwrite"),
259 _("You already have a pilot named %s. Their autosave and backup save will be overwritten. Do you wish to continue?"), player.name);
260 if (r==0) { /* no */
261 player_new();
262 return;
263 }
264 }
265
266 if (player_newMake())
267 return;
268
269 /* Display the intro. */
270 intro_display( INTRO_PATH, "intro" );
271
272 /* Play music. */
273 music_choose( "ambient" );
274
275 /* Set loaded version. */
276 player.loaded_version = strdup( naev_version(0) );
277
278 /* Add the mission if found. */
279 if (start_mission() != NULL) {
280 if (mission_start(start_mission(), NULL) < 0)
281 WARN(_("Failed to run start mission '%s'."), start_mission());
282 }
283
284 /* Add the event if found. */
285 if (start_event() != NULL) {
286 if (event_start( start_event(), NULL ))
287 WARN(_("Failed to run start event '%s'."), start_event());
288 }
289
290 /* Run the load event trigger. */
291 events_trigger( EVENT_TRIGGER_LOAD );
292
293 /* Load the GUI. */
294 gui_load( gui_pick() );
295}
296
302static int player_newMake (void)
303{
304 const Ship *ship;
305 const char *shipname, *acquired;
306 double x,y;
307 PlayerShip_t *ps;
308
309 if (player_stack==NULL)
311 if (player_outfits==NULL)
313
314 /* Time. */
316 /* Clear known economy info */
318 /* Welcome message - must be before space_init. */
319 player_message( _("#gWelcome to %s!"), APPNAME );
320 player_message( "#g v%s", naev_version(0) );
321
322 /* Try to create the pilot, if fails reask for player name. */
323 ship = ship_get( start_ship() );
324 shipname = _(start_shipname());
325 if (ship==NULL) {
326 WARN(_("Ship not properly set by module."));
327 return -1;
328 }
329 acquired = _(start_acquired());
330 /* Setting a default name in the XML prevents naming prompt. */
331 ps = player_newShip( ship, shipname, 0, acquired, (shipname==NULL) ? 0 : 1 );
332 if (ps == NULL) {
333 player_new();
334 return -1;
335 }
336 assert( &player.ps == ps );
337 start_position( &x, &y );
338 vec2_cset( &player.p->solid->pos, x, y );
339 vectnull( &player.p->solid->vel );
340 player.p->solid->dir = RNGF() * 2.*M_PI;
341 space_init( start_system(), 1 );
342
343 /* Bind camera. */
345
346 /* Set player speed to default 1 */
347 player.speed = 1.;
348
349 /* Reset speed (to make sure time dilation stuff is accounted for). */
351
352 /* Monies. */
354
355 /* clear the map */
356 map_clear();
357
358 /* Start the economy. */
359 economy_init();
360
361 /* clear the shiplog*/
363
364 /* Start the news */
365 news_init();
366
367 return 0;
368}
369
382PlayerShip_t* player_newShip( const Ship* ship, const char *def_name,
383 int trade, const char *acquired, int noname )
384{
385 char *ship_name, *old_name;
386 PlayerShip_t *ps;
387
388 /* temporary values while player doesn't exist */
389 player_creds = (player.p != NULL) ? player.p->credits : 0;
390 player_ship = ship;
391 if (!noname)
392 ship_name = dialogue_input( _("Ship Name"), 1, 60,
393 _("Please name your new ship:") );
394 else
395 ship_name = NULL;
396
397 /* Dialogue cancelled. */
398 if (ship_name == NULL) {
399 int i, len;
400
401 /* No default name, fail. */
402 if (def_name == NULL)
403 return NULL;
404
405 /* Add default name. */
406 i = 2;
407 len = strlen(def_name)+10;
408 ship_name = malloc( len );
409 strcpy( ship_name, def_name );
410 while (player_hasShip(ship_name)) {
411 snprintf( ship_name, len, "%s %d", def_name, i );
412 i++;
413 }
414 }
415
416 /* Must not have same name. */
417 if (player_hasShip(ship_name)) {
418 dialogue_msg( _("Name collision"),
419 _("Please do not give the ship the same name as another of your ships."));
420 free( ship_name );
421 return NULL;
422 }
423 if (trade && player.p == NULL)
424 ERR(_("Player ship isn't valid… This shouldn't happen!"));
425
426 ps = player_newShipMake( ship_name );
427 ps->autoweap = 1;
428 ps->favourite = 0;
429 ps->p->shipvar= array_create( lvar );
430 ps->acquired = (acquired!=NULL) ? strdup( acquired ) : NULL;
431 ps->acquired_date = ntime_get();
432
433 /* Player is trading ship in. */
434 if (trade) {
435 old_name = player.p->name;
436 player_swapShip( ship_name, 1 ); /* Move to the new ship. */
437 player_rmShip( old_name );
438 }
439
440 free(ship_name);
442
443 /* Update ship list if landed. */
444 if (landed) {
445 int w = land_getWid( LAND_WINDOW_EQUIPMENT );
446 equipment_regenLists( w, 0, 1 );
447 }
448
449 return ps;
450}
451
455static PlayerShip_t *player_newShipMake( const char *name )
456{
457 PilotFlags flags;
458 PlayerShip_t *ps;
459
460 /* store the current ship if it exists */
461 pilot_clearFlagsRaw( flags );
462 pilot_setFlagRaw( flags, PILOT_PLAYER );
463 pilot_setFlagRaw( flags, PILOT_NO_OUTFITS );
464
465 /* in case we're respawning */
466 player_rmFlag( PLAYER_CREATING );
467
468 /* Grow memory. */
469 ps = (player.p == NULL) ? &player.ps : &array_grow( &player_stack );
470 memset( ps, 0, sizeof(PlayerShip_t) );
471 pilot_setFlagRaw( flags, PILOT_PLAYER_FLEET );
472 /* Create the ship. */
473 ps->p = pilot_createEmpty( player_ship, name, faction_get("Player"), flags );
474 if (player.p == NULL) {
475 pilot_reset( ps->p );
476 pilot_setPlayer( ps->p );
477 }
478 /* Initialize parent weapon sets. */
479 ws_copy( ps->weapon_sets, ps->p->weapon_sets );
480
481 if (player.p == NULL)
482 ERR(_("Something seriously wonky went on, newly created player does not exist, bailing!"));
483
484 /* Add GUI. */
486
487 /* money. */
489 player_creds = 0;
490 player_payback = 0;
491
492 return ps;
493}
494
501void player_swapShip( const char *shipname, int move_cargo )
502{
503 HookParam hparam[5];
504 Pilot *ship;
505 vec2 v;
506 double dir;
507 int removed;
508 PlayerShip_t *ps = NULL;
509 PlayerShip_t ptemp;
510
511 /* Try to find the ship. */
512 for (int i=0; i<array_size(player_stack); i++) {
513 if (strcmp(shipname,player_stack[i].p->name)==0) {
514 ps = &player_stack[i];
515 break;
516 }
517 }
518 if (ps==NULL) {
519 WARN( _("Unable to swap player.p with ship '%s': ship does not exist!"), shipname );
520 return;
521 }
522
523 /* Run onremove hook for all old outfits. */
524 for (int i=0; i<array_size(player.p->outfits); i++)
526
527 /* Get rid of deployed escorts and swap existing escorts. */
529 escort_freeList( ps->p );
530 ps->p->escorts = array_create( Escort_t );
531 /* Just copying the array over has unforeseen consequences, so recreate. */
532 for (int i=0; i<array_size(player.p->escorts); i++) {
533 Escort_t *e = &player.p->escorts[i];
534 Escort_t ne = *e;
535
536 /* Must not be new ship. */
537 if (e->id == ps->p->id )
538 continue;
539
540 ne.ship = strdup(e->ship); /* Might be worth having an escort_copy function. */
541 array_push_back( &ps->p->escorts, ne );
542 }
544
545 /* Swap information over. */
546 ptemp = player.ps;
547 player.ps= *ps;
548 *ps = ptemp;
549 ship = player.ps.p;
550
551 /* Move credits over */
552 ship->credits = player.p->credits;
553
554 /* Copy target info */
555 ship->target = player.p->target;
556 ship->nav_spob = player.p->nav_spob;
558 ship->nav_anchor = player.p->nav_anchor;
560
561 /* Store position. */
562 v = player.p->solid->pos;
563 dir = player.p->solid->dir;
564
565 /* Copy over weapon sets. */
567
568 /* If the pilot is deployed, we must redeploy. */
569 removed = 0;
570 if (ps->p->id > 0) {
571 pilot_stackRemove( ps->p );
572 removed = 1;
573 }
574 pilot_setPlayer( ship );
575 player.ps.deployed = 0; /* Player themselves can't be deployed. */
576 if (ps->deployed)
577 pfleet_deploy( ps );
578
579 /* Extra pass to calculate stats */
581 pilot_calcStats( ps->p );
582
583 /* Run onadd hook for all new outfits. */
584 for (int j=0; j<array_size(ship->outfits); j++)
585 pilot_outfitLAdd( ship, ship->outfits[j] );
586
587 /* Move cargo over. */
588 if (move_cargo) {
590 pfleet_update(); /* Update fleet and move cargo. */
591 }
592
593 /* Clean up, AFTER cargo is updated. */
594 if (!ps->deployed && removed)
595 pilot_free( ps->p );
596
597 /* Copy position back. */
598 player.p->solid->pos = v;
599 player.p->solid->dir = dir;
600
601 /* Fill the tank. */
602 if (landed)
603 land_refuel();
604
605 /* Clear targets. */
607
608 /* Set some gui stuff. */
609 gui_load( gui_pick() );
610
611 /* Bind camera. */
613
614 /* Recompute stuff if necessary. */
617
618 /* Run hook. */
619 hparam[0].type = HOOK_PARAM_STRING;
620 hparam[0].u.str = player.p->name;
621 hparam[1].type = HOOK_PARAM_STRING;
622 hparam[1].u.str = player.p->ship->name;
623 hparam[2].type = HOOK_PARAM_STRING;
624 hparam[2].u.str = ps->p->name;
625 hparam[3].type = HOOK_PARAM_STRING;
626 hparam[3].u.str = ps->p->ship->name;
627 hparam[4].type = HOOK_PARAM_SENTINEL;
628 hooks_runParam( "ship_swap", hparam );
629
630 return;
631}
632
639credits_t player_shipPrice( const char *shipname )
640{
641 Pilot *ship = NULL;
642
643 if (strcmp(shipname,player.p->name)==0)
644 ship = player.p;
645 else {
646 /* Find the ship. */
647 for (int i=0; i<array_size(player_stack); i++) {
648 if (strcmp(shipname,player_stack[i].p->name)==0) {
649 ship = player_stack[i].p;
650 break;
651 }
652 }
653 }
654
655 /* Not found. */
656 if (ship == NULL) {
657 WARN( _("Unable to find price for player's ship '%s': ship does not exist!"), shipname );
658 return -1;
659 }
660
661 return pilot_worth( ship );
662}
663
669void player_rmShip( const char *shipname )
670{
671 for (int i=0; i<array_size(player_stack); i++) {
672 PlayerShip_t *ps = &player_stack[i];
673
674 /* Not the ship we are looking for. */
675 if (strcmp(shipname,ps->p->name)!=0)
676 continue;
677
678 /* Free player ship. */
679 pilot_rmFlag( ps->p, PILOT_NOFREE );
680 pilot_free( ps->p );
681 ws_free( ps->weapon_sets );
682 free( ps->acquired );
683
684 array_erase( &player_stack, ps, ps+1 );
685 }
686
687 /* Update ship list if landed. */
688 if (landed) {
689 int w = land_getWid( LAND_WINDOW_EQUIPMENT );
690 equipment_regenLists( w, 0, 1 );
691 }
692}
693
697void player_cleanup (void)
698{
699 /* Enable all input. */
701
702 /* Clean up other stuff. */
703 diff_clear();
704 var_cleanup();
708 land_cleanup();
709 map_cleanup();
712
713 /* Reset controls. */
715 player_left = 0.;
716 player_right = 0.;
717
718 /* Clear player. */
719 player_clear();
720
721 /* Clear hail timer. */
723 player_hailTimer = 0.;
724
725 /* Clear messages. */
727
728 /* Reset factions. */
730
731 /* Free stuff. */
732 free(player.name);
733 player.name = NULL;
734 free( player.ps.acquired );
735 player.ps.acquired = NULL;
737
740
741 /* Clean up gui. */
742 gui_cleanup();
744 ovr_setOpen(0);
745
746 /* Clear up info buttons. */
748
750 player_outfits = NULL;
751
753 missions_done = NULL;
754
756 events_done = NULL;
757
758 /* Clean up licenses. */
759 for (int i=0; i<array_size(player_licenses); i++)
760 free(player_licenses[i]);
762 player_licenses = NULL;
763
764 /* Clear claims. */
765 claim_clear();
766
767 /* Purge the pilot stack, and player.p. */
769
770 /* clean up the stack */
771 for (int i=0; i<array_size(player_stack); i++) {
772 PlayerShip_t *ps = &player_stack[i];
773 pilot_rmFlag( ps->p, PILOT_NOFREE );
774 pilot_free( ps->p );
775 ws_free( ps->weapon_sets );
776 free( ps->acquired );
777 }
779 player_stack = NULL;
780 /* nothing left */
781
782 /* Reset some player stuff. */
783 player_creds = 0;
784 player_payback = 0;
785 free( player.gui );
786 player.gui = NULL;
787 free( player.chapter );
788 player.chapter = NULL;
789 free( player.difficulty );
790 player.difficulty = NULL;
791
792 /* Clear omsg. */
793 omsg_cleanup();
794
795 /* Stop the sounds. */
797
798 /* Clean up local difficulty. */
799 difficulty_setLocal( NULL );
800
801 /* Reset time compression. */
802 pause_setSpeed( 1. );
803 sound_setSpeed( 1. );
804
805 free( player.loaded_version );
806 player.loaded_version = NULL;
807
808 /* Clean up. */
809 memset( &player, 0, sizeof(Player_t) );
810 player_setFlag(PLAYER_CREATING);
811}
812
813static int player_soundReserved = 0;
817static void player_initSound (void)
818{
820 return;
821
822 /* Allocate channels. */
823 player_engine_group = sound_createGroup(1); /* Channel for engine noises. */
826 sound_speedGroup( player_gui_group, 0 ); /* Disable pitch shift. */
828
829 /* Get sounds. */
830 snd_target = sound_get("target");
831 snd_jump = sound_get("jump");
832 snd_nav = sound_get("nav");
833 snd_hail = sound_get("hail");
834 snd_hypPowUp = sound_get("hyperspace_powerup");
835 snd_hypEng = sound_get("hyperspace_engine");
836 snd_hypPowDown = sound_get("hyperspace_powerdown");
837 snd_hypPowUpJump = sound_get("hyperspace_powerupjump");
838 snd_hypJump = sound_get("hyperspace_jump");
839}
840
847void player_soundPlayGUI( int sound, int once )
848{
849 sound_playGroup( player_gui_group, sound, once );
850}
851
858void player_soundPlay( int sound, int once )
859{
860 sound_playGroup( player_hyper_group, sound, once );
861}
862
867{
868 if (player_gui_group >= 0)
870 if (player_engine_group >= 0)
872 if (player_hyper_group >= 0)
874
875 /* No last engine sound. */
877}
878
883{
884 if (player_engine_group >= 0)
886 if (player_hyper_group >= 0)
888}
889
894{
895 if (player_engine_group >= 0)
897 if (player_hyper_group >= 0)
899}
900
907void player_warp( double x, double y )
908{
909 unsigned int target = cam_getTarget();
910 vec2_cset( &player.p->solid->pos, x, y );
911 /* Have to move camera over to avoid moving stars when loading. */
912 if (target == player.p->id)
913 cam_setTargetPilot( target, 0 );
914}
915
919void player_clear (void)
920{
921 if (player.p != NULL) {
924 }
925
926 /* Clear the noland flag. */
927 player_rmFlag( PLAYER_NOLAND );
928}
929
936int player_hasCredits( credits_t amount )
937{
938 return pilot_hasCredits( player.p, amount );
939}
940
947credits_t player_modCredits( credits_t amount )
948{
949 return pilot_modCredits( player.p, amount );
950}
951
955void player_render( double dt )
956{
957 /*
958 * Check to see if the death menu should pop up.
959 */
960 if (player_isFlag(PLAYER_DESTROYED)) {
961 player_timer -= dt;
962 if (!toolkit_isOpen() && !player_isFlag(PLAYER_CREATING) &&
963 (player_timer < 0.))
964 menu_death();
965 }
966
967 /* Skip rendering. */
968 if ((player.p == NULL) || (player.p->id == 0) || player_isFlag(PLAYER_CREATING) ||
969 pilot_isFlag( player.p, PILOT_HIDE))
970 return;
971
972 /* Render stealth overlay. */
973 if (pilot_isFlag( player.p, PILOT_STEALTH ))
975
976 /* Render the aiming lines. */
977 if ((player.p->target != PLAYER_ID) && player.p->aimLines
978 && !pilot_isFlag( player.p, PILOT_HYPERSPACE ) && !pilot_isFlag( player.p, PILOT_DISABLED )
979 && !pilot_isFlag( player.p, PILOT_LANDING ) && !pilot_isFlag( player.p, PILOT_TAKEOFF )
980 && !player_isFlag( PLAYER_CINEMATICS_GUI ))
982
983 /* Render the player's pilot. */
985
986 /* Render the player's overlay. */
988}
989
993void player_renderUnderlay( double dt )
994{
995 /* Skip rendering. */
996 if ((player.p == NULL) || player_isFlag(PLAYER_CREATING) ||
997 pilot_isFlag( player.p, PILOT_HIDE))
998 return;
999
1000 if (pilot_isFlag( player.p, PILOT_STEALTH ))
1002}
1003
1007static void player_renderStealthUnderlay( double dt )
1008{
1009 (void) dt;
1010 double detectz;
1011 glColour col;
1012 Pilot *const* ps;
1013
1014 /* Don't display if overlay is open. */
1015 if (ovr_isOpen())
1016 return;
1017
1018 /* Iterate and draw for all pilots. */
1019 detectz = player.p->ew_stealth * cam_getZoom();
1020 col = cRed;
1021 col.a = 0.3;
1022 ps = pilot_getAll();
1023 for (int i=0; i<array_size(ps); i++) {
1024 double x, y, r;
1025 Pilot *t = ps[i];
1027 continue;
1028 if (pilot_isDisabled(t))
1029 continue;
1030 /* Only show pilots the player can see. */
1031 if (!pilot_validTarget( player.p, t ))
1032 continue;
1033
1034 gl_gameToScreenCoords( &x, &y, t->solid->pos.x, t->solid->pos.y );
1035 r = detectz * t->stats.ew_detect;
1036 if (r > 0.) {
1037 glUseProgram( shaders.stealthaura.program );
1038 gl_renderShader( x, y, r, r, 0., &shaders.stealthaura, &col, 1 );
1039 }
1040 }
1041}
1042
1046static void player_renderStealthOverlay( double dt )
1047{
1048 (void) dt;
1049 double x, y, r, st, z;
1050 glColour col;
1051
1052 z = cam_getZoom();
1054
1055 /* Determine the arcs. */
1057
1058 /* We do red to yellow. */
1059 col_blend( &col, &cYellow, &cRed, st );
1060 col.a = 0.5;
1061
1062 /* Determine size. */
1063 r = 1.2/2. * (double)player.p->ship->gfx_space->sw;
1064
1065 /* Draw the main circle. */
1066 glUseProgram( shaders.stealthmarker.program );
1067 glUniform1f( shaders.stealthmarker.paramf, st );
1068 gl_renderShader( x, y, r*z, r*z, 0., &shaders.stealthmarker, &col, 1 );
1069}
1070
1074static void player_renderAimHelper( double dt )
1075{
1076 (void) dt;
1077 double a, b, d, x1, y1, x2, y2, r, theta;
1078 glColour c, c2;
1079 Pilot *target;
1080
1081 target = pilot_getTarget( player.p );
1082 if (target == NULL)
1083 return;
1084
1085 a = player.p->solid->dir;
1086 r = 200.;
1088
1089 b = pilot_aimAngle( player.p, &target->solid->pos, &target->solid->vel );
1090
1091 theta = 22.*M_PI/180.;
1092
1093 /* The angular error will give the exact colour that is used. */
1094 d = ABS( angle_diff(a,b) / (2*theta) );
1095 d = MIN( 1, d );
1096
1097 c = cInert;
1098 c.a = 0.3;
1099 gl_gameToScreenCoords( &x2, &y2, player.p->solid->pos.x + r*cos( a+theta ),
1100 player.p->solid->pos.y + r*sin( a+theta ) );
1101 gl_renderLine( x1, y1, x2, y2, &c );
1102 gl_gameToScreenCoords( &x2, &y2, player.p->solid->pos.x + r*cos( a-theta ),
1103 player.p->solid->pos.y + r*sin( a-theta ) );
1104 gl_renderLine( x1, y1, x2, y2, &c );
1105
1106 c.r = d*0.9;
1107 c.g = d*0.2 + (1.-d)*0.8;
1108 c.b = (1-d)*0.2;
1109 c.a = 0.7;
1110 col_gammaToLinear( &c );
1111 gl_gameToScreenCoords( &x2, &y2, player.p->solid->pos.x + r*cos( a ),
1112 player.p->solid->pos.y + r*sin( a ) );
1113
1114 gl_renderLine( x1, y1, x2, y2, &c );
1115
1116 c2 = cWhite;
1117 c2.a = 0.7;
1118 glUseProgram(shaders.crosshairs.program);
1119 glUniform1f(shaders.crosshairs.paramf, 1.);
1120 gl_renderShader( x2, y2, 7, 7, 0., &shaders.crosshairs, &c2, 1 );
1121
1122 gl_gameToScreenCoords( &x2, &y2, player.p->solid->pos.x + r*cos( b ),
1123 player.p->solid->pos.y + r*sin( b ) );
1124
1125 c.a = 0.4;
1126 gl_renderLine( x1, y1, x2, y2, &c );
1127
1128 /* TODO this should be converted into a single SDF call. */
1129 glColour c3 = cBlack;
1130 c3.a = c2.a;
1131 gl_renderCircle( x2, y2, 8., &c3, 0 );
1132 gl_renderCircle( x2, y2, 10., &c3, 0 );
1133 gl_renderCircle( x2, y2, 9., &c2, 0 );
1134}
1135
1142void player_think( Pilot* pplayer, const double dt )
1143{
1144 Pilot *target;
1145 double acc, turn;
1146 int facing, fired;
1147
1148 /* last i heard, the dead don't think */
1149 if (pilot_isFlag(pplayer,PILOT_DEAD)) {
1150 /* no sense in accelerating or turning */
1151 pilot_setThrust( pplayer, 0. );
1152 pilot_setTurn( pplayer, 0. );
1153 return;
1154 }
1155
1156 /* We always have to run ai_think in the case the player has escorts so that
1157 * they properly form formations. */
1158 ai_think( pplayer, dt );
1159
1160 /* Under manual control is special. */
1161 if (pilot_isFlag( pplayer, PILOT_MANUAL_CONTROL ) || pilot_isFlag( pplayer, PILOT_HIDE )) {
1162 return;
1163 }
1164
1165 /* Not facing anything yet. */
1166 facing = 0;
1167
1168 /* Autonav takes over normal controls. */
1169 if (player_isFlag(PLAYER_AUTONAV)) {
1170 player_thinkAutonav( pplayer, dt );
1171
1172 /* Disable turning. */
1173 facing = 1;
1174 }
1175
1176 /* Mouse-flying is enabled. */
1177 if (!facing && player_isFlag(PLAYER_MFLY))
1178 facing = player_thinkMouseFly();
1179
1180 /* turning taken over by PLAYER_FACE */
1181 if (!facing && player_isFlag(PLAYER_FACE)) {
1182 /* Try to face pilot target. */
1183 if (player.p->target != PLAYER_ID) {
1184 target = pilot_getTarget( player.p );
1185 if (target != NULL) {
1186 pilot_face( pplayer,
1187 vec2_angle( &player.p->solid->pos, &target->solid->pos ));
1188
1189 /* Disable turning. */
1190 facing = 1;
1191 }
1192 }
1193 /* Try to face asteroid. */
1194 else if (player.p->nav_asteroid != -1) {
1195 AsteroidAnchor *field = &cur_system->asteroids[player.p->nav_anchor];
1196 Asteroid *ast = &field->asteroids[player.p->nav_asteroid];
1197 pilot_face( pplayer,
1198 vec2_angle( &player.p->solid->pos, &ast->pos ));
1199 /* Disable turning. */
1200 facing = 1;
1201 }
1202 /* If not try to face spob target. */
1203 else if ((player.p->nav_spob != -1) && ((preemption == 0) || (player.p->nav_hyperspace == -1))) {
1204 pilot_face( pplayer,
1205 vec2_angle( &player.p->solid->pos,
1206 &cur_system->spobs[ player.p->nav_spob ]->pos ));
1207 /* Disable turning. */
1208 facing = 1;
1209 }
1210 else if (player.p->nav_hyperspace != -1) {
1211 pilot_face( pplayer,
1212 vec2_angle( &player.p->solid->pos,
1213 &cur_system->jumps[ player.p->nav_hyperspace ].pos ));
1214 /* Disable turning. */
1215 facing = 1;
1216 }
1217 }
1218
1219 /* turning taken over by PLAYER_REVERSE */
1220 if (player_isFlag(PLAYER_REVERSE)) {
1221 /*
1222 * If the player has reverse thrusters, fire those.
1223 */
1224 if (!player.p->stats.misc_reverse_thrust && !facing) {
1225 pilot_face( pplayer, VANGLE(player.p->solid->vel) + M_PI );
1226 /* Disable turning. */
1227 facing = 1;
1228 }
1229 }
1230
1231 /* Normal turning scheme */
1232 if (!facing) {
1233 turn = 0;
1234 if (player_isFlag(PLAYER_TURN_LEFT))
1235 turn -= player_left;
1236 if (player_isFlag(PLAYER_TURN_RIGHT))
1237 turn += player_right;
1238 turn = CLAMP( -1., 1., turn );
1239 pilot_setTurn( pplayer, -turn );
1240 }
1241
1242 /*
1243 * Weapon shooting stuff
1244 */
1245 fired = 0;
1246
1247 /* Primary weapon. */
1248 if (player_isFlag(PLAYER_PRIMARY)) {
1249 fired |= pilot_shoot( pplayer, 0 );
1250 player_setFlag(PLAYER_PRIMARY_L);
1251 }
1252 else if (player_isFlag(PLAYER_PRIMARY_L)) {
1253 pilot_shootStop( pplayer, 0 );
1254 player_rmFlag(PLAYER_PRIMARY_L);
1255 }
1256 /* Secondary weapon - we use PLAYER_SECONDARY_L to track last frame. */
1257 if (player_isFlag(PLAYER_SECONDARY)) { /* needs target */
1258 fired |= pilot_shoot( pplayer, 1 );
1259 player_setFlag(PLAYER_SECONDARY_L);
1260 }
1261 else if (player_isFlag(PLAYER_SECONDARY_L)) {
1262 pilot_shootStop( pplayer, 1 );
1263 player_rmFlag(PLAYER_SECONDARY_L);
1264 }
1265
1266 if (fired) {
1269 }
1270
1271 acc = player_acc;
1272 /* Have to handle the case the player is doing reverse. This takes priority
1273 * over normal accel. */
1274 if (player_isFlag(PLAYER_REVERSE) && player.p->stats.misc_reverse_thrust
1275 && !pilot_isFlag(player.p, PILOT_HYP_PREP)
1276 && !pilot_isFlag(player.p, PILOT_HYPERSPACE) )
1277 acc = -PILOT_REVERSE_THRUST;
1278
1279 pilot_setThrust( pplayer, acc );
1280}
1281
1288void player_update( Pilot *pplayer, const double dt )
1289{
1290 /* Update normally. */
1291 pilot_update( pplayer, dt );
1292
1293 /* Update player.p specific stuff. */
1294 if (!player_isFlag(PLAYER_DESTROYED))
1295 player_updateSpecific( pplayer, dt );
1296}
1297
1304void player_updateSpecific( Pilot *pplayer, const double dt )
1305{
1306 int engsound;
1307 double pitch = 1.;
1308
1309 /* Calculate engine sound to use. */
1310 if (pilot_isFlag(pplayer, PILOT_AFTERBURNER))
1311 engsound = pplayer->afterburner->outfit->u.afb.sound;
1312 else if (pilot_isFlag(pplayer, PILOT_HYPERSPACE))
1313 engsound = snd_hypEng;
1314 else if (pplayer->engine_glow > 0.) {
1315 engsound = pplayer->ship->sound;
1316 pitch = pplayer->ship->engine_pitch;
1317 }
1318 else
1319 engsound = -1;
1320 if (engsound >= 0)
1322 /* See if sound must change. */
1323 if (player_lastEngineSound != engsound) {
1325 if (engsound >= 0) {
1327 sound_playGroup( player_engine_group, engsound, 0 );
1328 }
1329 }
1330 player_lastEngineSound = engsound;
1331
1332 /* Sound. */
1333 /*
1334 * Sound is now camera-specific and thus not player specific. A bit sad really.
1335 sound_updateListener( pplayer->solid->dir,
1336 pplayer->solid->pos.x, pplayer->solid->pos.y,
1337 pplayer->solid->vel.x, pplayer->solid->vel.y );
1338 */
1339
1340 /* See if must play hail sound. */
1341 if (player_hailCounter > 0) {
1342 player_hailTimer -= dt;
1343 if (player_hailTimer < 0.) {
1346 player_hailTimer = 3.;
1347 }
1348 }
1349
1350 /* Handle passive scanning of nearby asteroids. */
1351 /* TODO should probably handle player escorts in the future. */
1352 if (player.p->stats.asteroid_scan > 0.) {
1353 double range = player.p->stats.asteroid_scan;
1354 for (int i=0; i<array_size(cur_system->asteroids); i++) {
1355 double r2;
1356 AsteroidAnchor *ast = &cur_system->asteroids[i];
1357
1358 /* Field out of range. */
1359 if (vec2_dist2( &ast->pos, &player.p->solid->pos ) > pow2(range+ast->radius+ast->margin))
1360 continue;
1361
1362 r2 = pow2(range);
1363 for (int j=0; j<ast->nb; j++) {
1364 HookParam hparam[2];
1365 Asteroid *a = &ast->asteroids[j];
1366
1367 if (a->scanned) /* Ignore scanned outfits. */
1368 continue;
1369
1370 if (vec2_dist2( &a->pos, &player.p->solid->pos ) > r2)
1371 continue;
1372
1373 a->scanned = 1;
1374
1375 /* Run the hook. */
1376 hparam[0].type = HOOK_PARAM_ASTEROID;
1377 hparam[0].u.ast.parent = ast->id;
1378 hparam[0].u.ast.id = a->id;
1379 hparam[1].type = HOOK_PARAM_SENTINEL;
1380 hooks_runParamDeferred( "asteroid_scan", hparam );
1381 }
1382 }
1383 }
1384}
1385
1386/*
1387 * For use in keybindings
1388 */
1392void player_weapSetPress( int id, double value, int repeat )
1393{
1394 int type;
1395
1396 if (repeat || (player.p == NULL))
1397 return;
1398
1399 type = (value>=0) ? +1 : -1;
1400
1401 if (toolkit_isOpen() && (type>0 || pilot_weapSet(player.p,id)->type != WEAPSET_TYPE_WEAPON))
1402 return;
1403
1404 if ((type>0) && (pilot_isFlag(player.p, PILOT_HYP_PREP) ||
1405 pilot_isFlag(player.p, PILOT_HYPERSPACE) ||
1406 pilot_isFlag(player.p, PILOT_LANDING) ||
1407 pilot_isFlag(player.p, PILOT_TAKEOFF)))
1408 return;
1409
1410 pilot_weapSetPress( player.p, id, type );
1411}
1412
1417{
1418 double spd = player.speed * player_dt_default();
1419 pause_setSpeed( spd );
1420 sound_setSpeed( spd );
1421}
1422
1429void player_restoreControl( int reason, const char *str )
1430{
1431 if (player.p==NULL)
1432 return;
1433
1434 if (reason != PINPUT_AUTONAV) {
1435 /* Autonav should be harder to abort when paused. */
1436 if ((!paused || reason != PINPUT_MOVEMENT))
1438 }
1439
1440 if (reason != PINPUT_BRAKING) {
1441 pilot_rmFlag(player.p, PILOT_BRAKING);
1442 pilot_rmFlag(player.p, PILOT_COOLDOWN_BRAKE);
1443 if (pilot_isFlag(player.p, PILOT_COOLDOWN))
1445 }
1446}
1447
1454{
1455 int old;
1456
1457 /* Player must exist. */
1458 if (player.p == NULL)
1459 return;
1460
1461 if (id >= array_size(cur_system->spobs)) {
1462 WARN(_("Trying to set player's spob target to invalid ID '%d'"), id);
1463 return;
1464 }
1465
1466 if ((player.p == NULL) || pilot_isFlag( player.p, PILOT_LANDING ))
1467 return;
1468
1469 old = player.p->nav_spob;
1470 player.p->nav_spob = id;
1471 player_hyperspacePreempt((id < 0) ? 1 : 0);
1472 if (old != id) {
1473 player_rmFlag(PLAYER_LANDACK);
1474 if (id >= 0)
1476 }
1478 gui_setNav();
1479
1480 if ((player.autonav == AUTONAV_SPOB_LAND_APPROACH) ||
1481 (player.autonav == AUTONAV_SPOB_APPROACH) ||
1482 (player.autonav == AUTONAV_SPOB_LAND_BRAKE))
1483 player_autonavAbort(NULL);
1484}
1485
1492void player_targetAsteroidSet( int field, int id )
1493{
1494 int old;
1495
1496 if ((player.p == NULL) || pilot_isFlag( player.p, PILOT_LANDING ))
1497 return;
1498
1499 old = player.p->nav_asteroid;
1500 player.p->nav_asteroid = id;
1501 if (old != id) {
1502 if (id >= 0) {
1504 }
1505 }
1506
1507 player.p->nav_anchor = field;
1508
1509 /* Untarget pilot. */
1510 player.p->target = player.p->id;
1511}
1512
1517{
1518 int id;
1519
1520 /* Not under manual control. */
1521 if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ))
1522 return;
1523
1524 /* Find next spob target. */
1525 for (id=player.p->nav_spob+1; id<array_size(cur_system->spobs); id++)
1526 if (spob_isKnown( cur_system->spobs[id] ))
1527 break;
1528
1529 /* Try to select the lowest-indexed valid spob. */
1530 if (id >= array_size(cur_system->spobs) ) {
1531 id = -1;
1532 for (int i=0; i<array_size(cur_system->spobs); i++)
1533 if (spob_isKnown( cur_system->spobs[i] )) {
1534 id = i;
1535 break;
1536 }
1537 }
1538
1539 /* Untarget if out of range. */
1541}
1542
1549int player_land( int loud )
1550{
1551 Spob *spob;
1552 int silent = 0; /* Whether to suppress the land ack noise. */
1553
1554 if (landed) { /* player is already landed */
1555 takeoff( 1, 0 );
1556 return PLAYER_LAND_DENIED;
1557 }
1558
1559 /* Not under manual control or disabled. */
1560 if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ) ||
1561 pilot_isDisabled(player.p))
1562 return PLAYER_LAND_DENIED;
1563
1564 /* Already landing. */
1565 if ((pilot_isFlag( player.p, PILOT_LANDING) ||
1566 pilot_isFlag( player.p, PILOT_TAKEOFF)))
1567 return PLAYER_LAND_DENIED;
1568
1569 /* Check if there are spobs to land on. */
1570 if (array_size(cur_system->spobs) == 0) {
1571 player_message( "#r%s", _("There are no spobs to land on.") );
1572 return PLAYER_LAND_DENIED;
1573 }
1574
1575 /* Find new target. */
1576 if (player.p->nav_spob == -1) { /* get nearest spob target */
1577 double td = -1.; /* temporary distance */
1578 int tp = -1; /* temporary spob */
1579 for (int i=0; i<array_size(cur_system->spobs); i++) {
1580 spob = cur_system->spobs[i];
1581 double d = vec2_dist(&player.p->solid->pos,&spob->pos);
1582 if (pilot_inRangeSpob( player.p, i ) &&
1583 spob_hasService(spob,SPOB_SERVICE_LAND) &&
1584 ((tp==-1) || ((td == -1) || (td > d)))) {
1585 tp = i;
1586 td = d;
1587 }
1588 }
1591
1592 /* no landable spob */
1593 if (player.p->nav_spob < 0)
1594 return PLAYER_LAND_DENIED;
1595
1596 silent = 1; /* Suppress further targeting noises. */
1597 }
1598 /* Check if spob is in range when not uninhabited. */
1599 else if (!spob_isFlag(cur_system->spobs[ player.p->nav_spob ], SPOB_UNINHABITED) && !pilot_inRangeSpob( player.p, player.p->nav_spob )) {
1601 return PLAYER_LAND_AGAIN;
1602 }
1603
1604 if (player_isFlag(PLAYER_NOLAND)) {
1606 return PLAYER_LAND_DENIED;
1607 }
1608 else if (pilot_isFlag( player.p, PILOT_NOLAND)) {
1609 player_message( "#r%s", _("Docking stabilizers malfunctioning, cannot land.") );
1610 return PLAYER_LAND_DENIED;
1611 }
1612
1613 /* attempt to land at selected spob */
1614 spob = cur_system->spobs[player.p->nav_spob];
1615 spob_updateLand( spob ); /* Update if necessary. */
1616 if ((spob->lua_can_land==LUA_NOREF) && !spob_hasService(spob, SPOB_SERVICE_LAND)) {
1617 player_message( "#r%s", _("You can't land here.") );
1618 return PLAYER_LAND_DENIED;
1619 }
1620 else if ((spob->lua_can_land!=LUA_NOREF) && !spob->can_land) {
1621 if (spob->land_msg)
1622 player_message( _("#%c%s>#0 %s"), spob_getColourChar(spob),
1623 spob_name(spob), spob->land_msg );
1624 else
1625 player_message( "#r%s", _("You can't land here.") );
1626 return PLAYER_LAND_DENIED;
1627 }
1628 else if (!player_isFlag(PLAYER_LANDACK)) { /* no landing authorization */
1629 if (spob_hasService(spob,SPOB_SERVICE_INHABITED)) { /* Basic services */
1630 if (spob->can_land)
1631 player_message( _("#%c%s>#0 %s"), spob_getColourChar(spob),
1632 spob_name(spob), spob->land_msg );
1633 else if (spob->land_override > 0)
1634 player_message( _("#%c%s>#0 %s"), spob_getColourChar(spob),
1635 spob_name(spob), _("Landing authorized.") );
1636 else { /* Hostile */
1637 player_message( _("#%c%s>#0 %s"), spob_getColourChar(spob),
1638 spob_name(spob), spob->land_msg );
1639 return PLAYER_LAND_DENIED;
1640 }
1641 }
1642 else /* No shoes, no shirt, no lifeforms, no service. */
1643 player_message( _("#oReady to land on %s."), spob_name(spob) );
1644
1645 player_setFlag(PLAYER_LANDACK);
1646 if (!silent)
1648
1649 return player_land(loud);
1650 }
1651 else if (vec2_dist2(&player.p->solid->pos,&spob->pos) > pow2(spob->radius)) {
1652 if (loud)
1653 player_message(_("#rYou are too far away to land on %s."), spob_name(spob));
1654 return PLAYER_LAND_AGAIN;
1655 }
1656 else if (vec2_odist2( &player.p->solid->vel ) > pow2(MAX_HYPERSPACE_VEL)) {
1657 if (loud)
1658 player_message(_("#rYou are going too fast to land on %s."), spob_name(spob));
1659 return PLAYER_LAND_AGAIN;
1660 }
1661
1662 /* End autonav. */
1664
1665 /* Stop afterburning. */
1667 /* Stop accelerating. */
1669 /* Stop stealth. */
1671
1672 /* Stop all on outfits. */
1673 if (pilot_outfitOffAll( player.p ) > 0)
1675
1676 /* Do whatever the spob wants to do. */
1677 if (spob->lua_land != LUA_NOREF) {
1678 lua_rawgeti(naevL, LUA_REGISTRYINDEX, spob->lua_land); /* f */
1679 lua_pushspob( naevL, spob_index(spob) );
1680 lua_pushpilot( naevL, player.p->id );
1681 if (nlua_pcall( spob->lua_env, 2, 0 )) {
1682 WARN(_("Spob '%s' failed to run '%s':\n%s"), spob->name, "land", lua_tostring(naevL,-1));
1683 lua_pop(naevL,1);
1684 }
1685
1686 return PLAYER_LAND_OK;
1687 }
1688
1689 /* Start landing. */
1691 player.p->landing_delay = PILOT_LANDING_DELAY * player_dt_default();
1693 pilot_setFlag( player.p, PILOT_LANDING );
1694 pilot_setThrust( player.p, 0. );
1695 pilot_setTurn( player.p, 0. );
1696
1697 return PLAYER_LAND_OK;
1698}
1699
1704{
1705 Spob *p;
1706
1707 /* No authorization to revoke. */
1708 if ((player.p == NULL) || !player_isFlag(PLAYER_LANDACK))
1709 return;
1710
1711 /* Avoid a potential crash if PLAYER_LANDACK is set inappropriately. */
1712 if (player.p->nav_spob < 0) {
1713 WARN(_("Player has landing permission, but no valid spob targeted."));
1714 return;
1715 }
1716
1717 p = cur_system->spobs[ player.p->nav_spob ];
1718
1719 /* Player can still land. */
1720 if (p->can_land || (p->land_override > 0))
1721 return;
1722
1723 player_rmFlag(PLAYER_LANDACK);
1724 player_message( _("#%c%s>#0 Landing permission revoked."),
1726}
1727
1733void player_nolandMsg( const char *str )
1734{
1736
1737 /* Duplicate so that Lua memory which might be garbage-collected isn't relied on. */
1738 if (str != NULL)
1739 player_message_noland = strdup(str);
1740 else
1741 player_message_noland = strdup(_("You are not allowed to land at this moment."));
1742}
1743
1746void player_board (void)
1747{
1748 /* Not under manual control or disabled. */
1749 if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ) ||
1750 pilot_isDisabled(player.p))
1751 return;
1752
1753 /* Try to grab target if not available. */
1754 if (player.p->target==PLAYER_ID) {
1755 Pilot *p;
1756 /* We don't try to find far away targets, only nearest and see if it matches.
1757 * However, perhaps looking for first boardable target within a certain range
1758 * could be more interesting. */
1760 p = pilot_getTarget( player.p );
1761 if ((!pilot_isDisabled(p) && !pilot_isFlag(p,PILOT_BOARDABLE)) ||
1762 pilot_isFlag(p,PILOT_NOBOARD)) {
1764 player_message( "#r%s", _("You need a target to board first!") );
1765 return;
1766 }
1767 }
1768
1770}
1771
1778void player_targetHyperspaceSet( int id, int nomsg )
1779{
1780 int old;
1781
1782 /* Player must exist. */
1783 if (player.p == NULL)
1784 return;
1785
1786 if (id >= array_size(cur_system->jumps)) {
1787 WARN(_("Trying to set player's hyperspace target to invalid ID '%d'"), id);
1788 return;
1789 }
1790
1791 if (pilot_isFlag(player.p, PILOT_HYP_PREP) ||
1792 pilot_isFlag(player.p, PILOT_HYP_BEGIN) ||
1793 pilot_isFlag(player.p, PILOT_HYPERSPACE))
1794 return;
1795
1796 old = player.p->nav_hyperspace;
1797 player.p->nav_hyperspace = id;
1798 player_hyperspacePreempt((id < 0) ? 0 : 1);
1799 if ((old != id) && (id >= 0))
1801 gui_setNav();
1802
1803 if (!nomsg && (old != id) && ((player.autonav == AUTONAV_JUMP_APPROACH) ||
1804 (player.autonav == AUTONAV_JUMP_BRAKE)))
1805 player_autonavAbort(NULL);
1806
1807 hooks_run( "target_hyperspace" );
1808}
1809
1814{
1815 int id;
1816
1817 /* Not under manual control. */
1818 if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ))
1819 return;
1820
1821 map_clear(); /* clear the current map path */
1822
1823 for (id=player.p->nav_hyperspace+1; id<array_size(cur_system->jumps); id++)
1824 if (jp_isKnown( &cur_system->jumps[id]))
1825 break;
1826
1827 /* Try to find the lowest-indexed valid jump. */
1828 if (id >= array_size(cur_system->jumps)) {
1829 id = -1;
1830 for (int i=0; i<array_size(cur_system->jumps); i++)
1831 if (jp_isUsable( &cur_system->jumps[i])) {
1832 id = i;
1833 break;
1834 }
1835 }
1836
1838
1839 /* Map gets special treatment if open. */
1840 if (id == -1)
1841 map_select( NULL , 0);
1842 else
1843 map_select( cur_system->jumps[ id ].target, 0 );
1844}
1845
1851void player_hyperspacePreempt( int preempt )
1852{
1853 preemption = preempt;
1854}
1855
1862{
1863 return preemption;
1864}
1865
1872{
1873 if (player.p != NULL && player.p->ship != NULL)
1875 return 1.;
1876}
1877
1882{
1883 char buf[128];
1884
1886
1887 input_getKeybindDisplay( "autohail", buf, sizeof(buf) );
1888 player_message( _("#rReceiving hail! Press #b%s#0 to respond."), buf );
1889
1890 /* Reset speed. */
1893}
1894
1900int player_jump (void)
1901{
1902 int h;
1903 double mindist;
1904
1905 /* Must have a jump target and not be already jumping. */
1906 if (pilot_isFlag(player.p, PILOT_HYPERSPACE))
1907 return 0;
1908
1909 /* Not under manual control or disabled. */
1910 if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ) ||
1911 pilot_isDisabled(player.p))
1912 return 0;
1913
1914 /* Select nearest jump if not target. */
1915 if (player.p->nav_hyperspace == -1) {
1916 int j = -1;
1917 mindist = INFINITY;
1918 for (int i=0; i<array_size(cur_system->jumps); i++) {
1919 double dist = vec2_dist2( &player.p->solid->pos, &cur_system->jumps[i].pos );
1920 if (dist < mindist && jp_isUsable(&cur_system->jumps[i])) {
1921 mindist = dist;
1922 j = i;
1923 }
1924 }
1925 if (j < 0)
1926 return 0;
1927
1928 player.p->nav_hyperspace = j;
1930 map_select( cur_system->jumps[player.p->nav_hyperspace].target, 0 );
1931 gui_setNav();
1932
1933 /* Only follow through if within range. */
1934 if (mindist > pow2( cur_system->jumps[j].radius ))
1935 return 0;
1936 }
1937
1938 /* Already jumping, so we break jump. */
1939 if (pilot_isFlag(player.p, PILOT_HYP_PREP)) {
1941 player_message( "#r%s", _("Aborting hyperspace sequence."));
1942 return 0;
1943 }
1944
1945 /* Try to hyperspace. */
1947 if (h == -1) {
1950 //player_message( "#r%s", _("You are too far from a jump point to initiate hyperspace."));
1951 }
1952 else if (h == -2)
1953 player_message( "#r%s", _("Hyperspace drive is offline."));
1954 else if (h == -3)
1955 player_message( "#r%s", _("You do not have enough fuel to hyperspace jump."));
1956 else {
1957 player_message( "#o%s", _("Preparing for hyperspace."));
1958 /* Stop acceleration noise. */
1960 /* Stop possible shooting. */
1961 pilot_shootStop( player.p, 0 );
1962 pilot_shootStop( player.p, 1 );
1963
1964 /* Order escorts to jump; just for aesthetics (for now) */
1966
1967 return 1;
1968 }
1969
1970 return 0;
1971}
1972
1977{
1978 ntime_t t;
1979 StarSystem *sys, *destsys;
1980 JumpPoint *jp;
1981 Pilot *const* pilot_stack;
1982 int map_npath;
1983
1984 /* First run jump hook. */
1985 hooks_run( "jumpout" );
1986
1987 /* Prevent targeted spob # from carrying over. */
1988 gui_setNav();
1989 gui_setTarget();
1991 player_targetAsteroidSet( -1, -1 );
1992
1993 /* calculates the time it takes, call before space_init */
1995 ntime_inc( t );
1996
1997 /* Save old system. */
1998 sys = cur_system;
1999
2000 /* Free old graphics. */
2001 space_gfxUnload( sys );
2002
2003 /* enter the new system */
2004 jp = &cur_system->jumps[player.p->nav_hyperspace];
2005 space_init( jp->target->name, 1 );
2006
2007 /* Set up the overlay. */
2008 ovr_initAlpha();
2009
2010 /* set position, the pilot_update will handle lowering vel */
2013
2014 /* reduce fuel */
2016
2017 /* Set the ptimer. */
2018 player.p->ptimer = HYPERSPACE_FADEIN;
2019
2020 /* Update the map, we have to remove the player flags first or it breaks down. */
2021 pilot_rmFlag( player.p, PILOT_HYPERSPACE );
2022 pilot_rmFlag( player.p, PILOT_HYP_BEGIN );
2023 pilot_rmFlag( player.p, PILOT_HYP_BRAKE );
2024 pilot_rmFlag( player.p, PILOT_HYP_PREP );
2025 map_jump();
2026
2027 /* Add persisted pilots */
2029 for (int i=0; i<array_size(pilot_stack); i++) {
2030 Pilot *p = pilot_stack[i];
2031
2032 if (pilot_isFlag(p, PILOT_PERSIST) || pilot_isFlag(p, PILOT_PLAYER)) {
2033 if (p != player.p)
2034 space_calcJumpInPos( cur_system, sys, &p->solid->pos, &p->solid->vel, &p->solid->dir, player.p );
2035
2036 /* Run Lua stuff for all persistant pilots. */
2039
2040 /* Invulnerable delay too. */
2041 p->itimer = PILOT_PLAYER_NONTARGETABLE_JUMPIN_DELAY;
2042 pilot_setFlag( p, PILOT_NONTARGETABLE );
2043
2044 /* Clear flags as necessary. */
2045 pilot_rmFlag( p, PILOT_HYPERSPACE );
2046 pilot_rmFlag( p, PILOT_HYP_BEGIN );
2047 pilot_rmFlag( p, PILOT_HYP_BRAKE );
2048 pilot_rmFlag( p, PILOT_HYP_PREP );
2049 }
2050 }
2051
2052 /* Disable autonavigation if arrived. */
2053 if (player_isFlag(PLAYER_AUTONAV)) {
2054 if (player.p->nav_hyperspace == -1) {
2055 player_message( _("#oAutonav arrived at the %s system."), _(cur_system->name) );
2057 }
2058 else {
2059 destsys = map_getDestination( &map_npath );
2060 player_message( n_(
2061 "#oAutonav continuing until %s (%d jump left).",
2062 "#oAutonav continuing until %s (%d jumps left).",
2063 map_npath),
2064 (sys_isKnown(destsys) ? _(destsys->name) : _("Unknown")),
2065 map_npath );
2066 }
2067 }
2068
2069 /* Safe since this is run in the player hook section. */
2070 hooks_run( "jumpin" );
2071 hooks_run( "enter" );
2072 events_trigger( EVENT_TRIGGER_ENTER );
2073 missions_run( MIS_AVAIL_ENTER, -1, NULL, NULL );
2074
2075 /* Player sound. */
2077
2078 /* Increment times jumped. */
2081}
2082
2088void player_accel( double acc )
2089{
2090 if ((player.p == NULL) || pilot_isFlag(player.p, PILOT_HYP_PREP) ||
2091 pilot_isFlag(player.p, PILOT_HYPERSPACE))
2092 return;
2093
2094 player_acc = acc;
2095 if (toolkit_isOpen() || paused)
2097}
2098
2103{
2104 player_acc = 0.;
2105}
2106
2112void player_targetSet( unsigned int id )
2113{
2114 unsigned int old;
2115 old = player.p->target;
2116 pilot_setTarget( player.p, id );
2117 if ((old != id) && (player.p->target != PLAYER_ID)) {
2120 }
2121 gui_setTarget();
2122
2123 /* Clear the asteroid target. */
2124 player.p->nav_asteroid = -1;
2125 player.p->nav_anchor = -1;
2126
2127 /* The player should not continue following if the target pilot has been changed. */
2128 if ((old != id) && player_isFlag(PLAYER_AUTONAV) &&
2129 (player.autonav == AUTONAV_PLT_FOLLOW ||
2130 player.autonav == AUTONAV_PLT_BOARD_APPROACH ||
2131 player.autonav == AUTONAV_PLT_BOARD_BRAKE))
2132 player_autonavAbort(NULL);
2133}
2134
2142{
2143 unsigned int tp;
2144 double d, td;
2145 Pilot *const* pilot_stack;
2146
2147 tp = PLAYER_ID;
2148 d = 0;
2150 for (int i=0; i<array_size(pilot_stack); i++) {
2151 /* Shouldn't be disabled. */
2152 if (pilot_isDisabled(pilot_stack[i]))
2153 continue;
2154
2155 /* Must be a valid target. */
2156 if (!pilot_canTarget( pilot_stack[i] ))
2157 continue;
2158
2159 /* Must be hostile. */
2161 continue;
2162
2163 if (pilot_inRangePilot(player.p, pilot_stack[i], &td) != 1 )
2164 continue;
2165
2166 if (tp == PLAYER_ID || ((td < d))) {
2167 d = td;
2168 tp = pilot_stack[i]->id;
2169 }
2170 }
2171
2172 player_targetSet( tp );
2173}
2174
2180void player_targetNext( int mode )
2181{
2183}
2184
2190void player_targetPrev( int mode )
2191{
2193}
2194
2199{
2201 if (player.p->target != PLAYER_ID)
2202 player_targetSet( PLAYER_ID );
2203 else if (player.p->nav_asteroid >= 0)
2204 player_targetAsteroidSet( -1, -1 );
2205 else if (player.p->nav_spob >= 0)
2207 else if ((preemption == 1 || player.p->nav_spob == -1) &&
2208 !pilot_isFlag(player.p, PILOT_HYP_PREP)) {
2209 player.p->nav_hyperspace = -1;
2211 map_clear();
2212 }
2213 gui_setNav();
2214}
2215
2220{
2223 player_targetAsteroidSet( -1, -1 );
2224 player_targetSet( PLAYER_ID );
2225}
2226
2232void player_targetEscort( int prev )
2233{
2234 int i;
2235 /* Check if current target is an escort. */
2236 for (i=0; i<array_size(player.p->escorts); i++) {
2237 if (player.p->target == player.p->escorts[i].id) {
2238
2239 /* Cycle targets. */
2240 if (prev)
2241 pilot_setTarget( player.p, (i > 0) ?
2242 player.p->escorts[i-1].id : player.p->id );
2243 else
2245 player.p->escorts[i+1].id : player.p->id );
2246
2247 break;
2248 }
2249 }
2250
2251 /* Not found in loop. */
2252 if (i >= array_size(player.p->escorts)) {
2253 /* Check to see if he actually has escorts. */
2254 if (array_size(player.p->escorts) > 0) {
2255 /* Cycle forward or backwards. */
2256 if (prev)
2258 else
2260 }
2261 else
2263 }
2264
2265 if (player.p->target != PLAYER_ID) {
2268 }
2269 gui_setTarget();
2270}
2271
2276{
2277 unsigned int t, dt;
2278 double d;
2279
2281 player.p->solid->pos.y, 1 );
2282 t = dt;
2283
2284 /* Disabled ships are typically only valid if within 500 px of the player. */
2285 if ((d > pow2(500.)) && (pilot_isDisabled( pilot_get(dt) ))) {
2287 /* Try to target a disabled ship if there are no active ships in range. */
2288 if (t == PLAYER_ID)
2289 t = dt;
2290 }
2291
2292 player_targetSet( t );
2293}
2294
2295static int screenshot_cur = 0;
2300{
2301 char filename[PATH_MAX];
2302
2303 if (PHYSFS_mkdir("screenshots") == 0) {
2304 WARN(_("Aborting screenshot"));
2305 return;
2306 }
2307
2308 /* Try to find current screenshots. */
2309 for ( ; screenshot_cur < 1000; screenshot_cur++) {
2310 snprintf( filename, sizeof(filename), "screenshots/screenshot%03d.png", screenshot_cur );
2311 if (!PHYSFS_exists( filename ))
2312 break;
2313 }
2314
2315 if (screenshot_cur >= 999) { /* in case the crap system breaks :) */
2316 WARN(_("You have reached the maximum amount of screenshots [999]"));
2317 return;
2318 }
2319
2320 /* now proceed to take the screenshot */
2321 DEBUG( _("Taking screenshot [%03d]..."), screenshot_cur );
2322 gl_screenshot( filename );
2323}
2324
2329static void player_checkHail (void)
2330{
2331 Pilot *const* pilot_stack = pilot_getAll();
2332 for (int i=0; i<array_size(pilot_stack); i++) {
2333 Pilot *p = pilot_stack[i];
2334
2335 /* Must be hailing. */
2336 if (pilot_isFlag(p, PILOT_HAILING))
2337 return;
2338 }
2339
2340 /* Clear hail timer. */
2342 player_hailTimer = 0.;
2343}
2344
2349{
2350 Spob *spob = cur_system->spobs[player.p->nav_spob];
2351 const char *name = spob_name(spob);
2352 player_message( _("#r%s is out of comm range, unable to contact."), name );
2353}
2354
2358void player_hail (void)
2359{
2360 /* Not under manual control or disabled. */
2361 if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ) ||
2362 pilot_isDisabled(player.p))
2363 return;
2364
2365 if (player.p->target != player.p->id)
2367 else if (player.p->nav_spob != -1) {
2368 Spob *spob = cur_system->spobs[ player.p->nav_spob ];
2369 if (spob_isFlag(spob, SPOB_UNINHABITED))
2370 player_message( _("#r%s does not respond."), spob_name(spob) );
2371 else if (pilot_inRangeSpob( player.p, player.p->nav_spob ))
2372 comm_openSpob( spob );
2373 else
2375 }
2376 else
2377 player_message( "#r%s", _("No target selected to hail.") );
2378
2379 /* Clear hails if none found. */
2381}
2382
2387{
2388 /* Not under manual control. */
2389 if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ))
2390 return;
2391
2392 if (player.p->nav_spob != -1) {
2395 else
2397 }
2398 else
2399 player_message( "#r%s", _("No target selected to hail.") );
2400}
2401
2406{
2407 Pilot *const* pilot_stack;
2408
2409 /* Not under manual control or disabled. */
2410 if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ) ||
2411 pilot_isDisabled(player.p))
2412 return;
2413
2414 /* Find pilot to autohail. */
2416 for (int i=0; i<array_size(pilot_stack); i++) {
2417 Pilot *p = pilot_stack[i];
2418
2419 /* Must be hailing. */
2420 if (pilot_isFlag(p, PILOT_HAILING)) {
2421 /* Try to hail. */
2422 pilot_setTarget( player.p, p->id );
2423 gui_setTarget();
2424 player_hail();
2425
2426 /* Clear hails if none found. */
2428 return;
2429 }
2430 }
2431
2432 player_message( "#r%s", _("You haven't been hailed by any pilots.") );
2433}
2434
2439{
2440 if (!conf.mouse_fly)
2441 return;
2442
2443 if (!player_isFlag(PLAYER_MFLY)) {
2445 player_message( "#o%s", _("Mouse flying enabled.") );
2446 player_setFlag(PLAYER_MFLY);
2447 }
2448 else {
2450 player_rmFlag(PLAYER_MFLY);
2451 player_message( "#o%s", _("Mouse flying disabled.") );
2452
2453 if (conf.mouse_thrust)
2455 }
2456}
2457
2462{
2463 int stopped;
2464
2465 if (pilot_isFlag(player.p, PILOT_TAKEOFF))
2466 return;
2467
2468 /* Not under manual control or disabled. */
2469 if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ) ||
2470 pilot_isDisabled(player.p))
2471 return;
2472
2473 stopped = pilot_isStopped(player.p);
2474 if (stopped && !pilot_isFlag(player.p, PILOT_COOLDOWN))
2476 else {
2477 pilot_setFlag(player.p, PILOT_BRAKING);
2478 pilot_setFlag(player.p, PILOT_COOLDOWN_BRAKE);
2479 }
2480}
2481
2487static int player_thinkMouseFly (void)
2488{
2489 double px, py, r, x, y;
2490
2491 px = player.p->solid->pos.x;
2492 py = player.p->solid->pos.y;
2494 r = sqrt(pow2(x-px) + pow2(y-py));
2495 if (r > 50.) { /* Ignore mouse input within a 50 px radius of the centre. */
2496 pilot_face(player.p, atan2( y - py, x - px));
2497 if (conf.mouse_thrust) { /* Only alter thrust if option is enabled. */
2498 double acc = CLAMP(0., 1., (r - 100.) / 200.);
2499 acc = 3. * pow2(acc) - 2. * pow(acc, 3.);
2500 /* Only accelerate when within 180 degrees of the intended direction. */
2501 if (ABS(angle_diff(atan2( y - py, x - px), player.p->solid->dir)) < M_PI_2 )
2502 player_accel(acc);
2503 else
2504 player_accel(0.);
2505 }
2506 return 1;
2507 }
2508 else
2509 return 0;
2510}
2511
2515void player_dead (void)
2516{
2517 /* Explode at normal speed. */
2518 pause_setSpeed(1.);
2519 sound_setSpeed(1.);
2520
2521 /* Close the overlay. */
2522 ovr_setOpen(0);
2523}
2524
2529{
2530 if (player_isFlag(PLAYER_DESTROYED))
2531 return;
2532
2533 /* Mark as destroyed. */
2534 player_setFlag(PLAYER_DESTROYED);
2535
2536 /* Set timer for death menu. */
2537 player_timer = 5.;
2538
2539 /* Stop sounds. */
2541
2542 /* Stop autonav */
2544
2545 /* Reset time compression when player dies. */
2546 pause_setSpeed(1.);
2547 sound_setSpeed(1.);
2548}
2549
2553static int player_shipsCompare( const void *arg1, const void *arg2 )
2554{
2555 PlayerShip_t *ps1, *ps2;
2556 credits_t p1, p2;
2557
2558 /* Get the arguments. */
2559 ps1 = (PlayerShip_t*) arg1;
2560 ps2 = (PlayerShip_t*) arg2;
2561
2562 if (ps1->favourite && !ps2->favourite)
2563 return -1;
2564 else if (ps2->favourite && !ps1->favourite)
2565 return +1;
2566
2567 if (ps1->deployed && !ps2->deployed)
2568 return -1;
2569 else if (ps2->deployed && !ps1->deployed)
2570 return +1;
2571
2572 /* Get prices. */
2573 p1 = pilot_worth( ps1->p );
2574 p2 = pilot_worth( ps2->p );
2575
2576 /* Compare price INVERSELY */
2577 if (p1 < p2)
2578 return +1;
2579 else if (p1 > p2)
2580 return -1;
2581
2582 /* In case of tie sort by name so they don't flip or something. */
2583 return strcmp( ps1->p->name, ps2->p->name );
2584}
2585
2590{
2591 if (array_size(player_stack) == 0)
2592 return;
2593
2594 /* Sort. */
2596}
2597
2606int player_ships( char** sships, glTexture** tships )
2607{
2608 /* Sort. */
2610
2611 /* Create the struct. */
2612 for (int i=0; i < array_size(player_stack); i++) {
2613 sships[i] = strdup(player_stack[i].p->name);
2614 tships[i] = player_stack[i].p->ship->gfx_store;
2615 }
2616
2617 return array_size(player_stack);
2618}
2619
2624{
2625 return player_stack;
2626}
2627
2634{
2635 return array_size(player_stack);
2636}
2637
2644int player_hasShip( const char *shipname )
2645{
2646 /* Check current ship. */
2647 if ((player.p != NULL) && (strcmp(player.p->name,shipname)==0))
2648 return 1;
2649
2650 /* Check stocked ships. */
2651 for (int i=0; i < array_size(player_stack); i++)
2652 if (strcmp(player_stack[i].p->name, shipname)==0)
2653 return 1;
2654 return 0;
2655}
2656
2663Pilot *player_getShip( const char *shipname )
2664{
2665 if ((player.p != NULL) && (strcmp(shipname,player.p->name)==0))
2666 return player.p;
2667
2668 for (int i=0; i < array_size(player_stack); i++)
2669 if (strcmp(player_stack[i].p->name, shipname)==0)
2670 return player_stack[i].p;
2671
2672 WARN(_("Player ship '%s' not found in stack"), shipname);
2673 return NULL;
2674}
2675
2682PlayerShip_t *player_getPlayerShip( const char *shipname )
2683{
2684 if ((player.p != NULL) && (strcmp(shipname,player.p->name)==0))
2685 return NULL;
2686
2687 for (int i=0; i < array_size(player_stack); i++)
2688 if (strcmp(player_stack[i].p->name, shipname)==0)
2689 return &player_stack[i];
2690
2691 WARN(_("Player ship '%s' not found in stack"), shipname);
2692 return NULL;
2693}
2694
2702{
2703 /* Special case map. */
2704 if ((outfit_isMap(o) && map_isUseless(o)) ||
2705 (outfit_isLocalMap(o) && localmap_isUseless(o)))
2706 return 1;
2707
2708 /* Special case license. */
2709 if (outfit_isLicense(o) &&
2711 return 1;
2712
2713 /* Special case GUI. */
2714 if (outfit_isGUI(o) &&
2716 return 1;
2717
2718 /* Try to find it. */
2719 for (int i=0; i<array_size(player_outfits); i++)
2720 if (player_outfits[i].o == o)
2721 return player_outfits[i].q;
2722
2723 return 0;
2724}
2725
2730{
2731 int q = player_outfitOwned(o);
2732 q += pilot_numOutfit( player.p, o );
2733 for (int i=0; i<array_size(player_stack); i++)
2734 q += pilot_numOutfit( player_stack[i].p, o );
2735
2736 return q;
2737}
2738
2742static int player_outfitCompare( const void *arg1, const void *arg2 )
2743{
2744 PlayerOutfit_t *po1, *po2;
2745
2746 /* Get type. */
2747 po1 = (PlayerOutfit_t*) arg1;
2748 po2 = (PlayerOutfit_t*) arg2;
2749
2750 /* Compare. */
2751 return outfit_compareTech( &po1->o, &po2->o );
2752}
2753
2758{
2759 return player_outfits;
2760}
2761
2771 int(*filter)( const Outfit *o ), const char *name )
2772{
2773 if (array_size(player_outfits) == 0)
2774 return 0;
2775
2776 /* We'll sort. */
2779
2780 for (int i=0; i<array_size(player_outfits); i++)
2781 outfits[i] = (Outfit*)player_outfits[i].o;
2782
2783 return outfits_filter( outfits, array_size(player_outfits), filter, name );
2784}
2785
2792{
2793 return array_size(player_outfits);
2794}
2795
2803int player_addOutfit( const Outfit *o, int quantity )
2804{
2805 PlayerOutfit_t *po;
2806
2807 /* Validity check. */
2808 if (quantity == 0)
2809 return 0;
2810
2811 /* Don't readd uniques. */
2812 if (outfit_isProp(o,OUTFIT_PROP_UNIQUE) && (player_outfitOwned(o)>0))
2813 return 0;
2814
2815 /* special case if it's a map */
2816 if (outfit_isMap(o)) {
2817 map_map(o);
2818 return 1; /* Success. */
2819 }
2820 else if (outfit_isLocalMap(o)) {
2821 localmap_map(o);
2822 return 1;
2823 }
2824 /* special case if it's an outfit */
2825 else if (outfit_isGUI(o)) {
2826 player_guiAdd(o->u.gui.gui);
2827 return 1; /* Success. */
2828 }
2829 /* special case if it's a license. */
2830 else if (outfit_isLicense(o)) {
2832 return 1; /* Success. */
2833 }
2834
2835 /* Try to find it. */
2836 for (int i=0; i<array_size(player_outfits); i++) {
2837 if (player_outfits[i].o == o) {
2838 player_outfits[i].q += quantity;
2839 return quantity;
2840 }
2841 }
2842
2843 /* Allocate if needed. */
2844 po = &array_grow( &player_outfits );
2845
2846 /* Add the outfit. */
2847 po->o = o;
2848 po->q = quantity;
2849 return quantity;
2850}
2851
2859int player_rmOutfit( const Outfit *o, int quantity )
2860{
2861 /* Try to find it. */
2862 for (int i=0; i<array_size(player_outfits); i++) {
2863 if (player_outfits[i].o != o)
2864 continue;
2865 /* See how many to remove. */
2866 int q = MIN( player_outfits[i].q, quantity );
2867 player_outfits[i].q -= q;
2868
2869 /* See if must remove element. */
2870 if (player_outfits[i].q <= 0)
2872
2873 /* Return removed outfits. */
2874 return q;
2875 }
2876
2877 /* Nothing removed. */
2878 return 0;
2879}
2880
2881/*
2882 * Trivial sorting function for arrays of integers.
2883 */
2884static int cmp_int( const void *p1, const void *p2 )
2885{
2886 const int *i1 = (const int*) p1;
2887 const int *i2 = (const int*) p2;
2888 return (*i1) - (*i2);
2889}
2890
2897{
2898 HookParam h[2];
2899 const MissionData *m;
2900
2901 /* Make sure not already marked. */
2903 return;
2904
2905 /* Mark as done. */
2906 if (missions_done == NULL)
2907 missions_done = array_create( int );
2909
2910 qsort( missions_done, array_size(missions_done), sizeof(int), cmp_int );
2911
2912 /* Run the completion hook. */
2913 m = mission_get( id );
2914 mission_toLuaTable( naevL, m ); /* Push to stack. */
2915 h[0].type = HOOK_PARAM_REF;
2916 h[0].u.ref = luaL_ref( naevL, LUA_REGISTRYINDEX ); /* Pops from stack. */
2917 h[1].type = HOOK_PARAM_SENTINEL;
2918 hooks_runParam( "mission_done", h );
2919}
2920
2928{
2929 if (missions_done == NULL)
2930 return 0;
2931
2932 const int *i = bsearch( &id, missions_done, array_size(missions_done), sizeof(int), cmp_int );
2933 return i!=NULL;
2934}
2935
2942{
2943 return missions_done;
2944}
2945
2952{
2953 /* Make sure not already done. */
2955 return;
2956
2957 /* Mark as done. */
2958 if (events_done == NULL)
2959 events_done = array_create( int );
2961
2962 qsort( events_done, array_size(events_done), sizeof(int), cmp_int );
2963}
2964
2972{
2973 if (events_done == NULL)
2974 return 0;
2975
2976 const int *i = bsearch( &id, events_done, array_size(events_done), sizeof(int), cmp_int );
2977 return i!=NULL;
2978}
2979
2986{
2987 return events_done;
2988}
2989
2996int player_hasLicense( const char *license )
2997{
2998 if (license == NULL)
2999 return 1;
3000 if (player_licenses == NULL)
3001 return 0;
3002
3003 const char *s = bsearch( &license, player_licenses, array_size(player_licenses), sizeof(char*), strsort );
3004 return s!=NULL;
3005}
3006
3012void player_addLicense( const char *license )
3013{
3014 if (player_hasLicense(license))
3015 return;
3016 if (player_licenses == NULL)
3017 player_licenses = array_create( char* );
3018 array_push_back( &player_licenses, strdup(license) );
3019
3020 qsort( player_licenses, array_size(player_licenses), sizeof(char*), strsort );
3021}
3022
3026const char **player_getLicenses ()
3027{
3028 return (const char**) player_licenses;
3029}
3030
3035{
3036 if (player_isFlag( PLAYER_HOOK_HYPER )) {
3038 player_rmFlag( PLAYER_HOOK_HYPER );
3039 }
3040 if (player_isFlag( PLAYER_HOOK_JUMPIN)) {
3042 hooks_run( "jumpin" );
3043 hooks_run( "enter" );
3044 events_trigger( EVENT_TRIGGER_ENTER );
3045 missions_run( MIS_AVAIL_ENTER, -1, NULL, NULL );
3046 player_rmFlag( PLAYER_HOOK_JUMPIN );
3047 }
3048 if (player_isFlag( PLAYER_HOOK_LAND )) {
3049 if (player.p->nav_spob >= 0)
3050 land( cur_system->spobs[ player.p->nav_spob ], 0 );
3051 player_rmFlag( PLAYER_HOOK_LAND );
3052 }
3053}
3054
3058static void player_clearEscorts (void)
3059{
3060 for (int i=0; i<array_size(player.p->outfits); i++) {
3061 if (player.p->outfits[i]->outfit == NULL)
3062 continue;
3063
3065 player.p->outfits[i]->u.ammo.deployed = 0;
3066 }
3067}
3068
3075{
3076 /* Clear escorts first. */
3078
3079 /* Go over escorts. */
3080 for (int i=0; i<array_size(player.p->escorts); i++) {
3081 int q;
3082 PilotOutfitSlot *po;
3083 Escort_t *e = &player.p->escorts[i];
3084 Pilot *pe = pilot_get( e->id );
3085
3086 /* Non-persistent pilots should have been wiped already. */
3087 if (pe == NULL) {
3089 i--;
3090 continue;
3091 }
3092
3093 /* Update to random position. */
3094 pe->solid->dir = RNGF() * 2. * M_PI;
3095 vec2_cset( &pe->solid->pos, player.p->solid->pos.x + 50.*cos(pe->solid->dir),
3096 player.p->solid->pos.y + 50.*sin(pe->solid->dir) );
3097 vec2_cset( &pe->solid->vel, 0., 0. );
3098
3099 /* Update outfit if needed. */
3100 if (e->type != ESCORT_TYPE_BAY)
3101 continue;
3102
3103 po = pilot_getDockSlot( pe );
3104 if (po == NULL) {
3105 /* We just want to delete the pilot and not trigger other stuff. */
3106 pilot_setFlag( pe, PILOT_DELETE );
3107 WARN(_("Escort is undeployed, removing."));
3109 i--;
3110 continue;
3111 }
3112
3113 po->u.ammo.deployed++;
3114 q = po->u.ammo.deployed + po->u.ammo.quantity;
3115 if (q > pilot_maxAmmoO(player.p,po->outfit)) {
3116 /* We just want to delete the pilot and not trigger other stuff. */
3117 pilot_setFlag( pe, PILOT_DELETE );
3118 WARN(_("Escort is deployed past outfit limits, removing."));
3120 i--;
3121 continue;
3122 }
3123 }
3124
3125 /* Add the player fleets. */
3126 for (int i=0; i<array_size(player_stack); i++) {
3127 PlayerShip_t *ps = &player_stack[i];
3128
3129 /* Already exists. */
3130 if (ps->p->id)
3131 continue;
3132
3133 /* Only deploy escorts that are deployed. */
3134 if (!ps->deployed)
3135 continue;
3136
3137 /* Only deploy spaceworthy escorts. */
3138 if (!pilot_isSpaceworthy(ps->p))
3139 continue;
3140
3141 pfleet_deploy( ps );
3142 }
3143
3144 return 0;
3145}
3146
3150static int player_saveEscorts( xmlTextWriterPtr writer )
3151{
3152 for (int i=0; i<array_size(player.p->escorts); i++) {
3153 Escort_t *e = &player.p->escorts[i];
3154 Pilot *pe;
3155 if (!e->persist)
3156 continue;
3157 switch (e->type) {
3158 case ESCORT_TYPE_BAY:
3159 xmlw_startElem(writer, "escort");
3160 xmlw_attr(writer,"type","bay");
3161 xmlw_attr(writer, "name", "%s", e->ship);
3162 xmlw_endElem(writer); /* "escort" */
3163 break;
3164
3165 case ESCORT_TYPE_FLEET:
3166 pe = pilot_get( e->id );
3167 if (pe != NULL) {
3168 xmlw_startElem(writer, "escort");
3169 xmlw_attr(writer,"type","fleet");
3170 xmlw_attr(writer, "name", "%s", pe->name);
3171 xmlw_endElem(writer); /* "escort" */
3172 }
3173 break;
3174
3175 default:
3176 break;
3177 }
3178 }
3179
3180 return 0;
3181}
3182
3189int player_save( xmlTextWriterPtr writer )
3190{
3191 char **guis;
3192 int cycles, periods, seconds;
3193 double rem;
3194 const PlayerItem *inventory;
3195
3196 xmlw_startElem(writer,"player");
3197
3198 /* Standard player details. */
3199 xmlw_attr(writer,"name","%s",player.name);
3200 xmlw_elem(writer,"credits","%"CREDITS_PRI,player.p->credits);
3201 xmlw_elem(writer,"chapter","%s",player.chapter);
3202 if (player.difficulty != NULL)
3203 xmlw_elem(writer,"difficulty","%s",player.difficulty);
3204 if (player.gui != NULL)
3205 xmlw_elem(writer,"gui","%s",player.gui);
3206 xmlw_elem(writer,"mapOverlay","%d",ovr_isOpen());
3208 xmlw_elem(writer,"radar_res","%f",player.radar_res);
3209 xmlw_elem(writer,"eq_outfitMode","%d",player.eq_outfitMode);
3210 xmlw_elem(writer,"map_minimal","%d",player.map_minimal);
3211 xmlw_elem(writer,"fleet_capacity","%d",player.fleet_capacity);
3212
3213 /* Time. */
3214 xmlw_startElem(writer,"time");
3215 ntime_getR( &cycles, &periods, &seconds, &rem );
3216 xmlw_elem(writer,"SCU","%d", cycles);
3217 xmlw_elem(writer,"STP","%d", periods);
3218 xmlw_elem(writer,"STU","%d", seconds);
3219 xmlw_elem(writer,"Remainder","%lf", rem);
3220 xmlw_endElem(writer); /* "time" */
3221
3222 /* Current ship. */
3223 xmlw_elem(writer, "location", "%s", land_spob->name);
3224 player_saveShip( writer, &player.ps ); /* current ship */
3225
3226 /* Ships. */
3227 xmlw_startElem(writer,"ships");
3228 for (int i=0; i<array_size(player_stack); i++)
3229 player_saveShip( writer, &player_stack[i] );
3230 xmlw_endElem(writer); /* "ships" */
3231
3232 /* GUIs. */
3233 xmlw_startElem(writer,"guis");
3234 guis = player_guiList();
3235 for (int i=0; i<array_size(guis); i++)
3236 xmlw_elem(writer,"gui","%s",guis[i]);
3237 xmlw_endElem(writer); /* "guis" */
3238
3239 /* Outfits. */
3240 xmlw_startElem(writer,"outfits");
3241 for (int i=0; i<array_size(player_outfits); i++) {
3242 xmlw_startElem(writer, "outfit");
3243 xmlw_attr(writer, "quantity", "%d", player_outfits[i].q);
3244 xmlw_str(writer, "%s", player_outfits[i].o->name);
3245 xmlw_endElem(writer); /* "outfit" */
3246 }
3247 xmlw_endElem(writer); /* "outfits" */
3248
3249 /* Licenses. */
3250 xmlw_startElem(writer, "licenses");
3251 for (int i=0; i<array_size(player_licenses); i++)
3252 xmlw_elem(writer, "license", "%s", player_licenses[i]);
3253 xmlw_endElem(writer); /* "licenses" */
3254
3255 /* Inventory. */
3256 xmlw_startElem(writer, "inventory");
3258 for (int i=0; i<array_size(inventory); i++) {
3259 const PlayerItem *pi = &inventory[i];
3260 xmlw_startElem(writer, "item");
3261 xmlw_attr(writer, "quantity", "%d", pi->quantity);
3262 xmlw_str(writer, "%s", pi->name);
3263 xmlw_endElem(writer); /* "item" */
3264 }
3265 xmlw_endElem(writer); /* "inventory" */
3266
3267 xmlw_endElem(writer); /* "player" */
3268
3269 /* Mission the player has done. */
3270 xmlw_startElem(writer,"missions_done");
3271 for (int i=0; i<array_size(missions_done); i++) {
3272 const MissionData *m = mission_get(missions_done[i]);
3273 if (m != NULL) /* In case mission name changes between versions */
3274 xmlw_elem(writer, "done", "%s", m->name);
3275 }
3276 xmlw_endElem(writer); /* "missions_done" */
3277
3278 /* Events the player has done. */
3279 xmlw_startElem(writer, "events_done");
3280 for (int i=0; i<array_size(events_done); i++) {
3281 const char *ev = event_dataName(events_done[i]);
3282 if (ev != NULL) /* In case mission name changes between versions */
3283 xmlw_elem(writer, "done", "%s", ev);
3284 }
3285 xmlw_endElem(writer); /* "events_done" */
3286
3287 /* Escorts. */
3288 xmlw_startElem(writer, "escorts");
3289 player_saveEscorts(writer);
3290 xmlw_endElem(writer); /* "escorts" */
3291
3292 /* Metadata. */
3293 xmlw_startElem(writer,"metadata");
3294 player_saveMetadata( writer );
3295 xmlw_endElem(writer); /* "metadata" */
3296
3297 return 0;
3298}
3299
3303static int player_saveShipSlot( xmlTextWriterPtr writer, const PilotOutfitSlot *slot, int i )
3304{
3305 const Outfit *o = slot->outfit;
3306 xmlw_startElem(writer,"outfit");
3307 xmlw_attr(writer,"slot","%d",i);
3309 xmlw_attr(writer,"quantity","%d", slot->u.ammo.quantity);
3310 xmlw_str(writer,"%s",o->name);
3311 xmlw_endElem(writer); /* "outfit" */
3312
3313 return 0;
3314}
3315
3323static int player_saveShip( xmlTextWriterPtr writer, PlayerShip_t *pship )
3324{
3325 Pilot *ship = pship->p;
3326 xmlw_startElem(writer,"ship");
3327 xmlw_attr(writer,"name","%s",ship->name);
3328 xmlw_attr(writer,"model","%s",ship->ship->name);
3329 xmlw_attr(writer,"favourite", "%d",pship->favourite);
3330 xmlw_attr(writer,"deployed", "%d",pship->deployed);
3331
3332 /* Metadata. */
3333 if (pship->acquired)
3334 xmlw_elem(writer, "acquired","%s", pship->acquired);
3335 xmlw_saveTime(writer, "acquired_date", pship->acquired_date);
3336 xmlw_elem(writer, "time_played","%f", pship->time_played);
3337 xmlw_elem(writer, "dmg_done_shield", "%f", pship->dmg_done_shield);
3338 xmlw_elem(writer, "dmg_done_armour", "%f", pship->dmg_done_armour);
3339 xmlw_elem(writer, "dmg_taken_shield", "%f", pship->dmg_taken_shield);
3340 xmlw_elem(writer, "dmg_taken_armour", "%f", pship->dmg_taken_armour);
3341 xmlw_elem(writer, "jumped_times", "%u", pship->jumped_times);
3342 xmlw_elem(writer, "landed_times", "%u", pship->landed_times);
3343 xmlw_elem(writer, "death_counter", "%u", pship->death_counter);
3344
3345 /* Ships destroyed by class. */
3346 xmlw_startElem(writer,"ships_destroyed");
3347 for (int i=SHIP_CLASS_NULL+1; i<SHIP_CLASS_TOTAL; i++) {
3348 char buf[STRMAX_SHORT];
3349 strncpy( buf, ship_classToString(i), sizeof(buf)-1 );
3350 for (size_t j=0; j<strlen(buf); j++)
3351 if (buf[j]==' ')
3352 buf[j]='_';
3353 xmlw_elem(writer, buf, "%u", pship->ships_destroyed[i]);
3354 }
3355 xmlw_endElem(writer); /* "ships_destroyed" */
3356
3357 /* save the fuel */
3358 xmlw_elem(writer,"fuel","%f",ship->fuel);
3359
3360 /* save the outfits */
3361 xmlw_startElem(writer,"outfits_intrinsic"); /* Want them to be first. */
3362 for (int i=0; i<array_size(ship->outfit_intrinsic); i++)
3363 player_saveShipSlot( writer, &ship->outfit_intrinsic[i], i );
3364 xmlw_endElem(writer); /* "outfits_intrinsic" */
3365 xmlw_startElem(writer,"outfits_structure");
3366 for (int i=0; i<array_size(ship->outfit_structure); i++) {
3367 if (ship->outfit_structure[i].outfit==NULL)
3368 continue;
3369 player_saveShipSlot( writer, &ship->outfit_structure[i], i );
3370 }
3371 xmlw_endElem(writer); /* "outfits_structure" */
3372 xmlw_startElem(writer,"outfits_utility");
3373 for (int i=0; i<array_size(ship->outfit_utility); i++) {
3374 if (ship->outfit_utility[i].outfit==NULL)
3375 continue;
3376 player_saveShipSlot( writer, &ship->outfit_utility[i], i );
3377 }
3378 xmlw_endElem(writer); /* "outfits_utility" */
3379 xmlw_startElem(writer,"outfits_weapon");
3380 for (int i=0; i<array_size(ship->outfit_weapon); i++) {
3381 if (ship->outfit_weapon[i].outfit==NULL)
3382 continue;
3383 player_saveShipSlot( writer, &ship->outfit_weapon[i], i );
3384 }
3385 xmlw_endElem(writer); /* "outfits_weapon" */
3386
3387 /* save the commodities */
3388 xmlw_startElem(writer,"commodities");
3389 for (int i=0; i<array_size(ship->commodities); i++) {
3390 PilotCommodity *pc = &ship->commodities[i];
3391 /* Remove cargo with id and no mission. */
3392 if (pc->id > 0) {
3393 int found = 0;
3394 for (int j=0; j<array_size(player_missions); j++) {
3395 /* Only check active missions. */
3396 if (player_missions[j]->id > 0) {
3397 /* Now check if it's in the cargo list. */
3398 for (int k=0; k<array_size(player_missions[j]->cargo); k++) {
3399 /* See if it matches a cargo. */
3400 if (player_missions[j]->cargo[k] == pc->id) {
3401 found = 1;
3402 break;
3403 }
3404 }
3405 }
3406 if (found)
3407 break;
3408 }
3409
3410 if (!found) {
3411 WARN(_("Found mission cargo '%s' without associated mission."),pc->commodity->name);
3412 WARN(_("Please reload save game to remove the dead cargo."));
3413 continue;
3414 }
3415 }
3416 else if (pc->quantity==0) {
3417 WARN(_("Found cargo '%s' with 0 quantity."),pc->commodity->name);
3418 WARN(_("Please reload save game to remove the dead cargo."));
3419 continue;
3420 }
3421
3422 xmlw_startElem(writer,"commodity");
3423
3424 xmlw_attr(writer,"quantity","%d",pc->quantity);
3425 if (pc->id > 0)
3426 xmlw_attr(writer,"id","%d",pc->id);
3427 xmlw_str(writer,"%s",pc->commodity->name);
3428
3429 xmlw_endElem(writer); /* commodity */
3430 }
3431 xmlw_endElem(writer); /* "commodities" */
3432
3433 xmlw_startElem(writer, "weaponsets");
3434 xmlw_attr(writer, "autoweap", "%d", ship->autoweap);
3435 xmlw_attr(writer, "active_set", "%d", ship->active_set);
3436 xmlw_attr(writer, "aim_lines", "%d", ship->aimLines);
3437 for (int i=0; i<PILOT_WEAPON_SETS; i++) {
3438 PilotWeaponSet *ws = &pship->weapon_sets[i];
3439 PilotWeaponSetOutfit *weaps = ws->slots;
3440 xmlw_startElem(writer,"weaponset");
3441 /* Inrange isn't handled by autoweap for the player. */
3442 xmlw_attr(writer,"inrange","%d",ws->inrange);
3443 xmlw_attr(writer,"manual","%d",ws->manual);
3444 xmlw_attr(writer,"id","%d",i);
3445 if (!ship->autoweap) {
3446 xmlw_attr(writer,"type","%d",ws->type);
3447 for (int j=0; j<array_size(weaps); j++) {
3448 xmlw_startElem(writer,"weapon");
3449 xmlw_attr(writer,"level","%d",weaps[j].level);
3450 xmlw_str(writer,"%d",weaps[j].slotid);
3451 xmlw_endElem(writer); /* "weapon" */
3452 }
3453 }
3454 xmlw_endElem(writer); /* "weaponset" */
3455 }
3456 xmlw_endElem(writer); /* "weaponsets" */
3457
3458 /* Ship variables. */
3459 xmlw_startElem(writer, "vars");
3460 lvar_save( pship->p->shipvar, writer );
3461 xmlw_endElem(writer); /* "vars" */
3462
3463 xmlw_endElem(writer); /* "ship" */
3464
3465 return 0;
3466}
3467
3474static int player_saveMetadata( xmlTextWriterPtr writer )
3475{
3476 time_t t = time(NULL);
3477 double diff = difftime( t, player.time_since_save );
3478
3479 /* Compute elapsed time. */
3480 player.time_played += diff;
3481 player.ps.time_played += diff;
3483
3484 /* Save the stuff. */
3485 xmlw_saveTime(writer, "last_played", time(NULL));
3486 xmlw_saveTime(writer, "date_created", player.date_created);
3487
3488 /* Meta-data. */
3489 xmlw_elem(writer, "time_played","%f", player.time_played);
3490 xmlw_elem(writer, "dmg_done_shield", "%f", player.dmg_done_shield);
3491 xmlw_elem(writer, "dmg_done_armour", "%f", player.dmg_done_armour);
3492 xmlw_elem(writer, "dmg_taken_shield", "%f", player.dmg_taken_shield);
3493 xmlw_elem(writer, "dmg_taken_armour", "%f", player.dmg_taken_armour);
3494 xmlw_elem(writer, "jumped_times", "%u", player.jumped_times);
3495 xmlw_elem(writer, "landed_times", "%u", player.landed_times);
3496 xmlw_elem(writer, "death_counter", "%u", player.death_counter);
3497
3498 /* Ships destroyed by class. */
3499 xmlw_startElem(writer,"ships_destroyed");
3500 for (int i=SHIP_CLASS_NULL+1; i<SHIP_CLASS_TOTAL; i++) {
3501 char buf[STRMAX_SHORT];
3502 strncpy( buf, ship_classToString(i), sizeof(buf)-1 );
3503 for (size_t j=0; j<strlen(buf); j++)
3504 if (buf[j]==' ')
3505 buf[j]='_';
3506 xmlw_elem(writer, buf, "%u", player.ships_destroyed[i]);
3507 }
3508 xmlw_endElem(writer); /* "ships_destroyed" */
3509
3510 return 0;
3511}
3512
3519Spob* player_load( xmlNodePtr parent )
3520{
3521 xmlNodePtr node;
3522 Spob *pnt;
3523
3524 /* some cleaning up */
3525 memset( &player, 0, sizeof(Player_t) );
3526 player.speed = 1.;
3527 pnt = NULL;
3528 map_cleanup();
3529
3530 /* Sane time defaults. */
3531 player.last_played = time(NULL);
3534
3535 if (player_stack==NULL)
3537 if (player_outfits==NULL)
3539
3540 node = parent->xmlChildrenNode;
3541 do {
3542 if (xml_isNode(node,"metadata"))
3544 else if (xml_isNode(node,"player"))
3545 pnt = player_parse( node );
3546 else if (xml_isNode(node,"missions_done"))
3548 else if (xml_isNode(node,"events_done"))
3549 player_parseDoneEvents( node );
3550 else if (xml_isNode(node,"escorts"))
3551 player_parseEscorts(node);
3552 } while (xml_nextNode(node));
3553
3554 /* Set up meta-data. */
3555 player.time_since_save = time(NULL);
3556
3557 /* Defaults as necessary. */
3558 if (player.chapter==NULL)
3559 player.chapter = strdup( start_chapter() );
3560 if (player.difficulty!=NULL)
3561 difficulty_setLocal( difficulty_get(player.difficulty) );
3562 else
3563 difficulty_setLocal( NULL ); /* Sets the default. */
3564
3565 /* Updates the fleet internals. */
3566 pfleet_update();
3567
3568 /* Update weapon set. */
3570
3571 return pnt;
3572}
3573
3582static int player_runUpdaterScript( const char* type, const char* name, int q )
3583{
3584 static nlua_env player_updater_env = LUA_NOREF;
3585
3587
3588 /* Load env if necessary. */
3589 if (player_updater_env == LUA_NOREF) {
3590 player_updater_env = nlua_newEnv();
3591 size_t bufsize;
3592 char *buf = ndata_read( SAVE_UPDATER_PATH, &bufsize );
3593 if (nlua_dobufenv(player_updater_env, buf, bufsize, SAVE_UPDATER_PATH) != 0) {
3594 WARN( _("Error loading file: %s\n"
3595 "%s\n"
3596 "Most likely Lua file has improper syntax, please check"),
3597 SAVE_UPDATER_PATH, lua_tostring(naevL,-1));
3598 free(buf);
3599 return 0;
3600 }
3601 free(buf);
3602 }
3603
3604 /* Try to find out equivalent. */
3605 nlua_getenv( naevL, player_updater_env, type );
3606 lua_pushstring( naevL, name );
3607 if (nlua_pcall(player_updater_env, 1, 1)) { /* error has occurred */
3608 WARN( _("Board: '%s'"), lua_tostring(naevL,-1));
3609 lua_pop(naevL,1);
3610 return 0;
3611 }
3612 if (lua_type(naevL,-1) == LUA_TNUMBER) {
3613 player_payback += q * round( lua_tonumber(naevL,-1) );
3614 lua_pop(naevL,1);
3615 return 0;
3616 }
3617
3618 return 1;
3619}
3620
3624static const Outfit* player_tryGetOutfit( const char *name, int q )
3625{
3626 const Outfit *o = outfit_getW( name );
3627
3628 /* Outfit was found normally. */
3629 if (o != NULL)
3630 return o;
3632
3633 /* Try to find out equivalent. */
3634 if (player_runUpdaterScript( "outfit", name, q ) == 0)
3635 return NULL;
3636 else if (lua_type(naevL,-1) == LUA_TSTRING)
3637 o = outfit_get( lua_tostring(naevL,-1) );
3638 else if (lua_isoutfit(naevL,-1))
3639 o = lua_tooutfit(naevL,-1);
3640 else
3641 WARN(_("Outfit '%s' in player save not found!"), name );
3642
3643 lua_pop(naevL,1);
3644
3645 return o;
3646}
3647
3651static const Ship* player_tryGetShip( const char *name )
3652{
3653 const Ship *s = ship_getW( name );
3654
3655 /* Ship was found normally. */
3656 if (s != NULL)
3657 return s;
3659
3660 /* Try to find out equivalent. */
3661 if (player_runUpdaterScript( "ship", name, 1 ) == 0)
3662 return NULL;
3663 else if (lua_type(naevL,-1) == LUA_TSTRING)
3664 s = ship_get( lua_tostring(naevL,-1) );
3665 else if (lua_isship(naevL,-1))
3666 s = lua_toship(naevL,-1);
3667 else
3668 WARN(_("Ship '%s' in player save not found!"), name );
3669
3670 lua_pop(naevL,1);
3671
3672 return s;
3673}
3674
3678static void player_tryAddLicense( const char *name )
3679{
3680 /* Found normally. */
3681 if (outfit_licenseExists(name)) {
3682 player_addLicense( name );
3683 return;
3684 }
3686
3687 /* Try to find out equivalent. */
3688 if (player_runUpdaterScript( "license", name, 1 ) == 0)
3689 return;
3690 else if (lua_type(naevL,-1) == LUA_TSTRING)
3691 player_addLicense( lua_tostring(naevL,-1) );
3692 else
3693 WARN(_("Saved license does not exist and could not be found or updated: '%s'!"), name);
3694 lua_pop(naevL,1);
3695}
3696
3703static Spob* player_parse( xmlNodePtr parent )
3704{
3705 const char *spob = NULL;
3706 unsigned int services;
3707 Spob *pnt = NULL;
3708 xmlNodePtr node, cur;
3709 int map_overlay_enabled = 0;
3710 StarSystem *sys;
3711 double a, r;
3712 Pilot *old_ship;
3713 PilotFlags flags;
3714 int time_set = 0;
3715
3716 xmlr_attr_strd(parent, "name", player.name);
3717 assert( player.p == NULL );
3719
3721
3722 /* Must get spob first. */
3723 node = parent->xmlChildrenNode;
3724 do {
3725 xmlr_str(node,"location",spob);
3726 } while (xml_nextNode(node));
3727
3728 /* Parse rest. */
3729 node = parent->xmlChildrenNode;
3730 do {
3731 /* global stuff */
3732 xmlr_ulong(node, "credits", player_creds);
3733 xmlr_strd(node, "gui", player.gui);
3734 xmlr_strd(node, "chapter", player.chapter);
3735 xmlr_int(node, "mapOverlay", map_overlay_enabled);
3736 xmlr_float(node, "radar_res", player.radar_res);
3737 xmlr_int(node, "eq_outfitMode", player.eq_outfitMode);
3738 xmlr_int(node, "map_minimal", player.map_minimal);
3739 xmlr_int(node, "fleet_capacity", player.fleet_capacity);
3740
3741 /* Time. */
3742 if (xml_isNode(node,"time")) {
3743 double rem = -1.;
3744 int cycles=-1, periods=-1, seconds=-1;
3745 cur = node->xmlChildrenNode;
3746 do {
3747 xmlr_int(cur, "SCU", cycles);
3748 xmlr_int(cur, "STP", periods);
3749 xmlr_int(cur, "STU", seconds);
3750 xmlr_float(cur, "Remainder", rem);
3751 } while (xml_nextNode(cur));
3752 if ((cycles < 0) || (periods < 0) || (seconds < 0) || (rem<0.))
3753 WARN(_("Malformed time in save game!"));
3754 ntime_setR( cycles, periods, seconds, rem );
3755 if ((cycles >= 0) || (periods >= 0) || (seconds >= 0))
3756 time_set = 1;
3757 }
3758
3759 if (xml_isNode(node, "ship"))
3760 player_parseShip(node, 1);
3761
3762 /* Parse ships. */
3763 else if (xml_isNode(node,"ships")) {
3764 cur = node->xmlChildrenNode;
3765 do {
3766 if (xml_isNode(cur,"ship"))
3767 player_parseShip(cur, 0);
3768 } while (xml_nextNode(cur));
3769 }
3770
3771 /* Parse GUIs. */
3772 else if (xml_isNode(node,"guis")) {
3773 cur = node->xmlChildrenNode;
3774 do {
3775 if (xml_isNode(cur,"gui"))
3776 player_guiAdd( xml_get(cur) );
3777 } while (xml_nextNode(cur));
3778 }
3779
3780 /* Parse outfits. */
3781 else if (xml_isNode(node,"outfits")) {
3782 cur = node->xmlChildrenNode;
3783 do {
3784 if (xml_isNode(cur,"outfit")) {
3785 int q;
3786 const Outfit *o;
3787 const char *oname = xml_get(cur);
3788 xmlr_attr_float( cur, "quantity", q );
3789 if (q == 0) {
3790 WARN(_("Outfit '%s' was saved without quantity!"), (oname!=NULL) ? oname : "NULL" );
3791 continue;
3792 }
3793
3794 o = player_tryGetOutfit( oname, q );
3795 if (o == NULL)
3796 continue;
3797
3798 player_addOutfit( o, q );
3799 }
3800 } while (xml_nextNode(cur));
3801 }
3802
3803 /* Parse licenses. */
3804 else if (xml_isNode(node,"licenses"))
3806
3807 else if (xml_isNode(node,"inventory"))
3809
3810 } while (xml_nextNode(node));
3811
3812 /* Handle cases where ship is missing. */
3813 if (player.p == NULL) {
3814 pilot_clearFlagsRaw( flags );
3815 pilot_setFlagRaw( flags, PILOT_PLAYER );
3816 pilot_setFlagRaw( flags, PILOT_NO_OUTFITS );
3817 WARN(_("Player ship does not exist!"));
3818
3819 if (array_size(player_stack) == 0) {
3820 WARN(_("Player has no other ships, giving starting ship."));
3821 pilot_create( ship_get(start_ship()), "MIA",
3822 faction_get("Player"), "player", 0., NULL, NULL, flags, 0, 0 );
3823 }
3824 else {
3825
3826 /* Just give player.p a random ship in the stack. */
3827 old_ship = player_stack[array_size(player_stack)-1].p;
3828 pilot_create( old_ship->ship, old_ship->name,
3829 faction_get("Player"), "player", 0., NULL, NULL, flags, 0, 0 );
3830 player_rmShip( old_ship->name );
3831 WARN(_("Giving player ship '%s'."), player.p->name );
3832 }
3833 }
3834
3835 /* Check. */
3836 if (player.p == NULL) {
3837 ERR(_("Something went horribly wrong, player does not exist after load..."));
3838 return NULL;
3839 }
3840
3841 /* Reset player speed */
3842 player.speed = 1.;
3843
3844 /* set global thingies */
3846 if (!time_set) {
3847 WARN(_("Save has no time information, setting to start information."));
3848 ntime_set( start_date() );
3849 }
3850
3851 /* Updater message. */
3852 if (player_ran_updater) {
3853 DEBUG(_("Player save was updated!"));
3854 dialogue_msg(_("Save Game Updated"),_("The loaded save games has had outfits and ships updated to the current Naev version. You will find that some outfits and ships you have had have been changed. In the case no equivalent outfit or ship was found, you have been refunded the cost in credits."));
3855 }
3856
3857 /* set player in system */
3858 pnt = spob_get( spob );
3859 /* Get random spob if it's NULL. */
3860 if ((pnt == NULL) || (spob_getSystem(spob) == NULL) ||
3861 !spob_hasService(pnt, SPOB_SERVICE_LAND)) {
3862 WARN(_("Player starts out in non-existent or invalid spob '%s',"
3863 "trying to find a suitable one instead."),
3864 spob );
3865
3866 /* Find a landable, inhabited spob that's in a system, offers refueling
3867 * and meets the following additional criteria:
3868 *
3869 * 0: Shipyard, outfitter, non-hostile
3870 * 1: Outfitter, non-hostile
3871 * 2: None
3872 *
3873 * If no spob meeting the current criteria can be found, the next
3874 * set of criteria is tried until none remain.
3875 */
3876 const char *found = NULL;
3877 for (int i=0; i<3; i++) {
3878 services = SPOB_SERVICE_LAND | SPOB_SERVICE_INHABITED | SPOB_SERVICE_REFUEL;
3879
3880 if (i == 0)
3881 services |= SPOB_SERVICE_SHIPYARD;
3882
3883 if (i != 2)
3884 services |= SPOB_SERVICE_OUTFITS;
3885
3886 found = space_getRndSpob( 1, services,
3887 (i != 2) ? player_filterSuitableSpob : NULL );
3888 if (found != NULL)
3889 break;
3890
3891 WARN(_("Could not find a spob satisfying criteria %d."), i);
3892 }
3893
3894 if (found == NULL) {
3895 WARN(_("Could not find a suitable spob. Choosing a random spob."));
3896 found = space_getRndSpob(0, 0, NULL); /* This should never, ever fail. */
3897 }
3898 pnt = spob_get( found );
3899 }
3900
3901 /* Initialize system. */
3902 sys = system_get( spob_getSystem( pnt->name ) );
3903 space_gfxLoad( sys );
3904 a = RNGF() * 2.*M_PI;
3905 r = RNGF() * pnt->radius * 0.8;
3906 player_warp( pnt->pos.x + r*cos(a), pnt->pos.y + r*sin(a) );
3907 player.p->solid->dir = RNG(0,359) * M_PI/180.;
3908
3909 /* Initialize outfits. */
3911
3912 /* initialize the system */
3913 space_init( sys->name, 0 );
3914 map_clear(); /* sets the map up */
3915 ovr_setOpen(map_overlay_enabled);
3916
3917 /* initialize the sound */
3919
3920 return pnt;
3921}
3922
3930{
3931 return !areEnemies(p->presence.faction, FACTION_PLAYER);
3932}
3933
3940static int player_parseDoneMissions( xmlNodePtr parent )
3941{
3942 xmlNodePtr node = parent->xmlChildrenNode;
3943 do {
3944 xml_onlyNodes(node);
3945
3946 if (!xml_isNode(node,"done"))
3947 continue;
3948
3949 int id = mission_getID( xml_get(node) );
3950 if (id < 0)
3951 DEBUG(_("Mission '%s' doesn't seem to exist anymore, removing from save."),
3952 xml_get(node));
3953 else
3955 } while (xml_nextNode(node));
3956 return 0;
3957}
3958
3965static int player_parseDoneEvents( xmlNodePtr parent )
3966{
3967 xmlNodePtr node = parent->xmlChildrenNode;
3968 do {
3969 xml_onlyNodes(node);
3970
3971 if (!xml_isNode(node,"done"))
3972 continue;
3973
3974 int id = event_dataID( xml_get(node) );
3975 if (id < 0)
3976 DEBUG(_("Event '%s' doesn't seem to exist anymore, removing from save."),
3977 xml_get(node));
3978 else
3980 } while (xml_nextNode(node));
3981 return 0;
3982}
3983
3990static int player_parseLicenses( xmlNodePtr parent )
3991{
3992 xmlNodePtr node = parent->xmlChildrenNode;
3993 do {
3994 xml_onlyNodes(node);
3995
3996 if (!xml_isNode( node, "license" ))
3997 continue;
3998
3999 char *name = xml_get( node );
4000 if (name == NULL) {
4001 WARN( _( "License node is missing name." ) );
4002 continue;
4003 }
4004 player_tryAddLicense( name );
4005 } while (xml_nextNode(node));
4006 return 0;
4007}
4008
4015static int player_parseInventory( xmlNodePtr parent )
4016{
4017 xmlNodePtr node = parent->xmlChildrenNode;
4018 do {
4019 int q;
4020 xml_onlyNodes(node);
4021
4022 if (!xml_isNode( node, "item" ))
4023 continue;
4024
4025 xmlr_attr_int_def( node, "quantity", q, 1 );
4026 char *name = xml_get( node );
4027 if (name == NULL) {
4028 WARN( _( "Inventory item node is missing name." ) );
4029 continue;
4030 }
4031 player_inventoryAdd( name, q );
4032 } while (xml_nextNode(node));
4033 return 0;
4034}
4035
4042static int player_parseEscorts( xmlNodePtr parent )
4043{
4044 xmlNodePtr node = parent->xmlChildrenNode;
4045 do {
4046 char *buf, *name;
4047
4048 /* Skip non-escorts. */
4049 if (!xml_isNode(node,"escort"))
4050 continue;
4051
4052 xmlr_attr_strd( node, "type", buf );
4053 xmlr_attr_strd( node, "name", name );
4054 if (name==NULL) /* Workaround for old saves, TODO remove around 0.11 */
4055 name = xml_getStrd( node );
4056 if (strcmp(buf,"bay")==0)
4057 escort_addList( player.p, name, ESCORT_TYPE_BAY, 0, 1 );
4058
4059 else if (strcmp(buf,"fleet")==0) {
4060 PlayerShip_t *ps = player_getPlayerShip( name );
4061
4062 /* Only deploy escorts that are deployed. */
4063 if (!ps->deployed)
4064 WARN(_("Fleet ship '%s' is deployed despite not being marked for deployal!"), ps->p->name);
4065
4066 /* Only deploy spaceworthy escorts. */
4067 if (!pilot_isSpaceworthy(ps->p))
4068 WARN(_("Fleet ship '%s' is deployed despite not being space worthy!"), ps->p->name);
4069
4070 pfleet_deploy( ps );
4071 }
4072 else
4073 WARN(_("Escort has invalid type '%s'."), buf);
4074 free(buf);
4075 free(name);
4076 } while (xml_nextNode(node));
4077 return 0;
4078}
4079
4086static int player_parseMetadata( xmlNodePtr parent )
4087{
4088 xmlNodePtr node = parent->xmlChildrenNode;
4089 do {
4090 xml_onlyNodes(node);
4091
4092 xmlr_float(node,"dmg_done_shield",player.dmg_done_shield);
4093 xmlr_float(node,"dmg_done_armour",player.dmg_done_armour);
4094 xmlr_float(node,"dmg_taken_shield",player.dmg_taken_shield);
4095 xmlr_float(node,"dmg_taken_armour",player.dmg_taken_armour);
4096 xmlr_uint(node,"jumped_times",player.jumped_times);
4097 xmlr_uint(node,"landed_times",player.landed_times);
4098 xmlr_uint(node,"death_counter",player.death_counter);
4099 xmlr_float(node,"time_played",player.time_played);
4100
4101 if (xml_isNode(node,"last_played")) {
4102 xml_parseTime(node, &player.last_played);
4103 continue;
4104 }
4105 else if (xml_isNode(node,"date_created")) {
4106 xml_parseTime(node, &player.date_created);
4107 continue;
4108 }
4109 else if (xml_isNode(node,"ships_destroyed")) {
4110 xmlNodePtr cur = node->xmlChildrenNode;
4111 do {
4112 char buf[STRMAX_SHORT];
4113 int class;
4114
4115 xml_onlyNodes(cur);
4116
4117 strncpy( buf, (const char*)cur->name, sizeof(buf)-1 );
4118 for (size_t i=0; i<strlen(buf); i++)
4119 if (buf[i]=='_')
4120 buf[i] = ' ';
4121
4122 class = ship_classFromString( buf );
4123 if (class==SHIP_CLASS_NULL) {
4124 WARN(_("Unknown ship class '%s' when parsing 'ships_destroyed' node!"), (const char*)cur->name );
4125 continue;
4126 }
4127
4128 player.ships_destroyed[class] = xml_getULong(cur);
4129 } while (xml_nextNode(cur));
4130 }
4131 } while (xml_nextNode(node));
4132 return 0;
4133}
4134
4138static void player_addOutfitToPilot( Pilot* pilot, const Outfit* outfit, PilotOutfitSlot *s )
4139{
4140 int ret;
4141
4142 if (!outfit_fitsSlot( outfit, &s->sslot->slot )) {
4143 DEBUG( _("Outfit '%s' does not fit designated slot on player's pilot '%s', adding to stock."),
4144 outfit->name, pilot->name );
4145 player_addOutfit( outfit, 1 );
4146 return;
4147 }
4148
4149 ret = pilot_addOutfitRaw( pilot, outfit, s );
4150 if (ret != 0) {
4151 DEBUG(_("Outfit '%s' does not fit on player's pilot '%s', adding to stock."),
4152 outfit->name, pilot->name);
4153 player_addOutfit( outfit, 1 );
4154 return;
4155 }
4156
4157 /* Update stats. */
4158 pilot_calcStats( pilot );
4159}
4160
4164static void player_parseShipSlot( xmlNodePtr node, Pilot *ship, PilotOutfitSlot *slot )
4165{
4166 const Outfit *o;
4167 int q;
4168
4169 char *name = xml_get(node);
4170 if (name == NULL) {
4171 WARN(_("Empty ship slot node found, skipping."));
4172 return;
4173 }
4174
4175 /* Add the outfit. */
4176 o = player_tryGetOutfit( name, 1 );
4177 if (o==NULL)
4178 return;
4179 player_addOutfitToPilot( ship, o, slot );
4180
4181 /* Doesn't have ammo. */
4183 return;
4184
4185 /* See if has quantity. */
4186 xmlr_attr_int(node,"quantity",q);
4187 if (q > 0)
4188 pilot_addAmmo( ship, slot, q );
4189}
4190
4198static int player_parseShip( xmlNodePtr parent, int is_player )
4199{
4200 char *name, *model;
4201 int id, fuel;
4202 const Ship *ship_parsed;
4203 Pilot* ship;
4204 xmlNodePtr node;
4205 Commodity *com;
4206 PilotFlags flags;
4207 int autoweap, level, weapid, active_set, aim_lines, in_range, manual, weap_type;
4208 PlayerShip_t ps;
4209
4210 memset( &ps, 0, sizeof(PlayerShip_t) );
4211
4212 /* Parse attributes. */
4213 xmlr_attr_strd( parent, "name", name );
4214 xmlr_attr_strd( parent, "model", model );
4215 xmlr_attr_int_def( parent, "favourite", ps.favourite, 0 );
4216 xmlr_attr_int_def( parent, "deployed", ps.deployed, 0 );
4217
4218 /* Safe defaults. */
4219 pilot_clearFlagsRaw( flags );
4220 if (is_player)
4221 pilot_setFlagRaw( flags, PILOT_PLAYER );
4222 pilot_setFlagRaw( flags, PILOT_NO_OUTFITS );
4223
4224 /* Handle certain 0.10.0-alpha saves where it's possible that... */
4225 if (!is_player && strcmp( name, player.p->name ) == 0) {
4226 DEBUG( _("Ignoring player-owned ship '%s': duplicate of player's current ship."), name );
4227 free(name);
4228 free(model);
4229 return 0;
4230 }
4231
4232 /* Get the ship. */
4233 ship_parsed = player_tryGetShip( model );
4234 if (ship_parsed == NULL) {
4235 WARN(_("Player ship '%s' not found!"), model);
4236
4237 /* TODO we should probably parse the outfits and give them to the player. */
4238
4239 /* Clean up. */
4240 free(name);
4241 free(model);
4242
4243 return -1;
4244 }
4245
4246 /* Add GUI if applicable. */
4247 player_guiAdd( ship_parsed->gui );
4248
4249 /* Create the ship. */
4250 ship = pilot_createEmpty( ship_parsed, name, faction_get("Player"), flags );
4251 /* Player is currently on this ship */
4252 if (is_player) {
4253 ps.deployed = 0; /* Current ship can't be deployed. */
4254 pilot_setPlayer( ship );
4255 }
4256 ps.p = ship;
4257
4258 /* Ship should not have default outfits. */
4259 for (int i=0; i<array_size(ship->outfits); i++)
4260 pilot_rmOutfitRaw( ship, ship->outfits[i] );
4261
4262 /* Clean up. */
4263 free(name);
4264 free(model);
4265
4266 /* Defaults. */
4267 fuel = -1;
4268 autoweap = 1;
4269 aim_lines = 0;
4270
4271 /* Start parsing. */
4272 node = parent->xmlChildrenNode;
4273 do {
4274 xml_onlyNodes(node);
4275
4276 /* Meta-data. */
4277 xmlr_strd(node,"acquired",ps.acquired);
4278 if (xml_isNode(node,"acquired_date")) {
4279 xml_parseTime(node, &ps.acquired_date);
4280 continue;
4281 }
4282 xmlr_float(node,"time_played",ps.time_played);
4283 xmlr_float(node,"dmg_done_shield",ps.dmg_done_shield);
4284 xmlr_float(node,"dmg_done_armour",ps.dmg_done_armour);
4285 xmlr_float(node,"dmg_taken_shield",ps.dmg_taken_shield);
4286 xmlr_float(node,"dmg_taken_armour",ps.dmg_taken_armour);
4287 xmlr_uint(node,"jumped_times",ps.jumped_times);
4288 xmlr_uint(node,"landed_times",ps.landed_times);
4289 xmlr_uint(node,"death_counter",ps.death_counter);
4290 if (xml_isNode(node,"ships_destroyed")) {
4291 xmlNodePtr cur = node->xmlChildrenNode;
4292 do {
4293 char buf[STRMAX_SHORT];
4294 int class;
4295
4296 xml_onlyNodes(cur);
4297
4298 strncpy( buf, (const char*)cur->name, sizeof(buf)-1 );
4299 for (size_t i=0; i<strlen(buf); i++)
4300 if (buf[i]=='_')
4301 buf[i] = ' ';
4302
4303 class = ship_classFromString( buf );
4304 if (class==SHIP_CLASS_NULL) {
4305 WARN(_("Unknown ship class '%s' when parsing 'ships_destroyed' node!"), (const char*)cur->name );
4306 continue;
4307 }
4308
4309 ps.ships_destroyed[class] = xml_getULong(cur);
4310 } while (xml_nextNode(cur));
4311 }
4312
4313 /* Get fuel. */
4314 xmlr_int(node,"fuel",fuel);
4315
4316 /* New outfit loading. */
4317 if (xml_isNode(node,"outfits_structure")) {
4318 xmlNodePtr cur = node->xmlChildrenNode;
4319 do { /* load each outfit */
4320 int n;
4321 xml_onlyNodes(cur);
4322 if (!xml_isNode(cur,"outfit")) {
4323 WARN(_("Save has unknown '%s' tag!"),xml_get(cur));
4324 continue;
4325 }
4326 xmlr_attr_int_def( cur, "slot", n, -1 );
4327 if ((n<0) || (n >= array_size(ship->outfit_structure))) {
4328 WARN(_("Outfit slot out of range, not adding to ship."));
4329 continue;
4330 }
4331 player_parseShipSlot( cur, ship, &ship->outfit_structure[n] );
4332 } while (xml_nextNode(cur));
4333 continue;
4334 }
4335 else if (xml_isNode(node,"outfits_utility")) {
4336 xmlNodePtr cur = node->xmlChildrenNode;
4337 do { /* load each outfit */
4338 int n;
4339 xml_onlyNodes(cur);
4340 if (!xml_isNode(cur,"outfit")) {
4341 WARN(_("Save has unknown '%s' tag!"),xml_get(cur));
4342 continue;
4343 }
4344 xmlr_attr_int_def( cur, "slot", n, -1 );
4345 if ((n<0) || (n >= array_size(ship->outfit_utility))) {
4346 WARN(_("Outfit slot out of range, not adding."));
4347 continue;
4348 }
4349 player_parseShipSlot( cur, ship, &ship->outfit_utility[n] );
4350 } while (xml_nextNode(cur));
4351 continue;
4352 }
4353 else if (xml_isNode(node,"outfits_weapon")) {
4354 xmlNodePtr cur = node->xmlChildrenNode;
4355 do { /* load each outfit */
4356 int n;
4357 xml_onlyNodes(cur);
4358 if (!xml_isNode(cur,"outfit")) {
4359 WARN(_("Save has unknown '%s' tag!"),xml_get(cur));
4360 continue;
4361 }
4362 xmlr_attr_int_def( cur, "slot", n, -1 );
4363 if ((n<0) || (n >= array_size(ship->outfit_weapon))) {
4364 WARN(_("Outfit slot out of range, not adding."));
4365 continue;
4366 }
4367 player_parseShipSlot( cur, ship, &ship->outfit_weapon[n] );
4368 } while (xml_nextNode(cur));
4369 continue;
4370 }
4371 else if (xml_isNode(node,"outfits_intrinsic")) {
4372 xmlNodePtr cur = node->xmlChildrenNode;
4373 do { /* load each outfit */
4374 xml_onlyNodes(cur);
4375 if (!xml_isNode(cur,"outfit")) {
4376 WARN(_("Save has unknown '%s' tag!"),xml_get(cur));
4377 continue;
4378 }
4379 const Outfit *o = player_tryGetOutfit( xml_get(cur), 1 );
4380 if (o!=NULL)
4381 pilot_addOutfitIntrinsic( ship, o );
4382 } while (xml_nextNode(cur));
4383 continue;
4384 }
4385 else if (xml_isNode(node, "commodities")) {
4386 xmlNodePtr cur = node->xmlChildrenNode;
4387 do {
4388 if (xml_isNode(cur, "commodity")) {
4389 int cid, quantity;
4390
4391 xmlr_attr_int( cur, "quantity", quantity );
4392 xmlr_attr_int_def( cur, "id", cid, 0 );
4393
4394 /* Get the commodity. */
4395 com = commodity_get(xml_get(cur));
4396 if (com == NULL) {
4397 WARN(_("Unknown commodity '%s' detected, removing."), xml_get(cur));
4398 continue;
4399 }
4400
4401 /* actually add the cargo with id hack
4402 * Note that the player's cargo_free is ignored here. */
4403 if ((quantity==0) && (cid==0))
4404 WARN(_("Adding cargo '%s' to ship '%s' that is not a mission cargo with quantity=0!"), com->name, ship->name );
4405 pilot_cargoAddRaw( ship, com, quantity, cid );
4406 }
4407 } while (xml_nextNode(cur));
4408 continue;
4409 }
4410 //WARN(_("Save has unknown '%s' tag!"),xml_get(node));
4411 } while (xml_nextNode(node));
4412
4413 /* Update stats. */
4414 pilot_calcStats( ship );
4415
4416 /* Test for validity. */
4417 if (fuel >= 0)
4418 ship->fuel = MIN(ship->fuel_max, fuel);
4419 /* ships can now be non-spaceworthy on save
4420 * str = pilot_isSpaceworthy( ship ); */
4421 if (!pilot_slotsCheckSafety( ship )) {
4422 DEBUG(_("Player ship '%s' failed slot validity check , removing all outfits and adding to stock."),
4423 ship->name );
4424 /* Remove all outfits. */
4425 for (int i=0; i<array_size(ship->outfits); i++) {
4426 const Outfit *o = ship->outfits[i]->outfit;
4427 int ret = pilot_rmOutfitRaw( ship, ship->outfits[i] );
4428 if (ret==0)
4429 player_addOutfit( o, 1 );
4430 }
4431 pilot_calcStats( ship );
4432 }
4433
4434 /* Sets inrange by default if weapon sets are missing. */
4435 for (int i=0; i<PILOT_WEAPON_SETS; i++)
4436 pilot_weapSetInrange( ship, i, WEAPSET_INRANGE_PLAYER_DEF );
4437
4438 /* Second pass for weapon sets. */
4439 active_set = 0;
4440 node = parent->xmlChildrenNode;
4441 do {
4442 xmlNodePtr cur;
4443
4444 if (xml_isNode(node,"vars")) {
4445 ps.p->shipvar = lvar_load( node );
4446 continue;
4447 }
4448 else if (!xml_isNode(node,"weaponsets"))
4449 continue;
4450
4451 /* Check for autoweap. */
4452 xmlr_attr_int( node, "autoweap", autoweap );
4453
4454 /* Load the last weaponset the player used on this ship. */
4455 xmlr_attr_int_def( node, "active_set", active_set, -1 );
4456
4457 /* Check for aim_lines. */
4458 xmlr_attr_int( node, "aim_lines", aim_lines );
4459
4460 /* Parse weapon sets. */
4461 cur = node->xmlChildrenNode;
4462 do { /* Load each weapon set. */
4463 xmlNodePtr ccur;
4464
4465 xml_onlyNodes(cur);
4466 if (!xml_isNode(cur,"weaponset")) {
4467 WARN(_("Player ship '%s' has unknown node '%s' in 'weaponsets' (expected 'weaponset')."),
4468 ship->name, cur->name);
4469 continue;
4470 }
4471
4472 /* Get id. */
4473 xmlr_attr_int_def(cur, "id", id, -1);
4474 if (id == -1) {
4475 WARN(_("Player ship '%s' missing 'id' tag for weapon set."),ship->name);
4476 continue;
4477 }
4478 if ((id < 0) || (id >= PILOT_WEAPON_SETS)) {
4479 WARN(_("Player ship '%s' has invalid weapon set id '%d' [max %d]."),
4480 ship->name, id, PILOT_WEAPON_SETS-1 );
4481 continue;
4482 }
4483
4484 /* Set inrange mode. */
4485 xmlr_attr_int( cur, "inrange", in_range );
4486 if (in_range > 0)
4487 pilot_weapSetInrange( ship, id, in_range );
4488
4489 /* Set manual mode. */
4490 xmlr_attr_int( cur, "manual", manual );
4491 if (manual > 0)
4492 pilot_weapSetManual( ship, id, manual );
4493
4494 if (autoweap) /* Autoweap handles everything except inrange and manual. */
4495 continue;
4496
4497 /* Set type mode. */
4498 xmlr_attr_int_def( cur, "type", weap_type, -1 );
4499 if (weap_type == -1) {
4500 WARN(_("Player ship '%s' missing 'type' tag for weapon set."),ship->name);
4501 continue;
4502 }
4503 pilot_weapSetType( ship, id, weap_type );
4504
4505 /* Parse individual weapons. */
4506 ccur = cur->xmlChildrenNode;
4507 do {
4508 /* Only nodes. */
4509 xml_onlyNodes(ccur);
4510
4511 /* Only weapon nodes. */
4512 if (!xml_isNode(ccur,"weapon")) {
4513 WARN(_("Player ship '%s' has unknown 'weaponset' child node '%s' (expected 'weapon')."),
4514 ship->name, ccur->name );
4515 continue;
4516 }
4517
4518 /* Get level. */
4519 xmlr_attr_int_def( ccur, "level", level, -1 );
4520 if (level == -1) {
4521 WARN(_("Player ship '%s' missing 'level' tag for weapon set weapon."), ship->name);
4522 continue;
4523 }
4524 weapid = xml_getInt(ccur);
4525 if ((weapid < 0) || (weapid >= array_size(ship->outfits))) {
4526 WARN(_("Player ship '%s' has invalid weapon id %d [max %d]."),
4527 ship->name, weapid, array_size(ship->outfits)-1 );
4528 continue;
4529 }
4530
4531 /* Add the weapon set. */
4532 pilot_weapSetAdd( ship, id, ship->outfits[weapid], level );
4533
4534 } while (xml_nextNode(ccur));
4535 } while (xml_nextNode(cur));
4536 } while (xml_nextNode(node));
4537
4538 /* Set up autoweap if necessary. */
4539 ship->autoweap = autoweap;
4540 if (autoweap)
4541 pilot_weaponAuto( ship );
4542 pilot_weaponSafe( ship );
4543 if (active_set >= 0 && active_set < PILOT_WEAPON_SETS)
4544 ship->active_set = active_set;
4545 else
4546 pilot_weaponSetDefault( ship );
4547 /* Copy the weapon set over to the player ship, where we store it. */
4548 ws_copy( ps.weapon_sets, ship->weapon_sets );
4549
4550 /* Set aimLines */
4551 ship->aimLines = aim_lines;
4552
4553 /* Add it to the stack if it's not what the player is in */
4554 if (is_player == 0)
4556 else
4557 player.ps = ps;
4558
4559 return 0;
4560}
4561
4566{
4567 if (player.p == NULL)
4568 return;
4569
4570 /* Handle destealth first. */
4571 if (pilot_isFlag(player.p, PILOT_STEALTH)) {
4573 player_message(_("You have destealthed."));
4574 return;
4575 }
4576
4577 /* Stealth case. */
4578 if (pilot_stealth( player.p )) {
4579 player_message( "#g%s", _("You have entered stealth mode.") );
4580 }
4581 else {
4582 /* Stealth failed. */
4583 if (player.p->lockons > 0)
4584 player_message( "#r%s", _("Unable to stealth: missiles locked on!") );
4585 else
4586 player_message( "#r%s", _("Unable to stealth: other pilots nearby!") );
4587 }
4588}
void ai_think(Pilot *pilot, const double dt)
Heart of the AI, brains of the pilot.
Definition: ai.c:715
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition: array.h:158
#define array_front(ptr_array)
Returns the first element in the array.
Definition: array.h:209
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
Definition: array.h:140
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_back(ptr_array)
Returns the last element in the array.
Definition: array.h:216
#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 cam_setZoom(double zoom)
Sets the camera zoom.
Definition: camera.c:73
void cam_setTargetPilot(unsigned int follow, int soft_over)
Sets the target to follow.
Definition: camera.c:145
void cam_setTargetPos(double x, double y, int soft_over)
Sets the camera target to a position.
Definition: camera.c:182
double cam_getZoom(void)
Gets the camera zoom.
Definition: camera.c:97
int cam_getTarget(void)
Returns the camera's current target.
Definition: camera.c:211
void claim_clear(void)
Clears the claims on all systems.
Definition: claim.c:221
void col_blend(glColour *blend, const glColour *fg, const glColour *bg, float alpha)
Blends two colours.
Definition: colour.c:192
int comm_openPilot(unsigned int pilot)
Opens the communication dialogue with a pilot.
Definition: comm.c:70
int comm_openSpob(Spob *spob)
Opens a communication dialogue with a spob.
Definition: comm.c:189
char * dialogue_input(const char *title, int min, int max, const char *fmt,...)
Creates a dialogue that allows the player to write a message.
Definition: dialogue.c:436
void dialogue_msg(const char *caption, const char *fmt,...)
Opens a dialogue window with an ok button and a message.
Definition: dialogue.c:218
int dialogue_YesNo(const char *caption, const char *fmt,...)
Runs a dialogue with both yes and no options.
Definition: dialogue.c:344
int economy_init(void)
Initializes the economy.
Definition: economy.c:449
void economy_clearKnown(void)
Clears all system knowledge.
Definition: economy.c:962
void equipment_regenLists(unsigned int wid, int outfits, int ships)
Regenerates the equipment window lists.
Definition: equipment.c:1235
void escort_freeList(Pilot *p)
Remove all escorts from a pilot.
Definition: escort.c:60
int escorts_jump(Pilot *parent, JumpPoint *jp)
Have a pilot order its escorts to jump.
Definition: escort.c:409
void escort_rmListIndex(Pilot *p, int i)
Remove from escorts list.
Definition: escort.c:75
int escort_addList(Pilot *p, const char *ship, EscortType_t type, unsigned int id, int persist)
Adds an escort to the escort list of a pilot.
Definition: escort.c:40
int escort_clearDeployed(Pilot *p)
Clears deployed escorts of a pilot.
Definition: escort.c:229
int event_start(const char *name, unsigned int *id)
Starts an event.
Definition: event.c:119
const char * event_dataName(int dataid)
Gets the event data name from id.
Definition: event.c:710
void events_cleanup(void)
Cleans up and removes active events.
Definition: event.c:666
int event_dataID(const char *evdata)
Gets the event data id from name.
Definition: event.c:695
void events_trigger(EventTrigger_t trigger)
Runs all the events matching a trigger.
Definition: event.c:314
void factions_reset(void)
Resets player standing and flags of factions to default.
Definition: faction.c:1570
int areEnemies(int a, int b)
Checks whether two factions are enemies.
Definition: faction.c:1197
void factions_clearDynamic(void)
Clears dynamic factions.
Definition: faction.c:1858
int faction_get(const char *name)
Gets a faction ID by name.
Definition: faction.c:182
int areAllies(int a, int b)
Checks whether two factions are allies or not.
Definition: faction.c:1222
void gui_clearMessages(void)
Clears the GUI messages.
Definition: gui.c:973
void gui_setTarget(void)
Player just changed their pilot target.
Definition: gui.c:1757
void gui_setDefaults(void)
Definition: gui.c:199
int gui_load(const char *name)
Attempts to load the actual GUI.
Definition: gui.c:1839
char * gui_pick(void)
Determines which GUI should be used.
Definition: gui.c:1818
void gui_radarGetRes(double *res)
Outputs the radar's resolution.
Definition: gui.c:965
void gui_forceBlink(void)
Force sets the spob and pilot radar blink.
Definition: gui.c:1284
void gui_cleanup(void)
Cleans up the GUI.
Definition: gui.c:1915
void gui_setNav(void)
Player just changed their nav computer target.
Definition: gui.c:1749
void player_message(const char *fmt,...)
Adds a mesg to the queue to be displayed on screen.
Definition: gui.c:330
int hooks_runParam(const char *stack, const HookParam *param)
Runs all the hooks of stack.
Definition: hook.c:967
int hooks_runParamDeferred(const char *stack, const HookParam *param)
Runs all the hooks of stack in the next frame. Does not trigger right away.
Definition: hook.c:935
int hooks_run(const char *stack)
Runs all the hooks of stack.
Definition: hook.c:987
Handles the info menu.
void info_buttonClear(void)
Clears all the registered buttons.
Definition: info.c:241
void input_mouseShow(void)
Shows the mouse.
Definition: input.c:373
void input_enableAll(void)
Enables all the keybinds.
Definition: input.c:342
void input_getKeybindDisplay(const char *keybind, char *buf, int len)
Gets the display name (translated and human-readable) of a keybind.
Definition: input.c:458
void input_mouseHide(void)
Hides the mouse.
Definition: input.c:382
int intro_display(const char *text, const char *mus)
Displays the introduction sequence.
Definition: intro.c:306
void takeoff(int delay, int nosave)
Makes the player take off if landed.
Definition: land.c:1461
unsigned int land_getWid(int window)
Gets the WID of a window by type.
Definition: land.c:963
void land_cleanup(void)
Cleans up some land-related variables.
Definition: land.c:1672
int landed
Definition: land.c:74
void land(Spob *p, int load)
Opens up all the land dialogue stuff.
Definition: land.c:1201
Spob * land_spob
Definition: land.c:82
void land_refuel(void)
Refuels the player's current ship, if possible.
Definition: land.c:807
int outfits_filter(const Outfit **outfits, int n, int(*filter)(const Outfit *o), const char *name)
Applies a filter function and string to a list of outfits.
Definition: land_outfits.c:585
int load_refresh(void)
Loads or refreshes saved games for the player.
Definition: load.c:233
const nsave_t * load_getList(const char *name)
Gets the array (array.h) of loaded saves.
Definition: load.c:483
int lvar_save(const lvar *arr, xmlTextWriterPtr writer)
Saves the mission variables.
Definition: lvar.c:200
lvar * lvar_load(xmlNodePtr parent)
Loads the vars from XML file.
Definition: lvar.c:241
Handles the important game menus.
void menu_main(void)
Opens the main menu (titlescreen).
Definition: menu.c:165
void menu_death(void)
Player death menu, appears when player got creamed.
Definition: menu.c:622
Mission ** player_missions
Definition: mission.c:47
void missions_run(MissionAvailability loc, int faction, const Spob *pnt, const StarSystem *sys)
Runs missions matching location, all Lua side and one-shot.
Definition: mission.c:301
int mission_start(const char *name, unsigned int *id)
Starts a mission.
Definition: mission.c:338
int mission_getID(const char *name)
Gets id from mission name.
Definition: mission.c:98
void missions_cleanup(void)
Cleans up all the player's active missions.
Definition: mission.c:1179
const MissionData * mission_get(int id)
Gets a MissionData based on ID.
Definition: mission.c:114
int music_choose(const char *situation)
Actually runs the music stuff, based on situation.
Definition: music.c:413
Header file with generic functions and naev-specifics.
#define APPNAME
Definition: naev.h:34
const char * naev_version(int long_version)
Returns the version in a human readable string.
Definition: naev_version.c:25
#define MIN(x, y)
Definition: naev.h:40
#define CLAMP(a, b, x)
Definition: naev.h:41
#define ABS(x)
Definition: naev.h:36
#define pow2(x)
Definition: naev.h:46
#define MAX(x, y)
Definition: naev.h:39
#define PATH_MAX
Definition: naev.h:50
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
Definition: ndata.c:154
int news_init(void)
Initiate news linked list with a stack.
Definition: news.c:130
static char buf[NEWS_MAX_LENGTH]
Definition: news.c:45
int lua_isoutfit(lua_State *L, int ind)
Checks to see if ind is a outfit.
Definition: nlua_outfit.c:175
const Outfit * lua_tooutfit(lua_State *L, int ind)
Lua bindings to interact with outfits.
Definition: nlua_outfit.c:110
LuaPilot * lua_pushpilot(lua_State *L, LuaPilot pilot)
Pushes a pilot on the stack.
Definition: nlua_pilot.c:495
int lua_isship(lua_State *L, int ind)
Checks to see if ind is a ship.
Definition: nlua_ship.c:180
const Ship * lua_toship(lua_State *L, int ind)
Lua bindings to interact with ships.
Definition: nlua_ship.c:114
LuaSpob * lua_pushspob(lua_State *L, LuaSpob spob)
Pushes a spob on the stack.
Definition: nlua_spob.c:192
void var_cleanup(void)
Cleans up all the mission variables.
Definition: nlua_var.c:199
int strsort(const void *p1, const void *p2)
Sort function for sorting strings with qsort().
Definition: nstring.c:108
void ntime_set(ntime_t t)
Sets the time absolutely, does NOT generate an event, used at init.
Definition: ntime.c:215
ntime_t ntime_get(void)
Gets the current time.
Definition: ntime.c:108
void ntime_inc(ntime_t t)
Sets the time relatively.
Definition: ntime.c:236
void ntime_getR(int *cycles, int *periods, int *seconds, double *rem)
Gets the current time broken into individual components.
Definition: ntime.c:116
void ntime_setR(int cycles, int periods, int seconds, double rem)
Loads time including remainder.
Definition: ntime.c:224
void gl_screenshot(const char *filename)
Takes a screenshot.
Definition: opengl.c:86
void gl_renderShader(double x, double y, double w, double h, double r, const SimpleShader *shd, const glColour *c, int center)
Renders a simple shader.
void gl_renderLine(double x1, double y1, double x2, double y2, const glColour *c)
Draws a line.
void gl_gameToScreenCoords(double *nx, double *ny, double bx, double by)
Converts in-game coordinates to screen coordinates.
void gl_screenToGameCoords(double *nx, double *ny, int bx, int by)
Converts screen coordinates to in-game coordinates.
void gl_renderCircle(double cx, double cy, double r, const glColour *c, int filled)
Draws a circle.
const Outfit * outfit_get(const char *name)
Gets an outfit by name.
Definition: outfit.c:118
int outfit_isLauncher(const Outfit *o)
Checks if outfit is a weapon launcher.
Definition: outfit.c:498
int outfit_isLocalMap(const Outfit *o)
Checks if outfit is a local space map.
Definition: outfit.c:568
int outfit_compareTech(const void *outfit1, const void *outfit2)
Function meant for use with C89, C99 algorithm qsort().
Definition: outfit.c:195
const Outfit * outfit_getW(const char *name)
Gets an outfit by name without warning on no-find.
Definition: outfit.c:132
int outfit_fitsSlot(const Outfit *o, const OutfitSlot *s)
Checks to see if an outfit fits a slot.
Definition: outfit.c:981
int outfit_isFighterBay(const Outfit *o)
Checks if outfit is a fighter bay.
Definition: outfit.c:550
int outfit_isMap(const Outfit *o)
Checks if outfit is a space map.
Definition: outfit.c:559
int outfit_isLicense(const Outfit *o)
Checks if outfit is a license.
Definition: outfit.c:577
int outfit_isGUI(const Outfit *o)
Checks if outfit is a GUI.
Definition: outfit.c:586
int outfit_licenseExists(const char *name)
Checks to see if a license exists.
Definition: outfit.c:2748
void pause_setSpeed(double mod)
Adjusts the game's dt modifier.
Definition: pause.c:64
int paused
Definition: pause.c:21
void pilot_free(Pilot *p)
Frees and cleans up a pilot.
Definition: pilot.c:3428
void pilot_stackRemove(Pilot *p)
Tries to remove a pilot from the stack.
Definition: pilot.c:3506
credits_t pilot_worth(const Pilot *p)
Gets the price or worth of a pilot in credits.
Definition: pilot.c:3917
void pilot_setThrust(Pilot *p, double thrust)
Sets the pilot's thrust.
Definition: pilot.c:632
int pilot_isHostile(const Pilot *p)
Checks to see if pilot is hostile to the player.
Definition: pilot.c:651
void pilot_cooldown(Pilot *p, int dochecks)
Begins active cooldown, reducing hull and outfit temperatures.
Definition: pilot.c:941
unsigned int pilot_create(const Ship *ship, const char *name, int faction, const char *ai, const double dir, const vec2 *pos, const vec2 *vel, const PilotFlags flags, unsigned int dockpilot, int dockslot)
Creates a new pilot.
Definition: pilot.c:3151
unsigned int pilot_getNearestPilot(const Pilot *p)
Get the nearest pilot to a pilot.
Definition: pilot.c:412
Pilot * pilot_getTarget(Pilot *p)
Gets the target of a pilot using a fancy caching system.
Definition: pilot.c:607
Pilot * pilot_createEmpty(const Ship *ship, const char *name, int faction, PilotFlags flags)
Creates a pilot without adding it to the stack.
Definition: pilot.c:3205
double pilot_getNearestPos(const Pilot *p, unsigned int *tp, double x, double y, int disabled)
Get the nearest pilot to a pilot from a certain position.
Definition: pilot.c:492
ntime_t pilot_hyperspaceDelay(Pilot *p)
Calculates the hyperspace delay for a pilot.
Definition: pilot.c:2855
double pilot_face(Pilot *p, const double dir)
Tries to turn the pilot to face dir.
Definition: pilot.c:773
Pilot * pilot_setPlayer(Pilot *after)
Replaces the player's pilot with an alternate ship with the same ID.
Definition: pilot.c:3300
void pilot_renderOverlay(Pilot *p)
Renders the pilot overlay.
Definition: pilot.c:1968
void pilot_cooldownEnd(Pilot *p, const char *reason)
Terminates active cooldown.
Definition: pilot.c:1004
credits_t pilot_modCredits(Pilot *p, credits_t amount)
Modifies the amount of credits the pilot has.
Definition: pilot.c:2911
void pilot_hyperspaceAbort(Pilot *p)
Stops the pilot from hyperspacing.
Definition: pilot.c:2772
void pilot_setTurn(Pilot *p, double turn)
Sets the pilot's turn.
Definition: pilot.c:640
int pilot_validTarget(const Pilot *p, const Pilot *target)
Checks to see if a pilot is a valid target for another pilot.
Definition: pilot.c:226
void pilot_reset(Pilot *pilot)
Resets a pilot.
Definition: pilot.c:3088
int pilot_isFriendly(const Pilot *p)
Checks to see if pilot is friendly to the player.
Definition: pilot.c:681
PilotOutfitSlot * pilot_getDockSlot(Pilot *p)
Gets the dock slot of the pilot.
Definition: pilot.c:749
Pilot * pilot_get(unsigned int id)
Pulls a pilot out of the pilot_stack based on ID.
Definition: pilot.c:589
int pilot_hasCredits(Pilot *p, credits_t amount)
Checks to see if the pilot has at least a certain amount of credits.
Definition: pilot.c:2897
static Pilot ** pilot_stack
Definition: pilot.c:57
void pilot_render(Pilot *p)
Renders the pilot.
Definition: pilot.c:1826
Pilot *const * pilot_getAll(void)
Gets the pilot stack.
Definition: pilot.c:83
int pilot_canTarget(const Pilot *p)
Same as pilot_validTarget but without the range check.
Definition: pilot.c:243
double pilot_aimAngle(Pilot *p, const vec2 *pos, const vec2 *vel)
Returns the angle for a pilot to aim at another pilot.
Definition: pilot.c:1044
unsigned int pilot_getNextID(unsigned int id, int mode)
Gets the next pilot based on id.
Definition: pilot.c:124
void pilots_cleanAll(void)
Even cleans up the player.
Definition: pilot.c:3635
void pilot_update(Pilot *pilot, double dt)
Updates the pilot.
Definition: pilot.c:2050
unsigned int pilot_getPrevID(unsigned int id, int mode)
Gets the previous pilot based on ID.
Definition: pilot.c:172
int pilot_numOutfit(const Pilot *p, const Outfit *o)
Checks to see how many of an outfit a pilot has.
Definition: pilot.c:2880
void pilot_setTarget(Pilot *p, unsigned int id)
Sets the target of the pilot.
Definition: pilot.c:1351
int pilot_cargoMoveRaw(Pilot *dest, Pilot *src)
Moves cargo from one pilot to another without any checks.
Definition: pilot_cargo.c:65
int pilot_cargoAddRaw(Pilot *pilot, const Commodity *cargo, int quantity, unsigned int id)
Adds cargo without checking the pilot's free space.
Definition: pilot_cargo.c:145
int pilot_inRangePilot(const Pilot *p, const Pilot *target, double *dist2)
Check to see if a pilot is in sensor range of another.
Definition: pilot_ew.c:242
int pilot_inRangeSpob(const Pilot *p, int target)
Check to see if a spob is in sensor range of the pilot.
Definition: pilot_ew.c:277
void pilot_destealth(Pilot *p)
Destealths a pilot.
Definition: pilot_ew.c:549
int pilot_stealth(Pilot *p)
Stealths a pilot.
Definition: pilot_ew.c:513
int pilot_slotsCheckSafety(const Pilot *p)
Pilot slot safety check - makes sure stats are safe.
Definition: pilot_outfit.c:499
int pilot_maxAmmoO(const Pilot *p, const Outfit *o)
Gets the maximum available ammo for a pilot for a specific outfit.
Definition: pilot_outfit.c:767
void pilot_outfitLOnjumpin(Pilot *pilot)
Runs Lua outfits when pilot jumps into a system.
void pilot_calcStats(Pilot *pilot)
Recalculates the pilot's stats based on his outfits.
Definition: pilot_outfit.c:877
int pilot_addAmmo(Pilot *pilot, PilotOutfitSlot *s, int quantity)
Adds some ammo to the pilot stock.
Definition: pilot_outfit.c:661
int pilot_rmOutfitRaw(Pilot *pilot, PilotOutfitSlot *s)
Removes an outfit from the pilot without doing any checks.
Definition: pilot_outfit.c:424
int pilot_outfitLRemove(Pilot *pilot, PilotOutfitSlot *po)
Outfit is removed froma ship.
int pilot_outfitLAdd(Pilot *pilot, PilotOutfitSlot *po)
Outfit is added to a ship.
int pilot_addOutfitRaw(Pilot *pilot, const Outfit *outfit, PilotOutfitSlot *s)
Adds an outfit to the pilot, ignoring CPU or other limits.
Definition: pilot_outfit.c:273
int pilot_isSpaceworthy(const Pilot *p)
Pilot safety check - makes sure stats are safe.
Definition: pilot_outfit.c:528
int pilot_addOutfitIntrinsic(Pilot *pilot, const Outfit *outfit)
Adds an outfit as an intrinsic slot.
Definition: pilot_outfit.c:385
void pilot_outfitLInitAll(Pilot *pilot)
Runs the pilot's Lua outfits init script.
void pilot_weapSetInrange(Pilot *p, int id, int inrange)
Changes the weapon set inrange property.
Definition: pilot_weapon.c:346
void pilot_weaponSafe(Pilot *p)
Sets the weapon set as safe.
int pilot_shoot(Pilot *p, int level)
Makes the pilot shoot.
Definition: pilot_weapon.c:743
void pilot_weapSetManual(Pilot *p, int id, int manual)
Changes the weapon set manual property.
Definition: pilot_weapon.c:372
void pilot_afterburnOver(Pilot *p)
Deactivates the afterburner.
void pilot_shootStop(Pilot *p, int level)
Have pilot stop shooting their weapon.
Definition: pilot_weapon.c:769
void ws_copy(PilotWeaponSet dest[PILOT_WEAPON_SETS], const PilotWeaponSet src[PILOT_WEAPON_SETS])
Copies a weapon set over.
void ws_free(PilotWeaponSet ws[PILOT_WEAPON_SETS])
Frees a weapon set.
void pilot_weapSetAdd(Pilot *p, int id, PilotOutfitSlot *o, int level)
Adds an outfit to a weapon set.
Definition: pilot_weapon.c:431
void pilot_weapSetType(Pilot *p, int id, int type)
Changes the weapon sets mode.
Definition: pilot_weapon.c:314
PilotWeaponSet * pilot_weapSet(Pilot *p, int id)
Gets a weapon set from id.
Definition: pilot_weapon.c:58
int pilot_outfitOffAll(Pilot *p)
Disables all active outfits for a pilot.
void pilot_weaponSetDefault(Pilot *p)
Gives the pilot a default weapon set.
void pilot_weaponAuto(Pilot *p)
Tries to automatically set and create the pilot's weapon set.
void pilot_weapSetPress(Pilot *p, int id, int type)
Handles a weapon set press.
Definition: pilot_weapon.c:165
void player_hailStart(void)
Starts the hail sounds and aborts autoNav.
Definition: player.c:1881
void player_stealth(void)
Input binding for toggling stealth for the player.
Definition: player.c:4565
void player_weapSetPress(int id, double value, int repeat)
Handles keyboard events involving the player's weapon-set keys. It's valid to call this while gamepla...
Definition: player.c:1392
int player_eventAlreadyDone(int id)
Checks to see if player has already completed a event.
Definition: player.c:2971
int player_nships(void)
Gets the amount of ships player has in storage.
Definition: player.c:2633
int player_save(xmlTextWriterPtr writer)
Save the freaking player in a freaking xmlfile.
Definition: player.c:3189
int snd_jump
Definition: player.c:97
int snd_nav
Definition: player.c:98
void player_soundResume(void)
Resumes the ship's sounds.
Definition: player.c:893
static int player_saveShipSlot(xmlTextWriterPtr writer, const PilotOutfitSlot *slot, int i)
Saves an outfit slot.
Definition: player.c:3303
int player_rmOutfit(const Outfit *o, int quantity)
Remove an outfit from the player's outfit stack.
Definition: player.c:2859
void player_runHooks(void)
Runs hooks for the player.
Definition: player.c:3034
static int player_shipsCompare(const void *arg1, const void *arg2)
PlayerShip_t compare function for qsort().
Definition: player.c:2553
void player_updateSpecific(Pilot *pplayer, const double dt)
Does a player specific update.
Definition: player.c:1304
static void player_clearEscorts(void)
Clears escorts to make sure deployment is safe.
Definition: player.c:3058
int player_hasLicense(const char *license)
Checks to see if player has license.
Definition: player.c:2996
void player_autohail(void)
Automatically tries to hail a pilot that hailed the player.
Definition: player.c:2405
void player_dead(void)
Player got pwned.
Definition: player.c:2515
void player_swapShip(const char *shipname, int move_cargo)
Swaps player's current ship with their ship named shipname.
Definition: player.c:501
static void player_renderAimHelper(double dt)
Renders the aim helper.
Definition: player.c:1074
void player_accel(double acc)
Start accelerating.
Definition: player.c:2088
static double player_hailTimer
Definition: player.c:108
int player_ships(char **sships, glTexture **tships)
Returns a buffer with all the player's ships names.
Definition: player.c:2606
void player_targetEscort(int prev)
Targets the pilot.
Definition: player.c:2232
void player_targetAsteroidSet(int field, int id)
Sets the player's target asteroid.
Definition: player.c:1492
static void player_parseShipSlot(xmlNodePtr node, Pilot *ship, PilotOutfitSlot *slot)
Parses a ship outfit slot.
Definition: player.c:4164
static void player_renderStealthUnderlay(double dt)
Renders the stealth overlay for the player.
Definition: player.c:1007
int player_addOutfit(const Outfit *o, int quantity)
Adds an outfit to the player outfit stack.
Definition: player.c:2803
void player_soundPlay(int sound, int once)
Plays a sound at the player.
Definition: player.c:858
static int player_soundReserved
Definition: player.c:813
void player_new(void)
Creates a new player.
Definition: player.c:238
static PlayerShip_t * player_stack
Definition: player.c:113
int snd_hypJump
Definition: player.c:105
void player_warp(double x, double y)
Warps the player to the new position.
Definition: player.c:907
int snd_hypEng
Definition: player.c:102
static int player_parseDoneMissions(xmlNodePtr parent)
Parses player's done missions.
Definition: player.c:3940
static PlayerShip_t * player_newShipMake(const char *name)
Actually creates the new ship.
Definition: player.c:455
static int player_parseEscorts(xmlNodePtr parent)
Parses the escorts from the escort node.
Definition: player.c:4042
double player_right
Definition: player.c:121
credits_t player_shipPrice(const char *shipname)
Calculates the price of one of the player's ships.
Definition: player.c:639
void player_checkLandAck(void)
Revokes landing authorization if the player's reputation is too low.
Definition: player.c:1703
int player_numOutfits(void)
Gets the amount of different outfits in the player outfit stack.
Definition: player.c:2791
static int player_parseShip(xmlNodePtr parent, int is_player)
Parses a player's ship.
Definition: player.c:4198
void player_targetSet(unsigned int id)
Sets the player's target.
Definition: player.c:2112
static int screenshot_cur
Definition: player.c:2295
static void player_tryAddLicense(const char *name)
Tries to get an outfit for the player or looks for equivalents.
Definition: player.c:3678
void player_render(double dt)
Renders the player.
Definition: player.c:955
void player_hailSpob(void)
Opens communication with the player's spob target.
Definition: player.c:2386
void player_resetSpeed(void)
Resets the player speed stuff.
Definition: player.c:1416
static int player_lastEngineSound
Definition: player.c:106
const PlayerShip_t * player_getShipStack(void)
Gets the array (array.h) of the player's ships.
Definition: player.c:2623
static int player_outfitCompare(const void *arg1, const void *arg2)
qsort() compare function for PlayerOutfit_t sorting.
Definition: player.c:2742
void player_targetHyperspaceSet(int id, int nomsg)
Sets the player's hyperspace target.
Definition: player.c:1778
int snd_hail
Definition: player.c:99
static char * player_message_noland
Definition: player.c:78
static int player_parseMetadata(xmlNodePtr parent)
Parses the player metadata.
Definition: player.c:4086
void player_cleanup(void)
Cleans up player stuff like player_stack.
Definition: player.c:697
static int player_parseLicenses(xmlNodePtr parent)
Parses player's licenses.
Definition: player.c:3990
void player_targetHyperspace(void)
Gets a hyperspace target.
Definition: player.c:1813
static double player_timer
Definition: player.c:124
static int * events_done
Definition: player.c:130
int snd_hypPowDown
Definition: player.c:103
PlayerShip_t * player_newShip(const Ship *ship, const char *def_name, int trade, const char *acquired, int noname)
Creates a new ship for player.
Definition: player.c:382
void player_rmShip(const char *shipname)
Removes one of the player's ships.
Definition: player.c:669
int player_outfitOwnedTotal(const Outfit *o)
Definition: player.c:2729
void player_hyperspacePreempt(int preempt)
Enables or disables jump points preempting spobs in autoface and target clearing.
Definition: player.c:1851
PlayerShip_t * player_getPlayerShip(const char *shipname)
Gets a specific ship.
Definition: player.c:2682
void player_toggleMouseFly(void)
Toggles mouse flying.
Definition: player.c:2438
void player_targetNearest(void)
Player targets nearest pilot.
Definition: player.c:2275
static PlayerOutfit_t * player_outfits
Definition: player.c:114
static credits_t player_payback
Definition: player.c:76
double player_dt_default(void)
Returns the player's total default time delta based on time dilation stuff.
Definition: player.c:1871
void player_update(Pilot *pplayer, const double dt)
Player update function.
Definition: player.c:1288
static const Ship * player_tryGetShip(const char *name)
Tries to get an ship for the player or looks for equivalents.
Definition: player.c:3651
const char ** player_getLicenses()
Gets the array (array.h) of license names in the player's inventory.
Definition: player.c:3026
void player_brokeHyperspace(void)
Player actually broke hyperspace (entering new system).
Definition: player.c:1976
static credits_t player_creds
Definition: player.c:75
int player_getHypPreempt(void)
Returns whether the jump point target should preempt the spob target.
Definition: player.c:1861
int player_missionAlreadyDone(int id)
Checks to see if player has already completed a mission.
Definition: player.c:2927
void player_renderUnderlay(double dt)
Renders the player underlay.
Definition: player.c:993
static int player_hailCounter
Definition: player.c:107
int player_addEscorts(void)
Adds the player's escorts.
Definition: player.c:3074
static int player_parseDoneEvents(xmlNodePtr parent)
Parses player's done missions.
Definition: player.c:3965
#define RADAR_RES_DEFAULT
Definition: player.c:88
void player_soundStop(void)
Stops playing player sounds.
Definition: player.c:866
int player_getOutfitsFiltered(const Outfit **outfits, int(*filter)(const Outfit *o), const char *name)
Prepares two arrays for displaying in an image array.
Definition: player.c:2770
void player_restoreControl(int reason, const char *str)
Aborts autonav and other states that take control of the ship.
Definition: player.c:1429
void player_addLicense(const char *license)
Gives the player a license.
Definition: player.c:3012
double player_acc
Definition: player.c:122
credits_t player_modCredits(credits_t amount)
Modifies the amount of credits the player has.
Definition: player.c:947
int * player_eventsDoneList(void)
Gets a list of all the events the player has done.
Definition: player.c:2985
int snd_hypPowUpJump
Definition: player.c:104
int player_jump(void)
Actually attempts to jump in hyperspace.
Definition: player.c:1900
void player_targetSpobSet(int id)
Sets the player's target spob.
Definition: player.c:1453
static int player_filterSuitableSpob(Spob *p)
Filter function for space_getRndSpob.
Definition: player.c:3929
void player_clear(void)
Clears the targets.
Definition: player.c:919
static const Outfit * player_tryGetOutfit(const char *name, int q)
Tries to get an outfit for the player or looks for equivalents.
Definition: player.c:3624
static void player_addOutfitToPilot(Pilot *pilot, const Outfit *outfit, PilotOutfitSlot *s)
Adds outfit to pilot if it can.
Definition: player.c:4138
static void player_spobOutOfRangeMsg(void)
Displays an out of range message for the player's currently selected spob.
Definition: player.c:2348
static int player_runUpdaterScript(const char *type, const char *name, int q)
Runs the save updater script, leaving any result on the stack of naevL.
Definition: player.c:3582
int snd_hypPowUp
Definition: player.c:101
static Spob * player_parse(xmlNodePtr parent)
Parses the player node.
Definition: player.c:3703
int player_hasShip(const char *shipname)
Sees if player has a ship of a name.
Definition: player.c:2644
void player_accelOver(void)
Done accelerating.
Definition: player.c:2102
static int player_gui_group
Definition: player.c:95
void player_think(Pilot *pplayer, const double dt)
Basically uses keyboard input instead of AI input. Used in pilot.c.
Definition: player.c:1142
int snd_target
Definition: player.c:96
int player_land(int loud)
Try to land or target closest spob if no land target.
Definition: player.c:1549
static int player_newMake(void)
Actually creates a new player.
Definition: player.c:302
static int player_thinkMouseFly(void)
Handles mouse flying based on cursor position.
Definition: player.c:2487
static int player_saveShip(xmlTextWriterPtr writer, PlayerShip_t *pship)
Saves a ship.
Definition: player.c:3323
static int player_hyper_group
Definition: player.c:94
void player_soundPause(void)
Pauses the ship's sounds.
Definition: player.c:882
static int player_saveEscorts(xmlTextWriterPtr writer)
Saves the player's escorts.
Definition: player.c:3150
Player_t player
Definition: player.c:73
int player_hasCredits(credits_t amount)
Checks to see if the player has enough credits.
Definition: player.c:936
static int player_engine_group
Definition: player.c:93
void player_shipsSort(void)
Sorts the players ships.
Definition: player.c:2589
void player_brake(void)
Starts braking or active cooldown.
Definition: player.c:2461
void player_missionFinished(int id)
Marks a mission as completed.
Definition: player.c:2896
int player_outfitOwned(const Outfit *o)
Gets how many of the outfit the player owns.
Definition: player.c:2701
void player_targetClearAll(void)
Clears all player targets: hyperspace, spob, asteroid, etc...
Definition: player.c:2219
static int * missions_done
Definition: player.c:129
static char ** player_licenses
Definition: player.c:83
void player_nolandMsg(const char *str)
Sets the no land message.
Definition: player.c:1733
void player_targetPrev(int mode)
Cycles to previous target.
Definition: player.c:2190
const PlayerOutfit_t * player_getOutfits(void)
Gets an array (array.h) of the player's outfits.
Definition: player.c:2757
Spob * player_load(xmlNodePtr parent)
Loads the player stuff.
Definition: player.c:3519
double player_left
Definition: player.c:120
static void player_newSetup()
Sets up a new player.
Definition: player.c:198
static int player_ran_updater
Definition: player.c:77
static const Ship * player_ship
Definition: player.c:74
void player_soundPlayGUI(int sound, int once)
Plays a GUI sound (unaffected by time accel).
Definition: player.c:847
static void player_renderStealthOverlay(double dt)
Renders the stealth overlay for the player.
Definition: player.c:1046
void player_targetClear(void)
Clears the player's ship, spob or hyperspace target, in that order.
Definition: player.c:2198
void player_targetHostile(void)
Targets the nearest hostile enemy to the player.
Definition: player.c:2141
static void player_initSound(void)
Initializes the player sounds.
Definition: player.c:817
static int player_parseInventory(xmlNodePtr parent)
Parses player's inventory.
Definition: player.c:4015
void player_eventFinished(int id)
Marks a event as completed.
Definition: player.c:2951
void player_screenshot(void)
Takes a screenshot.
Definition: player.c:2299
void player_destroyed(void)
Player blew up in a fireball.
Definition: player.c:2528
void player_targetSpob(void)
Cycle through spob targets.
Definition: player.c:1516
int player_init(void)
Initializes player stuff.
Definition: player.c:184
int * player_missionsDoneList(void)
Gets a list of all the missions the player has done.
Definition: player.c:2941
static void player_checkHail(void)
Checks to see if player is still being hailed and clears hail counters if he isn't.
Definition: player.c:2329
Pilot * player_getShip(const char *shipname)
Gets a specific ship.
Definition: player.c:2663
void player_targetNext(int mode)
Cycles to next target.
Definition: player.c:2180
static int player_saveMetadata(xmlTextWriterPtr writer)
Saves the player meta-data.
Definition: player.c:3474
void player_hail(void)
Opens communication with the player's target.
Definition: player.c:2358
void player_autonavEnd(void)
Ends the autonav.
void player_autonavResetSpeed(void)
Resets the game speed.
void player_autonavStart(void)
Starts autonav.
void player_autonavBoard(unsigned int p)
Starts autonav with a pilot to board.
void player_autonavAbort(const char *reason)
Aborts autonav.
void player_thinkAutonav(Pilot *pplayer, double dt)
Handles autonav thinking.
int pfleet_deploy(PlayerShip_t *ps)
Deploys a player's pilot.
Definition: player_fleet.c:109
void pfleet_update(void)
Updates the used fleet capacity of the player.
Definition: player_fleet.c:24
int player_guiAdd(char *name)
Adds a gui to the player.
Definition: player_gui.c:48
char ** player_guiList(void)
Gets the list of GUIs.
Definition: player_gui.c:116
int player_guiCheck(char *name)
Check if player has a GUI.
Definition: player_gui.c:98
void player_guiCleanup(void)
Cleans up the player's GUI list.
Definition: player_gui.c:35
int player_inventoryAdd(const char *name, int amount)
Adds an item to the player inventory.
static PlayerItem * inventory
void player_inventoryClear(void)
Clears the inventory and frees memory.
const PlayerItem * player_inventory(void)
Gets the whole player inventory.
static const double c[]
Definition: rng.c:264
static const double a[]
Definition: rng.c:247
static const double d[]
Definition: rng.c:273
static const double b[]
Definition: rng.c:256
ShipClass ship_classFromString(const char *str)
Gets the machine ship class identifier from a human readable string.
Definition: ship.c:222
const Ship * ship_getW(const char *name)
Gets a ship based on its name without warning.
Definition: ship.c:87
const char * ship_classToString(ShipClass class)
Gets the ship class name in human readable form.
Definition: ship.c:175
const Ship * ship_get(const char *name)
Gets a ship based on its name.
Definition: ship.c:73
void shiplog_clear(void)
Clear the shiplog.
Definition: shiplog.c:355
int sound_createGroup(int size)
Creates a sound group.
Definition: sound.c:1340
void sound_pitchGroup(int group, double pitch)
Sets the pitch of a group.
Definition: sound.c:1616
void sound_resumeGroup(int group)
Resumes all the sounds in a group.
Definition: sound.c:1530
void sound_speedGroup(int group, int enable)
Sets whether or not the speed affects a group.
Definition: sound.c:1562
int sound_playGroup(int group, int sound, int once)
Plays a sound in a group.
Definition: sound.c:1412
void sound_stopGroup(int group)
Stops all the sounds in a group.
Definition: sound.c:1488
void sound_stopAll(void)
Stops all the playing voices.
Definition: sound.c:1052
int sound_get(const char *name)
Gets the buffer to sound of name.
Definition: sound.c:764
void sound_pauseGroup(int group)
Pauses all the sounds in a group.
Definition: sound.c:1508
void sound_volumeGroup(int group, double volume)
Sets the volume of a group.
Definition: sound.c:1586
void sound_setSpeed(double s)
Sets the speed to play the sound at.
Definition: sound.c:1160
void space_init(const char *sysname, int do_simulate)
Initializes the system.
Definition: space.c:1501
void space_gfxUnload(StarSystem *sys)
Unloads all the graphics for a star system.
Definition: space.c:2068
Spob * spob_get(const char *spobname)
Gets a spob based on its name.
Definition: space.c:1006
const char * space_getRndSpob(int landable, unsigned int services, int(*filter)(Spob *p))
Gets the name of a random spob.
Definition: space.c:601
int spob_index(const Spob *p)
Gets the ID of a spob.
Definition: space.c:1055
char spob_getColourChar(const Spob *p)
Gets the spob colour char.
Definition: space.c:1834
StarSystem * system_get(const char *sysname)
Get the system from its name.
Definition: space.c:914
char * spob_getSystem(const char *spobname)
Get the name of a system from a spobname.
Definition: space.c:980
int space_calcJumpInPos(const StarSystem *in, const StarSystem *out, vec2 *pos, vec2 *vel, double *dir, const Pilot *p)
Calculates the jump in pos for a pilot.
Definition: space.c:495
StarSystem * cur_system
Definition: space.c:105
void spob_updateLand(Spob *p)
Updates the land possibilities of a spob.
Definition: space.c:1896
void space_clearKnown(void)
Clears all system knowledge.
Definition: space.c:3633
const char * spob_name(const Spob *p)
Gets the translated name of a spob.
Definition: space.c:1705
void space_gfxLoad(StarSystem *sys)
Loads all the graphics for a star system.
Definition: space.c:2057
int space_hyperspace(Pilot *p)
Tries to get the pilot into hyperspace.
Definition: space.c:471
const char * start_acquired(void)
Gets the module's starting ship was acquired.
Definition: start.c:192
const char * start_event(void)
Gets the starting event of the player.
Definition: start.c:248
const char * start_mission(void)
Gets the starting mission of the player.
Definition: start.c:239
void start_position(double *x, double *y)
Gets the starting position of the player.
Definition: start.c:229
const char * start_chapter(void)
Gets the player's starting chapter.
Definition: start.c:257
const char * start_ship(void)
Gets the module player starting ship.
Definition: start.c:174
ntime_t start_date(void)
Gets the starting date.
Definition: start.c:210
const char * start_shipname(void)
Gets the module's starting ship's name.
Definition: start.c:183
const char * start_system(void)
Gets the starting system name.
Definition: start.c:219
unsigned int start_credits(void)
Gets the player's starting credits.
Definition: start.c:201
Represents an asteroid field anchor.
Definition: asteroid.h:100
double margin
Definition: asteroid.h:115
double radius
Definition: asteroid.h:107
Asteroid * asteroids
Definition: asteroid.h:105
Represents a single asteroid.
Definition: asteroid.h:76
vec2 pos
Definition: asteroid.h:86
int scanned
Definition: asteroid.h:94
Represents a commodity.
Definition: commodity.h:43
char * name
Definition: commodity.h:44
Stores an escort.
Definition: pilot.h:199
unsigned int id
Definition: pilot.h:202
int persist
Definition: pilot.h:204
EscortType_t type
Definition: pilot.h:201
char * ship
Definition: pilot.h:200
The actual hook parameter.
Definition: hook.h:35
const char * str
Definition: hook.h:39
union HookParam::@4 u
HookParamType type
Definition: hook.h:36
LuaAsteroid_t ast
Definition: hook.h:45
int ref
Definition: hook.h:46
Static mission data.
Definition: mission.h:61
char * name
Definition: mission.h:62
char * gui
Definition: outfit.h:291
char * provides
Definition: outfit.h:298
A ship outfit, depends radically on the type.
Definition: outfit.h:304
OutfitGUIData gui
Definition: outfit.h:379
OutfitAfterburnerData afb
Definition: outfit.h:375
union Outfit::@22 u
char * name
Definition: outfit.h:305
OutfitLicenseData lic
Definition: outfit.h:380
Stores a pilot commodity.
Definition: pilot.h:172
const Commodity * commodity
Definition: pilot.h:173
unsigned int id
Definition: pilot.h:175
int quantity
Definition: pilot.h:174
int deployed
Definition: pilot.h:100
int quantity
Definition: pilot.h:99
Stores an outfit the pilot has.
Definition: pilot.h:108
PilotOutfitAmmo ammo
Definition: pilot.h:135
ShipOutfitSlot * sslot
Definition: pilot.h:114
const Outfit * outfit
Definition: pilot.h:112
A pilot Weapon Set Outfit.
Definition: pilot.h:146
A weapon set represents a set of weapons that have an action.
Definition: pilot.h:158
int inrange
Definition: pilot.h:163
PilotWeaponSetOutfit * slots
Definition: pilot.h:161
int manual
Definition: pilot.h:164
The representation of an in-game pilot.
Definition: pilot.h:210
double engine_glow
Definition: pilot.h:371
Solid * solid
Definition: pilot.h:220
double ew_stealth_timer
Definition: pilot.h:272
ShipStats stats
Definition: pilot.h:286
unsigned int id
Definition: pilot.h:211
lvar * shipvar
Definition: pilot.h:373
PilotWeaponSet weapon_sets[PILOT_WEAPON_SETS]
Definition: pilot.h:311
PilotCommodity * commodities
Definition: pilot.h:318
int aimLines
Definition: pilot.h:314
double ew_stealth
Definition: pilot.h:266
PilotOutfitSlot * outfit_structure
Definition: pilot.h:293
credits_t credits
Definition: pilot.h:317
int nav_hyperspace
Definition: pilot.h:337
PilotOutfitSlot ** outfits
Definition: pilot.h:292
PilotOutfitSlot * outfit_utility
Definition: pilot.h:294
PilotOutfitSlot * outfit_intrinsic
Definition: pilot.h:296
const Ship * ship
Definition: pilot.h:219
int lockons
Definition: pilot.h:366
double fuel_max
Definition: pilot.h:252
int nav_anchor
Definition: pilot.h:338
double ptimer
Definition: pilot.h:356
int faction
Definition: pilot.h:215
int autoweap
Definition: pilot.h:313
double landing_delay
Definition: pilot.h:354
double fuel
Definition: pilot.h:253
PilotOutfitSlot * afterburner
Definition: pilot.h:308
char * name
Definition: pilot.h:212
Escort_t * escorts
Definition: pilot.h:326
double fuel_consumption
Definition: pilot.h:254
int active_set
Definition: pilot.h:312
unsigned int target
Definition: pilot.h:334
int nav_spob
Definition: pilot.h:336
PilotOutfitSlot * outfit_weapon
Definition: pilot.h:295
int nav_asteroid
Definition: pilot.h:339
double engine_vol
Definition: conf.h:110
int mouse_thrust
Definition: conf.h:154
double zoom_far
Definition: conf.h:135
int mouse_fly
Definition: conf.h:153
Represents an item in the player inventory.
Wrapper for outfits.
Definition: player.h:65
const Outfit * o
Definition: player.h:66
Player ship.
Definition: player.h:73
time_t acquired_date
Definition: player.h:85
double time_played
Definition: player.h:83
double dmg_done_armour
Definition: player.h:87
unsigned int death_counter
Definition: player.h:93
double dmg_taken_armour
Definition: player.h:89
int deployed
Definition: player.h:80
double dmg_taken_shield
Definition: player.h:88
unsigned int landed_times
Definition: player.h:92
Pilot * p
Definition: player.h:74
int autoweap
Definition: player.h:76
unsigned int ships_destroyed[SHIP_CLASS_TOTAL]
Definition: player.h:90
char * acquired
Definition: player.h:84
unsigned int jumped_times
Definition: player.h:91
PilotWeaponSet weapon_sets[PILOT_WEAPON_SETS]
Definition: player.h:75
double dmg_done_shield
Definition: player.h:86
int favourite
Definition: player.h:77
Pilot * p
Definition: player.h:101
double radar_res
Definition: player.h:125
double dmg_done_shield
Definition: player.h:137
double mousex
Definition: player.h:113
int autonav
Definition: player.h:107
unsigned int jumped_times
Definition: player.h:142
PlayerShip_t ps
Definition: player.h:102
char * name
Definition: player.h:103
char * loaded_version
Definition: player.h:121
double dmg_done_armour
Definition: player.h:138
double autonav_timer
Definition: player.h:112
unsigned int ships_destroyed[SHIP_CLASS_TOTAL]
Definition: player.h:141
time_t last_played
Definition: player.h:134
double dmg_taken_armour
Definition: player.h:140
char * gui
Definition: player.h:124
time_t time_since_save
Definition: player.h:147
int map_minimal
Definition: player.h:127
double time_played
Definition: player.h:135
char * chapter
Definition: player.h:116
time_t date_created
Definition: player.h:136
int fleet_capacity
Definition: player.h:131
double dmg_taken_shield
Definition: player.h:139
double speed
Definition: player.h:115
char * difficulty
Definition: player.h:117
double mousey
Definition: player.h:114
unsigned int death_counter
Definition: player.h:144
unsigned int landed_times
Definition: player.h:143
int eq_outfitMode
Definition: player.h:126
OutfitSlot slot
Definition: ship.h:71
double ew_detect
Definition: shipstats.h:244
int misc_reverse_thrust
Definition: shipstats.h:299
double time_mod
Definition: shipstats.h:308
double asteroid_scan
Definition: shipstats.h:300
Represents a space ship.
Definition: ship.h:94
double dt_default
Definition: ship.h:123
glTexture * gfx_space
Definition: ship.h:137
char * name
Definition: ship.h:95
int sound
Definition: ship.h:152
double engine_pitch
Definition: ship.h:153
glTexture * gfx_store
Definition: ship.h:140
char * gui
Definition: ship.h:149
vec2 vel
Definition: physics.h:21
double dir
Definition: physics.h:19
vec2 pos
Definition: physics.h:22
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition: space.h:88
int can_land
Definition: space.h:106
char * land_msg
Definition: space.h:108
int land_override
Definition: space.h:107
int lua_land
Definition: space.h:140
double radius
Definition: space.h:94
nlua_env lua_env
Definition: space.h:134
char * name
Definition: space.h:90
vec2 pos
Definition: space.h:93
int lua_can_land
Definition: space.h:139
Abstraction for rendering sprite sheets.
Definition: opengl_tex.h:34
double sw
Definition: opengl_tex.h:44
Contains a mission variable.
Definition: lvar.h:24
Definition: msgcat.c:199
Represents a 2d vector.
Definition: vec2.h:32
double y
Definition: vec2.h:34
double x
Definition: vec2.h:33
int toolkit_isOpen(void)
Checks to see if the toolkit is open.
Definition: toolkit.c:95
void diff_clear(void)
Removes all active diffs. (Call before economy_destroy().)
Definition: unidiff.c:1472