naev 0.11.5
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 "board.h"
20#include "camera.h"
21#include "claim.h"
22#include "comm.h"
23#include "conf.h"
24#include "dialogue.h"
25#include "difficulty.h"
26#include "economy.h"
27#include "equipment.h"
28#include "escort.h"
29#include "event.h"
30#include "font.h"
31#include "gui.h"
32#include "gui_omsg.h"
33#include "hook.h"
34#include "info.h"
35#include "input.h"
36#include "intro.h"
37#include "land.h"
38#include "land_outfits.h"
39#include "load.h"
40#include "log.h"
41#include "map.h"
42#include "map_overlay.h"
43#include "menu.h"
44#include "mission.h"
45#include "music.h"
46#include "ndata.h"
47#include "news.h"
48#include "nfile.h"
49#include "nlua_misn.h"
50#include "nlua_outfit.h"
51#include "nlua_ship.h"
52#include "nlua_var.h"
53#include "nstring.h"
54#include "ntime.h"
55#include "nxml.h"
56#include "opengl.h"
57#include "pause.h"
58#include "pilot.h"
59#include "player_gui.h"
60#include "player_fleet.h"
61#include "player_inventory.h"
62#include "rng.h"
63#include "shiplog.h"
64#include "sound.h"
65#include "space.h"
66#include "spfx.h"
67#include "start.h"
68#include "toolkit.h"
69#include "unidiff.h"
70
71/*
72 * Player stuff
73 */
75static const Ship* player_ship = NULL;
76static credits_t player_creds = 0;
77static credits_t player_payback = 0;
78static int player_ran_updater = 0;
79static char *player_message_noland = NULL;
81/*
82 * Licenses.
83 */
84static char **player_licenses = NULL;
86/*
87 * Default radar resolution.
88 */
89#define RADAR_RES_DEFAULT 50.
91/*
92 * player sounds.
93 */
94static int player_engine_group = -1;
95static int player_hyper_group = -1;
96static int player_gui_group = -1;
97int snd_target = -1;
98int snd_jump = -1;
99int snd_nav = -1;
100int snd_hail = -1;
101/* Hyperspace sounds. */
102int snd_hypPowUp = -1;
103int snd_hypEng = -1;
106int snd_hypJump = -1;
107static int player_lastEngineSound = -1;
108static int player_hailCounter = 0;
109static double player_hailTimer = 0.;
111/*
112 * Player pilot stack (ships they have) and outfit (outfits they have) stacks (array.h)
113 */
117/*
118 * player global properties
119 */
120/* used in input.c */
121double player_left = 0.;
122double player_right = 0.;
123double player_acc = 0.;
124/* for death and such */
125static double player_timer = 0.;
127/*
128 * unique mission and event stack.
129 */
130static int* missions_done = NULL;
131static int* events_done = NULL;
133/*
134 * prototypes
135 */
136/*
137 * internal
138 */
139static void player_checkHail (void);
140/* creation */
141static void player_newSetup();
142static int player_newMake (void);
143static PlayerShip_t* player_newShipMake( const char* name );
144/* sound */
145static void player_initSound (void);
146/* save/load */
147static int player_saveEscorts( xmlTextWriterPtr writer );
148static int player_saveShipSlot( xmlTextWriterPtr writer, const PilotOutfitSlot *slot, int i );
149static int player_saveShip( xmlTextWriterPtr writer, PlayerShip_t *pship );
150static int player_saveMetadata( xmlTextWriterPtr writer );
151static Spob* player_parse( xmlNodePtr parent );
152static int player_parseDoneMissions( xmlNodePtr parent );
153static int player_parseDoneEvents( xmlNodePtr parent );
154static int player_parseLicenses( xmlNodePtr parent );
155static int player_parseInventory( xmlNodePtr parent );
156static void player_parseShipSlot( xmlNodePtr node, Pilot *ship, PilotOutfitSlot *slot );
157static int player_parseShip( xmlNodePtr parent, int is_player );
158static int player_parseEscorts( xmlNodePtr parent );
159static int player_parseMetadata( xmlNodePtr parent );
160static void player_addOutfitToPilot( Pilot* pilot, const Outfit* outfit, PilotOutfitSlot *s );
161static int player_runUpdaterScript( const char* type, const char* name, int q );
162static const Outfit* player_tryGetOutfit( const char* name, int q );
163static const Ship* player_tryGetShip( const char* name );
164static void player_tryAddLicense( const char* name );
165/* Render. */
166static void player_renderStealthUnderlay( double dt );
167static void player_renderStealthOverlay( double dt );
168static void player_renderAimHelper( double dt );
169/* Misc. */
170static int player_filterSuitableSpob( Spob *p );
171static void player_spobOutOfRangeMsg (void);
172static int player_outfitCompare( const void *arg1, const void *arg2 );
173static int player_thinkMouseFly( double dt );
174static int preemption = 0; /* Hyperspace target/untarget preemption. */
175
176/*
177 * externed
178 */
179int player_save( xmlTextWriterPtr writer ); /* save.c */
180Spob* player_load( xmlNodePtr parent ); /* save.c */
181
185int player_init (void)
186{
187 if (player_stack==NULL)
189 if (player_outfits==NULL)
192 memset( &player, 0, sizeof(PlayerShip_t) );
193
194 player_autonavInit();
195
196 return 0;
197}
198
202static void player_newSetup()
203{
204 double x, y;
205
206 /* Setup sound */
208
209 /* Clean up player stuff if we'll be recreating. */
211
212 /* Set up GUI. */
215
216 /* Sane time defaults. */
217 player.last_played = time(NULL);
220 player.chapter = strdup( start_chapter() );
221
222 /* For pretty background. */
224 space_init( start_system(), 1 );
225 start_position( &x, &y );
226
227 cam_setTargetPos( x, y, 0 );
228 cam_setZoom( conf.zoom_far );
229
230 /* Clear the init message for new game. */
232}
233
242void player_new (void)
243{
244 int invalid = 1;
245
246 /* Set up new player. */
248
249 /* Some meta-data. */
250 player.date_created = time(NULL);
251
252 do {
253 const char *SAVEPATH = "_tmp";
254 char buf[PATH_MAX];
255
256 /* Get the name. */
257 player.name = dialogue_input( _("Player Name"), 1, 60,
258 _("Please write your name:") );
259
260 /* Player cancelled dialogue. */
261 if (player.name == NULL) {
262 menu_main();
263 return;
264 }
265
266 /* Try to see if we can save the game for a valid player name. */
267 snprintf( buf, sizeof(buf), "%s/%s", SAVEPATH, player.name );
268 if (PHYSFS_mkdir(buf)==0) /* In particular should be PHYSFS_ERR_BAD_FILENAME error. */
269 dialogue_alert(_("'%s' is an invalid player name as it can not be saved to your filesystem! Please choose another."), player.name);
270 else {
271 int ret = PHYSFS_delete( buf );
272 if (ret==0)
273 WARN(_("Unable to delete temporary file '%s': %s"), buf, PHYSFS_getErrorByCode( PHYSFS_getLastErrorCode() ));
274 else {
275 ret = PHYSFS_delete( SAVEPATH );
276 if (ret==0)
277 WARN(_("Unable to delete temporary file '%s': %s"), SAVEPATH, PHYSFS_getErrorByCode( PHYSFS_getLastErrorCode() ));
278 }
279 invalid = 0;
280 }
281 PHYSFS_getLastErrorCode(); /* Clear error code. */
282 } while (invalid);
283
284 load_refresh();
285 if (array_size( load_getList( player.name ) ) > 0) {
286 int r = dialogue_YesNo(_("Overwrite"),
287 _("You already have a pilot named %s. Their autosave and backup save will be overwritten. Do you wish to continue?"), player.name);
288 if (r==0) { /* no */
289 player_new();
290 return;
291 }
292 }
293
294 if (player_newMake())
295 return;
296
297 /* Display the intro. */
298 intro_display( INTRO_PATH, "intro" );
299
300 /* Play music. */
301 music_choose( "ambient" );
302
303 /* Set loaded version. */
304 player.loaded_version = strdup( naev_version(0) );
305
306 /* Add the mission if found. */
307 if (start_mission() != NULL) {
308 if (mission_start(start_mission(), NULL) < 0)
309 WARN(_("Failed to run start mission '%s'."), start_mission());
310 }
311
312 /* Add the event if found. */
313 if (start_event() != NULL) {
314 if (event_start( start_event(), NULL ))
315 WARN(_("Failed to run start event '%s'."), start_event());
316 }
317
318 /* Run the load event trigger. */
319 events_trigger( EVENT_TRIGGER_LOAD );
320
321 /* Load the GUI. */
322 gui_load( gui_pick() );
323}
324
330static int player_newMake (void)
331{
332 const Ship *ship;
333 const char *shipname, *acquired;
334 double x,y;
335 PlayerShip_t *ps;
336
337 if (player_stack==NULL)
339 if (player_outfits==NULL)
341
342 /* Time. */
344 /* Clear known economy info */
346 /* Welcome message - must be before space_init. */
347 player_message( _("#gWelcome to %s!"), APPNAME );
348 player_message( "#g v%s", naev_version(0) );
349
350 /* Try to create the pilot, if fails reask for player name. */
351 ship = ship_get( start_ship() );
352 shipname = _(start_shipname());
353 if (ship==NULL) {
354 WARN(_("Ship not properly set by module."));
355 return -1;
356 }
357 acquired = _(start_acquired());
358 /* Setting a default name in the XML prevents naming prompt. */
359 ps = player_newShip( ship, shipname, 0, acquired, (shipname==NULL) ? 0 : 1 );
360 if (ps == NULL) {
361 player_new();
362 return -1;
363 }
364 assert( &player.ps == ps );
365 start_position( &x, &y );
366 vec2_cset( &player.p->solid.pos, x, y );
367 vectnull( &player.p->solid.vel );
368 player.p->solid.dir = RNGF() * 2.*M_PI;
369 space_init( start_system(), 1 );
370
371 /* Bind camera. */
373
374 /* Set player speed to default 1 */
375 player.speed = 1.;
376
377 /* Reset speed (to make sure time dilation stuff is accounted for). */
379
380 /* Monies. */
382
383 /* clear the map */
384 map_clear();
385
386 /* Start the economy. */
387 economy_init();
388
389 /* clear the shiplog*/
391
392 /* Start the news */
393 news_init();
394
395 return 0;
396}
397
410PlayerShip_t* player_newShip( const Ship* ship, const char *def_name,
411 int trade, const char *acquired, int noname )
412{
413 char *ship_name;
414 PlayerShip_t *ps;
415
416 /* temporary values while player doesn't exist */
417 player_creds = (player.p != NULL) ? player.p->credits : 0;
418 player_ship = ship;
419 if (!noname)
420 ship_name = dialogue_input( _("Ship Name"), 1, 60,
421 _("Please name your new ship:") );
422 else
423 ship_name = NULL;
424
425 /* Dialogue cancelled. */
426 if (ship_name == NULL) {
427 int i, len;
428
429 /* No default name, fail. */
430 if (def_name == NULL)
431 return NULL;
432
433 /* Add default name. */
434 i = 2;
435 len = strlen(def_name)+10;
436 ship_name = malloc( len );
437 strcpy( ship_name, def_name );
438 while (player_hasShip(ship_name)) {
439 snprintf( ship_name, len, "%s %d", def_name, i );
440 i++;
441 }
442 }
443
444 /* Must not have same name. */
445 if (player_hasShip(ship_name)) {
446 dialogue_msg( _("Name collision"),
447 _("Please do not give the ship the same name as another of your ships."));
448 free( ship_name );
449 return NULL;
450 }
451 if (trade && player.p == NULL)
452 ERR(_("Player ship isn't valid… This shouldn't happen!"));
453
454 ps = player_newShipMake( ship_name );
455 ps->autoweap = 1;
456 ps->favourite = 0;
457 ps->p->shipvar= array_create( lvar );
458 ps->acquired = (acquired!=NULL) ? strdup( acquired ) : NULL;
459 ps->acquired_date = ntime_get();
460
461 /* Player is trading ship in. */
462 if (trade) {
463 const char *old_name = player.p->name;
464 player_swapShip( ship_name, 1 ); /* Move to the new ship. */
465 player_rmShip( old_name );
466 }
467
468 free(ship_name);
470
471 /* Update ship list if landed. */
472 if (landed) {
473 int w = land_getWid( LAND_WINDOW_EQUIPMENT );
474 equipment_regenLists( w, 0, 1 );
475 }
476
477 return ps;
478}
479
483static PlayerShip_t *player_newShipMake( const char *name )
484{
485 PilotFlags flags;
486 PlayerShip_t *ps;
487
488 /* store the current ship if it exists */
489 pilot_clearFlagsRaw( flags );
490 pilot_setFlagRaw( flags, PILOT_PLAYER );
491 pilot_setFlagRaw( flags, PILOT_NO_EQUIP ); /* We want to give default outfits though. */
492
493 /* in case we're respawning */
494 player_rmFlag( PLAYER_CREATING );
495
496 /* Grow memory. */
497 ps = (player.p == NULL) ? &player.ps : &array_grow( &player_stack );
498 memset( ps, 0, sizeof(PlayerShip_t) );
499 pilot_setFlagRaw( flags, PILOT_PLAYER_FLEET );
500 /* Create the ship. */
501 ps->p = pilot_createEmpty( player_ship, name, faction_get("Player"), flags );
502 if (player.p == NULL) {
503 pilot_reset( ps->p );
504 pilot_setPlayer( ps->p );
505 }
506 /* Initialize parent weapon sets. */
507 ws_copy( ps->weapon_sets, ps->p->weapon_sets );
508
509 if (player.p == NULL)
510 ERR(_("Something seriously wonky went on, newly created player does not exist, bailing!"));
511
512 /* money. */
514 player_creds = 0;
515 player_payback = 0;
516
517 return ps;
518}
519
526void player_swapShip( const char *shipname, int move_cargo )
527{
528 HookParam hparam[5];
529 Pilot *ship;
530 vec2 v;
531 double dir;
532 int removed, hyptarget;
533 PlayerShip_t *ps = NULL;
534 PlayerShip_t ptemp;
535
536 /* Try to find the ship. */
537 for (int i=0; i<array_size(player_stack); i++) {
538 if (strcmp(shipname,player_stack[i].p->name)==0) {
539 ps = &player_stack[i];
540 break;
541 }
542 }
543 if (ps==NULL) {
544 WARN( _("Unable to swap player.p with ship '%s': ship does not exist!"), shipname );
545 return;
546 }
547
548 /* Save some variables to restore later. */
549 hyptarget = player.p->nav_hyperspace;
550
551 /* Run onremove hook for all old outfits. */
552 for (int i=0; i<array_size(player.p->outfits); i++)
554
555 /* Get rid of deployed escorts and swap existing escorts. */
557 escort_freeList( ps->p );
558 ps->p->escorts = array_create( Escort_t );
559 /* Just copying the array over has unforeseen consequences, so recreate. */
560 for (int i=0; i<array_size(player.p->escorts); i++) {
561 const Escort_t *e = &player.p->escorts[i];
562 Escort_t ne = *e;
563
564 /* Must not be new ship. */
565 if (e->id == ps->p->id )
566 continue;
567
568 ne.ship = e->ship; /* Might be worth having an escort_copy function. */
569 array_push_back( &ps->p->escorts, ne );
570 }
572
573 /* Swap information over. */
574 ptemp = player.ps;
575 player.ps= *ps;
576 *ps = ptemp;
577 ship = player.ps.p;
578
579 /* Move credits over */
580 ship->credits = player.p->credits;
581
582 /* Copy target info */
583 ship->target = player.p->target;
584 ship->nav_spob = player.p->nav_spob;
586 ship->nav_anchor = player.p->nav_anchor;
588
589 /* Store position. */
590 v = player.p->solid.pos;
591 dir = player.p->solid.dir;
592
593 /* Copy over weapon sets. */
595
596 /* If the pilot is deployed, we must redeploy. */
597 removed = 0;
598 if (ps->p->id > 0) {
599 pilot_stackRemove( ps->p );
600 removed = 1;
601 }
602 pilot_setPlayer( ship );
603 player.ps.deployed = 0; /* Player themselves can't be deployed. */
604 if (ps->deployed)
605 pfleet_deploy( ps );
606
607 /* Extra pass to calculate stats */
609 pilot_calcStats( ps->p );
610
611 /* Run onadd hook for all new outfits. */
612 for (int j=0; j<array_size(ship->outfits); j++)
613 pilot_outfitLAdd( ship, ship->outfits[j] );
614
615 /* Move cargo over. */
616 if (move_cargo) {
618 pfleet_update(); /* Update fleet and move cargo. */
619 }
620
621 /* Clean up, AFTER cargo is updated. */
622 if (!ps->deployed && removed)
623 pilot_free( ps->p ); /* Has PILOT_NOFREE flag. */
624
625 /* Copy position back. */
626 player.p->solid.pos = v;
627 player.p->solid.dir = dir;
628
629 /* Fill the tank. */
630 if (landed)
631 land_refuel();
632
633 /* Clear targets. */
635 player.p->nav_hyperspace = hyptarget; /* Special case restore hyperspace target. */
636
637 /* Set some gui stuff. */
638 gui_load( gui_pick() );
639
640 /* Bind camera. */
642
643 /* Recompute stuff if necessary. */
646
647 /* Run hook. */
648 hparam[0].type = HOOK_PARAM_STRING;
649 hparam[0].u.str = player.p->name;
650 hparam[1].type = HOOK_PARAM_SHIP;
651 hparam[1].u.ship = player.p->ship;
652 hparam[2].type = HOOK_PARAM_STRING;
653 hparam[2].u.str = ps->p->name;
654 hparam[3].type = HOOK_PARAM_SHIP;
655 hparam[3].u.ship = ps->p->ship;
656 hparam[4].type = HOOK_PARAM_SENTINEL;
657 hooks_runParam( "ship_swap", hparam );
658}
659
667credits_t player_shipPrice( const char *shipname, int count_unique )
668{
669 Pilot *ship = NULL;
670
671 if (strcmp(shipname,player.p->name)==0)
672 ship = player.p;
673 else {
674 /* Find the ship. */
675 for (int i=0; i<array_size(player_stack); i++) {
676 if (strcmp(shipname,player_stack[i].p->name)==0) {
677 ship = player_stack[i].p;
678 break;
679 }
680 }
681 }
682
683 /* Not found. */
684 if (ship == NULL) {
685 WARN( _("Unable to find price for player's ship '%s': ship does not exist!"), shipname );
686 return -1;
687 }
688
689 return pilot_worth( ship, count_unique );
690}
691
692void player_rmPlayerShip( PlayerShip_t *ps )
693{
694 pilot_rmFlag( ps->p, PILOT_NOFREE );
695 pilot_free( ps->p );
696 ws_free( ps->weapon_sets );
697 free( ps->acquired );
698}
699
705void player_rmShip( const char *shipname )
706{
707 for (int i=0; i<array_size(player_stack); i++) {
708 PlayerShip_t *ps = &player_stack[i];
709
710 /* Not the ship we are looking for. */
711 if (strcmp(shipname,ps->p->name)!=0)
712 continue;
713
714 /* Free player ship. */
715 player_rmPlayerShip( ps );
716
717 array_erase( &player_stack, ps, ps+1 );
718 }
719
720 /* Update ship list if landed. */
721 if (landed) {
722 int w = land_getWid( LAND_WINDOW_EQUIPMENT );
723 equipment_regenLists( w, 0, 1 );
724 }
725}
726
730void player_cleanup (void)
731{
732 /* Enable all input. */
734
735 /* Clean up other stuff. */
736 land_cleanup(); /* Should be first. */
737 diff_clear();
738 var_cleanup();
742 map_cleanup();
745
746 /* Reset controls. */
748 player_left = 0.;
749 player_right = 0.;
750
751 /* Clear player. */
752 player_clear();
753
754 /* Clear hail timer. */
756 player_hailTimer = 0.;
757
758 /* Clear messages. */
760
761 /* Reset factions. */
763
764 /* Free stuff. */
765 free(player.name);
766 player.name = NULL;
767 free( player.ps.acquired );
768 player.ps.acquired = NULL;
770
773
774 /* Clean up gui. */
775 gui_cleanup();
777 ovr_setOpen(0);
778
779 /* Clear up info buttons. */
780 info_buttonClear();
781
783 player_outfits = NULL;
784
786 missions_done = NULL;
787
789 events_done = NULL;
790
791 /* Clean up licenses. */
792 for (int i=0; i<array_size(player_licenses); i++)
793 free(player_licenses[i]);
795 player_licenses = NULL;
796
797 /* Clear claims. */
798 claim_clear();
799
800 /* Purge the pilot stack, and player.p. */
802
803 /* clean up the stack */
804 for (int i=0; i<array_size(player_stack); i++)
805 player_rmPlayerShip( &player_stack[i] );
807 player_stack = NULL;
808 /* nothing left */
809
810 /* Reset some player stuff. */
811 player_creds = 0;
812 player_payback = 0;
813 free( player.gui );
814 player.gui = NULL;
815 free( player.chapter );
816 player.chapter = NULL;
817 free( player.difficulty );
818 player.difficulty = NULL;
819
820 /* Clear omsg. */
821 omsg_cleanup();
822
823 /* Stop the sounds. */
825
826 /* Clean up local difficulty. */
827 difficulty_setLocal( NULL );
828
829 /* Reset time compression. */
830 pause_setSpeed( 1. );
831 sound_setSpeed( 1. );
832
833 free( player.loaded_version );
834 player.loaded_version = NULL;
835
836 /* Clean up. */
837 memset( &player, 0, sizeof(Player_t) );
838 player_setFlag(PLAYER_CREATING);
839}
840
841static int player_soundReserved = 0;
845static void player_initSound (void)
846{
848 return;
849
850 /* Allocate channels. */
851 player_engine_group = sound_createGroup(1); /* Channel for engine noises. */
854 sound_speedGroup( player_gui_group, 0 ); /* Disable pitch shift. */
856
857 /* Get sounds. */
858 snd_target = sound_get("target");
859 snd_jump = sound_get("jump");
860 snd_nav = sound_get("nav");
861 snd_hail = sound_get("hail");
862 snd_hypPowUp = sound_get("hyperspace_powerup");
863 snd_hypEng = sound_get("hyperspace_engine");
864 snd_hypPowDown = sound_get("hyperspace_powerdown");
865 snd_hypPowUpJump = sound_get("hyperspace_powerupjump");
866 snd_hypJump = sound_get("hyperspace_jump");
867}
868
875void player_soundPlayGUI( int sound, int once )
876{
877 sound_playGroup( player_gui_group, sound, once );
878}
879
886void player_soundPlay( int sound, int once )
887{
888 sound_playGroup( player_hyper_group, sound, once );
889}
890
895{
896 if (player_gui_group >= 0)
898 if (player_engine_group >= 0)
900 if (player_hyper_group >= 0)
902
903 /* No last engine sound. */
905}
906
917
928
935void player_warp( double x, double y )
936{
937 unsigned int target = cam_getTarget();
938 vec2_cset( &player.p->solid.pos, x, y );
939 /* Have to move camera over to avoid moving stars when loading. */
940 if (target == player.p->id)
941 cam_setTargetPilot( target, 0 );
942}
943
947void player_clear (void)
948{
949 if (player.p != NULL) {
952 }
953
954 /* Clear the noland flag. */
955 player_rmFlag( PLAYER_NOLAND );
956}
957
964int player_hasCredits( credits_t amount )
965{
966 return pilot_hasCredits( player.p, amount );
967}
968
975credits_t player_modCredits( credits_t amount )
976{
977 return pilot_modCredits( player.p, amount );
978}
979
983void player_render( double dt )
984{
985 /*
986 * Check to see if the death menu should pop up.
987 */
988 if (player_isFlag(PLAYER_DESTROYED)) {
989 player_timer -= dt;
990 if (!toolkit_isOpen() && !player_isFlag(PLAYER_CREATING) &&
991 (player_timer < 0.))
992 menu_death();
993 }
994
995 /* Skip rendering. */
996 if ((player.p == NULL) || (player.p->id == 0) || player_isFlag(PLAYER_CREATING) ||
997 pilot_isFlag( player.p, PILOT_HIDE))
998 return;
999
1000 /* Render stealth overlay. */
1001 if (pilot_isFlag( player.p, PILOT_STEALTH ))
1003
1004 /* Render the aiming lines. */
1005 if ((player.p->target != PLAYER_ID) && player.p->aimLines
1006 && !pilot_isFlag( player.p, PILOT_HYPERSPACE ) && !pilot_isFlag( player.p, PILOT_DISABLED )
1007 && !pilot_isFlag( player.p, PILOT_LANDING ) && !pilot_isFlag( player.p, PILOT_TAKEOFF )
1008 && !player_isFlag( PLAYER_CINEMATICS_GUI ))
1010
1011 /* Render the player's pilot. */
1013
1014 /* Render the player's overlay. */
1016}
1017
1021void player_renderUnderlay( double dt )
1022{
1023 /* Skip rendering. */
1024 if ((player.p == NULL) || player_isFlag(PLAYER_CREATING) ||
1025 pilot_isFlag( player.p, PILOT_HIDE))
1026 return;
1027
1028 if (pilot_isFlag( player.p, PILOT_STEALTH ))
1030}
1031
1035static void player_renderStealthUnderlay( double dt )
1036{
1037 (void) dt;
1038 double detectz;
1039 glColour col;
1040 Pilot *const* ps;
1041
1042 /* Don't display if overlay is open. */
1043 if (ovr_isOpen())
1044 return;
1045
1046 /* Iterate and draw for all pilots. */
1047 detectz = player.p->ew_stealth * cam_getZoom();
1048 col = cRed;
1049 col.a = 0.3;
1050 ps = pilot_getAll();
1051 for (int i=0; i<array_size(ps); i++) {
1052 double x, y, r;
1053 Pilot *t = ps[i];
1055 continue;
1056 if (pilot_isDisabled(t))
1057 continue;
1058 /* Only show pilots the player can see. */
1059 if (!pilot_validTarget( player.p, t ))
1060 continue;
1061
1062 gl_gameToScreenCoords( &x, &y, t->solid.pos.x, t->solid.pos.y );
1063 r = detectz * t->stats.ew_detect;
1064 if (r > 0.) {
1065 glUseProgram( shaders.stealthaura.program );
1066 gl_renderShader( x, y, r, r, 0., &shaders.stealthaura, &col, 1 );
1067 }
1068 }
1069}
1070
1074static void player_renderStealthOverlay( double dt )
1075{
1076 (void) dt;
1077 double x, y, r, st, z;
1078 glColour col;
1079
1080 z = cam_getZoom();
1082
1083 /* Determine the arcs. */
1085
1086 /* We do red to yellow. */
1087 col_blend( &col, &cYellow, &cRed, st );
1088 col.a = 0.5;
1089
1090 /* Determine size. */
1091 r = 1.2/2. * (double)player.p->ship->gfx_space->sw;
1092
1093 /* Draw the main circle. */
1094 glUseProgram( shaders.stealthmarker.program );
1095 glUniform1f( shaders.stealthmarker.paramf, st );
1096 gl_renderShader( x, y, r*z, r*z, 0., &shaders.stealthmarker, &col, 1 );
1097}
1098
1102static void player_renderAimHelper( double dt )
1103{
1104 (void) dt;
1105 double a, b, d, x1, y1, x2, y2, r, theta;
1106 glColour c, c2;
1107 Pilot *target;
1108
1109 target = pilot_getTarget( player.p );
1110 if (target == NULL)
1111 return;
1112
1113 a = player.p->solid.dir;
1114 r = 200.;
1116
1117 b = pilot_aimAngle( player.p, &target->solid.pos, &target->solid.vel );
1118
1119 theta = 22.*M_PI/180.;
1120
1121 /* The angular error will give the exact colour that is used. */
1122 d = ABS( angle_diff(a,b) / (2*theta) );
1123 d = MIN( 1, d );
1124
1125 c = cInert;
1126 c.a = 0.3;
1127 gl_gameToScreenCoords( &x2, &y2, player.p->solid.pos.x + r*cos( a+theta ),
1128 player.p->solid.pos.y + r*sin( a+theta ) );
1129 gl_renderLine( x1, y1, x2, y2, &c );
1130 gl_gameToScreenCoords( &x2, &y2, player.p->solid.pos.x + r*cos( a-theta ),
1131 player.p->solid.pos.y + r*sin( a-theta ) );
1132 gl_renderLine( x1, y1, x2, y2, &c );
1133
1134 c.r = d*0.9;
1135 c.g = d*0.2 + (1.-d)*0.8;
1136 c.b = (1-d)*0.2;
1137 c.a = 0.7;
1138 col_gammaToLinear( &c );
1139 gl_gameToScreenCoords( &x2, &y2, player.p->solid.pos.x + r*cos( a ),
1140 player.p->solid.pos.y + r*sin( a ) );
1141
1142 gl_renderLine( x1, y1, x2, y2, &c );
1143
1144 c2 = cWhite;
1145 c2.a = 0.7;
1146 glUseProgram(shaders.crosshairs.program);
1147 glUniform1f(shaders.crosshairs.paramf, 1.);
1148 gl_renderShader( x2, y2, 7, 7, 0., &shaders.crosshairs, &c2, 1 );
1149
1150 gl_gameToScreenCoords( &x2, &y2, player.p->solid.pos.x + r*cos( b ),
1151 player.p->solid.pos.y + r*sin( b ) );
1152
1153 c.a = 0.4;
1154 gl_renderLine( x1, y1, x2, y2, &c );
1155
1156 /* TODO this should be converted into a single SDF call. */
1157 glColour c3 = cBlack;
1158 c3.a = c2.a;
1159 gl_renderCircle( x2, y2, 8., &c3, 0 );
1160 gl_renderCircle( x2, y2, 10., &c3, 0 );
1161 gl_renderCircle( x2, y2, 9., &c2, 0 );
1162}
1163
1170void player_think( Pilot* pplayer, const double dt )
1171{
1172 Pilot *target;
1173 int facing, fired;
1174
1175 /* last i heard, the dead don't think */
1176 if (pilot_isFlag(pplayer,PILOT_DEAD)) {
1177 /* no sense in accelerating or turning */
1178 pilot_setAccel( pplayer, 0. );
1179 pilot_setTurn( pplayer, 0. );
1180 return;
1181 }
1182
1183 /* We always have to run ai_think in the case the player has escorts so that
1184 * they properly form formations, however, we only have to do the task under manual control.. */
1185 ai_think( pplayer, dt, pilot_isFlag(pplayer, PILOT_MANUAL_CONTROL) );
1186
1187 /* Under manual control is special. */
1188 if (pilot_isFlag( pplayer, PILOT_MANUAL_CONTROL ) || pilot_isFlag( pplayer, PILOT_HIDE ))
1189 return;
1190
1191 /* Not facing anything yet. */
1192 facing = 0;
1193
1194 /* Autonav takes over normal controls. */
1195 if (player_isFlag(PLAYER_AUTONAV)) {
1196 player_thinkAutonav( pplayer, dt );
1197
1198 /* Disable turning. */
1199 facing = 1;
1200 }
1201
1202 /* Mouse-flying is enabled. */
1203 if (!facing && player_isFlag(PLAYER_MFLY))
1204 facing = player_thinkMouseFly( dt );
1205
1206 /* turning taken over by PLAYER_FACE */
1207 if (!facing && player_isFlag(PLAYER_FACE)) {
1208 /* Try to face pilot target. */
1209 if (player.p->target != PLAYER_ID) {
1210 target = pilot_getTarget( player.p );
1211 if (target != NULL) {
1212 pilot_face( pplayer,
1213 vec2_angle( &player.p->solid.pos, &target->solid.pos ),
1214 dt );
1215
1216 /* Disable turning. */
1217 facing = 1;
1218 }
1219 }
1220 /* Try to face asteroid. */
1221 else if (player.p->nav_asteroid != -1) {
1223 Asteroid *ast = &field->asteroids[player.p->nav_asteroid];
1224 pilot_face( pplayer,
1225 vec2_angle( &player.p->solid.pos, &ast->sol.pos ),
1226 dt);
1227 /* Disable turning. */
1228 facing = 1;
1229 }
1230 /* If not try to face spob target. */
1231 else if ((player.p->nav_spob != -1) && ((preemption == 0) || (player.p->nav_hyperspace == -1))) {
1232 pilot_face( pplayer,
1233 vec2_angle( &player.p->solid.pos,
1234 &cur_system->spobs[ player.p->nav_spob ]->pos ),
1235 dt);
1236 /* Disable turning. */
1237 facing = 1;
1238 }
1239 else if (player.p->nav_hyperspace != -1) {
1240 pilot_face( pplayer,
1241 vec2_angle( &player.p->solid.pos,
1242 &cur_system->jumps[ player.p->nav_hyperspace ].pos ),
1243 dt);
1244 /* Disable turning. */
1245 facing = 1;
1246 }
1247 }
1248
1249 /* turning taken over by PLAYER_REVERSE */
1250 if (player_isFlag(PLAYER_REVERSE)) {
1251 /*
1252 * If the player has reverse thrusters, fire those.
1253 */
1254 if (!player.p->stats.misc_reverse_thrust && !facing) {
1255 pilot_face( pplayer, VANGLE(player.p->solid.vel) + M_PI, dt );
1256 /* Disable turning. */
1257 facing = 1;
1258 }
1259 }
1260
1261 /* Normal turning scheme */
1262 if (!facing) {
1263 double turn = 0;
1264 if (player_isFlag(PLAYER_TURN_LEFT))
1265 turn -= player_left;
1266 if (player_isFlag(PLAYER_TURN_RIGHT))
1267 turn += player_right;
1268 turn = CLAMP( -1., 1., turn );
1269 pilot_setTurn( pplayer, -turn );
1270 }
1271
1272 /*
1273 * Weapon shooting stuff
1274 */
1275 fired = 0;
1276
1277 /* Primary weapon. */
1278 if (player_isFlag(PLAYER_PRIMARY)) {
1279 fired |= pilot_shoot( pplayer, 0 );
1280 player_setFlag(PLAYER_PRIMARY_L);
1281 }
1282 else if (player_isFlag(PLAYER_PRIMARY_L)) {
1283 pilot_shootStop( pplayer, 0 );
1284 player_rmFlag(PLAYER_PRIMARY_L);
1285 }
1286 /* Secondary weapon - we use PLAYER_SECONDARY_L to track last frame. */
1287 if (player_isFlag(PLAYER_SECONDARY)) { /* needs target */
1288 fired |= pilot_shoot( pplayer, 1 );
1289 player_setFlag(PLAYER_SECONDARY_L);
1290 }
1291 else if (player_isFlag(PLAYER_SECONDARY_L)) {
1292 pilot_shootStop( pplayer, 1 );
1293 player_rmFlag(PLAYER_SECONDARY_L);
1294 }
1295
1296 if (fired)
1297 player_autonavReset( 1. );
1298
1299 if (!player_isFlag(PLAYER_AUTONAV)) {
1300 double acc = player_acc;
1301 /* Have to handle the case the player is doing reverse. This takes priority
1302 * over normal accel. */
1303 if (player_isFlag(PLAYER_REVERSE) && player.p->stats.misc_reverse_thrust
1304 && !pilot_isFlag(player.p, PILOT_HYP_PREP)
1305 && !pilot_isFlag(player.p, PILOT_HYPERSPACE) )
1306 acc = -PILOT_REVERSE_THRUST;
1307
1308 pilot_setAccel( pplayer, acc );
1309 }
1310}
1311
1318void player_update( Pilot *pplayer, const double dt )
1319{
1320 /* Update normally. */
1321 pilot_update( pplayer, dt );
1322
1323 /* Update player.p specific stuff. */
1324 if (!player_isFlag(PLAYER_DESTROYED))
1325 player_updateSpecific( pplayer, dt );
1326}
1327
1334void player_updateSpecific( Pilot *pplayer, const double dt )
1335{
1336 int engsound;
1337 double pitch = 1.;
1338
1339 /* Calculate engine sound to use. */
1340 if (pilot_isFlag(pplayer, PILOT_AFTERBURNER))
1341 engsound = pplayer->afterburner->outfit->u.afb.sound;
1342 else if (pilot_isFlag(pplayer, PILOT_HYPERSPACE))
1343 engsound = snd_hypEng;
1344 else if (pplayer->engine_glow > 0.) {
1345 engsound = pplayer->ship->sound;
1346 pitch = pplayer->ship->engine_pitch;
1347 }
1348 else
1349 engsound = -1;
1350 if (engsound >= 0)
1352 /* See if sound must change. */
1353 if (player_lastEngineSound != engsound) {
1355 if (engsound >= 0) {
1357 sound_playGroup( player_engine_group, engsound, 0 );
1358 }
1359 }
1360 player_lastEngineSound = engsound;
1361
1362 /* Sound. */
1363 /*
1364 * Sound is now camera-specific and thus not player specific. A bit sad really.
1365 sound_updateListener( pplayer->solid.dir,
1366 pplayer->solid.pos.x, pplayer->solid.pos.y,
1367 pplayer->solid.vel.x, pplayer->solid.vel.y );
1368 */
1369
1370 /* See if must play hail sound. */
1371 if (player_hailCounter > 0) {
1372 player_hailTimer -= dt;
1373 if (player_hailTimer < 0.) {
1376 player_hailTimer = 3.;
1377 }
1378 }
1379
1380 /* Handle passive scanning of nearby asteroids. */
1381 /* TODO should probably handle player escorts in the future. */
1382 if (player.p->stats.asteroid_scan > 0.) {
1383 double range = player.p->stats.asteroid_scan;
1384 for (int i=0; i<array_size(cur_system->asteroids); i++) {
1385 double r2;
1387
1388 /* Field out of range. */
1389 if (vec2_dist2( &ast->pos, &player.p->solid.pos ) > pow2(range+ast->radius+ast->margin))
1390 continue;
1391
1392 r2 = pow2(range);
1393 for (int j=0; j<ast->nb; j++) {
1394 HookParam hparam[2];
1395 Asteroid *a = &ast->asteroids[j];
1396
1397 if (a->scanned) /* Ignore scanned outfits. */
1398 continue;
1399
1400 if (vec2_dist2( &a->sol.pos, &player.p->solid.pos ) > r2)
1401 continue;
1402
1403 a->scanned = 1;
1404
1405 /* Run the hook. */
1406 hparam[0].type = HOOK_PARAM_ASTEROID;
1407 hparam[0].u.ast.parent = ast->id;
1408 hparam[0].u.ast.id = a->id;
1409 hparam[1].type = HOOK_PARAM_SENTINEL;
1410 hooks_runParamDeferred( "asteroid_scan", hparam );
1411 }
1412 }
1413 }
1414}
1415
1416/*
1417 * For use in keybindings
1418 */
1422void player_weapSetPress( int id, double value, int repeat )
1423{
1424 int type;
1425
1426 if (repeat || (player.p == NULL))
1427 return;
1428
1429 type = (value>=0) ? +1 : -1;
1430
1431 if (type > 0) {
1432 if (toolkit_isOpen())
1433 return;
1434
1435 if ((pilot_isFlag(player.p, PILOT_HYP_PREP) ||
1436 pilot_isFlag(player.p, PILOT_HYPERSPACE) ||
1437 pilot_isFlag(player.p, PILOT_LANDING) ||
1438 pilot_isFlag(player.p, PILOT_TAKEOFF)))
1439 return;
1440 }
1441
1442 pilot_weapSetPress( player.p, id, type );
1443}
1444
1449{
1450 double spd = player.speed * player_dt_default();
1451 pause_setSpeed( spd );
1452 sound_setSpeed( spd );
1453}
1454
1461void player_restoreControl( int reason, const char *str )
1462{
1463 if (player.p==NULL)
1464 return;
1465
1466 if (reason != PINPUT_AUTONAV) {
1467 /* Autonav should be harder to abort when paused. */
1468 if ((!paused || reason != PINPUT_MOVEMENT))
1470 }
1471
1472 if (reason != PINPUT_BRAKING) {
1473 pilot_rmFlag(player.p, PILOT_BRAKING);
1474 pilot_rmFlag(player.p, PILOT_COOLDOWN_BRAKE);
1475 if (pilot_isFlag(player.p, PILOT_COOLDOWN))
1477 }
1478}
1479
1486{
1487 int old;
1488
1489 /* Player must exist. */
1490 if (player.p == NULL)
1491 return;
1492
1493 if (id >= array_size(cur_system->spobs)) {
1494 WARN(_("Trying to set player's spob target to invalid ID '%d'"), id);
1495 return;
1496 }
1497
1498 if ((player.p == NULL) || pilot_isFlag( player.p, PILOT_LANDING ))
1499 return;
1500
1501 old = player.p->nav_spob;
1502 player.p->nav_spob = id;
1503 player_hyperspacePreempt((id < 0) ? 1 : 0);
1504 if (old != id) {
1505 player_rmFlag(PLAYER_LANDACK);
1506 if (id >= 0)
1508 }
1510 gui_setNav();
1511
1512 if (player.autonav==AUTONAV_SPOB)
1513 player_autonavAbort(NULL);
1514}
1515
1522void player_targetAsteroidSet( int field, int id )
1523{
1524 int old;
1525
1526 if ((player.p == NULL) || pilot_isFlag( player.p, PILOT_LANDING ))
1527 return;
1528
1529 old = player.p->nav_asteroid;
1530 player.p->nav_asteroid = id;
1531 if (old != id) {
1532 if (id >= 0) {
1534 }
1535 }
1536
1537 player.p->nav_anchor = field;
1538
1539 /* Untarget pilot. */
1540 player.p->target = player.p->id;
1541}
1542
1547{
1548 int id;
1549
1550 /* Not under manual control. */
1551 if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ))
1552 return;
1553
1554 /* Find next spob target. */
1555 for (id=player.p->nav_spob+1; id<array_size(cur_system->spobs); id++)
1556 if (spob_isKnown( cur_system->spobs[id] ))
1557 break;
1558
1559 /* Try to select the lowest-indexed valid spob. */
1560 if (id >= array_size(cur_system->spobs) ) {
1561 id = -1;
1562 for (int i=0; i<array_size(cur_system->spobs); i++)
1563 if (spob_isKnown( cur_system->spobs[i] )) {
1564 id = i;
1565 break;
1566 }
1567 }
1568
1569 /* Untarget if out of range. */
1571}
1572
1579int player_land( int loud )
1580{
1581 Spob *spob;
1582 int silent = 0; /* Whether to suppress the land ack noise. */
1583
1584 if (landed) { /* player is already landed */
1585 takeoff( 1, 0 );
1586 return PLAYER_LAND_DENIED;
1587 }
1588
1589 /* Not under manual control or disabled. */
1590 if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ) ||
1591 pilot_isDisabled(player.p))
1592 return PLAYER_LAND_DENIED;
1593
1594 /* Already landing. */
1595 if ((pilot_isFlag( player.p, PILOT_LANDING) ||
1596 pilot_isFlag( player.p, PILOT_TAKEOFF)))
1597 return PLAYER_LAND_DENIED;
1598
1599 /* Check if there are spobs to land on. */
1600 if (array_size(cur_system->spobs) == 0) {
1601 player_message( "#r%s", _("There are no spobs to land on.") );
1602 return PLAYER_LAND_DENIED;
1603 }
1604
1605 if (player_isFlag(PLAYER_NOLAND)) {
1607 return PLAYER_LAND_DENIED;
1608 }
1609 else if (pilot_isFlag( player.p, PILOT_NOLAND)) {
1610 player_message( "#r%s", _("Docking stabilizers malfunctioning, cannot land.") );
1611 return PLAYER_LAND_DENIED;
1612 }
1613
1614 /* No target means no land. */
1615 if (player.p->nav_spob == -1)
1616 return PLAYER_LAND_DENIED;
1617 /* Check if spob is in range when not uninhabited. */
1618 else if (!spob_isFlag(cur_system->spobs[ player.p->nav_spob ], SPOB_UNINHABITED) && !pilot_inRangeSpob( player.p, player.p->nav_spob )) {
1620 return PLAYER_LAND_AGAIN;
1621 }
1622
1623 /* attempt to land at selected spob */
1624 spob = cur_system->spobs[player.p->nav_spob];
1625 spob_updateLand( spob ); /* Update if necessary. */
1626 if ((spob->lua_can_land==LUA_NOREF) && !spob_hasService(spob, SPOB_SERVICE_LAND)) {
1627 player_message( "#r%s", _("You can't land here.") );
1628 return PLAYER_LAND_DENIED;
1629 }
1630 else if ((spob->lua_can_land!=LUA_NOREF) && !spob->can_land) {
1631 if (spob->land_msg)
1632 player_message( _("#%c%s>#0 %s"), spob_getColourChar(spob),
1633 spob_name(spob), spob->land_msg );
1634 else
1635 player_message( "#r%s", _("You can't land here.") );
1636 return PLAYER_LAND_DENIED;
1637 }
1638 else if (!player_isFlag(PLAYER_LANDACK)) { /* no landing authorization */
1639 if (spob_hasService(spob,SPOB_SERVICE_INHABITED)) { /* Basic services */
1640 if (spob->can_land)
1641 player_message( _("#%c%s>#0 %s"), spob_getColourChar(spob),
1642 spob_name(spob), spob->land_msg );
1643 else if (spob->land_override > 0)
1644 player_message( _("#%c%s>#0 %s"), spob_getColourChar(spob),
1645 spob_name(spob), _("Landing authorized.") );
1646 else { /* Hostile */
1647 player_message( _("#%c%s>#0 %s"), spob_getColourChar(spob),
1648 spob_name(spob), spob->land_msg );
1649 return PLAYER_LAND_DENIED;
1650 }
1651 }
1652 else /* No shoes, no shirt, no lifeforms, no service. */
1653 player_message( _("#oReady to land on %s."), spob_name(spob) );
1654
1655 player_setFlag(PLAYER_LANDACK);
1656 if (!silent)
1658
1659 return player_land(loud);
1660 }
1661 else if (vec2_dist2(&player.p->solid.pos,&spob->pos) > pow2(spob->radius)) {
1662 if (loud)
1663 player_message(_("#rYou are too far away to land on %s."), spob_name(spob));
1664 return PLAYER_LAND_AGAIN;
1665 }
1666 else if (vec2_odist2( &player.p->solid.vel ) > pow2(MAX_HYPERSPACE_VEL)) {
1667 if (loud)
1668 player_message(_("#rYou are going too fast to land on %s."), spob_name(spob));
1669 return PLAYER_LAND_AGAIN;
1670 }
1671
1672 /* End autonav. */
1674
1675 /* Stop afterburning. */
1677 /* Stop accelerating. */
1679 /* Stop stealth. */
1681
1682 /* Stop all on outfits. */
1683 if (pilot_outfitOffAll( player.p ) > 0)
1685
1686 /* Do whatever the spob wants to do. */
1687 if (spob->lua_land != LUA_NOREF) {
1688 lua_rawgeti(naevL, LUA_REGISTRYINDEX, spob->lua_land); /* f */
1689 lua_pushspob( naevL, spob_index(spob) );
1690 lua_pushpilot( naevL, player.p->id );
1691 if (nlua_pcall( spob->lua_env, 2, 0 )) {
1692 WARN(_("Spob '%s' failed to run '%s':\n%s"), spob->name, "land", lua_tostring(naevL,-1));
1693 lua_pop(naevL,1);
1694 }
1695
1696 return PLAYER_LAND_OK;
1697 }
1698
1699 /* Start landing. */
1701 player.p->landing_delay = PILOT_LANDING_DELAY * player_dt_default();
1703 pilot_setFlag( player.p, PILOT_LANDING );
1704 pilot_setAccel( player.p, 0. );
1705 pilot_setTurn( player.p, 0. );
1706
1707 return PLAYER_LAND_OK;
1708}
1709
1714{
1715 Spob *p;
1716
1717 /* No authorization to revoke. */
1718 if ((player.p == NULL) || !player_isFlag(PLAYER_LANDACK))
1719 return;
1720
1721 /* Avoid a potential crash if PLAYER_LANDACK is set inappropriately. */
1722 if (player.p->nav_spob < 0) {
1723 WARN(_("Player has landing permission, but no valid spob targeted."));
1724 return;
1725 }
1726
1727 p = cur_system->spobs[ player.p->nav_spob ];
1728
1729 /* Player can still land. */
1730 if (p->can_land || (p->land_override > 0))
1731 return;
1732
1733 player_rmFlag(PLAYER_LANDACK);
1734 player_message( _("#%c%s>#0 Landing permission revoked."),
1736}
1737
1743void player_nolandMsg( const char *str )
1744{
1746
1747 /* Duplicate so that Lua memory which might be garbage-collected isn't relied on. */
1748 if (str != NULL)
1749 player_message_noland = strdup(str);
1750 else
1751 player_message_noland = strdup(_("You are not allowed to land at this moment."));
1752}
1753
1758{
1759 int plt = (player.p->target!=PLAYER_ID);
1760 int lnd = (player.p->nav_spob != -1);
1761
1762 if (plt && (player_canBoard(0)!=PLAYER_BOARD_IMPOSSIBLE)) {
1763 if (player_tryBoard(1) == PLAYER_BOARD_RETRY)
1765 return;
1766 }
1767 else if (lnd) {
1768 int canland = player_land(1);
1769 if (canland == PLAYER_LAND_AGAIN)
1770 player_autonavSpob( cur_system->spobs[player.p->nav_spob]->name, 1 );
1771 else if (canland == PLAYER_LAND_DENIED)
1772 player_autonavSpob( cur_system->spobs[player.p->nav_spob]->name, 0 );
1773 return;
1774 }
1775 else {
1776 /* In the case they have no target already, we just try to find a target
1777 * first, with priority for boarding. */
1778 if (!plt) {
1779 Pilot *nearp;
1780 double d = pilot_getNearestPosPilot( player.p, &nearp, player.p->solid.pos.x, player.p->solid.pos.y, 1 );
1781 if ((nearp!=NULL) && !pilot_isFlag(nearp,PILOT_NOBOARD) && (d<pow2(5e3)) &&
1782 (pilot_isDisabled(nearp) || pilot_isFlag(nearp,PILOT_BOARDABLE))) {
1783 player_targetSet( nearp->id );
1784 player_tryBoard(0); /* Try to board if can. */
1785 return;
1786 }
1787 }
1788
1789 /* Now try to find a landing target. */
1790 if (!lnd) {
1791 double td = -1.; /* temporary distance */
1792 int tp = -1; /* temporary spob */
1793 for (int i=0; i<array_size(cur_system->spobs); i++) {
1794 const Spob *spob = cur_system->spobs[i];
1795 double d = vec2_dist(&player.p->solid.pos,&spob->pos);
1796 if (!pilot_inRangeSpob( player.p, i ))
1797 continue;
1798 if (!spob_hasService(spob,SPOB_SERVICE_LAND))
1799 continue;
1800 if ((tp==-1) || ((td==-1) || (td > d))) {
1801 tp = i;
1802 td = d;
1803 }
1804 }
1805 if (tp>=0) {
1808 player_land(0); /* Try to land if can. */
1809 return;
1810 }
1811 }
1812 }
1813}
1814
1821void player_targetHyperspaceSet( int id, int nomsg )
1822{
1823 int old;
1824
1825 /* Player must exist. */
1826 if (player.p == NULL)
1827 return;
1828
1829 if (id >= array_size(cur_system->jumps)) {
1830 WARN(_("Trying to set player's hyperspace target to invalid ID '%d'"), id);
1831 return;
1832 }
1833
1834 if (pilot_isFlag(player.p, PILOT_HYP_PREP) ||
1835 pilot_isFlag(player.p, PILOT_HYP_BEGIN) ||
1836 pilot_isFlag(player.p, PILOT_HYPERSPACE))
1837 return;
1838
1839 old = player.p->nav_hyperspace;
1840 player.p->nav_hyperspace = id;
1841 player_hyperspacePreempt((id < 0) ? 0 : 1);
1842 if ((old != id) && (id >= 0))
1844 gui_setNav();
1845
1846 if (!nomsg && (old != id) && (player.autonav==AUTONAV_JUMP))
1847 player_autonavAbort(NULL);
1848
1849 hooks_run( "target_hyperspace" );
1850}
1851
1856{
1857 int id;
1858
1859 /* Not under manual control. */
1860 if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ))
1861 return;
1862
1863 map_clear(); /* clear the current map path */
1864
1865 for (id=player.p->nav_hyperspace+1; id<array_size(cur_system->jumps); id++)
1866 if (jp_isKnown( &cur_system->jumps[id]))
1867 break;
1868
1869 /* Try to find the lowest-indexed valid jump. */
1870 if (id >= array_size(cur_system->jumps)) {
1871 id = -1;
1872 for (int i=0; i<array_size(cur_system->jumps); i++)
1873 if (jp_isUsable( &cur_system->jumps[i])) {
1874 id = i;
1875 break;
1876 }
1877 }
1878
1880
1881 /* Map gets special treatment if open. */
1882 if (id == -1)
1883 map_select( NULL , 0);
1884 else
1885 map_select( cur_system->jumps[ id ].target, 0 );
1886}
1887
1893void player_hyperspacePreempt( int preempt )
1894{
1895 preemption = preempt;
1896}
1897
1904{
1905 return preemption;
1906}
1907
1914{
1915 if (player.p != NULL && player.p->ship != NULL)
1917 return 1.;
1918}
1919
1924{
1925 char buf[128];
1926
1928
1929 input_getKeybindDisplay( "autohail", buf, sizeof(buf) );
1930 player_message( _("#rReceiving hail! Press #b%s#r to respond.#0"), buf );
1931
1932 /* Reset speed. */
1933 player_autonavReset( 10. );
1934}
1935
1941int player_jump (void)
1942{
1943 int h;
1944
1945 /* Must have a jump target and not be already jumping. */
1946 if (pilot_isFlag(player.p, PILOT_HYPERSPACE))
1947 return 0;
1948
1949 /* Not under manual control or disabled. */
1950 if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ) ||
1951 pilot_isDisabled(player.p))
1952 return 0;
1953
1954 /* Select nearest jump if not target. */
1955 if (player.p->nav_hyperspace == -1) {
1956 int j = -1;
1957 double mindist = INFINITY;
1958 for (int i=0; i<array_size(cur_system->jumps); i++) {
1959 double dist = vec2_dist2( &player.p->solid.pos, &cur_system->jumps[i].pos );
1960 if (dist < mindist && jp_isUsable(&cur_system->jumps[i])) {
1961 mindist = dist;
1962 j = i;
1963 }
1964 }
1965 if (j < 0)
1966 return 0;
1967
1968 player.p->nav_hyperspace = j;
1970 map_select( cur_system->jumps[player.p->nav_hyperspace].target, 0 );
1971 gui_setNav();
1972
1973 /* Only follow through if within range. */
1974 if (mindist > pow2( cur_system->jumps[j].radius ))
1975 return 0;
1976 }
1977
1978 /* Already jumping, so we break jump. */
1979 if (pilot_isFlag(player.p, PILOT_HYP_PREP)) {
1981 player_message( "#r%s", _("Aborting hyperspace sequence."));
1982 return 0;
1983 }
1984
1985 /* Try to hyperspace. */
1987 if (h == -1) {
1990 //player_message( "#r%s", _("You are too far from a jump point to initiate hyperspace."));
1991 }
1992 else if (h == -2)
1993 player_message( "#r%s", _("Hyperspace drive is offline."));
1994 else if (h == -3)
1995 player_message( "#r%s", _("You do not have enough fuel to hyperspace jump."));
1996 else {
1997 player_message( "#o%s", _("Preparing for hyperspace."));
1998 /* Stop acceleration noise. */
2000 /* Stop possible shooting. */
2001 pilot_shootStop( player.p, 0 );
2002 pilot_shootStop( player.p, 1 );
2003
2004 /* Order escorts to jump; just for aesthetics (for now) */
2006
2007 return 1;
2008 }
2009
2010 return 0;
2011}
2012
2017{
2018 ntime_t t;
2019 StarSystem *sys;
2020 JumpPoint *jp;
2021 Pilot *const* pilot_stack;
2022
2023 /* First run jump hook. */
2024 hooks_run( "jumpout" );
2025
2026 /* Prevent targeted spob # from carrying over. */
2027 gui_setNav();
2028 gui_setTarget();
2030 player_targetAsteroidSet( -1, -1 );
2031
2032 /* calculates the time it takes, call before space_init */
2034 ntime_inc( t );
2035
2036 /* Save old system. */
2037 sys = cur_system;
2038
2039 /* Free old graphics. */
2040 space_gfxUnload( sys );
2041
2042 /* enter the new system */
2043 jp = &cur_system->jumps[player.p->nav_hyperspace];
2044 space_init( jp->target->name, 1 );
2045
2046 /* Set up the overlay. */
2047 ovr_initAlpha();
2048
2049 /* set position, the pilot_update will handle lowering vel */
2052
2053 /* reduce fuel */
2055
2056 /* Set the ptimer. */
2057 player.p->ptimer = HYPERSPACE_FADEIN;
2058
2059 /* Update the map, we have to remove the player flags first or it breaks down. */
2060 pilot_rmFlag( player.p, PILOT_HYPERSPACE );
2061 pilot_rmFlag( player.p, PILOT_HYP_BEGIN );
2062 pilot_rmFlag( player.p, PILOT_HYP_BRAKE );
2063 pilot_rmFlag( player.p, PILOT_HYP_PREP );
2064 map_jump();
2065
2066 /* Add persisted pilots */
2068 for (int i=0; i<array_size(pilot_stack); i++) {
2069 Pilot *p = pilot_stack[i];
2070
2071 if (pilot_isFlag(p, PILOT_PERSIST) || pilot_isFlag(p, PILOT_PLAYER)) {
2072 if (p != player.p)
2073 space_calcJumpInPos( cur_system, sys, &p->solid.pos, &p->solid.vel, &p->solid.dir, player.p );
2074
2075 /* Run Lua stuff for all persistant pilots. */
2078
2079 /* Invulnerable delay too. */
2080 p->itimer = PILOT_PLAYER_NONTARGETABLE_JUMPIN_DELAY;
2081 pilot_setFlag( p, PILOT_NONTARGETABLE );
2082
2083 /* Clear flags as necessary. */
2084 pilot_rmFlag( p, PILOT_HYPERSPACE );
2085 pilot_rmFlag( p, PILOT_HYP_BEGIN );
2086 pilot_rmFlag( p, PILOT_HYP_BRAKE );
2087 pilot_rmFlag( p, PILOT_HYP_PREP );
2088 }
2089 }
2090
2091 /* Disable autonavigation if arrived. */
2092 player_autonavEnter();
2093
2094 /* Safe since this is run in the player hook section. */
2095 hooks_run( "jumpin" );
2096 hooks_run( "enter" );
2097 events_trigger( EVENT_TRIGGER_ENTER );
2098 missions_run( MIS_AVAIL_ENTER, -1, NULL, NULL );
2099
2100 /* Player sound. */
2102
2103 /* Increment times jumped. */
2106}
2107
2113void player_accel( double acc )
2114{
2115 if ((player.p == NULL) || pilot_isFlag(player.p, PILOT_HYP_PREP) ||
2116 pilot_isFlag(player.p, PILOT_HYPERSPACE))
2117 return;
2118
2119 player_acc = acc;
2120 if (toolkit_isOpen() || paused)
2122}
2123
2128{
2129 player_acc = 0.;
2130}
2131
2137void player_targetSet( unsigned int id )
2138{
2139 unsigned int old;
2140 old = player.p->target;
2141 pilot_setTarget( player.p, id );
2142 if ((old != id) && (player.p->target != PLAYER_ID)) {
2145 }
2146 gui_setTarget();
2147
2148 /* Clear the asteroid target. */
2149 player.p->nav_asteroid = -1;
2150 player.p->nav_anchor = -1;
2151
2152 /* The player should not continue following if the target pilot has been changed. */
2153 if ((old != id) && player_isFlag(PLAYER_AUTONAV) && (player.autonav==AUTONAV_PILOT))
2154 player_autonavAbort(NULL);
2155}
2156
2164{
2165 unsigned int tp;
2166 double d, td;
2167 Pilot *const* pilot_stack;
2168
2169 tp = PLAYER_ID;
2170 d = 0;
2172 for (int i=0; i<array_size(pilot_stack); i++) {
2173 /* Shouldn't be disabled. */
2174 if (pilot_isDisabled(pilot_stack[i]))
2175 continue;
2176
2177 /* Must be a valid target. */
2178 if (!pilot_canTarget( pilot_stack[i] ))
2179 continue;
2180
2181 /* Must be hostile. */
2183 continue;
2184
2185 if (pilot_inRangePilot(player.p, pilot_stack[i], &td) != 1 )
2186 continue;
2187
2188 if (tp == PLAYER_ID || ((td < d))) {
2189 d = td;
2190 tp = pilot_stack[i]->id;
2191 }
2192 }
2193
2194 player_targetSet( tp );
2195}
2196
2202void player_targetNext( int mode )
2203{
2205}
2206
2212void player_targetPrev( int mode )
2213{
2215}
2216
2221{
2223 if (player.p->target != PLAYER_ID)
2224 player_targetSet( PLAYER_ID );
2225 else if (player.p->nav_asteroid >= 0)
2226 player_targetAsteroidSet( -1, -1 );
2227 else if (player.p->nav_spob >= 0)
2229 else if ((preemption == 1 || player.p->nav_spob == -1) &&
2230 !pilot_isFlag(player.p, PILOT_HYP_PREP)) {
2231 player.p->nav_hyperspace = -1;
2233 map_clear();
2234 }
2235 gui_setNav();
2236}
2237
2242{
2245 player_targetAsteroidSet( -1, -1 );
2246 player_targetSet( PLAYER_ID );
2247}
2248
2254void player_targetEscort( int prev )
2255{
2256 int i;
2257 /* Check if current target is an escort. */
2258 for (i=0; i<array_size(player.p->escorts); i++) {
2259 if (player.p->target == player.p->escorts[i].id) {
2260
2261 /* Cycle targets. */
2262 if (prev)
2263 pilot_setTarget( player.p, (i > 0) ?
2264 player.p->escorts[i-1].id : player.p->id );
2265 else
2267 player.p->escorts[i+1].id : player.p->id );
2268
2269 break;
2270 }
2271 }
2272
2273 /* Not found in loop. */
2274 if (i >= array_size(player.p->escorts)) {
2275 /* Check to see if he actually has escorts. */
2276 if (array_size(player.p->escorts) > 0) {
2277 /* Cycle forward or backwards. */
2278 if (prev)
2280 else
2282 }
2283 else
2285 }
2286
2287 if (player.p->target != PLAYER_ID) {
2290 }
2291 gui_setTarget();
2292}
2293
2298{
2299 unsigned int t, dt;
2300 double d = pilot_getNearestPos( player.p, &dt, player.p->solid.pos.x,
2301 player.p->solid.pos.y, 1 );
2302 t = dt;
2303
2304 /* Disabled ships are typically only valid if within 500 px of the player. */
2305 if ((d > pow2(500.)) && (pilot_isDisabled( pilot_get(dt) ))) {
2307 /* Try to target a disabled ship if there are no active ships in range. */
2308 if (t == PLAYER_ID)
2309 t = dt;
2310 }
2311
2312 player_targetSet( t );
2313}
2314
2315static int screenshot_cur = 0;
2320{
2321 char filename[PATH_MAX];
2322
2323 if (PHYSFS_mkdir("screenshots") == 0) {
2324 WARN(_("Aborting screenshot"));
2325 return;
2326 }
2327
2328 /* Try to find current screenshots. */
2329 for ( ; screenshot_cur < 1000; screenshot_cur++) {
2330 snprintf( filename, sizeof(filename), "screenshots/screenshot%03d.png", screenshot_cur );
2331 if (!PHYSFS_exists( filename ))
2332 break;
2333 }
2334
2335 if (screenshot_cur >= 999) { /* in case the crap system breaks :) */
2336 WARN(_("You have reached the maximum amount of screenshots [999]"));
2337 return;
2338 }
2339
2340 /* now proceed to take the screenshot */
2341 DEBUG( _("Taking screenshot [%03d]..."), screenshot_cur );
2342 gl_screenshot( filename );
2343}
2344
2349static void player_checkHail (void)
2350{
2351 Pilot *const* pilot_stack = pilot_getAll();
2352 for (int i=0; i<array_size(pilot_stack); i++) {
2353 const Pilot *p = pilot_stack[i];
2354
2355 /* Must be hailing. */
2356 if (pilot_isFlag(p, PILOT_HAILING))
2357 return;
2358 }
2359
2360 /* Clear hail timer. */
2362 player_hailTimer = 0.;
2363}
2364
2369{
2370 const Spob *spob = cur_system->spobs[player.p->nav_spob];
2371 const char *name = spob_name(spob);
2372 player_message( _("#r%s is out of comm range, unable to contact."), name );
2373}
2374
2378void player_hail (void)
2379{
2380 /* Not under manual control or disabled. */
2381 if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ) ||
2382 pilot_isDisabled(player.p))
2383 return;
2384
2385 if (player.p->target != player.p->id)
2387 else if (player.p->nav_spob != -1) {
2388 Spob *spob = cur_system->spobs[ player.p->nav_spob ];
2389 if (spob_isFlag(spob, SPOB_UNINHABITED))
2390 player_message( _("#r%s does not respond."), spob_name(spob) );
2391 else if (pilot_inRangeSpob( player.p, player.p->nav_spob ))
2392 comm_openSpob( spob );
2393 else
2395 }
2396 else
2397 player_message( "#r%s", _("No target selected to hail.") );
2398
2399 /* Clear hails if none found. */
2401}
2402
2407{
2408 /* Not under manual control. */
2409 if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ))
2410 return;
2411
2412 if (player.p->nav_spob != -1) {
2415 else
2417 }
2418 else
2419 player_message( "#r%s", _("No target selected to hail.") );
2420}
2421
2426{
2427 Pilot *const* pilot_stack;
2428
2429 /* Not under manual control or disabled. */
2430 if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ) ||
2431 pilot_isDisabled(player.p))
2432 return;
2433
2434 /* Find pilot to autohail. */
2436 for (int i=0; i<array_size(pilot_stack); i++) {
2437 const Pilot *p = pilot_stack[i];
2438
2439 /* Must be hailing. */
2440 if (pilot_isFlag(p, PILOT_HAILING)) {
2441 /* Try to hail. */
2442 pilot_setTarget( player.p, p->id );
2443 gui_setTarget();
2444 player_hail();
2445
2446 /* Clear hails if none found. */
2448 return;
2449 }
2450 }
2451
2452 player_message( "#r%s", _("You haven't been hailed by any pilots.") );
2453}
2454
2459{
2460 if (!conf.mouse_fly)
2461 return;
2462
2463 if (!player_isFlag(PLAYER_MFLY)) {
2465 player_message( "#o%s", _("Mouse flying enabled.") );
2466 player_setFlag(PLAYER_MFLY);
2467 }
2468 else {
2470 player_rmFlag(PLAYER_MFLY);
2471 player_message( "#o%s", _("Mouse flying disabled.") );
2472
2473 if (conf.mouse_accel)
2475 }
2476}
2477
2482{
2483 int stopped;
2484
2485 if (pilot_isFlag(player.p, PILOT_TAKEOFF))
2486 return;
2487
2488 /* Not under manual control or disabled. */
2489 if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ) ||
2490 pilot_isDisabled(player.p))
2491 return;
2492
2493 stopped = pilot_isStopped(player.p);
2494 if (stopped && !pilot_isFlag(player.p, PILOT_COOLDOWN))
2496 else {
2497 pilot_setFlag(player.p, PILOT_BRAKING);
2498 pilot_setFlag(player.p, PILOT_COOLDOWN_BRAKE);
2499 }
2500}
2501
2508static int player_thinkMouseFly( double dt )
2509{
2510 double px, py, r, x, y;
2511
2512 px = player.p->solid.pos.x;
2513 py = player.p->solid.pos.y;
2515 r = sqrt(pow2(x-px) + pow2(y-py));
2516 if (r > 50.) { /* Ignore mouse input within a 50 px radius of the centre. */
2517 pilot_face(player.p, atan2( y-py, x-px), dt);
2518 if (conf.mouse_accel) { /* Only alter thrust if option is enabled. */
2519 double acc = CLAMP(0., 1., (r - 100.) / 200.);
2520 acc = 3. * pow2(acc) - 2. * pow(acc, 3.);
2521 /* Only accelerate when within 180 degrees of the intended direction. */
2522 if (ABS(angle_diff(atan2( y - py, x - px), player.p->solid.dir)) < M_PI_2 )
2523 player_accel(acc);
2524 else
2525 player_accel(0.);
2526 }
2527 return 1;
2528 }
2529 else
2530 return 0;
2531}
2532
2536void player_dead (void)
2537{
2538 /* Explode at normal speed. */
2539 pause_setSpeed(1.);
2540 sound_setSpeed(1.);
2541
2542 /* Close the overlay. */
2543 ovr_setOpen(0);
2544}
2545
2550{
2551 if (player_isFlag(PLAYER_DESTROYED))
2552 return;
2553
2554 /* Mark as destroyed. */
2555 player_setFlag(PLAYER_DESTROYED);
2556
2557 /* Set timer for death menu. */
2558 player_timer = 5.;
2559
2560 /* Stop sounds. */
2562
2563 /* Stop autonav */
2565
2566 /* Reset time compression when player dies. */
2567 pause_setSpeed(1.);
2568 sound_setSpeed(1.);
2569}
2570
2574static int player_shipsCompare( const void *arg1, const void *arg2 )
2575{
2576 PlayerShip_t *ps1, *ps2;
2577 credits_t p1, p2;
2578
2579 /* Get the arguments. */
2580 ps1 = (PlayerShip_t*) arg1;
2581 ps2 = (PlayerShip_t*) arg2;
2582
2583 if (ps1->favourite && !ps2->favourite)
2584 return -1;
2585 else if (ps2->favourite && !ps1->favourite)
2586 return +1;
2587
2588 if (ps1->deployed && !ps2->deployed)
2589 return -1;
2590 else if (ps2->deployed && !ps1->deployed)
2591 return +1;
2592
2593 /* Get prices. */
2594 p1 = pilot_worth( ps1->p, 0 );
2595 p2 = pilot_worth( ps2->p, 0 );
2596
2597 /* Compare price INVERSELY */
2598 if (p1 < p2)
2599 return +1;
2600 else if (p1 > p2)
2601 return -1;
2602
2603 /* In case of tie sort by name so they don't flip or something. */
2604 return strcmp( ps1->p->name, ps2->p->name );
2605}
2606
2611{
2612 if (array_size(player_stack) == 0)
2613 return;
2614
2615 /* Sort. */
2617}
2618
2627int player_ships( char** sships, glTexture** tships )
2628{
2629 /* Sort. */
2631
2632 /* Create the struct. */
2633 for (int i=0; i < array_size(player_stack); i++) {
2634 sships[i] = strdup(player_stack[i].p->name);
2635 tships[i] = player_stack[i].p->ship->gfx_store;
2636 }
2637
2638 return array_size(player_stack);
2639}
2640
2645{
2646 return player_stack;
2647}
2648
2655{
2656 return array_size(player_stack);
2657}
2658
2665int player_hasShip( const char *shipname )
2666{
2667 /* Check current ship. */
2668 if ((player.p != NULL) && (strcmp(player.p->name,shipname)==0))
2669 return 1;
2670
2671 /* Check stocked ships. */
2672 for (int i=0; i < array_size(player_stack); i++)
2673 if (strcmp(player_stack[i].p->name, shipname)==0)
2674 return 1;
2675 return 0;
2676}
2677
2684Pilot *player_getShip( const char *shipname )
2685{
2686 if ((player.p != NULL) && (strcmp(shipname,player.p->name)==0))
2687 return player.p;
2688
2689 for (int i=0; i < array_size(player_stack); i++)
2690 if (strcmp(player_stack[i].p->name, shipname)==0)
2691 return player_stack[i].p;
2692
2693 WARN(_("Player ship '%s' not found in stack"), shipname);
2694 return NULL;
2695}
2696
2703PlayerShip_t *player_getPlayerShip( const char *shipname )
2704{
2705 if ((player.p != NULL) && (strcmp(shipname,player.p->name)==0))
2706 return NULL;
2707
2708 for (int i=0; i < array_size(player_stack); i++)
2709 if (strcmp(player_stack[i].p->name, shipname)==0)
2710 return &player_stack[i];
2711
2712 WARN(_("Player ship '%s' not found in stack"), shipname);
2713 return NULL;
2714}
2715
2723{
2724 /* Special case map. */
2725 if ((outfit_isMap(o) && map_isUseless(o)) ||
2726 (outfit_isLocalMap(o) && localmap_isUseless(o)))
2727 return 1;
2728
2729 /* Special case license. */
2730 if (outfit_isLicense(o) &&
2732 return 1;
2733
2734 /* Special case GUI. */
2735 if (outfit_isGUI(o) &&
2737 return 1;
2738
2739 /* Special case intrinsics. */
2740 if (o->slot.type==OUTFIT_SLOT_INTRINSIC)
2741 return pilot_hasIntrinsic( player.p, o );
2742
2743 /* Try to find it. */
2744 for (int i=0; i<array_size(player_outfits); i++)
2745 if (player_outfits[i].o == o)
2746 return player_outfits[i].q;
2747
2748 return 0;
2749}
2750
2755{
2756 int q = player_outfitOwned(o);
2757 q += pilot_numOutfit( player.p, o );
2758 for (int i=0; i<array_size(player_stack); i++)
2759 q += pilot_numOutfit( player_stack[i].p, o );
2760
2761 return q;
2762}
2763
2767static int player_outfitCompare( const void *arg1, const void *arg2 )
2768{
2769 PlayerOutfit_t *po1, *po2;
2770
2771 /* Get type. */
2772 po1 = (PlayerOutfit_t*) arg1;
2773 po2 = (PlayerOutfit_t*) arg2;
2774
2775 /* Compare. */
2776 return outfit_compareTech( &po1->o, &po2->o );
2777}
2778
2783{
2784 return player_outfits;
2785}
2786
2795int player_getOutfitsFiltered( const Outfit ***outfits,
2796 int(*filter)( const Outfit *o ), const char *name )
2797{
2798 if (array_size(player_outfits) == 0)
2799 return 0;
2800
2801 /* We'll sort. */
2804
2805 for (int i=0; i<array_size(player_outfits); i++)
2806 array_push_back( outfits, (Outfit*)player_outfits[i].o );
2807
2808 return outfits_filter( *outfits, array_size(player_outfits), filter, name );
2809}
2810
2817{
2818 return array_size(player_outfits);
2819}
2820
2828int player_addOutfit( const Outfit *o, int quantity )
2829{
2830 PlayerOutfit_t *po;
2831
2832 /* Validity check. */
2833 if (quantity == 0)
2834 return 0;
2835
2836 /* Don't readd uniques. */
2837 if (outfit_isProp(o,OUTFIT_PROP_UNIQUE) && (player_outfitOwned(o)>0))
2838 return 0;
2839
2840 /* special case if it's a map */
2841 if (outfit_isMap(o)) {
2842 map_map(o);
2843 return 1; /* Success. */
2844 }
2845 else if (outfit_isLocalMap(o)) {
2846 localmap_map(o);
2847 return 1;
2848 }
2849 /* special case if it's an outfit */
2850 else if (outfit_isGUI(o)) {
2851 player_guiAdd(o->u.gui.gui);
2852 return 1; /* Success. */
2853 }
2854 /* special case if it's a license. */
2855 else if (outfit_isLicense(o)) {
2857 return 1; /* Success. */
2858 }
2859 /* intrinsic outfits get added as intinsics. */
2860 else if (o->slot.type==OUTFIT_SLOT_INTRINSIC) {
2862 return 0;
2863 return pilot_addOutfitIntrinsic( player.p, o );
2864 }
2865
2866 /* Try to find it. */
2867 for (int i=0; i<array_size(player_outfits); i++) {
2868 if (player_outfits[i].o == o) {
2869 player_outfits[i].q += quantity;
2870 return quantity;
2871 }
2872 }
2873
2874 /* Allocate if needed. */
2875 po = &array_grow( &player_outfits );
2876
2877 /* Add the outfit. */
2878 po->o = o;
2879 po->q = quantity;
2880 return quantity;
2881}
2882
2890int player_rmOutfit( const Outfit *o, int quantity )
2891{
2892 if (o->slot.type==OUTFIT_SLOT_INTRINSIC)
2893 return pilot_rmOutfitIntrinsic( player.p, o );
2894
2895 /* Try to find it. */
2896 for (int i=0; i<array_size(player_outfits); i++) {
2897 if (player_outfits[i].o != o)
2898 continue;
2899 /* See how many to remove. */
2900 int q = MIN( player_outfits[i].q, quantity );
2901 player_outfits[i].q -= q;
2902
2903 /* See if must remove element. */
2904 if (player_outfits[i].q <= 0)
2906
2907 /* Return removed outfits. */
2908 return q;
2909 }
2910
2911 /* Nothing removed. */
2912 return 0;
2913}
2914
2915/*
2916 * Trivial sorting function for arrays of integers.
2917 */
2918static int cmp_int( const void *p1, const void *p2 )
2919{
2920 const int *i1 = (const int*) p1;
2921 const int *i2 = (const int*) p2;
2922 return (*i1) - (*i2);
2923}
2924
2931{
2932 HookParam h[2];
2933 const MissionData *m;
2934
2935 /* Make sure not already marked. */
2937 return;
2938
2939 /* Mark as done. */
2940 if (missions_done == NULL)
2941 missions_done = array_create( int );
2943
2944 qsort( missions_done, array_size(missions_done), sizeof(int), cmp_int );
2945
2946 /* Run the completion hook. */
2947 m = mission_get( id );
2948 mission_toLuaTable( naevL, m ); /* Push to stack. */
2949 h[0].type = HOOK_PARAM_REF;
2950 h[0].u.ref = luaL_ref( naevL, LUA_REGISTRYINDEX ); /* Pops from stack. */
2951 h[1].type = HOOK_PARAM_SENTINEL;
2952 hooks_runParam( "mission_done", h );
2953}
2954
2962{
2963 if (missions_done == NULL)
2964 return 0;
2965
2966 const int *i = bsearch( &id, missions_done, array_size(missions_done), sizeof(int), cmp_int );
2967 return i!=NULL;
2968}
2969
2976{
2977 return missions_done;
2978}
2979
2986{
2987 HookParam h[2];
2988
2989 /* Make sure not already done. */
2991 return;
2992
2993 /* Mark as done. */
2994 if (events_done == NULL)
2995 events_done = array_create( int );
2997
2998 qsort( events_done, array_size(events_done), sizeof(int), cmp_int );
2999
3000 /* Run the completion hook. */
3001 event_toLuaTable( naevL, id ); /* Push to stack. */
3002 h[0].type = HOOK_PARAM_REF;
3003 h[0].u.ref = luaL_ref( naevL, LUA_REGISTRYINDEX ); /* Pops from stack. */
3004 h[1].type = HOOK_PARAM_SENTINEL;
3005 hooks_runParam( "event_done", h );
3006}
3007
3015{
3016 if (events_done == NULL)
3017 return 0;
3018
3019 const int *i = bsearch( &id, events_done, array_size(events_done), sizeof(int), cmp_int );
3020 return i!=NULL;
3021}
3022
3029{
3030 return events_done;
3031}
3032
3039int player_hasLicense( const char *license )
3040{
3041 if (license == NULL)
3042 return 1;
3043 if (player_licenses == NULL)
3044 return 0;
3045
3046 const char *s = bsearch( &license, player_licenses, array_size(player_licenses), sizeof(char*), strsort );
3047 return s!=NULL;
3048}
3049
3055void player_addLicense( const char *license )
3056{
3057 if (player_hasLicense(license))
3058 return;
3059 if (player_licenses == NULL)
3060 player_licenses = array_create( char* );
3061 array_push_back( &player_licenses, strdup(license) );
3062
3063 qsort( player_licenses, array_size(player_licenses), sizeof(char*), strsort );
3064}
3065
3069const char **player_getLicenses ()
3070{
3071 return (const char**) player_licenses;
3072}
3073
3078{
3079 if (player_isFlag( PLAYER_HOOK_HYPER )) {
3080 player_rmFlag( PLAYER_HOOK_HYPER );
3082 }
3083 if (player_isFlag( PLAYER_HOOK_JUMPIN)) {
3084 player_rmFlag( PLAYER_HOOK_JUMPIN );
3086 hooks_run( "jumpin" );
3087 hooks_run( "enter" );
3088 events_trigger( EVENT_TRIGGER_ENTER );
3089 missions_run( MIS_AVAIL_ENTER, -1, NULL, NULL );
3090 }
3091 if (player_isFlag( PLAYER_HOOK_LAND )) {
3092 player_rmFlag( PLAYER_HOOK_LAND );
3093 if (player.p->nav_spob >= 0)
3094 land( cur_system->spobs[ player.p->nav_spob ], 0 );
3095 }
3096}
3097
3101static void player_clearEscorts (void)
3102{
3103 for (int i=0; i<array_size(player.p->outfits); i++) {
3104 if (player.p->outfits[i]->outfit == NULL)
3105 continue;
3106
3108 player.p->outfits[i]->u.ammo.deployed = 0;
3109 }
3110}
3111
3118{
3119 /* Clear escorts first. */
3121
3122 /* Go over escorts. */
3123 for (int i=0; i<array_size(player.p->escorts); i++) {
3124 int q;
3125 PilotOutfitSlot *po;
3126 const Escort_t *e = &player.p->escorts[i];
3127 Pilot *pe = pilot_get( e->id );
3128
3129 /* Non-persistent pilots should have been wiped already. */
3130 if (pe == NULL) {
3132 i--;
3133 continue;
3134 }
3135
3136 /* Update to random position. */
3137 pe->solid.dir = RNGF() * 2. * M_PI;
3138 vec2_cset( &pe->solid.pos, player.p->solid.pos.x + 50.*cos(pe->solid.dir),
3139 player.p->solid.pos.y + 50.*sin(pe->solid.dir) );
3140 vec2_cset( &pe->solid.vel, 0., 0. );
3141
3142 /* Update outfit if needed. */
3143 if (e->type != ESCORT_TYPE_BAY)
3144 continue;
3145
3146 po = pilot_getDockSlot( pe );
3147 if (po == NULL) {
3148 /* We just want to delete the pilot and not trigger other stuff. */
3149 pilot_setFlag( pe, PILOT_DELETE );
3150 WARN(_("Escort is undeployed, removing."));
3152 i--;
3153 continue;
3154 }
3155
3156 po->u.ammo.deployed++;
3157 q = po->u.ammo.deployed + po->u.ammo.quantity;
3158 if (q > pilot_maxAmmoO(player.p,po->outfit)) {
3159 /* We just want to delete the pilot and not trigger other stuff. */
3160 pilot_setFlag( pe, PILOT_DELETE );
3161 WARN(_("Escort is deployed past outfit limits, removing."));
3163 i--;
3164 continue;
3165 }
3166 }
3167
3168 /* Add the player fleets. */
3169 for (int i=0; i<array_size(player_stack); i++) {
3170 PlayerShip_t *ps = &player_stack[i];
3171
3172 /* Already exists. */
3173 if (ps->p->id)
3174 continue;
3175
3176 /* Only deploy escorts that are deployed. */
3177 if (!ps->deployed)
3178 continue;
3179
3180 /* Only deploy spaceworthy escorts. */
3181 if (!pilot_isSpaceworthy(ps->p))
3182 continue;
3183
3184 pfleet_deploy( ps );
3185 }
3186
3187 return 0;
3188}
3189
3193static int player_saveEscorts( xmlTextWriterPtr writer )
3194{
3195 for (int i=0; i<array_size(player.p->escorts); i++) {
3196 Escort_t *e = &player.p->escorts[i];
3197 Pilot *pe;
3198 if (!e->persist)
3199 continue;
3200 switch (e->type) {
3201 case ESCORT_TYPE_BAY:
3202 xmlw_startElem(writer, "escort");
3203 xmlw_attr(writer,"type","bay");
3204 xmlw_attr(writer, "name", "%s", e->ship->name);
3205 xmlw_endElem(writer); /* "escort" */
3206 break;
3207
3208 case ESCORT_TYPE_FLEET:
3209 pe = pilot_get( e->id );
3210 if (pe != NULL) {
3211 xmlw_startElem(writer, "escort");
3212 xmlw_attr(writer,"type","fleet");
3213 xmlw_attr(writer, "name", "%s", pe->name);
3214 xmlw_endElem(writer); /* "escort" */
3215 }
3216 break;
3217
3218 default:
3219 break;
3220 }
3221 }
3222
3223 return 0;
3224}
3225
3232int player_save( xmlTextWriterPtr writer )
3233{
3234 const char **guis;
3235 int cycles, periods, seconds;
3236 double rem;
3237 const PlayerItem *inventory;
3238
3239 xmlw_startElem(writer,"player");
3240
3241 /* Standard player details. */
3242 xmlw_attr(writer,"name","%s",player.name);
3243 xmlw_elem(writer,"credits","%"CREDITS_PRI,player.p->credits);
3244 xmlw_elem(writer,"chapter","%s",player.chapter);
3245 if (player.difficulty != NULL)
3246 xmlw_elem(writer,"difficulty","%s",player.difficulty);
3247 if (player.gui != NULL)
3248 xmlw_elem(writer,"gui","%s",player.gui);
3249 xmlw_elem(writer,"mapOverlay","%d",ovr_isOpen());
3251 xmlw_elem(writer,"radar_res","%f",player.radar_res);
3252 xmlw_elem(writer,"eq_outfitMode","%d",player.eq_outfitMode);
3253 xmlw_elem(writer,"map_minimal","%d",player.map_minimal);
3254 xmlw_elem(writer,"fleet_capacity","%d",player.fleet_capacity);
3255
3256 /* Time. */
3257 xmlw_startElem(writer,"time");
3258 ntime_getR( &cycles, &periods, &seconds, &rem );
3259 xmlw_elem(writer,"SCU","%d", cycles);
3260 xmlw_elem(writer,"STP","%d", periods);
3261 xmlw_elem(writer,"STU","%d", seconds);
3262 xmlw_elem(writer,"Remainder","%lf", rem);
3263 xmlw_endElem(writer); /* "time" */
3264
3265 /* Current ship. */
3266 xmlw_elem(writer, "location", "%s", land_spob->name);
3267 player_saveShip( writer, &player.ps ); /* current ship */
3268
3269 /* Ships. */
3270 xmlw_startElem(writer,"ships");
3271 for (int i=0; i<array_size(player_stack); i++)
3272 player_saveShip( writer, &player_stack[i] );
3273 xmlw_endElem(writer); /* "ships" */
3274
3275 /* GUIs. */
3276 xmlw_startElem(writer,"guis");
3277 guis = player_guiList();
3278 for (int i=0; i<array_size(guis); i++)
3279 xmlw_elem(writer,"gui","%s",guis[i]);
3280 xmlw_endElem(writer); /* "guis" */
3281
3282 /* Outfits. */
3283 xmlw_startElem(writer,"outfits");
3284 for (int i=0; i<array_size(player_outfits); i++) {
3285 xmlw_startElem(writer, "outfit");
3286 xmlw_attr(writer, "quantity", "%d", player_outfits[i].q);
3287 xmlw_str(writer, "%s", player_outfits[i].o->name);
3288 xmlw_endElem(writer); /* "outfit" */
3289 }
3290 xmlw_endElem(writer); /* "outfits" */
3291
3292 /* Licenses. */
3293 xmlw_startElem(writer, "licenses");
3294 for (int i=0; i<array_size(player_licenses); i++)
3295 xmlw_elem(writer, "license", "%s", player_licenses[i]);
3296 xmlw_endElem(writer); /* "licenses" */
3297
3298 /* Inventory. */
3299 xmlw_startElem(writer, "inventory");
3301 for (int i=0; i<array_size(inventory); i++) {
3302 const PlayerItem *pi = &inventory[i];
3303 xmlw_startElem(writer, "item");
3304 xmlw_attr(writer, "quantity", "%d", pi->quantity);
3305 xmlw_str(writer, "%s", pi->name);
3306 xmlw_endElem(writer); /* "item" */
3307 }
3308 xmlw_endElem(writer); /* "inventory" */
3309
3310 xmlw_endElem(writer); /* "player" */
3311
3312 /* Mission the player has done. */
3313 xmlw_startElem(writer,"missions_done");
3314 for (int i=0; i<array_size(missions_done); i++) {
3315 const MissionData *m = mission_get(missions_done[i]);
3316 if (m != NULL) /* In case mission name changes between versions */
3317 xmlw_elem(writer, "done", "%s", m->name);
3318 }
3319 xmlw_endElem(writer); /* "missions_done" */
3320
3321 /* Events the player has done. */
3322 xmlw_startElem(writer, "events_done");
3323 for (int i=0; i<array_size(events_done); i++) {
3324 const char *ev = event_dataName(events_done[i]);
3325 if (ev != NULL) /* In case mission name changes between versions */
3326 xmlw_elem(writer, "done", "%s", ev);
3327 }
3328 xmlw_endElem(writer); /* "events_done" */
3329
3330 /* Escorts. */
3331 xmlw_startElem(writer, "escorts");
3332 player_saveEscorts(writer);
3333 xmlw_endElem(writer); /* "escorts" */
3334
3335 /* Metadata. */
3336 xmlw_startElem(writer,"metadata");
3337 player_saveMetadata( writer );
3338 xmlw_endElem(writer); /* "metadata" */
3339
3340 return 0;
3341}
3342
3346static int player_saveShipSlot( xmlTextWriterPtr writer, const PilotOutfitSlot *slot, int i )
3347{
3348 const Outfit *o = slot->outfit;
3349 xmlw_startElem(writer,"outfit");
3350 xmlw_attr(writer,"slot","%d",i);
3352 xmlw_attr(writer,"quantity","%d", slot->u.ammo.quantity);
3353 xmlw_str(writer,"%s",o->name);
3354 xmlw_endElem(writer); /* "outfit" */
3355
3356 return 0;
3357}
3358
3366static int player_saveShip( xmlTextWriterPtr writer, PlayerShip_t *pship )
3367{
3368 Pilot *ship = pship->p;
3369 xmlw_startElem(writer,"ship");
3370 xmlw_attr(writer,"name","%s",ship->name);
3371 xmlw_attr(writer,"model","%s",ship->ship->name);
3372 xmlw_attr(writer,"favourite", "%d",pship->favourite);
3373 xmlw_attr(writer,"deployed", "%d",pship->deployed);
3374
3375 /* Metadata. */
3376 if (pship->acquired)
3377 xmlw_elem(writer, "acquired","%s", pship->acquired);
3378 xmlw_saveTime(writer, "acquired_date", pship->acquired_date);
3379 xmlw_elem(writer, "time_played","%f", pship->time_played);
3380 xmlw_elem(writer, "dmg_done_shield", "%f", pship->dmg_done_shield);
3381 xmlw_elem(writer, "dmg_done_armour", "%f", pship->dmg_done_armour);
3382 xmlw_elem(writer, "dmg_taken_shield", "%f", pship->dmg_taken_shield);
3383 xmlw_elem(writer, "dmg_taken_armour", "%f", pship->dmg_taken_armour);
3384 xmlw_elem(writer, "jumped_times", "%u", pship->jumped_times);
3385 xmlw_elem(writer, "landed_times", "%u", pship->landed_times);
3386 xmlw_elem(writer, "death_counter", "%u", pship->death_counter);
3387
3388 /* Ships destroyed by class. */
3389 xmlw_startElem(writer,"ships_destroyed");
3390 for (int i=SHIP_CLASS_NULL+1; i<SHIP_CLASS_TOTAL; i++) {
3391 char buf[STRMAX_SHORT];
3392 strncpy( buf, ship_classToString(i), sizeof(buf)-1 );
3393 for (size_t j=0; j<strlen(buf); j++)
3394 if (buf[j]==' ')
3395 buf[j]='_';
3396 xmlw_elem(writer, buf, "%u", pship->ships_destroyed[i]);
3397 }
3398 xmlw_endElem(writer); /* "ships_destroyed" */
3399
3400 /* save the fuel */
3401 xmlw_elem(writer,"fuel","%f",ship->fuel);
3402
3403 /* save the outfits */
3404 xmlw_startElem(writer,"outfits_intrinsic"); /* Want them to be first. */
3405 for (int i=0; i<array_size(ship->outfit_intrinsic); i++)
3406 player_saveShipSlot( writer, &ship->outfit_intrinsic[i], i );
3407 xmlw_endElem(writer); /* "outfits_intrinsic" */
3408 xmlw_startElem(writer,"outfits_structure");
3409 for (int i=0; i<array_size(ship->outfit_structure); i++) {
3410 if (ship->outfit_structure[i].outfit==NULL)
3411 continue;
3412 player_saveShipSlot( writer, &ship->outfit_structure[i], i );
3413 }
3414 xmlw_endElem(writer); /* "outfits_structure" */
3415 xmlw_startElem(writer,"outfits_utility");
3416 for (int i=0; i<array_size(ship->outfit_utility); i++) {
3417 if (ship->outfit_utility[i].outfit==NULL)
3418 continue;
3419 player_saveShipSlot( writer, &ship->outfit_utility[i], i );
3420 }
3421 xmlw_endElem(writer); /* "outfits_utility" */
3422 xmlw_startElem(writer,"outfits_weapon");
3423 for (int i=0; i<array_size(ship->outfit_weapon); i++) {
3424 if (ship->outfit_weapon[i].outfit==NULL)
3425 continue;
3426 player_saveShipSlot( writer, &ship->outfit_weapon[i], i );
3427 }
3428 xmlw_endElem(writer); /* "outfits_weapon" */
3429
3430 /* save the commodities */
3431 xmlw_startElem(writer,"commodities");
3432 for (int i=0; i<array_size(ship->commodities); i++) {
3433 PilotCommodity *pc = &ship->commodities[i];
3434 /* Remove cargo with id and no mission. */
3435 if (pc->id > 0) {
3436 int found = 0;
3437 for (int j=0; j<array_size(player_missions); j++) {
3438 /* Only check active missions. */
3439 if (player_missions[j]->id > 0) {
3440 /* Now check if it's in the cargo list. */
3441 for (int k=0; k<array_size(player_missions[j]->cargo); k++) {
3442 /* See if it matches a cargo. */
3443 if (player_missions[j]->cargo[k] == pc->id) {
3444 found = 1;
3445 break;
3446 }
3447 }
3448 }
3449 if (found)
3450 break;
3451 }
3452
3453 if (!found) {
3454 WARN(_("Found mission cargo '%s' without associated mission."),pc->commodity->name);
3455 WARN(_("Please reload save game to remove the dead cargo."));
3456 continue;
3457 }
3458 }
3459 else if (pc->quantity==0) {
3460 WARN(_("Found cargo '%s' with 0 quantity."),pc->commodity->name);
3461 WARN(_("Please reload save game to remove the dead cargo."));
3462 continue;
3463 }
3464
3465 xmlw_startElem(writer,"commodity");
3466
3467 xmlw_attr(writer,"quantity","%d",pc->quantity);
3468 if (pc->id > 0)
3469 xmlw_attr(writer,"id","%d",pc->id);
3470 xmlw_str(writer,"%s",pc->commodity->name);
3471
3472 xmlw_endElem(writer); /* commodity */
3473 }
3474 xmlw_endElem(writer); /* "commodities" */
3475
3476 xmlw_startElem(writer, "weaponsets");
3477 xmlw_attr(writer, "autoweap", "%d", ship->autoweap);
3478 xmlw_attr(writer, "active_set", "%d", ship->active_set);
3479 xmlw_attr(writer, "aim_lines", "%d", ship->aimLines);
3480 for (int i=0; i<PILOT_WEAPON_SETS; i++) {
3481 PilotWeaponSet *ws = &pship->weapon_sets[i];
3482 PilotWeaponSetOutfit *weaps = ws->slots;
3483 xmlw_startElem(writer,"weaponset");
3484 /* Inrange isn't handled by autoweap for the player. */
3485 xmlw_attr(writer,"inrange","%d",ws->inrange);
3486 xmlw_attr(writer,"manual","%d",ws->manual);
3487 xmlw_attr(writer,"volley","%d",ws->volley);
3488 xmlw_attr(writer,"id","%d",i);
3489 if (!ship->autoweap) {
3490 xmlw_attr(writer,"type","%d",ws->type);
3491 for (int j=0; j<array_size(weaps); j++) {
3492 xmlw_startElem(writer,"weapon");
3493 xmlw_attr(writer,"level","%d",weaps[j].level);
3494 xmlw_str(writer,"%d",weaps[j].slotid);
3495 xmlw_endElem(writer); /* "weapon" */
3496 }
3497 }
3498 xmlw_endElem(writer); /* "weaponset" */
3499 }
3500 xmlw_endElem(writer); /* "weaponsets" */
3501
3502 /* Ship variables. */
3503 xmlw_startElem(writer, "vars");
3504 lvar_save( pship->p->shipvar, writer );
3505 xmlw_endElem(writer); /* "vars" */
3506
3507 xmlw_endElem(writer); /* "ship" */
3508
3509 return 0;
3510}
3511
3518static int player_saveMetadata( xmlTextWriterPtr writer )
3519{
3520 time_t t = time(NULL);
3521 double diff = difftime( t, player.time_since_save );
3522
3523 /* Compute elapsed time. */
3524 player.time_played += diff;
3525 player.ps.time_played += diff;
3527
3528 /* Save the stuff. */
3529 xmlw_saveTime(writer, "last_played", time(NULL));
3530 xmlw_saveTime(writer, "date_created", player.date_created);
3531
3532 /* Meta-data. */
3533 xmlw_elem(writer, "time_played","%f", player.time_played);
3534 xmlw_elem(writer, "dmg_done_shield", "%f", player.dmg_done_shield);
3535 xmlw_elem(writer, "dmg_done_armour", "%f", player.dmg_done_armour);
3536 xmlw_elem(writer, "dmg_taken_shield", "%f", player.dmg_taken_shield);
3537 xmlw_elem(writer, "dmg_taken_armour", "%f", player.dmg_taken_armour);
3538 xmlw_elem(writer, "jumped_times", "%u", player.jumped_times);
3539 xmlw_elem(writer, "landed_times", "%u", player.landed_times);
3540 xmlw_elem(writer, "death_counter", "%u", player.death_counter);
3541
3542 /* Ships destroyed by class. */
3543 xmlw_startElem(writer,"ships_destroyed");
3544 for (int i=SHIP_CLASS_NULL+1; i<SHIP_CLASS_TOTAL; i++) {
3545 char buf[STRMAX_SHORT];
3546 strncpy( buf, ship_classToString(i), sizeof(buf)-1 );
3547 for (size_t j=0; j<strlen(buf); j++)
3548 if (buf[j]==' ')
3549 buf[j]='_';
3550 xmlw_elem(writer, buf, "%u", player.ships_destroyed[i]);
3551 }
3552 xmlw_endElem(writer); /* "ships_destroyed" */
3553
3554 return 0;
3555}
3556
3563Spob* player_load( xmlNodePtr parent )
3564{
3565 xmlNodePtr node;
3566 Spob *pnt;
3567
3568 /* some cleaning up */
3569 memset( &player, 0, sizeof(Player_t) );
3570 player.speed = 1.;
3571 pnt = NULL;
3572 map_cleanup();
3573
3574 /* Sane time defaults. */
3575 player.last_played = time(NULL);
3578
3579 if (player_stack==NULL)
3581 if (player_outfits==NULL)
3583
3584 node = parent->xmlChildrenNode;
3585 do {
3586 if (xml_isNode(node,"metadata"))
3588 else if (xml_isNode(node,"player"))
3589 pnt = player_parse( node );
3590 else if (xml_isNode(node,"missions_done"))
3592 else if (xml_isNode(node,"events_done"))
3593 player_parseDoneEvents( node );
3594 else if (xml_isNode(node,"escorts"))
3595 player_parseEscorts(node);
3596 } while (xml_nextNode(node));
3597
3598 /* Set up meta-data. */
3599 player.time_since_save = time(NULL);
3600
3601 /* Defaults as necessary. */
3602 if (player.chapter==NULL)
3603 player.chapter = strdup( start_chapter() );
3604 if (player.difficulty!=NULL)
3605 difficulty_setLocal( difficulty_get(player.difficulty) );
3606 else
3607 difficulty_setLocal( NULL ); /* Sets the default. */
3608
3609 /* Updates the fleet internals. */
3610 pfleet_update();
3611
3612 /* Update weapon set. */
3614
3615 return pnt;
3616}
3617
3626static int player_runUpdaterScript( const char* type, const char* name, int q )
3627{
3628 static nlua_env player_updater_env = LUA_NOREF;
3629
3631
3632 /* Load env if necessary. */
3633 if (player_updater_env == LUA_NOREF) {
3634 player_updater_env = nlua_newEnv();
3635 size_t bufsize;
3636 char *buf = ndata_read( SAVE_UPDATER_PATH, &bufsize );
3637 if (nlua_dobufenv(player_updater_env, buf, bufsize, SAVE_UPDATER_PATH) != 0) {
3638 WARN( _("Error loading file: %s\n"
3639 "%s\n"
3640 "Most likely Lua file has improper syntax, please check"),
3641 SAVE_UPDATER_PATH, lua_tostring(naevL,-1));
3642 free(buf);
3643 return 0;
3644 }
3645 free(buf);
3646 }
3647
3648 /* Try to find out equivalent. */
3649 nlua_getenv( naevL, player_updater_env, type );
3650 lua_pushstring( naevL, name );
3651 if (nlua_pcall(player_updater_env, 1, 1)) { /* error has occurred */
3652 WARN( _("Board: '%s'"), lua_tostring(naevL,-1));
3653 lua_pop(naevL,1);
3654 return 0;
3655 }
3656 if (lua_type(naevL,-1) == LUA_TNUMBER) {
3657 player_payback += q * round( lua_tonumber(naevL,-1) );
3658 lua_pop(naevL,1);
3659 return 0;
3660 }
3661
3662 return 1;
3663}
3664
3668static const Outfit* player_tryGetOutfit( const char *name, int q )
3669{
3670 const Outfit *o = outfit_getW( name );
3671
3672 /* Outfit was found normally. */
3673 if (o != NULL)
3674 return o;
3676
3677 /* Try to find out equivalent. */
3678 if (player_runUpdaterScript( "outfit", name, q ) == 0)
3679 return NULL;
3680 else if (lua_type(naevL,-1) == LUA_TSTRING)
3681 o = outfit_get( lua_tostring(naevL,-1) );
3682 else if (lua_isoutfit(naevL,-1))
3683 o = lua_tooutfit(naevL,-1);
3684 else
3685 WARN(_("Outfit '%s' in player save not found!"), name );
3686
3687 lua_pop(naevL,1);
3688
3689 return o;
3690}
3691
3695static const Ship* player_tryGetShip( const char *name )
3696{
3697 const Ship *s = ship_getW( name );
3698
3699 /* Ship was found normally. */
3700 if (s != NULL)
3701 return s;
3703
3704 /* Try to find out equivalent. */
3705 if (player_runUpdaterScript( "ship", name, 1 ) == 0)
3706 return NULL;
3707 else if (lua_type(naevL,-1) == LUA_TSTRING)
3708 s = ship_get( lua_tostring(naevL,-1) );
3709 else if (lua_isship(naevL,-1))
3710 s = lua_toship(naevL,-1);
3711 else
3712 WARN(_("Ship '%s' in player save not found!"), name );
3713
3714 lua_pop(naevL,1);
3715
3716 return s;
3717}
3718
3722static void player_tryAddLicense( const char *name )
3723{
3724 /* Found normally. */
3725 if (outfit_licenseExists(name)) {
3726 player_addLicense( name );
3727 return;
3728 }
3730
3731 /* Try to find out equivalent. */
3732 if (player_runUpdaterScript( "license", name, 1 ) == 0)
3733 return;
3734 else if (lua_type(naevL,-1) == LUA_TSTRING)
3735 player_addLicense( lua_tostring(naevL,-1) );
3736 else
3737 WARN(_("Saved license does not exist and could not be found or updated: '%s'!"), name);
3738 lua_pop(naevL,1);
3739}
3740
3747static Spob* player_parse( xmlNodePtr parent )
3748{
3749 const char *spob = NULL;
3750 Spob *pnt = NULL;
3751 xmlNodePtr node, cur;
3752 int map_overlay_enabled = 0;
3753 StarSystem *sys;
3754 double a, r;
3755 int time_set = 0;
3756
3757 xmlr_attr_strd(parent, "name", player.name);
3758 assert( player.p == NULL );
3760
3762
3763 /* Must get spob first. */
3764 node = parent->xmlChildrenNode;
3765 do {
3766 xmlr_str(node,"location",spob);
3767 } while (xml_nextNode(node));
3768
3769 /* Parse rest. */
3770 node = parent->xmlChildrenNode;
3771 do {
3772 /* global stuff */
3773 xmlr_ulong(node, "credits", player_creds);
3774 xmlr_strd(node, "gui", player.gui);
3775 xmlr_strd(node, "chapter", player.chapter);
3776 xmlr_int(node, "mapOverlay", map_overlay_enabled);
3777 xmlr_float(node, "radar_res", player.radar_res);
3778 xmlr_int(node, "eq_outfitMode", player.eq_outfitMode);
3779 xmlr_int(node, "map_minimal", player.map_minimal);
3780 xmlr_int(node, "fleet_capacity", player.fleet_capacity);
3781
3782 /* Time. */
3783 if (xml_isNode(node,"time")) {
3784 double rem = -1.;
3785 int cycles=-1, periods=-1, seconds=-1;
3786 cur = node->xmlChildrenNode;
3787 do {
3788 xmlr_int(cur, "SCU", cycles);
3789 xmlr_int(cur, "STP", periods);
3790 xmlr_int(cur, "STU", seconds);
3791 xmlr_float(cur, "Remainder", rem);
3792 } while (xml_nextNode(cur));
3793 if ((cycles < 0) || (periods < 0) || (seconds < 0) || (rem<0.))
3794 WARN(_("Malformed time in save game!"));
3795 ntime_setR( cycles, periods, seconds, rem );
3796 if ((cycles >= 0) || (periods >= 0) || (seconds >= 0))
3797 time_set = 1;
3798 }
3799
3800 if (xml_isNode(node, "ship"))
3801 player_parseShip(node, 1);
3802
3803 /* Parse ships. */
3804 else if (xml_isNode(node,"ships")) {
3805 cur = node->xmlChildrenNode;
3806 do {
3807 if (xml_isNode(cur,"ship"))
3808 player_parseShip(cur, 0);
3809 } while (xml_nextNode(cur));
3810 }
3811
3812 /* Parse GUIs. */
3813 else if (xml_isNode(node,"guis")) {
3814 cur = node->xmlChildrenNode;
3815 do {
3816 if (xml_isNode(cur,"gui"))
3817 player_guiAdd( xml_get(cur) );
3818 } while (xml_nextNode(cur));
3819 }
3820
3821 /* Parse outfits. */
3822 else if (xml_isNode(node,"outfits")) {
3823 cur = node->xmlChildrenNode;
3824 do {
3825 if (xml_isNode(cur,"outfit")) {
3826 int q;
3827 const Outfit *o;
3828 const char *oname = xml_get(cur);
3829 xmlr_attr_float( cur, "quantity", q );
3830 if (q == 0) {
3831 WARN(_("Outfit '%s' was saved without quantity!"), (oname!=NULL) ? oname : "NULL" );
3832 continue;
3833 }
3834
3835 o = player_tryGetOutfit( oname, q );
3836 if (o == NULL)
3837 continue;
3838
3839 player_addOutfit( o, q );
3840 }
3841 } while (xml_nextNode(cur));
3842 }
3843
3844 /* Parse licenses. */
3845 else if (xml_isNode(node,"licenses"))
3847
3848 else if (xml_isNode(node,"inventory"))
3850
3851 } while (xml_nextNode(node));
3852
3853 /* Handle cases where ship is missing. */
3854 if (player.p == NULL) {
3855 PilotFlags flags;
3856 pilot_clearFlagsRaw( flags );
3857 pilot_setFlagRaw( flags, PILOT_PLAYER );
3858 pilot_setFlagRaw( flags, PILOT_NO_OUTFITS );
3859 WARN(_("Player ship does not exist!"));
3860
3861 if (array_size(player_stack) == 0) {
3862 WARN(_("Player has no other ships, giving starting ship."));
3863 pilot_create( ship_get(start_ship()), "MIA",
3864 faction_get("Player"), "player", 0., NULL, NULL, flags, 0, 0 );
3865 }
3866 else {
3867 /* Just give player.p a random ship in the stack. */
3868 const Pilot *old_ship = player_stack[array_size(player_stack)-1].p;
3869 pilot_create( old_ship->ship, old_ship->name,
3870 faction_get("Player"), "player", 0., NULL, NULL, flags, 0, 0 );
3871 player_rmShip( old_ship->name );
3872 WARN(_("Giving player ship '%s'."), player.p->name );
3873 }
3874 }
3875
3876 /* Check. */
3877 if (player.p == NULL) {
3878 ERR(_("Something went horribly wrong, player does not exist after load..."));
3879 return NULL;
3880 }
3881
3882 /* Reset player speed */
3883 player.speed = 1.;
3884
3885 /* set global thingies */
3887 if (!time_set) {
3888 WARN(_("Save has no time information, setting to start information."));
3889 ntime_set( start_date() );
3890 }
3891
3892 /* Updater message. */
3893 if (player_ran_updater) {
3894 DEBUG(_("Player save was updated!"));
3895 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."));
3896 }
3897
3898 /* set player in system */
3899 pnt = spob_get( spob );
3900 /* Get random spob if it's NULL. */
3901 if ((pnt == NULL) || (spob_getSystem(spob) == NULL) ||
3902 !spob_hasService(pnt, SPOB_SERVICE_LAND)) {
3903 WARN(_("Player starts out in non-existent or invalid spob '%s',"
3904 "trying to find a suitable one instead."),
3905 spob );
3906
3907 /* Find a landable, inhabited spob that's in a system, offers refueling
3908 * and meets the following additional criteria:
3909 *
3910 * 0: Shipyard, outfitter, non-hostile
3911 * 1: Outfitter, non-hostile
3912 * 2: None
3913 *
3914 * If no spob meeting the current criteria can be found, the next
3915 * set of criteria is tried until none remain.
3916 */
3917 const char *found = NULL;
3918 for (int i=0; i<3; i++) {
3919 unsigned int services = SPOB_SERVICE_LAND | SPOB_SERVICE_INHABITED | SPOB_SERVICE_REFUEL;
3920
3921 if (i == 0)
3922 services |= SPOB_SERVICE_SHIPYARD;
3923
3924 if (i != 2)
3925 services |= SPOB_SERVICE_OUTFITS;
3926
3927 found = space_getRndSpob( 1, services,
3928 (i != 2) ? player_filterSuitableSpob : NULL );
3929 if (found != NULL)
3930 break;
3931
3932 WARN(_("Could not find a spob satisfying criteria %d."), i);
3933 }
3934
3935 if (found == NULL) {
3936 WARN(_("Could not find a suitable spob. Choosing a random spob."));
3937 found = space_getRndSpob(0, 0, NULL); /* This should never, ever fail. */
3938 }
3939 pnt = spob_get( found );
3940 }
3941
3942 /* Initialize system. */
3943 sys = system_get( spob_getSystem( pnt->name ) );
3944 space_gfxLoad( sys );
3945 a = RNGF() * 2.*M_PI;
3946 r = RNGF() * pnt->radius * 0.8;
3947 player_warp( pnt->pos.x + r*cos(a), pnt->pos.y + r*sin(a) );
3948 player.p->solid.dir = RNG(0,359) * M_PI/180.;
3949
3950 /* Initialize outfits. */
3952
3953 /* initialize the system */
3954 space_init( sys->name, 0 );
3955 map_clear(); /* sets the map up */
3956 ovr_setOpen(map_overlay_enabled);
3957
3958 /* initialize the sound */
3960
3961 return pnt;
3962}
3963
3971{
3972 return !areEnemies(p->presence.faction, FACTION_PLAYER);
3973}
3974
3981static int player_parseDoneMissions( xmlNodePtr parent )
3982{
3983 xmlNodePtr node = parent->xmlChildrenNode;
3984 do {
3985 xml_onlyNodes(node);
3986
3987 if (!xml_isNode(node,"done"))
3988 continue;
3989
3990 int id = mission_getID( xml_get(node) );
3991 if (id < 0)
3992 DEBUG(_("Mission '%s' doesn't seem to exist anymore, removing from save."),
3993 xml_get(node));
3994 else
3996 } while (xml_nextNode(node));
3997 return 0;
3998}
3999
4006static int player_parseDoneEvents( xmlNodePtr parent )
4007{
4008 xmlNodePtr node = parent->xmlChildrenNode;
4009 do {
4010 xml_onlyNodes(node);
4011
4012 if (!xml_isNode(node,"done"))
4013 continue;
4014
4015 int id = event_dataID( xml_get(node) );
4016 if (id < 0)
4017 DEBUG(_("Event '%s' doesn't seem to exist anymore, removing from save."),
4018 xml_get(node));
4019 else
4021 } while (xml_nextNode(node));
4022 return 0;
4023}
4024
4031static int player_parseLicenses( xmlNodePtr parent )
4032{
4033 xmlNodePtr node = parent->xmlChildrenNode;
4034 do {
4035 xml_onlyNodes(node);
4036
4037 if (!xml_isNode( node, "license" ))
4038 continue;
4039
4040 const char *name = xml_get( node );
4041 if (name == NULL) {
4042 WARN( _( "License node is missing name." ) );
4043 continue;
4044 }
4045 player_tryAddLicense( name );
4046 } while (xml_nextNode(node));
4047 return 0;
4048}
4049
4056static int player_parseInventory( xmlNodePtr parent )
4057{
4058 xmlNodePtr node = parent->xmlChildrenNode;
4059 do {
4060 int q;
4061 xml_onlyNodes(node);
4062
4063 if (!xml_isNode( node, "item" ))
4064 continue;
4065
4066 xmlr_attr_int_def( node, "quantity", q, 1 );
4067 const char *name = xml_get( node );
4068 if (name == NULL) {
4069 WARN( _( "Inventory item node is missing name." ) );
4070 continue;
4071 }
4072 player_inventoryAdd( name, q );
4073 } while (xml_nextNode(node));
4074 return 0;
4075}
4076
4083static int player_parseEscorts( xmlNodePtr parent )
4084{
4085 xmlNodePtr node = parent->xmlChildrenNode;
4086 do {
4087 char *buf, *name;
4088
4089 /* Skip non-escorts. */
4090 if (!xml_isNode(node,"escort"))
4091 continue;
4092
4093 xmlr_attr_strd( node, "type", buf );
4094 xmlr_attr_strd( node, "name", name );
4095 if (name==NULL) /* Workaround for < 0.10.0 old saves, TODO remove around 0.12.0 or 0.13.0. */
4096 name = xml_getStrd( node );
4097 if (strcmp(buf,"bay")==0)
4098 escort_addList( player.p, ship_get(name), ESCORT_TYPE_BAY, 0, 1 );
4099
4100 else if (strcmp(buf,"fleet")==0) {
4101 PlayerShip_t *ps = player_getPlayerShip( name );
4102
4103 /* Only deploy escorts that are deployed. */
4104 if (!ps->deployed)
4105 WARN(_("Fleet ship '%s' is deployed despite not being marked for deployal!"), ps->p->name);
4106
4107 /* Only deploy spaceworthy escorts. */
4108 if (!pilot_isSpaceworthy(ps->p))
4109 WARN(_("Fleet ship '%s' is deployed despite not being space worthy!"), ps->p->name);
4110
4111 pfleet_deploy( ps );
4112 }
4113 else
4114 WARN(_("Escort has invalid type '%s'."), buf);
4115 free(buf);
4116 free(name);
4117 } while (xml_nextNode(node));
4118 return 0;
4119}
4120
4127static int player_parseMetadata( xmlNodePtr parent )
4128{
4129 xmlNodePtr node = parent->xmlChildrenNode;
4130 do {
4131 xml_onlyNodes(node);
4132
4133 xmlr_float(node,"dmg_done_shield",player.dmg_done_shield);
4134 xmlr_float(node,"dmg_done_armour",player.dmg_done_armour);
4135 xmlr_float(node,"dmg_taken_shield",player.dmg_taken_shield);
4136 xmlr_float(node,"dmg_taken_armour",player.dmg_taken_armour);
4137 xmlr_uint(node,"jumped_times",player.jumped_times);
4138 xmlr_uint(node,"landed_times",player.landed_times);
4139 xmlr_uint(node,"death_counter",player.death_counter);
4140 xmlr_float(node,"time_played",player.time_played);
4141
4142 if (xml_isNode(node,"last_played")) {
4143 xml_parseTime(node, &player.last_played);
4144 continue;
4145 }
4146 else if (xml_isNode(node,"date_created")) {
4147 xml_parseTime(node, &player.date_created);
4148 continue;
4149 }
4150 else if (xml_isNode(node,"ships_destroyed")) {
4151 xmlNodePtr cur = node->xmlChildrenNode;
4152 do {
4153 char buf[STRMAX_SHORT];
4154 int class;
4155
4156 xml_onlyNodes(cur);
4157
4158 strncpy( buf, (const char*)cur->name, sizeof(buf)-1 );
4159 for (size_t i=0; i<strlen(buf); i++)
4160 if (buf[i]=='_')
4161 buf[i] = ' ';
4162
4163 class = ship_classFromString( buf );
4164 if (class==SHIP_CLASS_NULL) {
4165 WARN(_("Unknown ship class '%s' when parsing 'ships_destroyed' node!"), (const char*)cur->name );
4166 continue;
4167 }
4168
4169 player.ships_destroyed[class] = xml_getULong(cur);
4170 } while (xml_nextNode(cur));
4171 }
4172 } while (xml_nextNode(node));
4173 return 0;
4174}
4175
4179static void player_addOutfitToPilot( Pilot* pilot, const Outfit* outfit, PilotOutfitSlot *s )
4180{
4181 int ret;
4182
4183 if (!outfit_fitsSlot( outfit, &s->sslot->slot )) {
4184 DEBUG( _("Outfit '%s' does not fit designated slot on player's pilot '%s', adding to stock."),
4185 outfit->name, pilot->name );
4186 player_addOutfit( outfit, 1 );
4187 return;
4188 }
4189
4190 ret = pilot_addOutfitRaw( pilot, outfit, s );
4191 if (ret != 0) {
4192 DEBUG(_("Outfit '%s' does not fit on player's pilot '%s', adding to stock."),
4193 outfit->name, pilot->name);
4194 player_addOutfit( outfit, 1 );
4195 return;
4196 }
4197
4198 /* Update stats. */
4199 pilot_calcStats( pilot );
4200}
4201
4205static void player_parseShipSlot( xmlNodePtr node, Pilot *ship, PilotOutfitSlot *slot )
4206{
4207 const Outfit *o;
4208 int q;
4209 const char *name = xml_get(node);
4210 if (name == NULL) {
4211 WARN(_("Empty ship slot node found, skipping."));
4212 return;
4213 }
4214
4215 /* Add the outfit. */
4216 o = player_tryGetOutfit( name, 1 );
4217 if (o==NULL)
4218 return;
4219 player_addOutfitToPilot( ship, o, slot );
4220
4221 /* Doesn't have ammo. */
4223 return;
4224
4225 /* See if has quantity. */
4226 xmlr_attr_int(node,"quantity",q);
4227 if (q > 0)
4228 pilot_addAmmo( ship, slot, q );
4229}
4230
4238static int player_parseShip( xmlNodePtr parent, int is_player )
4239{
4240 char *name, *model;
4241 int id, autoweap, fuel, aim_lines, active_set;
4242 const Ship *ship_parsed;
4243 Pilot* ship;
4244 xmlNodePtr node;
4245 Commodity *com;
4246 PilotFlags flags;
4247 PlayerShip_t ps;
4248
4249 memset( &ps, 0, sizeof(PlayerShip_t) );
4250
4251 /* Parse attributes. */
4252 xmlr_attr_strd( parent, "name", name );
4253 xmlr_attr_strd( parent, "model", model );
4254 xmlr_attr_int_def( parent, "favourite", ps.favourite, 0 );
4255 xmlr_attr_int_def( parent, "deployed", ps.deployed, 0 );
4256
4257 /* Safe defaults. */
4258 pilot_clearFlagsRaw( flags );
4259 if (is_player)
4260 pilot_setFlagRaw( flags, PILOT_PLAYER );
4261 pilot_setFlagRaw( flags, PILOT_NO_OUTFITS );
4262
4263 /* Handle certain 0.10.0-alpha saves where it's possible that... */
4264 if (!is_player && strcmp( name, player.p->name ) == 0) {
4265 DEBUG( _("Ignoring player-owned ship '%s': duplicate of player's current ship."), name );
4266 free(name);
4267 free(model);
4268 return 0;
4269 }
4270
4271 /* Get the ship. */
4272 ship_parsed = player_tryGetShip( model );
4273 if (ship_parsed == NULL) {
4274 WARN(_("Player ship '%s' not found!"), model);
4275
4276 /* TODO we should probably parse the outfits and give them to the player. */
4277
4278 /* Clean up. */
4279 free(name);
4280 free(model);
4281
4282 return -1;
4283 }
4284
4285 /* Create the ship. */
4286 ship = pilot_createEmpty( ship_parsed, name, faction_get("Player"), flags );
4287 /* Player is currently on this ship */
4288 if (is_player)
4289 ps.deployed = 0; /* Current ship can't be deployed. */
4290 ps.p = ship;
4291
4292 /* Ship should not have default outfits. */
4293 for (int i=0; i<array_size(ship->outfits); i++)
4294 pilot_rmOutfitRaw( ship, ship->outfits[i] );
4295
4296 /* Clean up. */
4297 free(name);
4298 free(model);
4299
4300 /* Defaults. */
4301 fuel = -1;
4302 autoweap = 1;
4303 aim_lines = 0;
4304
4305 /* Start parsing. */
4306 node = parent->xmlChildrenNode;
4307 do {
4308 xml_onlyNodes(node);
4309
4310 /* Meta-data. */
4311 xmlr_strd(node,"acquired",ps.acquired);
4312 if (xml_isNode(node,"acquired_date")) {
4313 xml_parseTime(node, &ps.acquired_date);
4314 continue;
4315 }
4316 xmlr_float(node,"time_played",ps.time_played);
4317 xmlr_float(node,"dmg_done_shield",ps.dmg_done_shield);
4318 xmlr_float(node,"dmg_done_armour",ps.dmg_done_armour);
4319 xmlr_float(node,"dmg_taken_shield",ps.dmg_taken_shield);
4320 xmlr_float(node,"dmg_taken_armour",ps.dmg_taken_armour);
4321 xmlr_uint(node,"jumped_times",ps.jumped_times);
4322 xmlr_uint(node,"landed_times",ps.landed_times);
4323 xmlr_uint(node,"death_counter",ps.death_counter);
4324 if (xml_isNode(node,"ships_destroyed")) {
4325 xmlNodePtr cur = node->xmlChildrenNode;
4326 do {
4327 char buf[STRMAX_SHORT];
4328 int class;
4329
4330 xml_onlyNodes(cur);
4331
4332 strncpy( buf, (const char*)cur->name, sizeof(buf)-1 );
4333 for (size_t i=0; i<strlen(buf); i++)
4334 if (buf[i]=='_')
4335 buf[i] = ' ';
4336
4337 class = ship_classFromString( buf );
4338 if (class==SHIP_CLASS_NULL) {
4339 WARN(_("Unknown ship class '%s' when parsing 'ships_destroyed' node!"), (const char*)cur->name );
4340 continue;
4341 }
4342
4343 ps.ships_destroyed[class] = xml_getULong(cur);
4344 } while (xml_nextNode(cur));
4345 }
4346
4347 /* Get fuel. */
4348 xmlr_int(node,"fuel",fuel);
4349
4350 /* New outfit loading. */
4351 if (xml_isNode(node,"outfits_structure")) {
4352 xmlNodePtr cur = node->xmlChildrenNode;
4353 do { /* load each outfit */
4354 int n;
4355 xml_onlyNodes(cur);
4356 if (!xml_isNode(cur,"outfit")) {
4357 WARN(_("Save has unknown '%s' tag!"),xml_get(cur));
4358 continue;
4359 }
4360 xmlr_attr_int_def( cur, "slot", n, -1 );
4361 if ((n<0) || (n >= array_size(ship->outfit_structure))) {
4362 WARN(_("Outfit slot out of range, not adding to ship."));
4363 continue;
4364 }
4365 player_parseShipSlot( cur, ship, &ship->outfit_structure[n] );
4366 } while (xml_nextNode(cur));
4367 continue;
4368 }
4369 else if (xml_isNode(node,"outfits_utility")) {
4370 xmlNodePtr cur = node->xmlChildrenNode;
4371 do { /* load each outfit */
4372 int n;
4373 xml_onlyNodes(cur);
4374 if (!xml_isNode(cur,"outfit")) {
4375 WARN(_("Save has unknown '%s' tag!"),xml_get(cur));
4376 continue;
4377 }
4378 xmlr_attr_int_def( cur, "slot", n, -1 );
4379 if ((n<0) || (n >= array_size(ship->outfit_utility))) {
4380 WARN(_("Outfit slot out of range, not adding."));
4381 continue;
4382 }
4383 player_parseShipSlot( cur, ship, &ship->outfit_utility[n] );
4384 } while (xml_nextNode(cur));
4385 continue;
4386 }
4387 else if (xml_isNode(node,"outfits_weapon")) {
4388 xmlNodePtr cur = node->xmlChildrenNode;
4389 do { /* load each outfit */
4390 int n;
4391 xml_onlyNodes(cur);
4392 if (!xml_isNode(cur,"outfit")) {
4393 WARN(_("Save has unknown '%s' tag!"),xml_get(cur));
4394 continue;
4395 }
4396 xmlr_attr_int_def( cur, "slot", n, -1 );
4397 if ((n<0) || (n >= array_size(ship->outfit_weapon))) {
4398 WARN(_("Outfit slot out of range, not adding."));
4399 continue;
4400 }
4401 player_parseShipSlot( cur, ship, &ship->outfit_weapon[n] );
4402 } while (xml_nextNode(cur));
4403 continue;
4404 }
4405 else if (xml_isNode(node,"outfits_intrinsic")) {
4406 xmlNodePtr cur = node->xmlChildrenNode;
4407 do { /* load each outfit */
4408 xml_onlyNodes(cur);
4409 if (!xml_isNode(cur,"outfit")) {
4410 WARN(_("Save has unknown '%s' tag!"),xml_get(cur));
4411 continue;
4412 }
4413 const Outfit *o = player_tryGetOutfit( xml_get(cur), 1 );
4414 if (o!=NULL) {
4415 if (pilot_hasOutfitLimit( ship, o->limit ))
4416 WARN(_("Player ship '%s' has intrinsic outfit '%s' exceeding limits! Removing."),ship->name,o->name);
4417 else
4418 pilot_addOutfitIntrinsic( ship, o );
4419 }
4420 } while (xml_nextNode(cur));
4421 continue;
4422 }
4423 else if (xml_isNode(node, "commodities")) {
4424 xmlNodePtr cur = node->xmlChildrenNode;
4425 do {
4426 if (xml_isNode(cur, "commodity")) {
4427 int cid, quantity;
4428
4429 xmlr_attr_int( cur, "quantity", quantity );
4430 xmlr_attr_int_def( cur, "id", cid, 0 );
4431
4432 /* Get the commodity. */
4433 com = commodity_get(xml_get(cur));
4434 if (com == NULL) {
4435 WARN(_("Unknown commodity '%s' detected, removing."), xml_get(cur));
4436 continue;
4437 }
4438
4439 /* actually add the cargo with id hack
4440 * Note that the player's cargo_free is ignored here. */
4441 if ((quantity==0) && (cid==0))
4442 WARN(_("Adding cargo '%s' to ship '%s' that is not a mission cargo with quantity=0!"), com->name, ship->name );
4443 pilot_cargoAddRaw( ship, com, quantity, cid );
4444 }
4445 } while (xml_nextNode(cur));
4446 continue;
4447 }
4448 //WARN(_("Save has unknown '%s' tag!"),xml_get(node));
4449 } while (xml_nextNode(node));
4450
4451 /* Update stats. */
4452 pilot_calcStats( ship );
4453
4454 /* Test for validity. */
4455 if (fuel >= 0)
4456 ship->fuel = MIN(ship->fuel_max, fuel);
4457 /* ships can now be non-spaceworthy on save
4458 * str = pilot_isSpaceworthy( ship ); */
4459 if (!pilot_slotsCheckSafety( ship )) {
4460 DEBUG(_("Player ship '%s' failed slot validity check , removing all outfits and adding to stock."),
4461 ship->name );
4462 /* Remove all outfits. */
4463 for (int i=0; i<array_size(ship->outfits); i++) {
4464 const Outfit *o = ship->outfits[i]->outfit;
4465 int ret = pilot_rmOutfitRaw( ship, ship->outfits[i] );
4466 if (ret==0)
4467 player_addOutfit( o, 1 );
4468 }
4469 pilot_calcStats( ship );
4470 }
4471
4472 /* Sets inrange by default if weapon sets are missing. */
4473 for (int i=0; i<PILOT_WEAPON_SETS; i++)
4474 pilot_weapSetInrange( ship, i, WEAPSET_INRANGE_PLAYER_DEF );
4475
4476 /* Second pass for weapon sets. */
4477 active_set = 0;
4478 node = parent->xmlChildrenNode;
4479 do {
4480 xmlNodePtr cur;
4481
4482 if (xml_isNode(node,"vars")) {
4483 ps.p->shipvar = lvar_load( node );
4484 continue;
4485 }
4486 else if (!xml_isNode(node,"weaponsets"))
4487 continue;
4488
4489 /* Check for autoweap. */
4490 xmlr_attr_int( node, "autoweap", autoweap );
4491
4492 /* Load the last weaponset the player used on this ship. */
4493 xmlr_attr_int_def( node, "active_set", active_set, -1 );
4494
4495 /* Check for aim_lines. */
4496 xmlr_attr_int( node, "aim_lines", aim_lines );
4497
4498 /* Parse weapon sets. */
4499 cur = node->xmlChildrenNode;
4500 do { /* Load each weapon set. */
4501 int in_range, manual, weap_type, volley;
4502 xmlNodePtr ccur;
4503
4504 xml_onlyNodes(cur);
4505 if (!xml_isNode(cur,"weaponset")) {
4506 WARN(_("Player ship '%s' has unknown node '%s' in 'weaponsets' (expected 'weaponset')."),
4507 ship->name, cur->name);
4508 continue;
4509 }
4510
4511 /* Get id. */
4512 xmlr_attr_int_def(cur, "id", id, -1);
4513 if (id == -1) {
4514 WARN(_("Player ship '%s' missing 'id' tag for weapon set."),ship->name);
4515 continue;
4516 }
4517 if ((id < 0) || (id >= PILOT_WEAPON_SETS)) {
4518 WARN(_("Player ship '%s' has invalid weapon set id '%d' [max %d]."),
4519 ship->name, id, PILOT_WEAPON_SETS-1 );
4520 continue;
4521 }
4522
4523 /* Clean up weapon set. */
4524 pilot_weapSetClear( ship, id );
4525
4526 /* Set inrange mode. */
4527 xmlr_attr_int( cur, "inrange", in_range );
4528 if (in_range > 0)
4529 pilot_weapSetInrange( ship, id, in_range );
4530
4531 /* Set manual mode. */
4532 xmlr_attr_int( cur, "manual", manual );
4533 if (manual > 0)
4534 pilot_weapSetManual( ship, id, manual );
4535
4536 /* Set volley mode. */
4537 xmlr_attr_int( cur, "volley", volley );
4538 if (volley > 0)
4539 pilot_weapSetVolley( ship, id, volley );
4540
4541 if (autoweap) /* Autoweap handles everything except inrange and manual. */
4542 continue;
4543
4544 /* Set type mode. */
4545 xmlr_attr_int_def( cur, "type", weap_type, -1 );
4546 if (weap_type == -1) {
4547 WARN(_("Player ship '%s' missing 'type' tag for weapon set."),ship->name);
4548 continue;
4549 }
4550 pilot_weapSetType( ship, id, weap_type );
4551
4552 /* Parse individual weapons. */
4553 ccur = cur->xmlChildrenNode;
4554 do {
4555 int level, weapid;
4556 /* Only nodes. */
4557 xml_onlyNodes(ccur);
4558
4559 /* Only weapon nodes. */
4560 if (!xml_isNode(ccur,"weapon")) {
4561 WARN(_("Player ship '%s' has unknown 'weaponset' child node '%s' (expected 'weapon')."),
4562 ship->name, ccur->name );
4563 continue;
4564 }
4565
4566 /* Get level. */
4567 xmlr_attr_int_def( ccur, "level", level, -1 );
4568 if (level == -1) {
4569 WARN(_("Player ship '%s' missing 'level' tag for weapon set weapon."), ship->name);
4570 continue;
4571 }
4572 weapid = xml_getInt(ccur);
4573 if ((weapid < 0) || (weapid >= array_size(ship->outfits))) {
4574 WARN(_("Player ship '%s' has invalid weapon id %d [max %d]."),
4575 ship->name, weapid, array_size(ship->outfits)-1 );
4576 continue;
4577 }
4578
4579 /* Add the weapon set. */
4580 pilot_weapSetAdd( ship, id, ship->outfits[weapid], level );
4581
4582 } while (xml_nextNode(ccur));
4583 } while (xml_nextNode(cur));
4584 } while (xml_nextNode(node));
4585
4586 /* Set up autoweap if necessary. */
4587 ship->autoweap = autoweap;
4588 if (autoweap)
4589 pilot_weaponAuto( ship );
4590 pilot_weaponSafe( ship );
4591 if (active_set >= 0 && active_set < PILOT_WEAPON_SETS)
4592 ship->active_set = active_set;
4593 else
4594 pilot_weaponSetDefault( ship );
4595 /* Copy the weapon set over to the player ship, where we store it. */
4596 ws_copy( ps.weapon_sets, ship->weapon_sets );
4597
4598 /* Set aimLines */
4599 ship->aimLines = aim_lines;
4600
4601 /* Add it to the stack if it's not what the player is in */
4602 if (is_player == 0)
4604 else {
4605 pilot_setPlayer( ship );
4606 player.ps = ps;
4607 }
4608
4609 return 0;
4610}
4611
4616{
4617 if (player.p == NULL)
4618 return;
4619
4620 /* Handle destealth first. */
4621 if (pilot_isFlag(player.p, PILOT_STEALTH)) {
4623 player_message(_("You have destealthed."));
4624 return;
4625 }
4626
4627 /* Stealth case. */
4628 if (pilot_stealth( player.p )) {
4629 player_message( "#g%s", _("You have entered stealth mode.") );
4630 }
4631 else {
4632 /* Stealth failed. */
4633 if (player.p->lockons > 0)
4634 player_message( "#r%s", _("Unable to stealth: missiles locked on!") );
4635 else
4636 player_message( "#r%s", _("Unable to stealth: other pilots nearby!") );
4637 }
4638}
void ai_think(Pilot *pilot, double dt, int dotask)
Heart of the AI, brains of the pilot.
Definition ai.c:797
#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
int player_canBoard(int noisy)
Sees if the pilot can board a pilot.
Definition board.c:114
int player_tryBoard(int noisy)
Attempt to board the player's target.
Definition board.c:152
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:193
Commodity * commodity_get(const char *name)
Gets a commodity by name.
Definition commodity.c:127
void dialogue_alert(const char *fmt,...)
Displays an alert popup with only an ok button and a message.
Definition dialogue.c:132
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:441
void dialogue_msg(const char *caption, const char *fmt,...)
Opens a dialogue window with an ok button and a message.
Definition dialogue.c:230
int dialogue_YesNo(const char *caption, const char *fmt,...)
Runs a dialogue with both yes and no options.
Definition dialogue.c:352
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:1261
void escort_freeList(Pilot *p)
Remove all escorts from a pilot.
Definition escort.c:60
int escort_addList(Pilot *p, const Ship *ship, EscortType_t type, unsigned int id, int persist)
Adds an escort to the escort list of a pilot.
Definition escort.c:40
void escort_rmListIndex(Pilot *p, int i)
Remove from escorts list.
Definition escort.c:73
int escort_clearDeployed(Pilot *p)
Clears deployed escorts of a pilot.
Definition escort.c:228
int escorts_jump(const Pilot *parent, const JumpPoint *jp)
Have a pilot order its escorts to jump.
Definition escort.c:414
int event_start(const char *name, unsigned int *id)
Starts an event.
Definition event.c:123
const char * event_dataName(int dataid)
Gets the event data name from id.
Definition event.c:760
void events_cleanup(void)
Cleans up and removes active events.
Definition event.c:716
int event_dataID(const char *evdata)
Gets the event data id from name.
Definition event.c:745
void events_trigger(EventTrigger_t trigger)
Runs all the events matching a trigger.
Definition event.c:319
void factions_reset(void)
Resets player standing and flags of factions to default.
Definition faction.c:1597
int areEnemies(int a, int b)
Checks whether two factions are enemies.
Definition faction.c:1227
void factions_clearDynamic(void)
Clears dynamic factions.
Definition faction.c:1893
int faction_get(const char *name)
Gets a faction ID by name.
Definition faction.c:184
int areAllies(int a, int b)
Checks whether two factions are allies or not.
Definition faction.c:1253
void gui_clearMessages(void)
Clears the GUI messages.
Definition gui.c:986
void gui_setTarget(void)
Player just changed their pilot target.
Definition gui.c:1783
void gui_setDefaults(void)
Definition gui.c:204
const char * gui_pick(void)
Determines which GUI should be used.
Definition gui.c:1844
int gui_load(const char *name)
Attempts to load the actual GUI.
Definition gui.c:1876
void gui_radarGetRes(double *res)
Outputs the radar's resolution.
Definition gui.c:978
void gui_forceBlink(void)
Force sets the spob and pilot radar blink.
Definition gui.c:1312
void gui_cleanup(void)
Cleans up the GUI.
Definition gui.c:1954
void gui_setNav(void)
Player just changed their nav computer target.
Definition gui.c:1775
void player_message(const char *fmt,...)
Adds a mesg to the queue to be displayed on screen.
Definition gui.c:335
int hooks_runParam(const char *stack, const HookParam *param)
Runs all the hooks of stack.
Definition hook.c:979
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:947
int hooks_run(const char *stack)
Runs all the hooks of stack.
Definition hook.c:999
Handles the info menu.
void input_mouseShow(void)
Shows the mouse.
Definition input.c:368
void input_enableAll(void)
Enables all the keybinds.
Definition input.c:337
void input_getKeybindDisplay(const char *keybind, char *buf, int len)
Gets the display name (translated and human-readable) of a keybind.
Definition input.c:453
void input_mouseHide(void)
Hides the mouse.
Definition input.c:377
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:1380
unsigned int land_getWid(int window)
Gets the WID of a window by type.
Definition land.c:889
void land_cleanup(void)
Cleans up some land-related variables.
Definition land.c:1596
int landed
Definition land.c:75
void land(Spob *p, int load)
Opens up all the land dialogue stuff.
Definition land.c:1124
Spob * land_spob
Definition land.c:83
void land_refuel(void)
Refuels the player's current ship, if possible.
Definition land.c:733
int outfits_filter(const Outfit **outfits, int n, int(*filter)(const Outfit *), const char *name)
Applies a filter function and string to a list of outfits.
int load_refresh(void)
Loads or refreshes saved games for the player.
Definition load.c:227
const nsave_t * load_getList(const char *name)
Gets the array (array.h) of loaded saves.
Definition load.c:477
int lvar_save(const lvar *arr, xmlTextWriterPtr writer)
Saves the mission variables.
Definition lvar.c:201
lvar * lvar_load(xmlNodePtr parent)
Loads the vars from XML file.
Definition lvar.c:242
Handles the important game menus.
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:321
int mission_start(const char *name, unsigned int *id)
Starts a mission.
Definition mission.c:358
int mission_getID(const char *name)
Gets id from mission name.
Definition mission.c:100
void missions_cleanup(void)
Cleans up all the player's active missions.
Definition mission.c:1268
const MissionData * mission_get(int id)
Gets a MissionData based on ID.
Definition mission.c:116
int music_choose(const char *situation)
Actually runs the music stuff, based on situation.
Definition music.c:412
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.
#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 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
int lua_isoutfit(lua_State *L, int ind)
Checks to see if ind is a outfit.
const Outfit * lua_tooutfit(lua_State *L, int ind)
Lua bindings to interact with outfits.
LuaPilot * lua_pushpilot(lua_State *L, LuaPilot pilot)
Pushes a pilot on the stack.
Definition nlua_pilot.c:563
int lua_isship(lua_State *L, int ind)
Checks to see if ind is a ship.
Definition nlua_ship.c:182
const Ship * lua_toship(lua_State *L, int ind)
Lua bindings to interact with ships.
Definition nlua_ship.c:116
LuaSpob * lua_pushspob(lua_State *L, LuaSpob spob)
Pushes a spob on the stack.
Definition nlua_spob.c:201
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:81
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:166
int outfit_isLauncher(const Outfit *o)
Checks if outfit is a weapon launcher.
Definition outfit.c:564
int outfit_isLocalMap(const Outfit *o)
Checks if outfit is a local space map.
Definition outfit.c:634
int outfit_compareTech(const void *outfit1, const void *outfit2)
Function meant for use with C89, C99 algorithm qsort().
Definition outfit.c:243
const Outfit * outfit_getW(const char *name)
Gets an outfit by name without warning on no-find.
Definition outfit.c:180
int outfit_fitsSlot(const Outfit *o, const OutfitSlot *s)
Checks to see if an outfit fits a slot.
Definition outfit.c:1047
int outfit_isFighterBay(const Outfit *o)
Checks if outfit is a fighter bay.
Definition outfit.c:616
int outfit_isMap(const Outfit *o)
Checks if outfit is a space map.
Definition outfit.c:625
int outfit_isLicense(const Outfit *o)
Checks if outfit is a license.
Definition outfit.c:643
int outfit_isGUI(const Outfit *o)
Checks if outfit is a GUI.
Definition outfit.c:652
int outfit_licenseExists(const char *name)
Checks to see if a license exists.
Definition outfit.c:3057
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:3555
void pilot_stackRemove(Pilot *p)
Tries to remove a pilot from the stack.
Definition pilot.c:3640
int pilot_isHostile(const Pilot *p)
Checks to see if pilot is hostile to the player.
Definition pilot.c:678
void pilot_cooldown(Pilot *p, int dochecks)
Begins active cooldown, reducing hull and outfit temperatures.
Definition pilot.c:893
unsigned int pilot_getNearestPilot(const Pilot *p)
Get the nearest pilot to a pilot.
Definition pilot.c:423
Pilot * pilot_getTarget(Pilot *p)
Gets the target of a pilot using a fancy caching system.
Definition pilot.c:634
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:3301
double pilot_face(Pilot *p, double dir, double dt)
Tries to turn the pilot to face dir.
Definition pilot.c:810
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:547
Pilot * pilot_setPlayer(Pilot *after)
Replaces the player's pilot with an alternate ship with the same ID.
Definition pilot.c:3396
void pilot_renderOverlay(Pilot *p)
Renders the pilot overlay.
Definition pilot.c:2026
void pilot_setAccel(Pilot *p, double accel)
Sets the pilot's accel.
Definition pilot.c:659
void pilot_cooldownEnd(Pilot *p, const char *reason)
Terminates active cooldown.
Definition pilot.c:959
credits_t pilot_modCredits(Pilot *p, credits_t amount)
Modifies the amount of credits the pilot has.
Definition pilot.c:3004
void pilot_hyperspaceAbort(Pilot *p)
Stops the pilot from hyperspacing.
Definition pilot.c:2857
void pilot_setTurn(Pilot *p, double turn)
Sets the pilot's turn.
Definition pilot.c:667
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:237
void pilot_reset(Pilot *pilot)
Resets a pilot.
Definition pilot.c:3185
int pilot_isFriendly(const Pilot *p)
Checks to see if pilot is friendly to the player.
Definition pilot.c:708
PilotOutfitSlot * pilot_getDockSlot(Pilot *p)
Gets the dock slot of the pilot.
Definition pilot.c:776
Pilot * pilot_get(unsigned int id)
Pulls a pilot out of the pilot_stack based on ID.
Definition pilot.c:620
ntime_t pilot_hyperspaceDelay(const Pilot *p)
Calculates the hyperspace delay for a pilot.
Definition pilot.c:2948
double pilot_getNearestPosPilot(const Pilot *p, Pilot **tp, double x, double y, int disabled)
Get the nearest pilot to a pilot from a certain position.
Definition pilot.c:503
static Pilot ** pilot_stack
Definition pilot.c:61
void pilot_render(Pilot *p)
Renders the pilot.
Definition pilot.c:1876
Pilot *const * pilot_getAll(void)
Gets the pilot stack.
Definition pilot.c:94
int pilot_canTarget(const Pilot *p)
Same as pilot_validTarget but without the range check.
Definition pilot.c:254
credits_t pilot_worth(const Pilot *p, int count_unique)
Gets the price or worth of a pilot in credits.
Definition pilot.c:4096
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:999
unsigned int pilot_getNextID(unsigned int id, int mode)
Gets the next pilot based on id.
Definition pilot.c:135
void pilots_cleanAll(void)
Even cleans up the player.
Definition pilot.c:3783
void pilot_update(Pilot *pilot, double dt)
Updates the pilot.
Definition pilot.c:2108
Pilot * 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:3248
unsigned int pilot_getPrevID(unsigned int id, int mode)
Gets the previous pilot based on ID.
Definition pilot.c:183
int pilot_numOutfit(const Pilot *p, const Outfit *o)
Checks to see how many of an outfit a pilot has.
Definition pilot.c:2973
int pilot_hasCredits(const Pilot *p, credits_t amount)
Checks to see if the pilot has at least a certain amount of credits.
Definition pilot.c:2990
void pilot_setTarget(Pilot *p, unsigned int id)
Sets the target of the pilot.
Definition pilot.c:1308
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.
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:244
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:279
void pilot_destealth(Pilot *p)
Destealths a pilot.
Definition pilot_ew.c:552
int pilot_stealth(Pilot *p)
Stealths a pilot.
Definition pilot_ew.c:513
int pilot_hasOutfitLimit(const Pilot *p, const char *limit)
Checks to see if a pilot has an outfit with a specific outfit type.
int pilot_slotsCheckSafety(const Pilot *p)
Pilot slot safety check - makes sure stats are safe.
int pilot_outfitLAdd(const Pilot *pilot, PilotOutfitSlot *po)
Outfit is added to a ship.
int pilot_maxAmmoO(const Pilot *p, const Outfit *o)
Gets the maximum available ammo for a pilot for a specific outfit.
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.
int pilot_addAmmo(Pilot *pilot, PilotOutfitSlot *s, int quantity)
Adds some ammo to the pilot stock.
int pilot_hasIntrinsic(const Pilot *pilot, const Outfit *outfit)
Gets how many copies of an intrinsic a pilot has.
int pilot_rmOutfitRaw(Pilot *pilot, PilotOutfitSlot *s)
Removes an outfit from the pilot without doing any checks.
int pilot_outfitLRemove(const Pilot *pilot, PilotOutfitSlot *po)
Outfit is removed froma ship.
int pilot_addOutfitRaw(Pilot *pilot, const Outfit *outfit, PilotOutfitSlot *s)
Adds an outfit to the pilot, ignoring CPU or other limits.
int pilot_rmOutfitIntrinsic(Pilot *pilot, const Outfit *outfit)
Removes an outfit from an intrinsic slot.
int pilot_isSpaceworthy(const Pilot *p)
Pilot safety check - makes sure stats are safe.
int pilot_addOutfitIntrinsic(Pilot *pilot, const Outfit *outfit)
Adds an outfit as an intrinsic slot.
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.
void pilot_weaponSafe(Pilot *p)
Sets the weapon set as safe.
int pilot_shoot(Pilot *p, int level)
Makes the pilot shoot.
void pilot_weapSetManual(Pilot *p, int id, int manual)
Changes the weapon set manual property.
void pilot_afterburnOver(Pilot *p)
Deactivates the afterburner.
void pilot_weapSetVolley(Pilot *p, int id, int volley)
Changes the weapon set volley property.
void pilot_shootStop(Pilot *p, int level)
Have pilot stop shooting their weapon.
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.
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_weapSetClear(Pilot *p, int id)
Clears a 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.
void pilot_weapSetType(Pilot *p, int id, WeaponSetType type)
Changes the weapon sets mode.
void pilot_weapSetAdd(Pilot *p, int id, const PilotOutfitSlot *o, int level)
Adds an outfit to a weapon set.
void player_hailStart(void)
Starts the hail sounds and aborts autoNav.
Definition player.c:1923
void player_stealth(void)
Input binding for toggling stealth for the player.
Definition player.c:4615
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:1422
int player_eventAlreadyDone(int id)
Checks to see if player has already completed a event.
Definition player.c:3014
int player_nships(void)
Gets the amount of ships player has in storage.
Definition player.c:2654
int player_save(xmlTextWriterPtr writer)
Save the freaking player in a freaking xmlfile.
Definition player.c:3232
int snd_jump
Definition player.c:98
int snd_nav
Definition player.c:99
void player_soundResume(void)
Resumes the ship's sounds.
Definition player.c:921
static int player_saveShipSlot(xmlTextWriterPtr writer, const PilotOutfitSlot *slot, int i)
Saves an outfit slot.
Definition player.c:3346
int player_rmOutfit(const Outfit *o, int quantity)
Remove an outfit from the player's outfit stack.
Definition player.c:2890
void player_runHooks(void)
Runs hooks for the player.
Definition player.c:3077
static int player_shipsCompare(const void *arg1, const void *arg2)
PlayerShip_t compare function for qsort().
Definition player.c:2574
void player_updateSpecific(Pilot *pplayer, const double dt)
Does a player specific update.
Definition player.c:1334
static void player_clearEscorts(void)
Clears escorts to make sure deployment is safe.
Definition player.c:3101
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:2795
int player_hasLicense(const char *license)
Checks to see if player has license.
Definition player.c:3039
void player_autohail(void)
Automatically tries to hail a pilot that hailed the player.
Definition player.c:2425
void player_dead(void)
Player got pwned.
Definition player.c:2536
void player_swapShip(const char *shipname, int move_cargo)
Swaps player's current ship with their ship named shipname.
Definition player.c:526
static void player_renderAimHelper(double dt)
Renders the aim helper.
Definition player.c:1102
void player_cooldownBrake(void)
Starts braking or active cooldown.
Definition player.c:2481
void player_accel(double acc)
Start accelerating.
Definition player.c:2113
static double player_hailTimer
Definition player.c:109
int player_ships(char **sships, glTexture **tships)
Returns a buffer with all the player's ships names.
Definition player.c:2627
void player_targetEscort(int prev)
Targets the pilot.
Definition player.c:2254
void player_targetAsteroidSet(int field, int id)
Sets the player's target asteroid.
Definition player.c:1522
static void player_parseShipSlot(xmlNodePtr node, Pilot *ship, PilotOutfitSlot *slot)
Parses a ship outfit slot.
Definition player.c:4205
static void player_renderStealthUnderlay(double dt)
Renders the stealth overlay for the player.
Definition player.c:1035
int player_addOutfit(const Outfit *o, int quantity)
Adds an outfit to the player outfit stack.
Definition player.c:2828
void player_soundPlay(int sound, int once)
Plays a sound at the player.
Definition player.c:886
static int player_soundReserved
Definition player.c:841
void player_new(void)
Creates a new player.
Definition player.c:242
static PlayerShip_t * player_stack
Definition player.c:114
int snd_hypJump
Definition player.c:106
void player_warp(double x, double y)
Warps the player to the new position.
Definition player.c:935
int snd_hypEng
Definition player.c:103
static int player_parseDoneMissions(xmlNodePtr parent)
Parses player's done missions.
Definition player.c:3981
static PlayerShip_t * player_newShipMake(const char *name)
Actually creates the new ship.
Definition player.c:483
static int player_parseEscorts(xmlNodePtr parent)
Parses the escorts from the escort node.
Definition player.c:4083
double player_right
Definition player.c:122
void player_checkLandAck(void)
Revokes landing authorization if the player's reputation is too low.
Definition player.c:1713
int player_numOutfits(void)
Gets the amount of different outfits in the player outfit stack.
Definition player.c:2816
static int player_parseShip(xmlNodePtr parent, int is_player)
Parses a player's ship.
Definition player.c:4238
void player_targetSet(unsigned int id)
Sets the player's target.
Definition player.c:2137
static int screenshot_cur
Definition player.c:2315
static void player_tryAddLicense(const char *name)
Tries to get an outfit for the player or looks for equivalents.
Definition player.c:3722
void player_render(double dt)
Renders the player.
Definition player.c:983
void player_hailSpob(void)
Opens communication with the player's spob target.
Definition player.c:2406
credits_t player_shipPrice(const char *shipname, int count_unique)
Calculates the price of one of the player's ships.
Definition player.c:667
void player_resetSpeed(void)
Resets the player speed stuff.
Definition player.c:1448
static int player_lastEngineSound
Definition player.c:107
const PlayerShip_t * player_getShipStack(void)
Gets the array (array.h) of the player's ships.
Definition player.c:2644
static int player_outfitCompare(const void *arg1, const void *arg2)
qsort() compare function for PlayerOutfit_t sorting.
Definition player.c:2767
void player_targetHyperspaceSet(int id, int nomsg)
Sets the player's hyperspace target.
Definition player.c:1821
int snd_hail
Definition player.c:100
static char * player_message_noland
Definition player.c:79
static int player_parseMetadata(xmlNodePtr parent)
Parses the player metadata.
Definition player.c:4127
void player_cleanup(void)
Cleans up player stuff like player_stack.
Definition player.c:730
static int player_parseLicenses(xmlNodePtr parent)
Parses player's licenses.
Definition player.c:4031
void player_targetHyperspace(void)
Gets a hyperspace target.
Definition player.c:1855
static double player_timer
Definition player.c:125
static int * events_done
Definition player.c:131
int snd_hypPowDown
Definition player.c:104
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:410
void player_rmShip(const char *shipname)
Removes one of the player's ships.
Definition player.c:705
int player_outfitOwnedTotal(const Outfit *o)
Definition player.c:2754
void player_hyperspacePreempt(int preempt)
Enables or disables jump points preempting spobs in autoface and target clearing.
Definition player.c:1893
PlayerShip_t * player_getPlayerShip(const char *shipname)
Gets a specific ship.
Definition player.c:2703
void player_toggleMouseFly(void)
Toggles mouse flying.
Definition player.c:2458
void player_targetNearest(void)
Player targets nearest pilot.
Definition player.c:2297
static PlayerOutfit_t * player_outfits
Definition player.c:115
static credits_t player_payback
Definition player.c:77
double player_dt_default(void)
Returns the player's total default time delta based on time dilation stuff.
Definition player.c:1913
void player_update(Pilot *pplayer, const double dt)
Player update function.
Definition player.c:1318
static const Ship * player_tryGetShip(const char *name)
Tries to get an ship for the player or looks for equivalents.
Definition player.c:3695
const char ** player_getLicenses()
Gets the array (array.h) of license names in the player's inventory.
Definition player.c:3069
void player_brokeHyperspace(void)
Player actually broke hyperspace (entering new system).
Definition player.c:2016
static credits_t player_creds
Definition player.c:76
int player_getHypPreempt(void)
Returns whether the jump point target should preempt the spob target.
Definition player.c:1903
int player_missionAlreadyDone(int id)
Checks to see if player has already completed a mission.
Definition player.c:2961
void player_renderUnderlay(double dt)
Renders the player underlay.
Definition player.c:1021
static int player_hailCounter
Definition player.c:108
int player_addEscorts(void)
Adds the player's escorts.
Definition player.c:3117
static int player_parseDoneEvents(xmlNodePtr parent)
Parses player's done missions.
Definition player.c:4006
#define RADAR_RES_DEFAULT
Definition player.c:89
void player_soundStop(void)
Stops playing player sounds.
Definition player.c:894
void player_restoreControl(int reason, const char *str)
Aborts autonav and other states that take control of the ship.
Definition player.c:1461
void player_addLicense(const char *license)
Gives the player a license.
Definition player.c:3055
double player_acc
Definition player.c:123
credits_t player_modCredits(credits_t amount)
Modifies the amount of credits the player has.
Definition player.c:975
int * player_eventsDoneList(void)
Gets a list of all the events the player has done.
Definition player.c:3028
int snd_hypPowUpJump
Definition player.c:105
int player_jump(void)
Actually attempts to jump in hyperspace.
Definition player.c:1941
void player_targetSpobSet(int id)
Sets the player's target spob.
Definition player.c:1485
static int player_filterSuitableSpob(Spob *p)
Filter function for space_getRndSpob.
Definition player.c:3970
void player_clear(void)
Clears the targets.
Definition player.c:947
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:3668
static void player_addOutfitToPilot(Pilot *pilot, const Outfit *outfit, PilotOutfitSlot *s)
Adds outfit to pilot if it can.
Definition player.c:4179
static void player_spobOutOfRangeMsg(void)
Displays an out of range message for the player's currently selected spob.
Definition player.c:2368
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:3626
int snd_hypPowUp
Definition player.c:102
static Spob * player_parse(xmlNodePtr parent)
Parses the player node.
Definition player.c:3747
int player_hasShip(const char *shipname)
Sees if player has a ship of a name.
Definition player.c:2665
void player_accelOver(void)
Done accelerating.
Definition player.c:2127
static int player_gui_group
Definition player.c:96
void player_think(Pilot *pplayer, const double dt)
Basically uses keyboard input instead of AI input. Used in pilot.c.
Definition player.c:1170
int snd_target
Definition player.c:97
int player_land(int loud)
Try to land or target closest spob if no land target.
Definition player.c:1579
static int player_newMake(void)
Actually creates a new player.
Definition player.c:330
static int player_saveShip(xmlTextWriterPtr writer, PlayerShip_t *pship)
Saves a ship.
Definition player.c:3366
static int player_hyper_group
Definition player.c:95
void player_soundPause(void)
Pauses the ship's sounds.
Definition player.c:910
static int player_saveEscorts(xmlTextWriterPtr writer)
Saves the player's escorts.
Definition player.c:3193
Player_t player
Definition player.c:74
int player_hasCredits(credits_t amount)
Checks to see if the player has enough credits.
Definition player.c:964
static int player_engine_group
Definition player.c:94
void player_shipsSort(void)
Sorts the players ships.
Definition player.c:2610
void player_missionFinished(int id)
Marks a mission as completed.
Definition player.c:2930
int player_outfitOwned(const Outfit *o)
Gets how many of the outfit the player owns.
Definition player.c:2722
void player_targetClearAll(void)
Clears all player targets: hyperspace, spob, asteroid, etc...
Definition player.c:2241
static int * missions_done
Definition player.c:130
static char ** player_licenses
Definition player.c:84
void player_nolandMsg(const char *str)
Sets the no land message.
Definition player.c:1743
void player_targetPrev(int mode)
Cycles to previous target.
Definition player.c:2212
const PlayerOutfit_t * player_getOutfits(void)
Gets an array (array.h) of the player's outfits.
Definition player.c:2782
Spob * player_load(xmlNodePtr parent)
Loads the player stuff.
Definition player.c:3563
double player_left
Definition player.c:121
static void player_newSetup()
Sets up a new player.
Definition player.c:202
static int player_ran_updater
Definition player.c:78
static const Ship * player_ship
Definition player.c:75
void player_soundPlayGUI(int sound, int once)
Plays a GUI sound (unaffected by time accel).
Definition player.c:875
static void player_renderStealthOverlay(double dt)
Renders the stealth overlay for the player.
Definition player.c:1074
void player_targetClear(void)
Clears the player's ship, spob or hyperspace target, in that order.
Definition player.c:2220
void player_targetHostile(void)
Targets the nearest hostile enemy to the player.
Definition player.c:2163
static void player_initSound(void)
Initializes the player sounds.
Definition player.c:845
static int player_parseInventory(xmlNodePtr parent)
Parses player's inventory.
Definition player.c:4056
void player_eventFinished(int id)
Marks a event as completed.
Definition player.c:2985
void player_screenshot(void)
Takes a screenshot.
Definition player.c:2319
void player_approach(void)
Logic to make the player approach a target pilot to board or spob to land on.
Definition player.c:1757
void player_destroyed(void)
Player blew up in a fireball.
Definition player.c:2549
void player_targetSpob(void)
Cycle through spob targets.
Definition player.c:1546
int player_init(void)
Initializes player stuff.
Definition player.c:185
int * player_missionsDoneList(void)
Gets a list of all the missions the player has done.
Definition player.c:2975
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:2349
Pilot * player_getShip(const char *shipname)
Gets a specific ship.
Definition player.c:2684
static int player_thinkMouseFly(double dt)
Handles mouse flying based on cursor position.
Definition player.c:2508
void player_targetNext(int mode)
Cycles to next target.
Definition player.c:2202
static int player_saveMetadata(xmlTextWriterPtr writer)
Saves the player meta-data.
Definition player.c:3518
void player_hail(void)
Opens communication with the player's target.
Definition player.c:2378
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_autonavSpob(const char *name, int tryland)
Starts autonav with a spob destination.
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.
void pfleet_update(void)
Updates the used fleet capacity of the player.
const char ** player_guiList(void)
Gets the list of GUIs.
Definition player_gui.c:103
int player_guiAdd(const char *name)
Adds a gui to the player.
Definition player_gui.c:40
int player_guiCheck(const char *name)
Check if player has a GUI.
Definition player_gui.c:88
void player_guiCleanup(void)
Cleans up the player's GUI list.
Definition player_gui.c:29
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 d[]
Definition rng.c:273
ShipClass ship_classFromString(const char *str)
Gets the machine ship class identifier from a human readable string.
Definition ship.c:236
const Ship * ship_getW(const char *name)
Gets a ship based on its name without warning.
Definition ship.c:101
const char * ship_classToString(ShipClass class)
Gets the ship class name in human readable form.
Definition ship.c:189
const Ship * ship_get(const char *name)
Gets a ship based on its name.
Definition ship.c:87
void shiplog_clear(void)
Clear the shiplog.
Definition shiplog.c:355
int sound_createGroup(int size)
Creates a sound group.
Definition sound.c:1329
void sound_pitchGroup(int group, double pitch)
Sets the pitch of a group.
Definition sound.c:1605
void sound_resumeGroup(int group)
Resumes all the sounds in a group.
Definition sound.c:1519
void sound_speedGroup(int group, int enable)
Sets whether or not the speed affects a group.
Definition sound.c:1551
int sound_playGroup(int group, int sound, int once)
Plays a sound in a group.
Definition sound.c:1401
void sound_stopGroup(int group)
Stops all the sounds in a group.
Definition sound.c:1477
void sound_stopAll(void)
Stops all the playing voices.
Definition sound.c:1044
int sound_get(const char *name)
Gets the buffer to sound of name.
Definition sound.c:756
void sound_pauseGroup(int group)
Pauses all the sounds in a group.
Definition sound.c:1497
void sound_volumeGroup(int group, double volume)
Sets the volume of a group.
Definition sound.c:1575
void sound_setSpeed(double s)
Sets the speed to play the sound at.
Definition sound.c:1152
void space_init(const char *sysname, int do_simulate)
Initializes the system.
Definition space.c:1549
void space_gfxUnload(StarSystem *sys)
Unloads all the graphics for a star system.
Definition space.c:2127
Spob * spob_get(const char *spobname)
Gets a spob based on its name.
Definition space.c:1051
const char * space_getRndSpob(int landable, unsigned int services, int(*filter)(Spob *p))
Gets the name of a random spob.
Definition space.c:633
int spob_index(const Spob *p)
Gets the ID of a spob.
Definition space.c:1099
char spob_getColourChar(const Spob *p)
Gets the spob colour char.
Definition space.c:1881
StarSystem * system_get(const char *sysname)
Get the system from its name.
Definition space.c:960
const char * spob_getSystem(const char *spobname)
Get the name of a system from a spobname.
Definition space.c:1025
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:527
StarSystem * cur_system
Definition space.c:106
void spob_updateLand(Spob *p)
Updates the land possibilities of a spob.
Definition space.c:1943
void space_clearKnown(void)
Clears all system knowledge.
Definition space.c:3677
const char * spob_name(const Spob *p)
Gets the translated name of a spob.
Definition space.c:1752
void space_gfxLoad(StarSystem *sys)
Loads all the graphics for a star system.
Definition space.c:2116
int space_hyperspace(Pilot *p)
Tries to get the pilot into hyperspace.
Definition space.c:503
const char * start_acquired(void)
Gets the module's starting ship was acquired.
Definition start.c:204
const char * start_event(void)
Gets the starting event of the player.
Definition start.c:269
const char * start_mission(void)
Gets the starting mission of the player.
Definition start.c:260
void start_position(double *x, double *y)
Gets the starting position of the player.
Definition start.c:250
const char * start_chapter(void)
Gets the player's starting chapter.
Definition start.c:278
const char * start_ship(void)
Gets the module player starting ship.
Definition start.c:186
ntime_t start_date(void)
Gets the starting date.
Definition start.c:231
const char * start_shipname(void)
Gets the module's starting ship's name.
Definition start.c:195
const char * start_system(void)
Gets the starting system name.
Definition start.c:240
unsigned int start_credits(void)
Gets the player's starting credits.
Definition start.c:222
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:77
Solid sol
Definition asteroid.h:87
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:206
unsigned int id
Definition pilot.h:209
int persist
Definition pilot.h:211
EscortType_t type
Definition pilot.h:208
const Ship * ship
Definition pilot.h:207
The actual hook parameter.
Definition hook.h:38
const char * str
Definition hook.h:42
HookParamType type
Definition hook.h:39
union HookParam::@25 u
LuaAsteroid_t ast
Definition hook.h:51
int ref
Definition hook.h:52
const Ship * ship
Definition hook.h:45
Static mission data.
Definition mission.h:62
char * name
Definition mission.h:63
char * gui
Definition outfit.h:315
char * provides
Definition outfit.h:322
OutfitSlotType type
Definition outfit.h:112
A ship outfit, depends radically on the type.
Definition outfit.h:328
char * limit
Definition outfit.h:342
OutfitGUIData gui
Definition outfit.h:412
union Outfit::@12 u
OutfitSlot slot
Definition outfit.h:336
OutfitAfterburnerData afb
Definition outfit.h:408
char * name
Definition outfit.h:329
OutfitLicenseData lic
Definition outfit.h:413
Stores a pilot commodity.
Definition pilot.h:179
const Commodity * commodity
Definition pilot.h:180
unsigned int id
Definition pilot.h:182
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:164
PilotWeaponSetOutfit * slots
Definition pilot.h:167
WeaponSetType type
Definition pilot.h:165
The representation of an in-game pilot.
Definition pilot.h:217
double engine_glow
Definition pilot.h:383
double ew_stealth_timer
Definition pilot.h:279
ShipStats stats
Definition pilot.h:294
unsigned int id
Definition pilot.h:218
lvar * shipvar
Definition pilot.h:385
PilotWeaponSet weapon_sets[PILOT_WEAPON_SETS]
Definition pilot.h:319
PilotCommodity * commodities
Definition pilot.h:326
int aimLines
Definition pilot.h:322
double ew_stealth
Definition pilot.h:273
PilotOutfitSlot * outfit_structure
Definition pilot.h:301
credits_t credits
Definition pilot.h:325
int nav_hyperspace
Definition pilot.h:345
PilotOutfitSlot ** outfits
Definition pilot.h:300
PilotOutfitSlot * outfit_utility
Definition pilot.h:302
PilotOutfitSlot * outfit_intrinsic
Definition pilot.h:304
const Ship * ship
Definition pilot.h:226
int lockons
Definition pilot.h:378
double fuel_max
Definition pilot.h:259
int nav_anchor
Definition pilot.h:346
double ptimer
Definition pilot.h:368
int faction
Definition pilot.h:222
int autoweap
Definition pilot.h:321
double landing_delay
Definition pilot.h:366
Solid solid
Definition pilot.h:227
double fuel
Definition pilot.h:260
PilotOutfitSlot * afterburner
Definition pilot.h:316
char * name
Definition pilot.h:219
Escort_t * escorts
Definition pilot.h:334
double fuel_consumption
Definition pilot.h:261
int active_set
Definition pilot.h:320
unsigned int target
Definition pilot.h:342
int nav_spob
Definition pilot.h:344
PilotOutfitSlot * outfit_weapon
Definition pilot.h:303
int nav_asteroid
Definition pilot.h:347
double engine_vol
Definition conf.h:109
int mouse_accel
Definition conf.h:153
double zoom_far
Definition conf.h:134
int mouse_fly
Definition conf.h:152
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:120
double dmg_done_shield
Definition player.h:132
double mousex
Definition player.h:108
int autonav
Definition player.h:107
unsigned int jumped_times
Definition player.h:137
PlayerShip_t ps
Definition player.h:102
char * name
Definition player.h:103
char * loaded_version
Definition player.h:116
double dmg_done_armour
Definition player.h:133
unsigned int ships_destroyed[SHIP_CLASS_TOTAL]
Definition player.h:136
time_t last_played
Definition player.h:129
double dmg_taken_armour
Definition player.h:135
char * gui
Definition player.h:119
time_t time_since_save
Definition player.h:142
int map_minimal
Definition player.h:122
double time_played
Definition player.h:130
char * chapter
Definition player.h:111
time_t date_created
Definition player.h:131
int fleet_capacity
Definition player.h:126
double dmg_taken_shield
Definition player.h:134
double speed
Definition player.h:110
char * difficulty
Definition player.h:112
double mousey
Definition player.h:109
unsigned int death_counter
Definition player.h:139
unsigned int landed_times
Definition player.h:138
int eq_outfitMode
Definition player.h:121
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:124
glTexture * gfx_space
Definition ship.h:138
char * name
Definition ship.h:95
int sound
Definition ship.h:150
double engine_pitch
Definition ship.h:151
glTexture * gfx_store
Definition ship.h:141
vec2 vel
Definition physics.h:48
double dir
Definition physics.h:46
vec2 pos
Definition physics.h:49
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition space.h:89
int can_land
Definition space.h:108
char * land_msg
Definition space.h:110
int land_override
Definition space.h:109
int lua_land
Definition space.h:144
double radius
Definition space.h:95
nlua_env lua_env
Definition space.h:138
char * name
Definition space.h:91
vec2 pos
Definition space.h:94
int lua_can_land
Definition space.h:143
Abstraction for rendering sprite sheets.
Definition opengl_tex.h:36
double sw
Definition opengl_tex.h:46
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:94
void diff_clear(void)
Removes all active diffs. (Call before economy_destroy().)
Definition unidiff.c:1522