naev 0.11.5
pilot.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <limits.h>
11#include <math.h>
12#include <stdlib.h>
13
14#include "naev.h"
17#include "pilot.h"
18
19#include "ai.h"
20#include "array.h"
21#include "board.h"
22#include "camera.h"
23#include "damagetype.h"
24#include "debris.h"
25#include "debug.h"
26#include "escort.h"
27#include "explosion.h"
28#include "faction.h"
29#include "font.h"
30#include "gatherable.h"
31#include "gui.h"
32#include "hook.h"
33#include "land.h"
34#include "land_outfits.h"
35#include "land_shipyard.h"
36#include "log.h"
37#include "map.h"
38#include "music.h"
39#include "nlua_pilotoutfit.h"
40#include "nlua_vec2.h"
41#include "nlua_outfit.h"
42#include "ndata.h"
43#include "nstring.h"
44#include "ntime.h"
45#include "nxml.h"
46#include "pause.h"
47#include "player.h"
48#include "player_autonav.h"
49#include "pilot_ship.h"
50#include "quadtree.h"
51#include "start.h"
52#include "rng.h"
53#include "weapon.h"
54
55#define PILOT_SIZE_MIN 128
57/* ID Generators. */
58static unsigned int pilot_id = PLAYER_ID;
60/* stack of pilots */
61static Pilot** pilot_stack = NULL;
64static int qt_init = 0;
65/* A simple grid search procedure was used to determine the following parameters. */
66static int qt_max_elem = 2;
67static int qt_depth = 5;
68
69/* misc */
70static const double pilot_commTimeout = 15.;
71static const double pilot_commFade = 5.;
73/*
74 * Prototypes
75 */
76/* Create. */
77static void pilot_init( Pilot* dest, const Ship* ship, const char* name, int faction,
78 const double dir, const vec2* pos, const vec2* vel,
79 const PilotFlags flags, unsigned int dockpilot, int dockslot );
80/* Update. */
81static void pilot_hyperspace( Pilot* pilot, double dt );
82static void pilot_refuel( Pilot *p, double dt );
83/* Clean up. */
84static void pilot_erase( Pilot *p );
85/* Misc. */
86static void pilot_renderFramebufferBase( Pilot *p, GLuint fbo, double fw, double fh );
87static int pilot_getStackPos( unsigned int id );
88static void pilot_init_trails( Pilot* p );
89static int pilot_trail_generated( Pilot* p, int generator );
90
94Pilot*const* pilot_getAll (void)
95{
96 return pilot_stack;
97}
98
102static int pilot_cmp( const void *ptr1, const void *ptr2 )
103{
104 const Pilot *p1, *p2;
105 p1 = *((const Pilot**) ptr1);
106 p2 = *((const Pilot**) ptr2);
107 return p1->id - p2->id;
108}
109
116static int pilot_getStackPos( unsigned int id )
117{
118 const Pilot pid = { .id = id };
119 const Pilot *pidptr = &pid;
120 /* binary search */
121 Pilot **pp = bsearch(&pidptr, pilot_stack, array_size(pilot_stack), sizeof(Pilot*), pilot_cmp);
122 if (pp == NULL)
123 return -1;
124 else
125 return pp - pilot_stack;
126}
127
135unsigned int pilot_getNextID( unsigned int id, int mode )
136{
137 int m, p;
138
139 /* Player must exist. */
140 if (player.p == NULL)
141 return PLAYER_ID;
142
143 /* Get the pilot. */
144 m = pilot_getStackPos(id);
145
146 /* Unselect. */
147 if ((m == (array_size(pilot_stack)-1)) || (m == -1))
148 return PLAYER_ID;
149
150 /* Get first one in range. */
151 p = m+1;
152 if (mode == 0) {
153 while (p < array_size(pilot_stack)) {
154 if ((!pilot_isWithPlayer(pilot_stack[p]) ||
155 pilot_isDisabled(pilot_stack[p])) &&
157 return pilot_stack[p]->id;
158 p++;
159 }
160 }
161 /* Get first hostile in range. */
162 if (mode == 1) {
163 while (p < array_size(pilot_stack)) {
164 if (!pilot_isWithPlayer(pilot_stack[p]) &&
167 return pilot_stack[p]->id;
168 p++;
169 }
170 }
171
172 /* None found. */
173 return PLAYER_ID;
174}
175
183unsigned int pilot_getPrevID( unsigned int id, int mode )
184{
185 int m, p;
186
187 /* Player must exist. */
188 if (player.p == NULL)
189 return PLAYER_ID;
190
191 /* Get the pilot. */
192 m = pilot_getStackPos(id);
193
194 /* Check to see what position to try. */
195 if (m == -1)
196 return PLAYER_ID;
197 else if (m == 0)
198 p = array_size(pilot_stack)-1;
199 else
200 p = m-1;
201
202 /* Get first one in range. */
203 if (mode == 0) {
204 while (p >= 0) {
205 if ((!pilot_isWithPlayer(pilot_stack[p]) ||
206 (pilot_isDisabled(pilot_stack[p]))) &&
208 return pilot_stack[p]->id;
209 p--;
210 }
211 }
212 /* Get first hostile in range. */
213 else if (mode == 1) {
214 while (p >= 0) {
215 if (!pilot_isWithPlayer(pilot_stack[p]) &&
216 !pilot_isFlag( pilot_stack[p], PILOT_HIDE ) &&
219 return pilot_stack[p]->id;
220 p--;
221 }
222 }
223
224 /* None found. */
225 return PLAYER_ID;
226}
227
237int pilot_validTarget( const Pilot* p, const Pilot* target )
238{
239 /* Must be targetable. */
240 if (!pilot_canTarget( target ))
241 return 0;
242
243 /* Must be in range. */
244 if (!pilot_inRangePilot( p, target, NULL ))
245 return 0;
246
247 /* Pilot is a valid target. */
248 return 1;
249}
250
254int pilot_canTarget( const Pilot* p )
255{
256 /* Must not be dead. */
257 if (pilot_isFlag( p, PILOT_DELETE ) ||
258 pilot_isFlag( p, PILOT_DEAD ))
259 return 0;
260
261 /* Must not be hidden nor invisible. */
262 if (pilot_isFlag( p, PILOT_HIDE ) ||
263 pilot_isFlag( p, PILOT_INVISIBLE))
264 return 0;
265
266 /* Pilot is a valid target. */
267 return 1;
268}
269
277int pilot_validEnemy( const Pilot* p, const Pilot* target )
278{
279 return pilot_validEnemyDist( p, target, NULL );
280}
281
285int pilot_validEnemyDist( const Pilot* p, const Pilot* target, double *dist )
286{
287 /* Shouldn't be disabled. */
288 if (pilot_isDisabled(target))
289 return 0;
290
291 /* Shouldn't be invincible. */
292 if (pilot_isFlag( target, PILOT_INVINCIBLE ))
293 return 0;
294
295 /* Shouldn't be landing or taking off. */
296 if (pilot_isFlag( target, PILOT_LANDING) ||
297 pilot_isFlag( target, PILOT_TAKEOFF ) ||
298 pilot_isFlag( target, PILOT_NONTARGETABLE))
299 return 0;
300
301 /* Must be a valid target. */
302 if (!pilot_validTarget( p, target ))
303 return 0;
304
305 /* Should either be hostile by faction or by player. */
306 if (!pilot_areEnemies( p, target ))
307 return 0;
308
309 /* Must not be fuzzy. */
310 if (pilot_inRangePilot( p, target, dist ) != 1)
311 return 0;
312
313 /* They're ok. */
314 return 1;
315}
316
323unsigned int pilot_getNearestEnemy( const Pilot* p )
324{
325 unsigned int tp = 0;
326 double d = 0.;
327
328 for (int i=0; i<array_size(pilot_stack); i++) {
329 double td;
330
331 if (!pilot_validEnemy( p, pilot_stack[i] ))
332 continue;
333
334 /* Check distance. */
335 td = vec2_dist2(&pilot_stack[i]->solid.pos, &p->solid.pos);
336 if (!tp || (td < d)) {
337 d = td;
338 tp = pilot_stack[i]->id;
339 }
340 }
341 return tp;
342}
343
352unsigned int pilot_getNearestEnemy_size( const Pilot* p, double target_mass_LB, double target_mass_UB )
353{
354 unsigned int tp = 0;
355 double d = 0.;
356
357 for (int i=0; i<array_size(pilot_stack); i++) {
358 double td;
359
360 if (!pilot_validEnemy( p, pilot_stack[i] ))
361 continue;
362
363 if (pilot_stack[i]->solid.mass < target_mass_LB || pilot_stack[i]->solid.mass > target_mass_UB)
364 continue;
365
366 /* Check distance. */
367 td = vec2_dist2(&pilot_stack[i]->solid.pos, &p->solid.pos);
368 if (!tp || (td < d)) {
369 d = td;
370 tp = pilot_stack[i]->id;
371 }
372 }
373
374 return tp;
375}
376
388 double mass_factor, double health_factor,
389 double damage_factor, double range_factor )
390{
391 unsigned int tp = 0;
392 double current_heuristic_value = 10e3;
393
394 for (int i=0; i<array_size(pilot_stack); i++) {
395 double temp;
396 Pilot *target = pilot_stack[i];
397
398 if (!pilot_validEnemy( p, target ))
399 continue;
400
401 /* Check distance. */
402 temp = range_factor *
403 vec2_dist2( &target->solid.pos, &p->solid.pos )
404 + FABS( pilot_relsize( p, target ) - mass_factor )
405 + FABS( pilot_relhp( p, target ) - health_factor )
406 + FABS( pilot_reldps( p, target ) - damage_factor );
407
408 if ((tp == 0) || (temp < current_heuristic_value)) {
409 current_heuristic_value = temp;
410 tp = target->id;
411 }
412 }
413
414 return tp;
415}
416
423unsigned int pilot_getNearestPilot( const Pilot* p )
424{
425 unsigned int t;
426 pilot_getNearestPos( p, &t, p->solid.pos.x, p->solid.pos.y, 0 );
427 return t;
428}
429
436unsigned int pilot_getBoss( const Pilot* p )
437{
438 unsigned int t;
439 double relpower, ppower;
440 /* TODO : all the parameters should be adjustable with arguments */
441
442 relpower = 0;
443 t = 0;
444
445 /* Initialized to 0.25 which would mean equivalent power. */
446 ppower = 0.5*0.5;
447
448 for (int i=0; i<array_size(pilot_stack); i++) {
449 double dx, dy, td, curpower;
450
451 /* Must not be self. */
452 if (pilot_stack[i] == p)
453 continue;
454
455 /* Shouldn't be disabled. */
456 if (pilot_isDisabled(pilot_stack[i]))
457 continue;
458
459 /* Must be a valid target. */
460 if (!pilot_validTarget( p, pilot_stack[i] ))
461 continue;
462
463 /* Maximum distance in 2 seconds. */
464 dx = pilot_stack[i]->solid.pos.x + 2*pilot_stack[i]->solid.vel.x -
465 p->solid.pos.x - 2*p->solid.vel.x;
466 dy = pilot_stack[i]->solid.pos.y + 2*pilot_stack[i]->solid.vel.y -
467 p->solid.pos.y - 2*p->solid.vel.y;
468 td = sqrt( pow2(dx) + pow2(dy) );
469 if (td > 5e3)
470 continue;
471
472 /* Must have the same faction. */
473 if (pilot_stack[i]->faction != p->faction)
474 continue;
475
476 /* Must be slower. */
477 if (pilot_stack[i]->speed > p->speed)
478 continue;
479
480 /* Should not be weaker than the current pilot*/
481 curpower = pilot_reldps( pilot_stack[i], p ) * pilot_relhp( pilot_stack[i], p );
482 if (ppower >= curpower )
483 continue;
484
485 if (relpower < curpower ) {
486 relpower = curpower;
487 t = pilot_stack[i]->id;
488 }
489 }
490 return t;
491}
492
503double pilot_getNearestPosPilot( const Pilot *p, Pilot **tp, double x, double y, int disabled )
504{
505 double d = 0.;
506 *tp = NULL;
507 for (int i=0; i<array_size(pilot_stack); i++) {
508 double td;
509
510 /* Must not be self. */
511 if (pilot_stack[i] == p)
512 continue;
513
514 /* Player doesn't select escorts (unless disabled is active). */
515 if (!disabled && pilot_isPlayer(p) &&
516 pilot_isWithPlayer(pilot_stack[i]))
517 continue;
518
519 /* Shouldn't be disabled. */
520 if (!disabled && pilot_isDisabled(pilot_stack[i]))
521 continue;
522
523 /* Must be a valid target. */
524 if (!pilot_validTarget( p, pilot_stack[i] ))
525 continue;
526
527 /* Minimum distance. */
528 td = pow2(x-pilot_stack[i]->solid.pos.x) + pow2(y-pilot_stack[i]->solid.pos.y);
529 if (((*tp==NULL) || (td < d))) {
530 d = td;
531 *tp = pilot_stack[i];
532 }
533 }
534 return d;
535}
536
547double pilot_getNearestPos( const Pilot *p, unsigned int *tp, double x, double y, int disabled )
548{
549 Pilot *pn;
550 double d = pilot_getNearestPosPilot( p, &pn, x, y, disabled );
551 if (pn==NULL)
552 *tp = PLAYER_ID;
553 else
554 *tp = pn->id;
555 return d;
556}
557
567double pilot_getNearestAng( const Pilot *p, unsigned int *tp, double ang, int disabled )
568{
569 double a = ang + M_PI;
570
571 *tp = PLAYER_ID;
572 for (int i=0; i<array_size(pilot_stack); i++) {
573 double rx, ry, ta;
574
575 /* Must not be self. */
576 if (pilot_stack[i] == p)
577 continue;
578
579 /* Player doesn't select escorts (unless disabled is active). */
580 if (!disabled && pilot_isPlayer(p) &&
581 pilot_isWithPlayer(pilot_stack[i]))
582 continue;
583
584 /* Shouldn't be disabled. */
585 if (!disabled && pilot_isDisabled(pilot_stack[i]))
586 continue;
587
588 /* Must be a valid target. */
589 if (!pilot_validTarget( p, pilot_stack[i] ))
590 continue;
591
592 /* Must be in range. */
593 if (!pilot_inRangePilot( p, pilot_stack[i], NULL ))
594 continue;
595
596 /* Only allow selection if off-screen. */
597 if (gui_onScreenPilot( &rx, &ry, pilot_stack[i] ))
598 continue;
599
600 ta = atan2( p->solid.pos.y - pilot_stack[i]->solid.pos.y,
601 p->solid.pos.x - pilot_stack[i]->solid.pos.x );
602 if (ABS(angle_diff(ang, ta)) < ABS(angle_diff(ang, a))) {
603 a = ta;
604 *tp = pilot_stack[i]->id;
605 }
606 }
607 return a;
608}
609
620Pilot* pilot_get( unsigned int id )
621{
622 const Pilot pid = { .id = id };
623 const Pilot *pidptr = &pid;
624 /* binary search */
625 Pilot **pp = bsearch(&pidptr, pilot_stack, array_size(pilot_stack), sizeof(Pilot*), pilot_cmp);
626 if ((pp==NULL) || (pilot_isFlag(*pp, PILOT_DELETE)))
627 return NULL;
628 return *pp;
629}
630
635{
636 Pilot *t;
637
638 /* Case no target. */
639 if (p->target==p->id)
640 return NULL;
641
642 t = p->ptarget;
643 /* Return ptarget if exists and valid. */
644 if (t != NULL) {
645 if (pilot_isFlag( t, PILOT_DELETE )) {
646 p->ptarget = NULL;
647 t = NULL;
648 }
649 return t;
650 }
651
652 p->ptarget = pilot_get( p->target );
653 return p->ptarget;
654}
655
659void pilot_setAccel( Pilot *p, double accel )
660{
661 p->solid.accel = p->accel * accel;
662}
663
667void pilot_setTurn( Pilot *p, double turn )
668{
669 p->solid.dir_vel = p->turn * turn;
670}
671
678int pilot_isHostile( const Pilot *p )
679{
680 if (!pilot_isFriendly( p )
681 && !pilot_isFlag( p, PILOT_BRIBED )
682 && (pilot_isFlag( p, PILOT_HOSTILE ) ||
683 areEnemies( FACTION_PLAYER, p->faction )))
684 return 1;
685
686 return 0;
687}
688
695int pilot_isNeutral( const Pilot *p )
696{
697 if (!pilot_isHostile(p) && !pilot_isFriendly(p))
698 return 1;
699 return 0;
700}
701
708int pilot_isFriendly( const Pilot *p )
709{
710 if (pilot_isFlag( p, PILOT_FRIENDLY) ||
711 (areAllies( FACTION_PLAYER,p->faction) &&
712 !pilot_isFlag( p, PILOT_HOSTILE ) ) )
713 return 1;
714
715 return 0;
716}
717
721int pilot_areAllies( const Pilot *p, const Pilot *target )
722{
723 if (pilot_isWithPlayer(p)) {
724 if (pilot_isFriendly(target))
725 return 1;
726 else if (pilot_isFlag( target, PILOT_HOSTILE ))
727 return 0;
728 }
729 else if (pilot_isWithPlayer(target)) {
730 if (pilot_isFriendly(p))
731 return 1;
732 else if (pilot_isFlag( p, PILOT_HOSTILE ))
733 return 0;
734 }
735 else {
736 if (areAllies( p->faction, target->faction ))
737 return 1;
738 }
739 return 0;
740}
741
745int pilot_areEnemies( const Pilot *p, const Pilot *target )
746{
747 if (pilot_isWithPlayer(p)) {
748 if (pilot_isHostile(target))
749 return 1;
750 else if (pilot_isFlag( target, PILOT_FRIENDLY ))
751 return 0;
752 else if (pilot_isFlag(target, PILOT_BRIBED))
753 return 0;
754 }
755 if (pilot_isWithPlayer(target)) {
756 if (pilot_isHostile(p))
757 return 1;
758 else if (pilot_isFlag( p, PILOT_FRIENDLY ))
759 return 0;
760 else if (pilot_isFlag(p, PILOT_BRIBED))
761 return 0;
762 }
763 else {
764 if (areEnemies( p->faction, target->faction ))
765 return 1;
766 }
767 return 0;
768}
769
777{
778 if ((p->dockpilot != 0) && (p->dockslot != -1)) {
779 Pilot *dockpilot = pilot_get(p->dockpilot);
780 if (dockpilot != NULL)
781 return dockpilot->outfits[p->dockslot];
782 }
783 p->dockpilot = 0;
784 p->dockslot = -1;
785 return NULL;
786}
787
788const IntList *pilot_collideQuery( int x1, int y1, int x2, int y2 )
789{
790 qt_query( &pilot_quadtree, &pilot_qtquery, x1, y1, x2, y2 );
791 return &pilot_qtquery;
792}
793
794void pilot_collideQueryIL( IntList *il, int x1, int y1, int x2, int y2 )
795{
796 qt_query( &pilot_quadtree, il, x1, y1, x2, y2 );
797}
798
810double pilot_face( Pilot* p, double dir, double dt )
811{
812 double diff = angle_diff( p->solid.dir, dir );
813 double turn = CLAMP( -1., 1., diff/dt );
814 pilot_setTurn( p, turn );
815 return diff;
816}
817
822{
823 if (p->stats.misc_reverse_thrust) {
824 double diff, btime, ftime, vel, t;
825 vel = MIN( VMOD(p->solid.vel), p->speed );
826 t = vel / p->accel;
827
828 /* Calculate the time to face backward and apply forward thrust. */
829 diff = angle_diff(p->solid.dir, VANGLE(p->solid.vel) + M_PI);
830 btime = ABS(diff) / p->turn + t;
831
832 /* Calculate the time to face forward and apply reverse thrust. */
833 diff = angle_diff(p->solid.dir, VANGLE(p->solid.vel));
834 ftime = ABS(diff) / p->turn + t / PILOT_REVERSE_THRUST;
835
836 if (btime > ftime)
837 return 1;
838 }
839 return 0;
840}
841
845double pilot_minbrakedist( const Pilot *p, double dt )
846{
847 double vel = MIN( MIN( VMOD(p->solid.vel), p->speed ), solid_maxspeed( &p->solid, p->speed, p->accel ) );
848 double accel = p->accel;
849 double t = vel / accel + dt; /* Try to improve accuracy. */
851 return vel * t - 0.5 * PILOT_REVERSE_THRUST * accel * t * t;
852 return vel*(t+M_PI/p->turn) - 0.5 * accel * t * t;
853}
854
862int pilot_brake( Pilot *p, double dt )
863{
864 double dir, accel, diff;
865 int isstopped = pilot_isStopped(p);
866
867 if (isstopped)
868 return 1;
869
871 dir = VANGLE(p->solid.vel);
872 accel = -PILOT_REVERSE_THRUST;
873 }
874 else {
875 dir = VANGLE(p->solid.vel) + M_PI;
876 accel = 1.;
877 }
878
879 diff = pilot_face(p, dir, dt);
880 if (ABS(diff) < MIN_DIR_ERR)
881 pilot_setAccel(p, accel);
882 else
883 pilot_setAccel(p, 0.);
884 return 0;
885}
886
893void pilot_cooldown( Pilot *p, int dochecks )
894{
895 double heat_capacity, heat_mean;
896
897 /* Brake if necessary. */
898 if (dochecks && !pilot_isStopped(p)) {
899 pilot_setFlag(p, PILOT_BRAKING);
900 pilot_setFlag(p, PILOT_COOLDOWN_BRAKE);
901 return;
902 }
903 else {
904 pilot_rmFlag(p, PILOT_BRAKING);
905 pilot_rmFlag(p, PILOT_COOLDOWN_BRAKE);
906 }
907
908 if (p->id == PLAYER_ID)
909 player_message(_("#oActive cooldown engaged."));
910
911 /* Turn off all weapon sets. */
913
914 /* Disable active outfits. */
915 if (pilot_outfitOffAll( p ) > 0)
916 pilot_calcStats( p );
917
918 /* Calculate the ship's overall heat. */
919 heat_capacity = p->heat_C;
920 heat_mean = p->heat_T * p->heat_C;
921 for (int i=0; i<array_size(p->outfits); i++) {
922 PilotOutfitSlot *o = p->outfits[i];
923 o->heat_start = o->heat_T;
924 heat_capacity += p->outfits[i]->heat_C;
925 heat_mean += o->heat_T * o->heat_C;
926 }
927
928 /* Paranoia - a negative mean heat will result in NaN cdelay. */
929 heat_mean = MAX( heat_mean, CONST_SPACE_STAR_TEMP );
930
931 heat_mean /= heat_capacity;
932
933 /*
934 * Base delay of about 9.5s for a Lancelot, 32.8s for a Peacemaker.
935 *
936 * Super heat penalty table:
937 * 300K: 13.4%
938 * 350K: 31.8%
939 * 400K: 52.8%
940 * 450K: 75.6%
941 * 500K: 100.0%
942 */
943 p->cdelay = (5. + sqrt(p->base_mass) / 2.) *
944 (1. + pow(MAX(heat_mean / CONST_SPACE_STAR_TEMP - 1.,0.), 1.25));
945 p->ctimer = p->cdelay * p->stats.cooldown_time;
946 p->heat_start = p->heat_T;
947 pilot_setFlag(p, PILOT_COOLDOWN);
948
949 /* Run outfit cooldown start hook. */
950 pilot_outfitLCooldown(p, 0, 0, p->ctimer);
951}
952
959void pilot_cooldownEnd( Pilot *p, const char *reason )
960{
961 if (pilot_isFlag(p, PILOT_COOLDOWN_BRAKE)) {
962 pilot_rmFlag(p, PILOT_COOLDOWN_BRAKE);
963 return;
964 }
965
966 /* Send message to player. */
967 if (p->id == PLAYER_ID) {
968 if (p->ctimer < 0.)
969 player_message("#o%s",_("Active cooldown completed."));
970 else {
971 if (reason != NULL)
972 player_message(_("#rActive cooldown aborted: %s!"), reason);
973 else
974 player_message("#r%s",_("Active cooldown aborted!"));
975 }
977 }
978
979 pilot_rmFlag(p, PILOT_COOLDOWN);
980
981 /* Cooldown finished naturally, reset heat just in case. */
982 if (p->ctimer < 0.) {
983 pilot_heatReset( p );
984 pilot_fillAmmo( p );
985 pilot_outfitLCooldown(p, 1, 1, 0.);
986 }
987 else {
988 pilot_outfitLCooldown(p, 1, 0, 0.);
989 }
990}
991
999double pilot_aimAngle( Pilot *p, const vec2* pos, const vec2* vel )
1000{
1001 double x, y;
1002 double t;
1003 vec2 tv, approach_vector, relative_location, orthoradial_vector;
1004 double dist;
1005 double speed;
1006 double radial_speed;
1007 double orthoradial_speed;
1008
1009 /* Get the distance */
1010 dist = vec2_dist( &p->solid.pos, pos );
1011
1012 /* Check if should recalculate weapon speed with secondary weapon. */
1013 speed = pilot_weapSetSpeed( p, p->active_set, -1 );
1014
1015 /* determine the radial, or approach speed */
1016 /*
1017 *approach_vector (denote Va) is the relative velocites of the pilot and target
1018 *relative_location (denote Vr) is the vector that points from the target to the pilot
1019 *
1020 *Va dot Vr is the rate of approach between the target and the pilot.
1021 *If this is greater than 0, the target is approaching the pilot, if less than 0, the target is fleeing.
1022 *
1023 *Va dot Vr + ShotSpeed is the net closing velocity for the shot, and is used to compute the time of flight for the shot.
1024 */
1025 vec2_cset(&approach_vector, VX(p->solid.vel) - VX(*vel), VY(p->solid.vel) - VY(*vel) );
1026 vec2_cset(&relative_location, VX(*pos) - VX(p->solid.pos), VY(*pos) - VY(p->solid.pos) );
1027 vec2_cset(&orthoradial_vector, VY(p->solid.pos) - VY(*pos), VX(*pos) - VX(p->solid.pos) );
1028
1029 radial_speed = vec2_dot(&approach_vector, &relative_location);
1030 radial_speed = radial_speed / VMOD(relative_location);
1031
1032 orthoradial_speed = vec2_dot(&approach_vector, &orthoradial_vector);
1033 orthoradial_speed = orthoradial_speed / VMOD(relative_location);
1034
1035 /* Time for shots to reach that distance */
1036 /* t is the real positive solution of a 2nd order equation*/
1037 /* if the target is not hittable (i.e., fleeing faster than our shots can fly, determinant <= 0), just face the target */
1038 if ( ((speed*speed - VMOD(approach_vector)*VMOD(approach_vector)) != 0) && (speed*speed - orthoradial_speed*orthoradial_speed) > 0)
1039 t = dist * (sqrt( speed*speed - orthoradial_speed*orthoradial_speed ) - radial_speed) /
1040 (speed*speed - VMOD(approach_vector)*VMOD(approach_vector));
1041 else
1042 t = 0;
1043
1044 /* if t < 0, try the other solution*/
1045 if (t < 0)
1046 t = - dist * (sqrt( speed*speed - orthoradial_speed*orthoradial_speed ) + radial_speed) /
1047 (speed*speed - VMOD(approach_vector)*VMOD(approach_vector));
1048
1049 /* if t still < 0, no solution*/
1050 if (t < 0)
1051 t = 0;
1052
1053 /* Position is calculated on where it should be */
1054 x = pos->x + vel->x*t - (p->solid.pos.x + p->solid.vel.x*t);
1055 y = pos->y + vel->y*t - (p->solid.pos.y + p->solid.vel.y*t);
1056 vec2_cset( &tv, x, y );
1057
1058 return VANGLE(tv);
1059}
1060
1067{
1068 if (pilot_isFriendly( p ) || pilot_isFlag( p, PILOT_BRIBED )
1069 || !pilot_isFlag( p, PILOT_HOSTILE ))
1070 pilot_setFlag( p, PILOT_HOSTILE );
1071 pilot_rmFriendly( p );
1072 pilot_rmFlag( p, PILOT_BRIBED );
1073}
1074
1081{
1082 if (pilot_isDisabled(p))
1083 return 'I';
1084 else if (pilot_isFriendly(p))
1085 return 'F';
1086 else if (pilot_isHostile(p))
1087 return 'H';
1088 else if (pilot_isFlag(p, PILOT_BRIBED))
1089 return 'N';
1090 return faction_getColourChar(p->faction);
1091}
1092
1096void pilot_setCommMsg( Pilot *p, const char *s )
1097{
1098 free( p->comm_msg );
1099 p->comm_msg = strdup( s );
1100 p->comm_msgWidth = gl_printWidthRaw( NULL, s );
1101 p->comm_msgTimer = pilot_commTimeout;
1102}
1103
1111void pilot_broadcast( Pilot *p, const char *msg, int ignore_int )
1112{
1113 char c;
1114
1115 /* Only display if player.p exists and is in range. */
1116 if (player.p==NULL)
1117 return;
1118
1119 /* Check if should ignore interference. */
1120 if (!ignore_int && !pilot_inRangePilot( player.p, p, NULL ))
1121 return;
1122
1124 player_message( _("#%cBroadcast %s>#0 \"%s\""), c, p->name, msg );
1125
1126 /* Set comm message. */
1127 pilot_setCommMsg( p, msg );
1128}
1129
1139void pilot_distress( Pilot *p, Pilot *attacker, const char *msg )
1140{
1141 int r;
1142 double d;
1143
1144 /* Broadcast the message. */
1145 if (msg[0] != '\0')
1146 pilot_broadcast( p, msg, 0 );
1147
1148 /* Use the victim's target if the attacker is unknown. */
1149 if (attacker == NULL)
1150 attacker = pilot_getTarget( p );
1151
1152 /* Now proceed to see if player.p should incur faction loss because
1153 * of the broadcast signal. */
1154
1155 /* Consider not in range at first. */
1156 r = 0;
1157
1158 if (!pilot_isFlag(p, PILOT_DISTRESSED)) {
1159 /* Check if spob is in range. */
1160 for (int i=0; i<array_size(cur_system->spobs); i++) {
1161 if (spob_hasService(cur_system->spobs[i], SPOB_SERVICE_INHABITED) &&
1162 pilot_inRangeSpob(p, i) &&
1163 !areEnemies(p->faction, cur_system->spobs[i]->presence.faction)) {
1164 r = 1;
1165 break;
1166 }
1167 }
1168 }
1169
1170 /* Now we must check to see if a pilot is in range. */
1171 for (int i=0; i<array_size(pilot_stack); i++) {
1172 Pilot *pi = pilot_stack[i];
1173
1174 /* Skip if unsuitable. */
1175 if ((pi->ai == NULL) || (pi->id == p->id) ||
1176 (pilot_isFlag(pi, PILOT_DEAD)) ||
1177 (pilot_isFlag(pi, PILOT_DELETE)))
1178 continue;
1179
1180 if (!pilot_inRangePilot(p, pi, NULL)) {
1181 /*
1182 * If the pilots are within sensor range of each other, send the
1183 * distress signal, regardless of electronic warfare hide values.
1184 */
1185 d = vec2_dist2( &p->solid.pos, &pi->solid.pos );
1186 if (d > pilot_sensorRange())
1187 continue;
1188 }
1189
1190 /* Send AI the distress signal. */
1191 ai_getDistress( pi, p, attacker );
1192
1193 /* Check if should take faction hit. */
1194 if (!pilot_isFlag(p, PILOT_DISTRESSED) &&
1195 !areEnemies(p->faction, pi->faction))
1196 r = 1;
1197 }
1198
1199 /* Player only gets one faction hit per pilot. */
1200 if (!pilot_isFlag(p, PILOT_DISTRESSED)) {
1201
1202 /* Modify faction, about 1 for a llama, 4.2 for a hawking */
1203 if (r && (attacker != NULL) && (pilot_isWithPlayer(attacker))) {
1204 if (p->ai == NULL)
1205 WARN(_("Pilot '%s' does not have an AI!"), p->name);
1206 else {
1207 double hit;
1208 lua_rawgeti( naevL, LUA_REGISTRYINDEX, p->lua_mem ); /* m */
1209 lua_getfield( naevL, -1, "distress_hit" );/* m, v */
1210 if (lua_isnil(naevL,-1))
1211 hit = (pow(p->base_mass, 0.2) - 1.);
1212 else if (lua_isnumber(naevL,-1))
1213 hit = lua_tonumber(naevL,-1);
1214 else {
1215 WARN(_("Pilot '%s' has non-number mem.distress_hit!"),p->name);
1216 hit = 0.;
1217 }
1218 lua_pop(naevL,2);
1219 faction_modPlayer( p->faction, -hit, "distress" );
1220 }
1221 }
1222
1223 /* Set flag to avoid a second faction hit. */
1224 pilot_setFlag(p, PILOT_DISTRESSED);
1225 }
1226}
1227
1234{
1235 if (!pilot_isHostile(p))
1236 return;
1237
1238 if (pilot_isFlag(p, PILOT_HOSTILE))
1239 pilot_rmFlag(p, PILOT_HOSTILE);
1240
1241 /* Set "bribed" flag if faction has poor reputation */
1242 if (areEnemies( FACTION_PLAYER, p->faction ))
1243 pilot_setFlag(p, PILOT_BRIBED);
1244}
1245
1252{
1253 pilot_rmHostile(p);
1254 pilot_setFlag(p, PILOT_FRIENDLY);
1255}
1256
1263{
1264 pilot_rmFlag(p, PILOT_FRIENDLY);
1265}
1266
1273int pilot_getJumps( const Pilot* p )
1274{
1275 return p->fuel / p->fuel_consumption;
1276}
1277
1284const glColour* pilot_getColour( const Pilot* p )
1285{
1286 const glColour *col;
1287
1288 if (pilot_inRangePilot(player.p, p, NULL) == -1)
1289 col = &cNeutral;
1290 else if (pilot_isDisabled(p) || pilot_isFlag(p,PILOT_DEAD))
1291 col = &cInert;
1292 else if (pilot_isFriendly(p))
1293 col = &cFriend;
1294 else if (pilot_isHostile(p))
1295 col = &cHostile;
1296 else
1297 col = &cNeutral;
1298
1299 return col;
1300}
1301
1308void pilot_setTarget( Pilot* p, unsigned int id )
1309{
1310 /* Case no change. */
1311 if (p->target == id)
1312 return;
1313
1314 p->target = id;
1315 p->ptarget = NULL; /* Gets recomputed later in pilot_getTarget. */
1316 pilot_lockClear( p );
1317
1318 /* Set the scan timer. */
1319 pilot_ewScanStart( p );
1320
1321 /* Untarget asteroid (if any). */
1322 p->nav_anchor = -1;
1323 p->nav_asteroid = -1;
1324}
1325
1338double pilot_hit( Pilot* p, const Solid* w, const Pilot *pshooter,
1339 const Damage *dmg, const Outfit *outfit, int lua_mem, int reset )
1340{
1341 int shooter;
1342 double damage_shield, damage_armour, disable, knockback, dam_mod, ddmg, ddis, absorb, dmod, start;
1343 double tdshield, tdarmour;
1344
1345 /* Invincible means no damage. */
1346 if (pilot_isFlag( p, PILOT_INVINCIBLE ) ||
1347 pilot_isFlag( p, PILOT_HIDE ) ||
1348 ((pshooter!=NULL) && pilot_isWithPlayer(pshooter) && pilot_isFlag( p, PILOT_INVINC_PLAYER )))
1349 return 0.;
1350
1351 /* Defaults. */
1352 dam_mod = 0.;
1353 ddmg = 0.;
1354 ddis = 0.;
1355 shooter = (pshooter==NULL) ? 0 : pshooter->id;
1356
1357 /* Calculate the damage. */
1358 absorb = 1. - CLAMP( 0., 1., p->dmg_absorb - dmg->penetration );
1359 disable = dmg->disable;
1360 dtype_calcDamage( &damage_shield, &damage_armour, absorb, &knockback, dmg, &p->stats );
1361
1362 /*
1363 * Delay undisable if necessary. Amount varies with damage, as e.g. a
1364 * single Laser Cannon shot should not reset a Peacemaker's timer.
1365 */
1366 if (!pilot_isFlag(p, PILOT_DEAD) && (p->dtimer_accum > 0.))
1367 p->dtimer_accum -= MIN( pow(disable, 0.8), p->dtimer_accum );
1368
1369 /* Ships that can not be disabled take raw armour damage instead of getting disabled. */
1370 if (pilot_isFlag( p, PILOT_NODISABLE )) {
1371 damage_armour += disable * absorb;
1372 disable = 0.;
1373 }
1374 else
1375 disable *= absorb;
1376 tdshield = 0.;
1377 tdarmour = 0.;
1378
1379 /*
1380 * Shields take entire blow.
1381 */
1382 if (p->shield - damage_shield > 0.) {
1383 start = p->shield;
1384 ddmg = damage_shield;
1385 p->shield -= damage_shield;
1386 dam_mod = damage_shield/p->shield_max;
1387
1388 /*
1389 * Disabling damage leaks accordingly:
1390 * 50% + (50% - mean shield % / 2)
1391 *
1392 * 50% leaks at 100% shield, scales to 100% by 0% shield.
1393 *
1394 * The damage is adjusted based on the mean of the starting and ending
1395 * shield percentages. Using the starting percentage biases towards
1396 * low-damage, high-ROF weapons, while using the ending percentage
1397 * biases towards high-damage, low-ROF weapons.
1398 */
1399 ddis = disable * (0.5 + (0.5 - ((start+p->shield) / p->shield_max) / 4.));
1400 p->stress += ddis;
1401
1402 /* True damage. */
1403 tdshield = damage_shield;
1404 }
1405 /*
1406 * Shields take part of the blow.
1407 */
1408 else if (p->shield > 0.) {
1409 start = p->shield;
1410 dmod = (1. - p->shield/damage_shield);
1411 ddmg = p->shield + dmod * damage_armour;
1412 tdshield = p->shield;
1413 p->shield = 0.;
1414
1415 /* Leak some disabling damage through the remaining bit of shields. */
1416 ddis = disable * (1. - dmod) * (0.5 + (0.5 - (start / p->shield_max / 4.)));
1417 p->stress += ddis;
1418
1419 /* Reduce stress as armour is eaten away. */
1420 //p->stress *= (p->armour - dmod * damage_armour) / p->armour;
1421 tdarmour = dmod * damage_armour;
1422 p->armour -= tdarmour;
1423 p->stress += dmod * disable;
1424 dam_mod = (damage_shield + damage_armour) /
1425 ((p->shield_max + p->armour_max) / 2.);
1426
1427 /* Increment shield timer or time before shield regeneration kicks in. */
1428 if (reset) {
1429 p->stimer = 3.;
1430 p->sbonus = 3.;
1431 }
1432 }
1433 /*
1434 * Armour takes the entire blow.
1435 */
1436 else if (p->armour > 0.) {
1437 ddmg = damage_armour;
1438 /* Reduce stress as armour is eaten away. */
1439 //p->stress *= (p->armour - damage_armour) / p->armour;
1440 p->armour -= damage_armour;
1441 ddis = disable;
1442 p->stress += ddis;
1443
1444 /* Increment shield timer or time before shield regeneration kicks in. */
1445 if (reset) {
1446 p->stimer = 3.;
1447 p->sbonus = 3.;
1448 }
1449
1450 /* True damage. */
1451 tdarmour = ddmg;
1452 }
1453
1454 /* Do not let pilot die. */
1455 if ((p->armour <= 0.) && pilot_isFlag( p, PILOT_NODEATH )) {
1456 p->armour = 1.;
1457 p->stress = 1.;
1458 }
1459
1460 /* Can't undisable permanently disabled pilots through shooting. */
1461 if (pilot_isFlag( p, PILOT_DISABLED_PERM ))
1462 p->stress = p->armour;
1463
1464 /* Some minor effects and stuff. */
1465 if (p->shield <= 0.) {
1466 if (p->id == PLAYER_ID) { /* a bit of shaking */
1467 double spfx_mod = tdarmour/p->armour_max;
1468 spfx_shake( 0.5 * spfx_mod );
1469 spfx_damage( spfx_mod );
1470 }
1471 }
1472
1473 /* Update player meta-data if applicable. */
1474 if (p->id == PLAYER_ID) {
1475 player.dmg_taken_shield += tdshield;
1476 player.dmg_taken_armour += tdarmour;
1477 player.ps.dmg_taken_shield += tdshield;
1478 player.ps.dmg_taken_armour += tdarmour;
1479 }
1480 /* See if shooter is with player. */
1481 else if ((pshooter!=NULL) && pilot_isWithPlayer(pshooter)) {
1482 player.dmg_done_shield += tdshield;
1483 player.dmg_done_armour += tdarmour;
1484 player.ps.dmg_done_shield += tdshield;
1485 player.ps.dmg_done_armour += tdarmour;
1486 }
1487
1488 if (w != NULL)
1489 /* knock back effect is dependent on both damage and mass of the weapon
1490 * should probably get turned into a partial conservative collision */
1491 vec2_cadd( &p->solid.vel,
1492 knockback * (w->vel.x * (dam_mod/9. + w->mass/p->solid.mass/6.)),
1493 knockback * (w->vel.y * (dam_mod/9. + w->mass/p->solid.mass/6.)) );
1494
1495 /* On hit weapon effects. */
1496 if ((outfit!=NULL) && (outfit->lua_onimpact != LUA_NOREF)) {
1497 lua_rawgeti(naevL, LUA_REGISTRYINDEX, lua_mem); /* mem */
1498 nlua_setenv(naevL, outfit->lua_env, "mem"); /* */
1499
1500 /* Set up the function: onimpact( pshooter, p ) */
1501 lua_rawgeti(naevL, LUA_REGISTRYINDEX, outfit->lua_onimpact); /* f */
1502 lua_pushpilot(naevL, shooter); /* f, p */
1503 lua_pushpilot(naevL, p->id); /* f, p, p */
1504 lua_pushvector(naevL, w->pos); /* f, p, p, x */
1505 lua_pushvector(naevL, w->vel); /* f, p, p, x, v */
1506 lua_pushoutfit(naevL, outfit); /* f, p, p, x, v, o */
1507 if (nlua_pcall( outfit->lua_env, 5, 0 )) { /* */
1508 WARN( _("Pilot '%s''s outfit '%s' -> '%s':\n%s"), p->name, outfit->name, "onimpact", lua_tostring(naevL,-1) );
1509 lua_pop(naevL, 1);
1510 }
1511 }
1512
1513 /* On hit Lua outfits activate. */
1514 pilot_outfitLOnhit( p, tdarmour, tdshield, shooter );
1515
1516 /* Run disabled before death. Should be run after on hit effects in case of regen. */
1517 pilot_updateDisable(p, shooter);
1518
1519 /* Officially dead, run after in case they are regenerated by outfit. */
1520 if (p->armour <= 0.) {
1521 p->armour = 0.;
1522
1523 if (!pilot_isFlag(p, PILOT_DEAD)) {
1524 pilot_dead( p, shooter );
1525
1526 /* adjust the combat rating based on pilot mass and ditto faction */
1527 if ((pshooter != NULL) && pilot_isWithPlayer(pshooter)) {
1528 /* About 6 for a llama, 52 for hawking. */
1529 int mod = 2. * (pow(p->base_mass, 0.4) - 1.);
1530
1531 /* Modify faction for him and friends. */
1532 faction_modPlayer( p->faction, -mod, "kill" );
1533
1534 /* Note that player destroyed the ship. */
1535 player.ships_destroyed[p->ship->class]++;
1536 player.ps.ships_destroyed[p->ship->class]++;
1537 }
1538 }
1539 }
1540
1541 return ddmg + ddis;
1542}
1543
1550void pilot_updateDisable( Pilot* p, unsigned int shooter )
1551{
1552 if ((!pilot_isFlag(p, PILOT_DISABLED)) &&
1553 (!pilot_isFlag(p, PILOT_NODISABLE) || (p->armour <= 0.)) &&
1554 (p->armour <= p->stress)) { /* Pilot should be disabled. */
1555 HookParam hparam;
1556
1557 /* Cooldown is an active process, so cancel it. */
1558 if (pilot_isFlag(p, PILOT_COOLDOWN))
1559 pilot_cooldownEnd(p, NULL);
1560
1561 /* Clear other active states. */
1562 pilot_rmFlag(p, PILOT_COOLDOWN_BRAKE);
1563 pilot_rmFlag(p, PILOT_BRAKING);
1564 pilot_rmFlag(p, PILOT_STEALTH);
1565
1566 /* Clear hyperspace flags. */
1567 pilot_rmFlag(p, PILOT_HYP_PREP);
1568 pilot_rmFlag(p, PILOT_HYP_BEGIN);
1569 pilot_rmFlag(p, PILOT_HYP_BRAKE);
1570 pilot_rmFlag(p, PILOT_HYPERSPACE);
1571
1572 /* Disabled ships don't use up presence. */
1573 if (p->presence > 0) {
1574 system_rmCurrentPresence( cur_system, p->faction, p->presence );
1575 p->presence = 0;
1576 }
1577
1578 /* Set disable timer. This is the time the pilot will remain disabled. */
1579 /* 200 mass llama => 46.78 s
1580 * 8000 mass peacemaker => 156 s
1581 */
1582 p->dtimer = 8. * pow( p->solid.mass, 1./3. );
1583 p->dtimer_accum = 0.;
1584
1585 /* Disable active outfits. */
1586 if (pilot_outfitOffAll( p ) > 0)
1587 pilot_calcStats( p );
1588
1589 pilot_setFlag( p, PILOT_DISABLED ); /* set as disabled */
1590 if (pilot_isPlayer( p ))
1591 player_message("#r%s",_("You have been disabled!"));
1592
1593 /* Run hook */
1594 if (shooter > 0) {
1595 hparam.type = HOOK_PARAM_PILOT;
1596 hparam.u.lp = shooter;
1597 }
1598 else {
1599 hparam.type = HOOK_PARAM_NIL;
1600 }
1601 pilot_runHookParam( p, PILOT_HOOK_DISABLE, &hparam, 1 ); /* Already disabled. */
1602 }
1603 else if (pilot_isFlag(p, PILOT_DISABLED) && (p->armour > p->stress)) { /* Pilot is disabled, but shouldn't be. */
1604 pilot_rmFlag( p, PILOT_DISABLED ); /* Undisable. */
1605 pilot_rmFlag( p, PILOT_DISABLED_PERM ); /* Clear perma-disable flag if necessary. */
1606 pilot_rmFlag( p, PILOT_BOARDING ); /* Can get boarded again. */
1607
1608 /* Reset the accumulated disable time. */
1609 p->dtimer_accum = 0.;
1610
1611 /* TODO: Make undisabled pilot use up presence again. */
1612 pilot_runHook( p, PILOT_HOOK_UNDISABLE );
1613
1614 /* This is sort of a hack to make sure it gets reset... */
1615 if (pilot_isPlayer(p)) {
1617 player_message("#g%s",_("You have recovered control of your ship!"));
1618 }
1619 }
1620}
1621
1628void pilot_dead( Pilot* p, unsigned int killer )
1629{
1630 HookParam hparam;
1631
1632 if (pilot_isFlag(p,PILOT_DEAD))
1633 return; /* he's already dead */
1634
1635 /* basically just set timers */
1636 if (p->id==PLAYER_ID) {
1637 pilot_setFlag(p, PILOT_DISABLED );
1638 player_dead();
1639 }
1640 p->timer[0] = 0.; /* no need for AI anymore */
1641 p->ptimer = MIN( 1. + sqrt(p->armour_max * p->shield_max) / 650.,
1642 3 + pow(p->armour_max * p->shield_max, 0.4) / 500);
1643 p->timer[1] = 0.; /* explosion timer */
1644
1645 /* flag cleanup - fixes some issues */
1646 pilot_rmFlag(p,PILOT_HYP_PREP);
1647 pilot_rmFlag(p,PILOT_HYP_BEGIN);
1648 pilot_rmFlag(p,PILOT_HYP_BRAKE);
1649 pilot_rmFlag(p,PILOT_HYPERSPACE);
1650
1651 /* Turn off all outfits, should disable Lua stuff as necessary. */
1652 pilot_outfitOffAll( p );
1653
1654 /* Pilot must die before setting death flag and probably messing with other flags. */
1655 if (killer > 0) {
1656 hparam.type = HOOK_PARAM_PILOT;
1657 hparam.u.lp = killer;
1658 }
1659 else
1660 hparam.type = HOOK_PARAM_NIL;
1661 pilot_runHookParam( p, PILOT_HOOK_DEATH, &hparam, 1 );
1662
1663 /* Need a check here in case the hook "regenerates" the pilot. */
1664 if (p->armour <= 0.) {
1665 if (p->parent == PLAYER_ID)
1666 player_message( _("#rShip under command '%s' was destroyed!#0"), p->name );
1667 /* PILOT R OFFICIALLY DEADZ0R */
1668 pilot_setFlag( p, PILOT_DEAD );
1669
1670 /* Run Lua if applicable. */
1672 }
1673}
1674
1683void pilot_explode( double x, double y, double radius, const Damage *dmg, const Pilot *parent )
1684{
1685 double rad2;
1686 Solid s; /* Only need to manipulate mass and vel. */
1687 Damage ddmg;
1688 const IntList *qt;
1689 int qx, qy, qr;
1690
1691 rad2 = radius*radius;
1692 ddmg = *dmg;
1693
1694 qx = round(x);
1695 qy = round(y);
1696 qr = ceil(radius);
1697 qt = pilot_collideQuery( qx-qr, qy-qr, qx+qr, qy+qr );
1698 for (int i=0; i<il_size(qt); i++) {
1699 Pilot *p = pilot_stack[ il_get( qt, i, 0 ) ];
1700 double rx, ry, dist;
1701
1702 /* Calculate a bit. */
1703 rx = p->solid.pos.x - x;
1704 ry = p->solid.pos.y - y;
1705 dist = pow2(rx) + pow2(ry);
1706 /* Take into account ship size. */
1707 dist -= pow2(p->ship->gfx_space->sw);
1708 dist = MAX(0,dist);
1709
1710 /* Pilot is not hit. */
1711 if (dist > rad2)
1712 continue;
1713
1714 /* Adjust damage based on distance. */
1715 ddmg.damage = dmg->damage * (1. - sqrt(dist / rad2));
1716
1717 /* Impact settings. */
1718 s.mass = pow2(dmg->damage) / 30.;
1719 s.vel.x = rx;
1720 s.vel.y = ry;
1721
1722 /* Actual damage calculations. */
1723 pilot_hit( p, &s, parent, &ddmg, NULL, LUA_NOREF, 1 );
1724
1725 /* Shock wave from the explosion. */
1726 if (p->id == PILOT_PLAYER)
1727 spfx_shake( pow2(ddmg.damage) / pow2(100.) );
1728 }
1729}
1730
1739static void pilot_renderFramebufferBase( Pilot *p, GLuint fbo, double fw, double fh )
1740{
1741 glColour c = { 1., 1., 1., 1. };
1742
1743 /* Add some transparency if stealthed. TODO better effect */
1744 if (!pilot_isPlayer(p) && pilot_isFlag(p, PILOT_STEALTH))
1745 c.a = 0.5;
1746
1747 glBindFramebuffer( GL_FRAMEBUFFER, fbo );
1748 glClearColor( 0., 0., 0., 0. );
1749
1750 if (p->ship->gfx_3d != NULL) {
1751 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1752 /* TODO fix 3D rendering. */
1753 }
1754 else {
1755 double tx,ty;
1756 const glTexture *sa, *sb;
1757 mat4 tmpm;
1758
1759 glClear( GL_COLOR_BUFFER_BIT );
1760
1761 sa = p->ship->gfx_space;
1762 sb = p->ship->gfx_engine;
1763
1764 /* texture coords */
1765 tx = sa->sw*(double)(p->tsx)/sa->w;
1766 ty = sa->sh*(sa->sy-(double)p->tsy-1)/sa->h;
1767
1768 tmpm = gl_view_matrix;
1769 gl_view_matrix = mat4_ortho( 0., fw, 0, fh, -1., 1. );
1770
1772 1.-p->engine_glow, 0., 0., sa->sw, sa->sh,
1773 tx, ty, sa->srw, sa->srh, &c );
1774
1775 gl_view_matrix = tmpm;
1776 }
1777
1778 glBindFramebuffer(GL_FRAMEBUFFER, gl_screen.current_fbo);
1779 glClearColor( 0., 0., 0., 1. );
1780}
1781
1792void pilot_renderFramebuffer( Pilot *p, GLuint fbo, double fw, double fh )
1793{
1794 double x,y, w,h;
1795 double timeleft, elapsed;
1796 Effect *e = NULL;
1797
1798 /* Transform coordinates. */
1799 w = p->ship->gfx_space->sw;
1800 h = p->ship->gfx_space->sh;
1801 gl_gameToScreenCoords( &x, &y, p->solid.pos.x-w/2., p->solid.pos.y-h/2. );
1802
1803 /* Render effects - already sorted by priority and then timer. */
1804 for (int i=0; i<array_size(p->effects); i++) {
1805 //for (int i=array_size(p->effects)-1; i>=0; i--) {
1806 Effect *eiter = &p->effects[i];
1807 if (eiter->data->program==0)
1808 continue;
1809
1810 if (e==NULL) {
1811 e = eiter;
1812 timeleft = e->timer;
1813 elapsed = e->elapsed;
1814 }
1815 else if (eiter->data==e->data) {
1816 timeleft = MAX( e->timer, eiter->timer );
1817 elapsed = MAX( e->elapsed, eiter->elapsed );
1818 }
1819 }
1820
1821 /* Render normally. */
1822 if (e==NULL)
1823 pilot_renderFramebufferBase( p, fbo, fw, fh );
1824 /* Render effect single effect. */
1825 else {
1826 mat4 projection, tex_mat;
1827 const EffectData *ed = e->data;
1828
1829 /* Render onto framebuffer. */
1831
1832 glBindFramebuffer( GL_FRAMEBUFFER, fbo );
1833
1834 glClearColor( 0., 0., 0., 0. );
1835 glClear( GL_COLOR_BUFFER_BIT );
1836
1837 glUseProgram( ed->program );
1838
1839 glActiveTexture( GL_TEXTURE0 );
1840 glBindTexture( GL_TEXTURE_2D, gl_screen.fbo_tex[2] );
1841 glUniform1i( ed->u_tex, 0 );
1842
1843 glEnableVertexAttribArray( ed->vertex );
1844 gl_vboActivateAttribOffset( gl_squareVBO, ed->vertex, 0, 2, GL_FLOAT, 0 );
1845
1846 projection = mat4_ortho( 0., fw, 0, fh, -1., 1. );
1847 mat4_scale( &projection, w, h, 1. );
1848 gl_uniformMat4(ed->projection, &projection);
1849
1850 tex_mat = mat4_identity();
1851 mat4_scale( &tex_mat, w/(double)gl_screen.nw, h/(double)gl_screen.nh, 1. );
1852 gl_uniformMat4(ed->tex_mat, &tex_mat);
1853
1854 glUniform3f( ed->dimensions, SCREEN_W, SCREEN_H, 1. );
1855 glUniform1f( ed->u_timer, timeleft );
1856 glUniform1f( ed->u_elapsed, elapsed );
1857 glUniform1f( ed->u_r, e->r );
1858 glUniform1f( ed->u_dir, p->solid.dir );
1859
1860 /* Draw. */
1861 glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
1862
1863 /* Clear state. */
1864 glDisableVertexAttribArray( ed->vertex );
1865
1866 glBindFramebuffer(GL_FRAMEBUFFER, gl_screen.current_fbo);
1867 glClearColor( 0., 0., 0., 1. );
1868 }
1869}
1870
1877{
1878 double scale, x,y, w,h, z;
1879 double timeleft, elapsed;
1880 int inbounds = 1;
1881 Effect *e = NULL;
1882 glColour c = {.r=1., .g=1., .b=1., .a=1.};
1883
1884 /* Don't render the pilot. */
1885 if (pilot_isFlag( p, PILOT_NORENDER ))
1886 return;
1887
1888 /* Transform coordinates. */
1889 z = cam_getZoom();
1890 w = p->ship->gfx_space->sw;
1891 h = p->ship->gfx_space->sh;
1892 gl_gameToScreenCoords( &x, &y, p->solid.pos.x-w/2., p->solid.pos.y-h/2. );
1893
1894 /* Check if inbounds */
1895 if ((x < -w) || (x > SCREEN_W+w) ||
1896 (y < -h) || (y > SCREEN_H+h))
1897 inbounds = 0;
1898
1899 if (inbounds) {
1900 /* Render effects. */
1901 for (int i=0; i<array_size(p->effects); i++) {
1902 //for (int i=array_size(p->effects)-1; i>=0; i--) {
1903 Effect *eiter = &p->effects[i];
1904 if (eiter->data->program==0)
1905 continue;
1906
1907 if (e==NULL) {
1908 e = eiter;
1909 timeleft = e->timer;
1910 elapsed = e->elapsed;
1911 }
1912 else if (eiter->data==e->data) {
1913 timeleft = MAX( e->timer, eiter->timer );
1914 elapsed = MAX( e->elapsed, eiter->elapsed );
1915 }
1916 }
1917
1918 /* Check if needs scaling. */
1919 if (pilot_isFlag( p, PILOT_LANDING ))
1920 scale = CLAMP( 0., 1., p->ptimer / p->landing_delay );
1921 else if (pilot_isFlag( p, PILOT_TAKEOFF ))
1922 scale = CLAMP( 0., 1., 1. - p->ptimer / p->landing_delay );
1923 else
1924 scale = 1.;
1925
1926 /* Add some transparency if stealthed. TODO better effect */
1927 if (!pilot_isPlayer(p) && pilot_isFlag(p, PILOT_STEALTH))
1928 c.a = 0.5;
1929
1930 /* Render normally. */
1931 if (e==NULL) {
1932 if (p->ship->gfx_3d != NULL) {
1933 /* 3d */
1934 object_renderSolidPart(p->ship->gfx_3d, &p->solid, "body", c.a, p->ship->gfx_3d_scale * scale);
1935 object_renderSolidPart(p->ship->gfx_3d, &p->solid, "engine", c.a * p->engine_glow, p->ship->gfx_3d_scale * scale);
1936 }
1937 else {
1938 gl_renderSpriteInterpolateScale( p->ship->gfx_space, p->ship->gfx_engine,
1939 1.-p->engine_glow, p->solid.pos.x, p->solid.pos.y,
1940 scale, scale, p->tsx, p->tsy, &c );
1941 }
1942 }
1943 /* Render effect single effect. */
1944 else {
1945 mat4 projection, tex_mat;
1946 const EffectData *ed = e->data;
1947
1948 /* Render onto framebuffer. */
1950
1951 glUseProgram( ed->program );
1952
1953 glActiveTexture( GL_TEXTURE0 );
1954 glBindTexture( GL_TEXTURE_2D, gl_screen.fbo_tex[2] );
1955 glUniform1i( ed->u_tex, 0 );
1956
1957 glEnableVertexAttribArray( ed->vertex );
1958 gl_vboActivateAttribOffset( gl_squareVBO, ed->vertex, 0, 2, GL_FLOAT, 0 );
1959
1960 projection = gl_view_matrix;
1961 mat4_translate( &projection, x + (1.-scale)*z*w/2., y + (1.-scale)*z*h/2., 0. );
1962 mat4_scale( &projection, scale*z*w, scale*z*h, 1. );
1963 gl_uniformMat4(ed->projection, &projection);
1964
1965 tex_mat = mat4_identity();
1966 mat4_scale( &tex_mat, w/(double)gl_screen.nw, h/(double)gl_screen.nh, 1. );
1967 gl_uniformMat4(ed->tex_mat, &tex_mat);
1968
1969 glUniform3f( ed->dimensions, SCREEN_W, SCREEN_H, cam_getZoom() );
1970 glUniform1f( ed->u_timer, timeleft );
1971 glUniform1f( ed->u_elapsed, elapsed );
1972 glUniform1f( ed->u_r, e->r );
1973 glUniform1f( ed->u_dir, p->solid.dir );
1974
1975 /* Draw. */
1976 glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
1977
1978 /* Clear state. */
1979 glDisableVertexAttribArray( ed->vertex );
1980 }
1981 }
1982
1983#ifdef DEBUGGING
1984 double dircos, dirsin;
1985 int debug_mark_emitter = debug_isFlag(DEBUG_MARK_EMITTER);
1986 vec2 v;
1987 if (debug_mark_emitter) {
1988 dircos = cos(p->solid.dir);
1989 dirsin = sin(p->solid.dir);
1990 }
1991#endif /* DEBUGGING */
1992
1993 /* Re-draw backwards trails. */
1994 for (int i=0,g=0; g<array_size(p->ship->trail_emitters); g++) {
1995#ifdef DEBUGGING
1996 if (debug_mark_emitter) {
1997 /* Visualize the trail emitters. */
1998 v.x = p->ship->trail_emitters[g].x_engine * dircos -
1999 p->ship->trail_emitters[g].y_engine * dirsin;
2000 v.y = p->ship->trail_emitters[g].x_engine * dirsin +
2001 p->ship->trail_emitters[g].y_engine * dircos +
2002 p->ship->trail_emitters[g].h_engine;
2003
2004 gl_gameToScreenCoords( &x, &y, p->solid.pos.x + v.x,
2005 p->solid.pos.y + v.y*M_SQRT1_2 );
2006 if (p->ship->trail_emitters[i].trail_spec->nebula)
2007 gl_renderCross(x, y, 2, &cFontBlue);
2008 else
2009 gl_renderCross(x, y, 4, &cInert);
2010 }
2011#endif /* DEBUGGING */
2012
2013 if (pilot_trail_generated( p, g )) {
2014 if (p->trail[i]->ontop)
2015 spfx_trail_draw( p->trail[i] );
2016 i++;
2017 }
2018 }
2019}
2020
2027{
2028 int playerdead;
2029
2030 /* Don't render the pilot. */
2031 if (pilot_isFlag( p, PILOT_NORENDER ))
2032 return;
2033
2034 playerdead = (player_isFlag(PLAYER_DESTROYED) || (player.p==NULL));
2035
2036 /* Render the hailing graphic if needed. */
2037 if (!playerdead && pilot_isFlag( p, PILOT_HAILING )) {
2038 glTexture *ico_hail = gui_hailIcon();
2039 if (ico_hail != NULL) {
2040 int sx = (int)ico_hail->sx;
2041
2042 /* Render. */
2043 gl_renderSprite( ico_hail,
2044 p->solid.pos.x + PILOT_SIZE_APPROX*p->ship->gfx_space->sw/2. + ico_hail->sw/4.,
2045 p->solid.pos.y + PILOT_SIZE_APPROX*p->ship->gfx_space->sh/2. + ico_hail->sh/4.,
2046 p->hail_pos % sx, p->hail_pos / sx, NULL );
2047 }
2048 }
2049
2050 /* Text ontop if needed. */
2051 if (p->comm_msg != NULL) {
2052 double x, y, dx, dy;
2053
2054 /* Coordinate translation. */
2055 gl_gameToScreenCoords( &x, &y, p->solid.pos.x, p->solid.pos.y );
2056
2057 /* Display the text. */
2058 glColour c = {1., 1., 1., 1.};
2059
2060 /* Colour. */
2061 if (p->comm_msgTimer - pilot_commFade < 0.)
2062 c.a = p->comm_msgTimer / pilot_commFade;
2063
2064 /* Position to render at. */
2065 dx = x - p->comm_msgWidth/2.;
2066 dy = y + PILOT_SIZE_APPROX*p->ship->gfx_space->sh/2.;
2067
2068 /* Background. */
2069 gl_renderRect( dx-2., dy-2., p->comm_msgWidth+4., gl_defFont.h+4., &cBlackHilight );
2070
2071 /* Display text. */
2072 gl_printRaw( NULL, dx, dy, &c, -1., p->comm_msg );
2073 }
2074
2075 /* Show health / friendlyness */
2076 if (conf.healthbars && !playerdead && !pilot_isPlayer(p) && !pilot_isFlag(p, PILOT_DEAD) && !pilot_isDisabled(p) &&
2077 (pilot_isFlag(p, PILOT_COMBAT) || (p->shield < p->shield_max))) {
2078 double x, y, w, h;
2079
2080 /* Coordinate translation. */
2081 gl_gameToScreenCoords( &x, &y, p->solid.pos.x, p->solid.pos.y );
2082
2083 w = p->ship->gfx_space->sw + 4.;
2084 h = p->ship->gfx_space->sh + 4.;
2085
2086 /* Can do an inbounds check now. */
2087 if ((x < -w) || (x > SCREEN_W+w) ||
2088 (y < -h) || (y > SCREEN_H+h))
2089 return;
2090
2091 w = PILOT_SIZE_APPROX * p->ship->gfx_space->sw;
2092 h = PILOT_SIZE_APPROX * p->ship->gfx_space->sh / 3.;
2093
2094 glUseProgram( shaders.healthbar.program );
2095 glUniform2f( shaders.healthbar.dimensions, 5., h );
2096 glUniform1f( shaders.healthbar.paramf, (p->armour + p->shield) / (p->armour_max + p->shield_max) );
2097 gl_uniformColour( shaders.healthbar.paramv, (p->shield > 0.) ? &cShield : &cArmour );
2098 gl_renderShader( x + w/2. + 2.5, y, 5., h, 0., &shaders.healthbar, pilot_getColour(p), 1 );
2099 }
2100}
2101
2108void pilot_update( Pilot* pilot, double dt )
2109{
2110 int cooling, nchg;
2111 Pilot *target;
2112 double a, px,py, vx,vy;
2113 double Q;
2114
2115 /* Modify the dt with speedup. */
2116 dt *= pilot->stats.time_speedup;
2117
2118 /* Check target validity. */
2119 target = pilot_getTarget( pilot );
2120 cooling = pilot_isFlag(pilot, PILOT_COOLDOWN);
2121
2122 /*
2123 * Update timers.
2124 */
2125 pilot->ptimer -= dt;
2126 pilot->tcontrol -= dt;
2127 if (cooling) {
2128 pilot->ctimer -= dt;
2129 if (pilot->ctimer < 0.) {
2130 pilot_cooldownEnd(pilot, NULL);
2131 cooling = 0;
2132 }
2133 }
2134 pilot->stimer -= dt;
2135 if (pilot->stimer <= 0.)
2136 pilot->sbonus -= dt;
2137 for (int i=0; i<MAX_AI_TIMERS; i++)
2138 if (pilot->timer[i] > 0.)
2139 pilot->timer[i] -= dt;
2140 if (pilot->comm_msg != NULL) {
2141 pilot->comm_msgTimer -= dt;
2142 if (pilot->comm_msgTimer < 0.) {
2143 free(pilot->comm_msg);
2144 pilot->comm_msg = NULL;
2145 }
2146 }
2147 if (pilot_isFlag( pilot, PILOT_HAILING )) {
2148 glTexture *ico_hail = gui_hailIcon();
2149 if (ico_hail != NULL) {
2150 int sx, sy;
2151 pilot->htimer -= dt;
2152 sx = (int)ico_hail->sx;
2153 sy = (int)ico_hail->sy;
2154 if (pilot->htimer < 0.) {
2155 pilot->htimer = 0.1;
2156 pilot->hail_pos++;
2157 pilot->hail_pos %= sx*sy;
2158 }
2159 }
2160 }
2161 /* Update heat. */
2162 a = -1.;
2163 Q = 0.;
2164 nchg = 0; /* Number of outfits that change state, processed at the end. */
2165 for (int i=0; i<array_size(pilot->outfits); i++) {
2166 PilotOutfitSlot *o = pilot->outfits[i];
2167
2168 /* Picky about our outfits. */
2169 if (o->outfit == NULL)
2170 continue;
2171 if (!o->active)
2172 continue;
2173
2174 /* Handle firerate timer. */
2175 if (o->timer > 0.)
2176 o->timer -= dt * pilot_heatFireRateMod( o->heat_T );
2177
2178 /* Handle reload timer. (Note: this works backwards compared to
2179 * other timers. This helps to simplify code resetting the timer
2180 * elsewhere.)
2181 */
2183 double ammo_threshold, reload_time;
2184
2185 /* Initial (raw) ammo threshold */
2186 if (outfit_isLauncher(o->outfit)) {
2187 ammo_threshold = o->outfit->u.lau.amount;
2188 ammo_threshold = round( (double)ammo_threshold * pilot->stats.ammo_capacity );
2189 reload_time = o->outfit->u.lau.reload_time / pilot->stats.launch_reload;
2190 }
2191 else { /* if (outfit_isFighterBay( o->outfit)) { */ /* Commented to shut up warning. */
2192 ammo_threshold = o->outfit->u.bay.amount;
2193 ammo_threshold = round( (double)ammo_threshold * pilot->stats.fbay_capacity );
2194 /* Adjust for deployed fighters if needed */
2195 ammo_threshold -= o->u.ammo.deployed;
2196 reload_time = o->outfit->u.bay.reload_time / pilot->stats.fbay_reload;
2197 }
2198
2199 /* Add to timer. */
2200 if (o->rtimer < reload_time)
2201 o->rtimer += dt;
2202
2203 /* Don't allow accumulation of the timer before reload allowed */
2204 if ( o->u.ammo.quantity >= ammo_threshold )
2205 o->rtimer = 0;
2206
2207 while ((o->rtimer >= reload_time) &&
2208 (o->u.ammo.quantity < ammo_threshold)) {
2209 o->rtimer -= reload_time;
2210 pilot_addAmmo( pilot, o, 1 );
2211 }
2212
2213 o->rtimer = MIN( o->rtimer, reload_time );
2214 }
2215
2216 /* Handle state timer. */
2217 if (o->stimer >= 0.) {
2218 o->stimer -= dt;
2219 if (o->stimer < 0.) {
2220 if (o->state == PILOT_OUTFIT_ON) {
2221 pilot_outfitOff( pilot, o );
2222 nchg++;
2223 }
2224 else if (o->state == PILOT_OUTFIT_COOLDOWN) {
2225 o->state = PILOT_OUTFIT_OFF;
2226 nchg++;
2227 }
2228 }
2229 }
2230
2231 /* Handle heat. */
2232 if (!cooling)
2233 Q += pilot_heatUpdateSlot( pilot, o, dt );
2234
2235 /* Handle lockons. */
2236 pilot_lockUpdateSlot( pilot, o, target, &a, dt );
2237 }
2238
2239 /* Global heat. */
2240 if (!cooling)
2241 pilot_heatUpdateShip( pilot, Q, dt );
2242 else
2243 pilot_heatUpdateCooldown( pilot );
2244
2245 /* Update electronic warfare. */
2246 pilot_ewUpdateDynamic( pilot, dt );
2247
2248 /* Update stress. */
2249 if (!pilot_isFlag(pilot, PILOT_DISABLED)) { /* Case pilot is not disabled. */
2250 double stress_falloff = 0.3*sqrt(pilot->solid.mass); /* Should be about 38 seconds for a 300 mass ship with 200 armour, and 172 seconds for a 6000 mass ship with 4000 armour. */
2251 pilot->stress -= stress_falloff * pilot->stats.stress_dissipation * dt;
2252 pilot->stress = MAX(pilot->stress, 0);
2253 }
2254 else if (!pilot_isFlag(pilot, PILOT_DISABLED_PERM)) { /* Case pilot is disabled (but not permanently so). */
2255 pilot->dtimer_accum += dt;
2256 if (pilot->dtimer_accum >= pilot->dtimer) {
2257 pilot->stress = 0.;
2258 pilot->dtimer_accum = 0;
2259 pilot_updateDisable(pilot, 0);
2260 }
2261 }
2262
2263 /* Damage effect. */
2264 if ((pilot->stats.damage > 0.) || (pilot->stats.disable > 0.)) {
2265 Damage dmg;
2266 dmg.type = dtype_get("raw");
2267 dmg.damage = pilot->stats.damage * dt;
2268 dmg.penetration = 1.; /* Full penetration. */
2269 dmg.disable = pilot->stats.disable * dt;
2270 pilot_hit( pilot, NULL, NULL, &dmg, NULL, LUA_NOREF, 0 );
2271 }
2272
2273 /* Handle takeoff/landing. */
2274 if (pilot_isFlag(pilot,PILOT_TAKEOFF)) {
2275 if (pilot->ptimer < 0.) {
2276 pilot_rmFlag(pilot,PILOT_TAKEOFF);
2277 if (pilot_isFlag(pilot, PILOT_PLAYER)) {
2278 pilot_setFlag(pilot, PILOT_NONTARGETABLE);
2279 pilot->itimer = PILOT_PLAYER_NONTARGETABLE_TAKEOFF_DELAY;
2280 }
2281 return;
2282 }
2283 }
2284 else if (pilot_isFlag(pilot,PILOT_LANDING)) {
2285 if (pilot->ptimer < 0.) {
2286 if (pilot_isPlayer(pilot)) {
2287 player_setFlag( PLAYER_HOOK_LAND );
2288 pilot->ptimer = 0.;
2289 }
2290 else
2291 pilot_delete(pilot);
2292 return;
2293 }
2294 }
2295 /* he's dead jim */
2296 else if (pilot_isFlag(pilot,PILOT_DEAD)) {
2297
2298 if (pilot->ship->lua_explode_update != LUA_NOREF) {
2299 /* Run Lua if applicable. */
2300 pilot_shipLExplodeUpdate( pilot, dt );
2301 }
2302 else {
2303 /* pilot death sound */
2304 if (!pilot_isFlag(pilot,PILOT_DEATH_SOUND) &&
2305 (pilot->ptimer < 0.050)) {
2306 char buf[16];
2307
2308 /* Play random explosion sound. */
2309 snprintf( buf, sizeof(buf), "explosion%d", RNG(0,2) );
2310 sound_playPos( sound_get(buf), pilot->solid.pos.x, pilot->solid.pos.y,
2311 pilot->solid.vel.x, pilot->solid.vel.y );
2312
2313 pilot_setFlag(pilot,PILOT_DEATH_SOUND);
2314 }
2315 /* final explosion */
2316 else if (!pilot_isFlag(pilot,PILOT_EXPLODED) &&
2317 (pilot->ptimer < 0.200)) {
2318 Damage dmg;
2319
2320 /* Damage from explosion. */
2321 a = sqrt(pilot->solid.mass);
2322 dmg.type = dtype_get("explosion_splash");
2323 dmg.damage = MAX(0., 2. * (a * (1. + sqrt(pilot->fuel + 1.) / 28.)));
2324 dmg.penetration = 1.; /* Full penetration. */
2325 dmg.disable = 0.;
2326 expl_explode( pilot->solid.pos.x, pilot->solid.pos.y,
2327 pilot->solid.vel.x, pilot->solid.vel.y,
2328 pilot->ship->gfx_space->sw/2./PILOT_SIZE_APPROX + a, &dmg, NULL, EXPL_MODE_SHIP );
2329 debris_add( pilot->solid.mass, pilot->ship->gfx_space->sw/2.,
2330 pilot->solid.pos.x, pilot->solid.pos.y,
2331 pilot->solid.vel.x, pilot->solid.vel.y );
2332 pilot_setFlag(pilot,PILOT_EXPLODED);
2333 pilot_runHook( pilot, PILOT_HOOK_EXPLODED );
2334
2335 /* We do a check here in case the pilot was regenerated. */
2336 if (pilot_isFlag(pilot, PILOT_EXPLODED)) {
2337 /* Release cargo */
2338 for (int i=0; i<array_size(pilot->commodities); i++)
2339 pilot_cargoJet( pilot, pilot->commodities[i].commodity,
2340 pilot->commodities[i].quantity, 1 );
2341 }
2342 }
2343 /* reset random explosion timer */
2344 else if (pilot->timer[1] <= 0.) {
2345 unsigned int l;
2346
2347 pilot->timer[1] = 0.08 * (pilot->ptimer - pilot->timer[1]) /
2348 pilot->ptimer;
2349
2350 /* random position on ship */
2351 a = RNGF()*2.*M_PI;
2352 px = VX(pilot->solid.pos) + cos(a)*RNGF()*pilot->ship->gfx_space->sw/2.;
2353 py = VY(pilot->solid.pos) + sin(a)*RNGF()*pilot->ship->gfx_space->sh/2.;
2354 vx = VX(pilot->solid.vel);
2355 vy = VY(pilot->solid.vel);
2356
2357 /* set explosions */
2358 l = (pilot->id==PLAYER_ID) ? SPFX_LAYER_FRONT : SPFX_LAYER_MIDDLE;
2359 if (RNGF() > 0.8)
2360 spfx_add( spfx_get("ExpM"), px, py, vx, vy, l );
2361 else
2362 spfx_add( spfx_get("ExpS"), px, py, vx, vy, l );
2363 }
2364
2365 /* completely destroyed with final explosion */
2366 if (pilot_isFlag(pilot,PILOT_DEAD) && (pilot->ptimer < 0.)) {
2367 if (pilot->id==PLAYER_ID) /* player.p handled differently */
2369 pilot_delete(pilot);
2370 return;
2371 }
2372 }
2373 }
2374 else if (pilot_isFlag(pilot, PILOT_NONTARGETABLE)) {
2375 pilot->itimer -= dt;
2376 if (pilot->itimer < 0.)
2377 pilot_rmFlag(pilot, PILOT_NONTARGETABLE);
2378 }
2379 else if (pilot->armour <= 0.) { /* PWNED */
2380 if (pilot_isFlag( pilot, PILOT_NODEATH ))
2381 pilot->armour = 1.;
2382 else
2383 pilot_dead( pilot, 0 ); /* start death stuff - dunno who killed. */
2384 }
2385
2386 /* Special handling for braking. */
2387 if (pilot_isFlag(pilot, PILOT_BRAKING )) {
2388 if (pilot_brake( pilot, dt )) {
2389 if (pilot_isFlag(pilot, PILOT_COOLDOWN_BRAKE))
2390 pilot_cooldown( pilot, 1 );
2391 else {
2392 /* Normal braking is done (we're below MIN_VEL_ERR), now sidestep
2393 * normal physics and bring the ship to a near-complete stop. */
2394 pilot->solid.speed_max = 0.;
2395 pilot->solid.update( &pilot->solid, dt );
2396
2397 if (VMOD(pilot->solid.vel) < 1e-1) {
2398 vectnull( &pilot->solid.vel ); /* Forcibly zero velocity. */
2399 pilot_rmFlag(pilot, PILOT_BRAKING);
2400 }
2401 }
2402 }
2403 }
2404
2405 /* Healing and energy usage is only done if not disabled. */
2406 if (!pilot_isDisabled(pilot)) {
2407 pilot_ewUpdateStealth(pilot, dt);
2408
2409 /* Pilot is still alive */
2410 pilot->armour += pilot->armour_regen * dt;
2411 if (pilot->armour > pilot->armour_max)
2412 pilot->armour = pilot->armour_max;
2413
2414 /* Regen shield */
2415 if (pilot->stimer <= 0.) {
2416 pilot->shield += pilot->shield_regen * dt;
2417 if (pilot->sbonus > 0.)
2418 pilot->shield += dt * (pilot->shield_regen * (pilot->sbonus / 1.5));
2419 pilot->shield = CLAMP( 0., pilot->shield_max, pilot->shield );
2420 }
2421
2422 /* Regen fuel. */
2423 pilot->fuel = MIN( pilot->fuel_max, pilot->fuel + pilot->stats.fuel_regen * dt );
2424
2425 /*
2426 * Using RC circuit energy loading.
2427 *
2428 * Calculations (using y = [0:1])
2429 *
2430 * \
2431 * y = 1 - exp( -x / tau ) |
2432 * y + dy = 1 - exp( -( x + dx ) / tau ) | ==>
2433 * /
2434 *
2435 * ==> dy = exp( -x / tau ) * ( 1 - exp( -dx / tau ) ==>
2436 * ==> [ dy = (1 - y) * ( 1 - exp( -dx / tau ) ) ]
2437 */
2438 pilot->energy += (pilot->energy_max - pilot->energy) *
2439 (1. - exp( -dt / pilot->energy_tau));
2440 pilot->energy -= pilot->energy_loss * dt;
2441 if (pilot->energy > pilot->energy_max)
2442 pilot->energy = pilot->energy_max;
2443 else if (pilot->energy < 0.) {
2444 pilot->energy = 0.;
2445 /* Stop all on outfits. */
2446 nchg += pilot_outfitOffAll( pilot );
2447 /* Run Lua stuff. */
2449 }
2450 }
2451
2452 /* Update effects. */
2453 nchg += effect_update( &pilot->effects, dt );
2454 if (pilot_isFlag( pilot, PILOT_DELETE ))
2455 return; /* It's possible for effects to remove the pilot causing future Lua to be unhappy. */
2456
2457 /* Must recalculate stats because something changed state. */
2458 if (nchg > 0)
2459 pilot_calcStats( pilot );
2460
2461 /* purpose fallthrough to get the movement like disabled */
2462 if (pilot_isDisabled(pilot) || cooling) {
2463 /* Do the slow brake thing */
2464 pilot->solid.speed_max = 0.;
2465 pilot_setAccel( pilot, 0. );
2466 pilot_setTurn( pilot, 0. );
2467
2468 /* update the solid */
2469 pilot->solid.update( &pilot->solid, dt );
2470
2471 gl_getSpriteFromDir( &pilot->tsx, &pilot->tsy,
2472 pilot->ship->gfx_space, pilot->solid.dir );
2473
2474 /* Engine glow decay. */
2475 if (pilot->engine_glow > 0.) {
2476 pilot->engine_glow -= pilot->speed / pilot->accel * dt;
2477 if (pilot->engine_glow < 0.)
2478 pilot->engine_glow = 0.;
2479 }
2480
2481 /* Update the trail. */
2482 pilot_sample_trails( pilot, 0 );
2483
2484 /* Cooldown still updates outfits. */
2485 pilot_shipLUpdate( pilot, dt );
2486
2487 /* Update outfits if necessary. */
2488 pilot->otimer += dt;
2489 while (pilot->otimer >= PILOT_OUTFIT_LUA_UPDATE_DT) {
2490 pilot_outfitLUpdate( pilot, PILOT_OUTFIT_LUA_UPDATE_DT );
2491 if (pilot_isFlag( pilot, PILOT_DELETE ))
2492 return; /* Same as with the effects, it is theoretically possible for the outfit to remove the pilot. */
2493 pilot->otimer -= PILOT_OUTFIT_LUA_UPDATE_DT;
2494 }
2495 return;
2496 }
2497
2498 /* Player damage decay. */
2499 if (pilot->player_damage > 0.)
2500 pilot->player_damage -= dt * PILOT_HOSTILE_DECAY;
2501 else
2502 pilot->player_damage = 0.;
2503
2504 /* Pilot is board/refueling. Hack to match speeds. */
2505 if (pilot_isFlag(pilot, PILOT_REFUELBOARDING))
2506 pilot_refuel(pilot, dt);
2507
2508 /* Pilot is boarding its target. Hack to match speeds. */
2509 if (pilot_isFlag(pilot, PILOT_BOARDING)) {
2510 if (target==NULL)
2511 pilot_rmFlag(pilot, PILOT_BOARDING);
2512 else {
2513 /* Match speeds. */
2514 pilot->solid.vel = target->solid.vel;
2515
2516 /* See if boarding is finished. */
2517 if (pilot->ptimer < 0.)
2518 pilot_boardComplete(pilot);
2519 }
2520 }
2521
2522 /* Update weapons. */
2523 pilot_weapSetUpdate( pilot );
2524
2525 if (!pilot_isFlag(pilot, PILOT_HYPERSPACE)) { /* limit the speed */
2526
2527 /* pilot is afterburning */
2528 if (pilot_isFlag(pilot, PILOT_AFTERBURNER)) {
2529 /* Heat up the afterburner. */
2530 pilot_heatAddSlotTime(pilot, pilot->afterburner, dt);
2531
2532 /* If the afterburner's efficiency is reduced to 0, shut it off. */
2535 pilot->afterburner->outfit->overheat_max)<=0.)
2536 pilot_afterburnOver(pilot);
2537 else {
2538 double efficiency, accel;
2539
2540 if (pilot->id == PLAYER_ID)
2541 spfx_shake( 0.75*SPFX_SHAKE_DECAY * dt ); /* shake goes down at quarter speed */
2542 efficiency = pilot_heatEfficiencyMod( pilot->afterburner->heat_T,
2544 pilot->afterburner->outfit->overheat_max );
2545 accel = MIN( 1., pilot->afterburner->outfit->u.afb.mass_limit / pilot->solid.mass ) * efficiency;
2546
2547 /* Adjust speed. Speed bonus falls as heat rises. */
2548 pilot->solid.speed_max = pilot->speed * (1. +
2549 pilot->afterburner->outfit->u.afb.speed * accel);
2550
2551 /* Adjust accel. Thrust bonus falls as heat rises. */
2552 pilot_setAccel(pilot, 1. + pilot->afterburner->outfit->u.afb.accel * accel);
2553 }
2554 }
2555 else
2556 pilot->solid.speed_max = pilot->speed;
2557 }
2558 else
2559 pilot->solid.speed_max = -1.; /* Disables max speed. */
2560
2561 /* Set engine glow. */
2562 if (pilot->solid.accel > 0.) {
2563 /*pilot->engine_glow += pilot->accel / pilot->speed * dt;*/
2564 pilot->engine_glow += pilot->speed / pilot->accel * dt;
2565 if (pilot->engine_glow > 1.)
2566 pilot->engine_glow = 1.;
2567 }
2568 else if (pilot->engine_glow > 0.) {
2569 pilot->engine_glow -= pilot->speed / pilot->accel * dt;
2570 if (pilot->engine_glow < 0.)
2571 pilot->engine_glow = 0.;
2572 }
2573
2574 /* Update the solid, must be run after limit_speed. */
2575 pilot->solid.update( &pilot->solid, dt );
2576 gl_getSpriteFromDir( &pilot->tsx, &pilot->tsy,
2577 pilot->ship->gfx_space, pilot->solid.dir );
2578
2579 /* Update the trail. */
2580 pilot_sample_trails( pilot, 0 );
2581
2582 /* Update pilot Lua. */
2583 pilot_shipLUpdate( pilot, dt );
2584
2585 /* Update outfits if necessary. */
2586 pilot->otimer += dt;
2587 while (pilot->otimer >= PILOT_OUTFIT_LUA_UPDATE_DT) {
2588 pilot_outfitLUpdate( pilot, PILOT_OUTFIT_LUA_UPDATE_DT );
2589 if (pilot_isFlag( pilot, PILOT_DELETE ))
2590 return; /* Same as with the effects, it is theoretically possible for the outfit to remove the pilot. */
2591 pilot->otimer -= PILOT_OUTFIT_LUA_UPDATE_DT;
2592 }
2593}
2594
2601void pilot_sample_trails( Pilot* p, int none )
2602{
2603 double d2, cx, cy, dircos, dirsin;
2604 TrailMode mode;
2605
2606 /* Ignore for simulation. */
2607 if (!space_needsEffects())
2608 return;
2609
2610 /* No trails to sample. */
2611 if (p->trail == NULL)
2612 return;
2613
2614 /* Skip if far away (pretty heuristic-based but seems to work). */
2615 cam_getPos( &cx, &cy );
2616 d2 = pow2(cx-p->solid.pos.x) + pow2(cy-p->solid.pos.y);
2617 if (d2 > pow2( MAX(SCREEN_W,SCREEN_H) / conf.zoom_far * 2. ))
2618 return;
2619
2620 dircos = cos(p->solid.dir);
2621 dirsin = sin(p->solid.dir);
2622
2623 /* Identify the emission type. */
2624 if (none)
2625 mode = MODE_NONE;
2626 else {
2627 if (pilot_isFlag(p, PILOT_HYPERSPACE) || pilot_isFlag(p, PILOT_HYP_END))
2628 mode = MODE_JUMPING;
2629 else if (pilot_isFlag(p, PILOT_AFTERBURNER))
2630 mode = MODE_AFTERBURN;
2631 else if (p->engine_glow > 0.)
2632 mode = MODE_GLOW;
2633 else
2634 mode = MODE_IDLE;
2635 }
2636
2637 /* Compute the engine offset and decide where to draw the trail. */
2638 for (int i=0, g=0; g<array_size(p->ship->trail_emitters); g++) {
2639 const ShipTrailEmitter *trail = &p->ship->trail_emitters[g];
2640 double dx, dy, scale;
2641
2642 if (!pilot_trail_generated( p, g ))
2643 continue;
2644
2645 p->trail[i]->ontop = 0;
2646 if (!(trail->always_under) && (dirsin > 0)) {
2647 /* See if the trail's front (tail) is in front of the ship. */
2648 double prod = (trail_front( p->trail[i] ).x - p->solid.pos.x) * dircos +
2649 (trail_front( p->trail[i] ).y - p->solid.pos.y) * dirsin;
2650
2651 p->trail[i]->ontop = (prod < 0);
2652 }
2653
2654 /* Figure our relative position. */
2655 dx = trail->x_engine * dircos - trail->y_engine * dirsin;
2656 dy = trail->x_engine * dirsin + trail->y_engine * dircos +
2657 trail->h_engine;
2658
2659 /* Check if needs scaling. */
2660 if (pilot_isFlag( p, PILOT_LANDING ))
2661 scale = CLAMP( 0., 1., p->ptimer / p->landing_delay );
2662 else if (pilot_isFlag( p, PILOT_TAKEOFF ))
2663 scale = CLAMP( 0., 1., 1. - p->ptimer / p->landing_delay );
2664 else
2665 scale = 1.;
2666 dx *= scale;
2667 dy *= scale;
2668
2669 /* Sample. */
2670 spfx_trail_sample( p->trail[i++], p->solid.pos.x + dx, p->solid.pos.y + dy*M_SQRT1_2, mode, mode==MODE_NONE );
2671 }
2672}
2673
2677static int pilot_trail_generated( Pilot* p, int generator )
2678{
2679 return !p->ship->trail_emitters[generator].trail_spec->nebula || cur_system->nebu_density>0;
2680}
2681
2688{
2689 PilotOutfitSlot* dockslot;
2690
2691 /* Don't double delete, just in case. */
2692 if (pilot_isFlag( p, PILOT_DELETE ))
2693 return;
2694
2695 /* Stop ship stuff. */
2697
2698 /* Handle Lua outfits. */
2701
2702 /* Remove from parent's escort list */
2703 if (p->parent != 0) {
2704 Pilot *leader = pilot_get(p->parent);
2705 if (leader != NULL)
2706 escort_rmList(leader, p->id);
2707 }
2708
2709 /* Remove faction if necessary. */
2710 if (p->presence > 0) {
2711 system_rmCurrentPresence( cur_system, p->faction, p->presence );
2712 p->presence = 0;
2713 }
2714
2715 /* Unmark as deployed if necessary */
2716 dockslot = pilot_getDockSlot( p );
2717 if (dockslot != NULL) {
2718 dockslot->u.ammo.deployed--;
2719 p->dockpilot = 0;
2720 p->dockslot = -1;
2721 }
2722
2723 /* Set flag to mark for deletion. */
2724 pilot_setFlag(p, PILOT_DELETE);
2725}
2726
2733static void pilot_hyperspace( Pilot* p, double dt )
2734{
2735 StarSystem *sys;
2736 double a, diff;
2737 int can_hyp;
2738 HookParam hparam;
2739
2740 /* pilot is actually in hyperspace */
2741 if (pilot_isFlag(p, PILOT_HYPERSPACE)) {
2742
2743 /* Time to play sound. */
2744 if ((p->id == PLAYER_ID) &&
2745 (p->ptimer < sound_getLength(snd_hypPowUpJump)) &&
2746 (p->timer[0] == -1.)) {
2747 p->timer[0] = -2.;
2749 }
2750
2751 /* has jump happened? */
2752 if (p->ptimer < 0.) {
2753 pilot_setFlag( p, PILOT_HYP_END );
2754 pilot_setAccel( p, 0. );
2755 if (p->id == PLAYER_ID) /* player.p just broke hyperspace */
2756 player_setFlag( PLAYER_HOOK_HYPER );
2757 else {
2758 hparam.type = HOOK_PARAM_JUMP;
2759 hparam.u.lj.srcid = cur_system->id;
2760 hparam.u.lj.destid = cur_system->jumps[ p->nav_hyperspace ].targetid;
2761
2762 /* Should be run before messing with delete flag. */
2763 pilot_runHookParam( p, PILOT_HOOK_JUMP, &hparam, 1 );
2764
2765 pilot_delete(p);
2766 }
2767 return;
2768 }
2769
2770 /* keep acceling - hyperspace uses much bigger accel */
2771 pilot_setAccel( p, HYPERSPACE_ACCEL/p->accel );
2772 }
2773 /* engines getting ready for the jump */
2774 else if (pilot_isFlag(p, PILOT_HYP_BEGIN)) {
2775
2776 /* Make sure still within range. */
2777 can_hyp = space_canHyperspace( p );
2778 if (!can_hyp) {
2780
2781 if (pilot_isPlayer(p))
2782 if (!player_isFlag(PLAYER_AUTONAV))
2783 player_message( "#r%s", _("Strayed too far from jump point: jump aborted.") );
2784 }
2785 else if (pilot_isFlag(p,PILOT_AFTERBURNER)) {
2787
2788 if (pilot_isPlayer(p))
2789 if (!player_isFlag(PLAYER_AUTONAV))
2790 player_message( "#r%s", _("Afterburner active: jump aborted.") );
2791 }
2792 else {
2793 if (p->ptimer < 0.) { /* engines ready */
2794 p->ptimer = HYPERSPACE_FLY_DELAY * p->stats.jump_delay;
2795 pilot_setFlag(p, PILOT_HYPERSPACE);
2796 if (p->id == PLAYER_ID)
2797 p->timer[0] = -1.;
2798 }
2799 }
2800 }
2801 /* pilot is getting ready for hyperspace */
2802 else {
2803 /* Make sure still within range. */
2804 can_hyp = space_canHyperspace( p );
2805 if (!can_hyp) {
2807
2808 if (pilot_isPlayer(p))
2809 if (!player_isFlag(PLAYER_AUTONAV))
2810 player_message( "#r%s", _("Strayed too far from jump point: jump aborted.") );
2811 }
2812 else {
2813 /* If the ship needs to charge up its hyperdrive, brake. */
2814 if (!p->stats.misc_instant_jump &&
2815 !pilot_isFlag(p, PILOT_HYP_BRAKE) && !pilot_isStopped(p))
2816 pilot_brake(p, dt);
2817 /* face target */
2818 else {
2819 /* Done braking or no braking required. */
2820 pilot_setFlag( p, PILOT_HYP_BRAKE );
2821 pilot_setAccel( p, 0. );
2822
2823 /* Face system headed to. */
2824 sys = cur_system->jumps[p->nav_hyperspace].target;
2825 a = ANGLE( sys->pos.x - cur_system->pos.x, sys->pos.y - cur_system->pos.y );
2826 diff = pilot_face( p, a, dt );
2827
2828 if (ABS(diff) < MIN_DIR_ERR) { /* we can now prepare the jump */
2829 if (jp_isFlag( &cur_system->jumps[p->nav_hyperspace], JP_EXITONLY )) {
2830 WARN( _("Pilot '%s' trying to jump through exit-only jump from '%s' to '%s'"),
2831 p->name, cur_system->name, sys->name );
2832 }
2833 else {
2834 pilot_setTurn( p, 0. );
2835 p->ptimer = HYPERSPACE_ENGINE_DELAY * p->stats.jump_warmup * !p->stats.misc_instant_jump;
2836 pilot_setFlag(p, PILOT_HYP_BEGIN);
2837 /* Player plays sound. */
2838 if ((p->id == PLAYER_ID) && !p->stats.misc_instant_jump)
2840 }
2841 }
2842 }
2843 }
2844 }
2845
2846 if (pilot_isPlayer(p))
2847 player_updateSpecific( p, dt );
2848}
2849
2858{
2859 if (pilot_isFlag(p, PILOT_HYPERSPACE))
2860 return;
2861
2862 if (pilot_isFlag(p, PILOT_HYP_BEGIN)) {
2863 /* Player plays sound. */
2864 if (p->id == PLAYER_ID) {
2867 }
2868 }
2869 pilot_rmFlag(p, PILOT_HYP_BEGIN);
2870 pilot_rmFlag(p, PILOT_HYP_BRAKE);
2871 pilot_rmFlag(p, PILOT_HYP_PREP);
2872
2873 /* Try to inform followers. */
2874 for (int i=0; i<array_size(p->escorts); i++) {
2875 const Pilot *e = pilot_get( p->escorts[i].id );
2876 if (e == NULL) /* Most likely died. */
2877 continue;
2878 pilot_msg( p, e, "hyperspace_abort", 0 );
2879 }
2880}
2881
2888{
2889 Pilot *target = pilot_getTarget( p );
2890 /* Check to see if target exists, remove flag if not. */
2891 if (target == NULL) {
2892 pilot_rmFlag(p, PILOT_REFUELING);
2893 return 0;
2894 }
2895
2896 /* Conditions are the same as boarding, except disabled. */
2897 if (vec2_dist(&p->solid.pos, &target->solid.pos) >
2898 target->ship->gfx_space->sw * PILOT_SIZE_APPROX )
2899 return 0;
2900 else if (vec2_dist2( &p->solid.vel, &target->solid.vel ) > pow2(MAX_HYPERSPACE_VEL))
2901 return 0;
2902
2903 /* Now start the boarding to refuel. */
2904 pilot_setFlag(p, PILOT_REFUELBOARDING);
2905 p->ptimer = PILOT_REFUEL_TIME; /* Use timer to handle refueling. */
2906 return 1;
2907}
2908
2915static void pilot_refuel( Pilot *p, double dt )
2916{
2917 (void) dt;
2918 /* Check to see if target exists, remove flag if not. */
2919 Pilot *target = pilot_getTarget( p );
2920 if (target == NULL) {
2921 pilot_rmFlag(p, PILOT_REFUELBOARDING);
2922 pilot_rmFlag(p, PILOT_REFUELING);
2923 return;
2924 }
2925
2926 /* Match speeds. */
2927 p->solid.vel = target->solid.vel;
2928
2929 /* Check to see if done. */
2930 if (p->ptimer < 0.) {
2931 /* Move fuel. */
2932 double amount = MIN( p->fuel, p->refuel_amount );
2933 amount = MIN( amount, target->fuel_max-target->fuel );
2934 p->fuel -= amount;
2935 target->fuel += amount;
2936
2937 pilot_rmFlag(p, PILOT_REFUELBOARDING);
2938 pilot_rmFlag(p, PILOT_REFUELING);
2939 }
2940}
2941
2948ntime_t pilot_hyperspaceDelay( const Pilot *p )
2949{
2950 int stu = (int)(NT_PERIOD_SECONDS * p->stats.jump_delay);
2951 return ntime_create( 0, 0, stu );
2952}
2953
2960void pilot_untargetAsteroid( int anchor, int asteroid )
2961{
2962 for (int i=0; i < array_size(pilot_stack); i++) {
2963 if ((pilot_stack[i]->nav_asteroid == asteroid) && (pilot_stack[i]->nav_anchor == anchor)) {
2964 pilot_stack[i]->nav_asteroid = -1;
2965 pilot_stack[i]->nav_anchor = -1;
2966 }
2967 }
2968}
2969
2973int pilot_numOutfit( const Pilot *p, const Outfit *o )
2974{
2975 int q = 0;
2976 for (int i=0; i<array_size(p->outfits); i++) {
2977 if (p->outfits[i]->outfit == o)
2978 q++;
2979 }
2980 return q;
2981}
2982
2990int pilot_hasCredits( const Pilot *p, credits_t amount )
2991{
2992 if (amount < 0)
2993 return 1;
2994 return (amount <= p->credits);
2995}
2996
3004credits_t pilot_modCredits( Pilot *p, credits_t amount )
3005{
3006 if (amount > 0) {
3007 if (CREDITS_MAX - p->credits <= amount)
3008 p->credits = CREDITS_MAX;
3009 else
3010 p->credits += amount;
3011 }
3012 else if (amount < 0) {
3013 /* ABS(CREDITS_MIN) doesn't work properly because it might be
3014 * -2,147,483,648, which ABS will try to convert to 2,147,483,648.
3015 * Problem is, that value would be represented like this in
3016 * binary:
3017 *
3018 * 10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
3019 *
3020 * Which is actually -2,147,483,648, causing the condition
3021 * ABS(amount) >= p->credits to return false (since -2,147,483,648
3022 * is less than any amount of credits the player could have). */
3023 if ( (amount <= CREDITS_MIN) || (ABS(amount) >= p->credits) )
3024 p->credits = 0;
3025 else
3026 p->credits += amount;
3027 }
3028 return p->credits;
3029}
3030
3045static void pilot_init( Pilot* pilot, const Ship* ship, const char* name, int faction,
3046 double dir, const vec2* pos, const vec2* vel,
3047 const PilotFlags flags, unsigned int dockpilot, int dockslot )
3048{
3049 PilotOutfitSlot *dslot;
3050 PilotOutfitSlot **pilot_list_ptr[] = { &pilot->outfit_structure, &pilot->outfit_utility, &pilot->outfit_weapon };
3051 ShipOutfitSlot *ship_list[] = { ship->outfit_structure, ship->outfit_utility, ship->outfit_weapon };
3052
3053 /* Clear memory. */
3054 memset( pilot, 0, sizeof(Pilot) );
3055
3056 /* Defaults. */
3057 pilot->lua_mem = LUA_NOREF;
3058 pilot->lua_ship_mem = LUA_NOREF;
3059 pilot->autoweap = 1;
3060 pilot->aimLines = 0;
3061 pilot->dockpilot = dockpilot;
3062 pilot->parent = dockpilot; /* leader will default to mothership if exists. */
3063 pilot->dockslot = dockslot;
3064
3065 /* Basic information. */
3066 pilot->ship = ship;
3067 pilot->name = strdup( (name==NULL) ? _(ship->name) : name );
3068
3069 /* faction */
3070 pilot->faction = faction;
3071
3072 /* solid */
3073 solid_init( &pilot->solid, ship->mass, dir, pos, vel, SOLID_UPDATE_RK4 );
3074
3075 /* First pass to make sure requirements make sense. */
3076 pilot->armour = pilot->armour_max = 1.; /* hack to have full armour */
3077 pilot->shield = pilot->shield_max = 1.; /* ditto shield */
3078 pilot->energy = pilot->energy_max = 1.; /* ditto energy */
3079 pilot->fuel = pilot->fuel_max = 1.; /* ditto fuel */
3080 pilot_calcStats(pilot);
3081 pilot->stress = 0.; /* No stress. */
3082
3083 /* Allocate outfit memory. */
3085 /* First pass copy data. */
3086 for (int i=0; i<3; i++) {
3087 *pilot_list_ptr[i] = array_create_size( PilotOutfitSlot, array_size(ship_list[i]) );
3088 for (int j=0; j<array_size(ship_list[i]); j++) {
3089 PilotOutfitSlot *slot = &array_grow( pilot_list_ptr[i] );
3090 memset( slot, 0, sizeof(PilotOutfitSlot) );
3091 slot->id = array_size(pilot->outfits);
3092 slot->sslot = &ship_list[i][j];
3093 array_push_back( &pilot->outfits, slot );
3094 if (pilot_list_ptr[i] != &pilot->outfit_weapon)
3095 slot->weapset = -1;
3096 /* We'll ignore non-required outfits if NO_OUTFITS is set. */
3097 if ((!pilot_isFlagRaw(flags, PILOT_NO_OUTFITS) || slot->sslot->required) && slot->sslot->data != NULL)
3098 pilot_addOutfitRaw( pilot, slot->sslot->data, slot );
3099 }
3100 }
3101 array_shrink( &pilot->outfits );
3102
3103 /* Add intrinsics if applicable. */
3104 if (!pilot_isFlagRaw(flags, PILOT_NO_OUTFITS)) {
3105 for (int i=0; i<array_size(ship->outfit_intrinsic); i++)
3107 }
3108
3109 /* We must set the weapon auto in case some of the outfits had a default
3110 * weapon equipped. */
3111 pilot_weaponAuto(pilot);
3112
3113 /* cargo - must be set before calcStats */
3114 pilot->cargo_free = pilot->ship->cap_cargo; /* should get redone with calcCargo */
3115
3116 /* Initialize heat. */
3117 pilot_heatReset( pilot );
3118
3119 /* Set the pilot stats based on their ship and outfits */
3120 pilot_calcStats( pilot );
3121
3122 /* Update dynamic electronic warfare (static should have already been done). */
3123 pilot_ewUpdateDynamic( pilot, 0. );
3124
3125 /* Heal up the ship. */
3126 pilot->armour = pilot->armour_max;
3127 pilot->shield = pilot->shield_max;
3128 pilot->energy = pilot->energy_max;
3129 pilot->fuel = pilot->fuel_max;
3130
3131 /* Mark as deployed if needed */
3132 dslot = pilot_getDockSlot( pilot );
3133 if (dslot != NULL)
3134 dslot->u.ammo.deployed++;
3135
3136 /* Safety check. */
3137#ifdef DEBUGGING
3138 if (!pilot_isFlagRaw(flags, PILOT_NO_OUTFITS)) {
3139 char message[STRMAX_SHORT];
3140 int notworthy = pilot_reportSpaceworthy( pilot, message, sizeof(message) );
3141 if (notworthy) {
3142 DEBUG( _("Pilot '%s' failed safety check: %s"), pilot->name, message );
3143 for (int i=0; i<array_size(pilot->outfits); i++) {
3144 if (pilot->outfits[i]->outfit != NULL)
3145 DEBUG(_(" [%d] %s"), i, _(pilot->outfits[i]->outfit->name) );
3146 }
3147 }
3148 }
3149#endif /* DEBUGGING */
3150
3151 /* Copy pilot flags. */
3152 pilot_copyFlagsRaw(pilot->flags, flags);
3153
3154 /* Clear timers. */
3155 pilot_clearTimers(pilot);
3156
3157 /* Update the x and y sprite positions. */
3158 gl_getSpriteFromDir( &pilot->tsx, &pilot->tsy,
3159 pilot->ship->gfx_space, pilot->solid.dir );
3160
3161 /* Targets. */
3162 pilot_setTarget( pilot, pilot->id ); /* No target. */
3163 pilot->nav_spob = -1;
3164 pilot->nav_hyperspace = -1;
3165 pilot->nav_anchor = -1;
3166 pilot->nav_asteroid = -1;
3167 pilot->shoot_indicator = 0;
3168
3169 /* Check takeoff. */
3170 if (pilot_isFlagRaw( flags, PILOT_TAKEOFF )) {
3171 pilot->landing_delay = PILOT_TAKEOFF_DELAY * pilot->ship->dt_default;
3172 pilot->ptimer = pilot->landing_delay;
3173 }
3174
3175 /* Create empty table for messages. */
3176 lua_newtable(naevL);
3177 pilot->messages = luaL_ref(naevL, LUA_REGISTRYINDEX);
3178}
3179
3185void pilot_reset( Pilot* pilot )
3186{
3187 /* Clean up flag.s */
3188 for (int i=PILOT_NOCLEAR+1; i<PILOT_FLAGS_MAX; i++)
3189 pilot->flags[i] = 0;
3190
3191 /* Initialize heat. */
3192 pilot_heatReset( pilot );
3193
3194 /* Set the pilot stats based on their ship and outfits */
3195 pilot_calcStats( pilot );
3196
3197 /* Update dynamic electronic warfare (static should have already been done). */
3198 pilot_ewUpdateDynamic( pilot, 0. );
3199
3200 /* Clear timers. */
3201 pilot_clearTimers(pilot);
3202
3203 /* Update the x and y sprite positions. */
3204 gl_getSpriteFromDir( &pilot->tsx, &pilot->tsy,
3205 pilot->ship->gfx_space, pilot->solid.dir );
3206
3207 /* Heal up. */
3208 pilot_healLanded( pilot );
3209
3210 /* Targets. */
3211 pilot_setTarget( pilot, pilot->id ); /* No target. */
3212 pilot->nav_spob = -1;
3213 pilot->nav_hyperspace = -1;
3214 pilot->nav_anchor = -1;
3215 pilot->nav_asteroid = -1;
3216
3217 /* AI */
3218 pilot->shoot_indicator = 0;
3219
3220 /* Run Lua stuff. */
3221 pilot_shipLInit( pilot );
3222 pilot_outfitLInitAll( pilot );
3223}
3224
3228static void pilot_init_trails( Pilot* p )
3229{
3230 int n = array_size(p->ship->trail_emitters);
3231 if (p->trail == NULL)
3232 p->trail = array_create_size( Trail_spfx*, n );
3233
3234 for (int g=0; g<n; g++)
3235 if (pilot_trail_generated( p, g ))
3236 array_push_back( &p->trail, spfx_trail_create( p->ship->trail_emitters[g].trail_spec ) );
3237}
3238
3248Pilot *pilot_create( const Ship* ship, const char* name, int faction, const char *ai,
3249 const double dir, const vec2* pos, const vec2* vel,
3250 const PilotFlags flags, unsigned int dockpilot, int dockslot )
3251{
3252 /* Allocate pilot memory. */
3253 Pilot *p = malloc(sizeof(Pilot));
3254 if (p == NULL) {
3255 WARN(_("Unable to allocate memory"));
3256 return 0;
3257 }
3258
3259 /* Set the pilot in the stack -- must be there before initializing */
3261
3262 /* Initialize the pilot. */
3263 pilot_init( p, ship, name, faction, dir, pos, vel, flags, dockpilot, dockslot );
3264
3265 /* Set the ID. */
3266 if (pilot_isFlagRaw(flags, PILOT_PLAYER)) { /* Set player ID. TODO should probably be fixed to something better someday. */
3267 p->id = PLAYER_ID;
3268 qsort( pilot_stack, array_size(pilot_stack), sizeof(Pilot*), pilot_cmp );
3269 }
3270 else
3271 p->id = ++pilot_id; /* new unique pilot id based on pilot_id, can't be 0 */
3272
3273 /* Initialize AI if applicable. */
3274 if (ai == NULL)
3275 ai = faction_default_ai( faction );
3276 if (ai != NULL)
3277 ai_pinit( p, ai ); /* Must run before ai_create */
3278
3279 /* Run Lua stuff. */
3280 pilot_shipLInit( p );
3282
3283 /* Animated trail. */
3284 pilot_init_trails( p );
3285
3286 /* Pilot creation hook. */
3287 pilot_runHook( p, PILOT_HOOK_CREATION );
3288
3289 return p;
3290}
3291
3301Pilot* pilot_createEmpty( const Ship* ship, const char* name,
3302 int faction, PilotFlags flags )
3303{
3304 Pilot *dyn = malloc(sizeof(Pilot));
3305 if (dyn == NULL) {
3306 WARN(_("Unable to allocate memory"));
3307 return 0;
3308 }
3309 pilot_init( dyn, ship, name, faction, 0., NULL, NULL, flags, 0, 0 );
3310 return dyn;
3311}
3312
3319unsigned int pilot_clone( const Pilot *ref )
3320{
3321 Pilot *dyn, **p;
3322 PilotFlags pf;
3323
3324 pilot_clearFlagsRaw( &pf );
3325 pilot_setFlagRaw( pf, PILOT_NO_OUTFITS );
3326
3327 /* Allocate pilot memory. */
3328 dyn = malloc(sizeof(Pilot));
3329 if (dyn == NULL) {
3330 WARN(_("Unable to allocate memory"));
3331 return 0;
3332 }
3333
3334 /* Set the pilot in the stack -- must be there before initializing */
3335 p = &array_grow( &pilot_stack );
3336 *p = dyn;
3337
3338 /* Initialize the pilot. */
3339 pilot_init( dyn, ref->ship, ref->name, ref->faction,
3340 ref->solid.dir, &ref->solid.pos, &ref->solid.vel, pf, 0, 0 );
3341
3342 /* Add outfits over. */
3343 for (int i=0; i<array_size(ref->outfits); i++)
3344 if (ref->outfits[i]->outfit != NULL)
3345 pilot_addOutfitRaw( dyn, ref->outfits[i]->outfit, dyn->outfits[i] );
3346 for (int i=0; i<array_size(ref->outfit_intrinsic); i++)
3348
3349 /* Reset the pilot. */
3350 pilot_reset( dyn );
3351
3352 return dyn->id;
3353}
3354
3358unsigned int pilot_addStack( Pilot *p )
3359{
3360 p->id = ++pilot_id; /* new unique pilot id based on pilot_id, can't be 0 */
3361 pilot_setFlag( p, PILOT_NOFREE );
3362
3364
3365 /* Have to reset after adding to stack, as some Lua functions will run code on the pilot. */
3366 pilot_reset( p );
3367
3368 /* Animated trail. */
3369 pilot_init_trails( p );
3370
3371#if DEBUGGING
3372 for (int i=1; i<array_size(pilot_stack); i++)
3373 if (pilot_stack[i]==pilot_stack[i-1])
3374 WARN(_("Duplicate pilots on stack!"));
3375#endif /* DEBUGGING */
3376
3377 return p->id;
3378}
3379
3384{
3385 for (int j=0; j<array_size(p->trail); j++)
3386 spfx_trail_remove( p->trail[j] );
3387 array_erase( &p->trail, array_begin(p->trail), array_end(p->trail) );
3388 pilot_init_trails( p );
3389}
3390
3397{
3398 int i = pilot_getStackPos( PLAYER_ID);
3399 int l = pilot_getStackPos( after->id );
3400
3401 if (i < 0) { /* No existing player ID. */
3402 if (l < 0) /* No existing pilot, have to create. */
3403 array_push_back( &pilot_stack, after );
3404 }
3405 else { /* Player pilot already exists. */
3406 if (l >= 0)
3407 pilot_delete( pilot_stack[i] ); /* Both player and after are on stack. Remove player. */
3408 else
3409 pilot_stack[i] = after; /* after overwrites player. */
3410 }
3411 after->id = PLAYER_ID;
3412 qsort( pilot_stack, array_size(pilot_stack), sizeof(Pilot*), pilot_cmp );
3413
3414 /* Set up stuff. */
3415 player.p = after;
3416 pilot_clearTrails( after );
3417
3418 /* Initialize AI as necessary. */
3419 ai_pinit( after, "player" );
3420
3421 /* Set player flag. */
3422 pilot_setFlag( after, PILOT_PLAYER );
3423 pilot_setFlag( after, PILOT_NOFREE );
3424
3425 /* Run Lua stuff. */
3426 pilot_shipLInit( after );
3427 pilot_outfitLInitAll( after );
3428
3429 return after;
3430}
3431
3442void pilot_choosePoint( vec2 *vp, Spob **spob, JumpPoint **jump, int lf, int ignore_rules, int guerilla )
3443{
3444 int *ind;
3445 JumpPoint **validJumpPoints;
3446
3447 /* Initialize. */
3448 *spob = NULL;
3449 *jump = NULL;
3450 vectnull( vp );
3451
3452 /* Build landable spob table. */
3453 ind = array_create_size( int, array_size(cur_system->spobs) );
3454 for (int i=0; i<array_size(cur_system->spobs); i++) {
3455 const Spob *pnt = cur_system->spobs[i];
3456 if (spob_hasService( pnt, SPOB_SERVICE_INHABITED ) &&
3457 !areEnemies( lf, pnt->presence.faction ))
3458 array_push_back( &ind, i );
3459 }
3460
3461 /* Build jumpable jump table. */
3462 validJumpPoints = array_create_size( JumpPoint*, array_size(cur_system->jumps) );
3463 if (array_size(cur_system->jumps) > 0) {
3464 for (int i=0; i<array_size(cur_system->jumps); i++) {
3465 /* The jump into the system must not be exit-only, and unless
3466 * ignore_rules is set, must also be non-hidden
3467 * (excepted if the pilot is guerilla) and have faction
3468 * presence matching the pilot's on the remote side. */
3469 const JumpPoint *jmp = &cur_system->jumps[i];
3470 JumpPoint *target = jmp->returnJump;
3471 double limit, pres;
3472 const int *fact;
3473
3474 /* Can't use exit only from the other-side. */
3475 if (jp_isFlag( target, JP_EXITONLY ))
3476 continue;
3477
3478 if (ignore_rules) {
3479 array_push_back( &validJumpPoints, target );
3480 continue;
3481 }
3482
3483 /* Only guerrila entrances can use hidden jumps. */
3484 if (jp_isFlag( jmp, JP_HIDDEN ) && !guerilla)
3485 continue;
3486
3487 /* Test presence on the other side, making sure there is presence. */
3488 pres = system_getPresence( jmp->target, lf );
3489 if (pres <= 0.)
3490 continue;
3491
3492 /* See if the remote system isn't dominantly controlled by enemies. */
3493 limit = 0.;
3494 fact = faction_getEnemies( lf );
3495 for (int j=0; j<array_size(fact); j++)
3496 limit += system_getPresence( jmp->target, fact[j] );
3497 if (pres > limit)
3498 array_push_back( &validJumpPoints, target );
3499 }
3500 }
3501
3502 /* Unusual case no landable nor presence, we'll just jump in randomly if possible. */
3503 if (array_size(ind)==0 && array_size(validJumpPoints)==0) {
3504 if (guerilla) /* Guerilla ships are created far away in deep space. */
3505 vec2_pset ( vp, 1.5*cur_system->radius, RNGF()*2*M_PI );
3506 else if (array_size(cur_system->jumps) > 0) {
3507 for (int i=0; i<array_size(cur_system->jumps); i++) {
3508 JumpPoint *jp = &cur_system->jumps[i];
3509 if (jp_isFlag( jp->returnJump, JP_EXITONLY ))
3510 continue;
3511 /* Ignore hidden jumps for now. */
3512 if (jp_isFlag( jp, JP_HIDDEN ))
3513 continue;
3514 array_push_back(&validJumpPoints, jp->returnJump);
3515 }
3516 /* Now add hidden jumps as a last resort - only for non guerillas as they should be added otherwise. */
3517 if (!guerilla && array_size(validJumpPoints)<=0) {
3518 for (int i=0; i<array_size(cur_system->jumps); i++) {
3519 JumpPoint *jp = &cur_system->jumps[i];
3520 if (jp_isFlag( jp->returnJump, JP_EXITONLY ))
3521 continue;
3522 array_push_back(&validJumpPoints, jp->returnJump);
3523 }
3524 }
3525 }
3526 else {
3527 WARN(_("Creating pilot in system with no jumps nor spobs to take off from!"));
3528 vectnull( vp );
3529 }
3530 }
3531
3532 /* Calculate jump chance. */
3533 if (array_size(ind)>0 || array_size(validJumpPoints)>0) {
3534 double chance = array_size(validJumpPoints);
3535 chance = chance / (chance + array_size(ind));
3536
3537 /* Random jump in. */
3538 if ((RNGF() <= chance) && (validJumpPoints != NULL))
3539 *jump = validJumpPoints[ RNG_BASE(0,array_size(validJumpPoints)-1) ];
3540 /* Random take off. */
3541 else if (array_size(ind) != 0)
3542 *spob = cur_system->spobs[ ind[ RNG_BASE(0, array_size(ind)-1) ] ];
3543 }
3544
3545 /* Free memory allocated. */
3546 array_free( ind );
3547 array_free(validJumpPoints);
3548}
3549
3556{
3557 /* Clear some useful things. */
3559 effect_cleanup( p->effects );
3560 p->effects = NULL;
3561 escort_freeList(p);
3562
3563 /* If hostile, must remove counter. */
3564 pilot_rmHostile(p);
3565
3566 /* Free animated trail. */
3567 for (int i=0; i<array_size(p->trail); i++)
3568 spfx_trail_remove( p->trail[i] );
3569 array_free(p->trail);
3570 p->trail = NULL;
3571
3572 /* We don't actually free internals of the pilot once we cleaned up stuff. */
3573 if (pilot_isFlag( p, PILOT_NOFREE )) {
3574 p->id = 0; /* Invalidate ID. */
3575 return;
3576 }
3577
3578 /* Only remove cargo at the end. */
3579 pilot_cargoRmAll( p, 1 );
3580
3581 /* Clean up stats. */
3582 ss_free( p->ship_stats );
3583 ss_free( p->intrinsic_stats );
3584
3585 lvar_freeArray( p->shipvar );
3586
3588
3589 /* Clean up outfit slots. */
3590 for (int i=0; i<array_size(p->outfits); i++) {
3591 ss_free( p->outfits[i]->lua_stats );
3592 }
3593 array_free(p->outfits);
3594 array_free(p->outfit_structure);
3595 array_free(p->outfit_utility);
3596 array_free(p->outfit_weapon);
3597 array_free(p->outfit_intrinsic);
3598
3599 /* Clean up data. */
3600 ai_destroy(p); /* Must be destroyed first if applicable. */
3601
3602 free(p->name);
3603 /* Case if pilot is the player. */
3604 if (player.p==p) {
3605 player.p = NULL;
3606 player.ps.p = NULL;
3607 }
3608 //solid_free(p->solid);
3609 free(p->mounted);
3610
3611 escort_freeList(p);
3612
3613 free(p->comm_msg);
3614
3615 /* Free messages. */
3616 luaL_unref(naevL, p->messages, LUA_REGISTRYINDEX);
3617
3618#ifdef DEBUGGING
3619 memset( p, 0, sizeof(Pilot) );
3620#endif /* DEBUGGING */
3621
3622 free(p);
3623}
3624
3630static void pilot_erase( Pilot *p )
3631{
3632 int i = pilot_getStackPos( p->id );
3633 pilot_free(p);
3635}
3636
3641{
3642 int i = pilot_getStackPos( p->id );
3643#ifdef DEBUGGING
3644 if (i < 0)
3645 WARN(_("Trying to remove non-existent pilot '%s' from stack!"), p->name);
3646#endif /* DEBUGGING */
3647 p->id = 0;
3649}
3650
3654void pilots_init (void)
3655{
3657 il_create( &pilot_qtquery, 1 );
3658}
3659
3663void pilots_free (void)
3664{
3666
3667 /* First pass to stop outfits. */
3668 for (int i=0; i < array_size(pilot_stack); i++) {
3669 /* Stop ship stuff. */
3671 /* Stop all outfits. */
3673 /* Handle Lua outfits. */
3675 }
3676
3677 /* Free pilots. */
3678 for (int i=0; i < array_size(pilot_stack); i++)
3681 pilot_stack = NULL;
3682 player.p = NULL;
3683 free( player.ps.acquired );
3684 memset( &player.ps, 0, sizeof(PlayerShip_t) );
3685
3686 /* Clean up quadtree. */
3687 qt_destroy( &pilot_quadtree );
3688 il_destroy( &pilot_qtquery );
3689}
3690
3696void pilots_clean( int persist )
3697{
3698 int persist_count = 0;
3699
3700 /* First pass to stop outfits without clearing stuff - this can call all
3701 * sorts of Lua stuff. */
3702 for (int i=0; i<array_size(pilot_stack); i++) {
3703 Pilot *p = pilot_stack[i];
3704 if (p == player.p &&
3705 (persist && pilot_isFlag(p, PILOT_PERSIST)))
3706 continue;
3707 /* Stop all outfits. */
3708 pilot_outfitOffAll( p );
3709 /* Handle Lua outfits. */
3711 }
3712
3713 /* Here we actually clean up stuff. */
3714 for (int i=0; i<array_size(pilot_stack); i++) {
3715 /* move player and persisted pilots to start */
3716 if (!pilot_isFlag(pilot_stack[i], PILOT_DELETE) &&
3717 (pilot_stack[i] == player.p ||
3718 (persist && pilot_isFlag(pilot_stack[i], PILOT_PERSIST)))) {
3719 /* Have to swap the pilots so it gets properly freed. */
3720 Pilot *p = pilot_stack[persist_count];
3721 pilot_stack[persist_count] = pilot_stack[i];
3722 pilot_stack[i] = p;
3723 p = pilot_stack[persist_count];
3724 /* Misc clean up. */
3725 p->lockons = 0; /* Clear lockons. */
3726 p->projectiles = 0; /* Clear projectiles. */
3727 pilot_clearTimers( p ); /* Reset timers. */
3728 /* Reset trails */
3729 for (int g=0; g<array_size(p->trail); g++)
3730 spfx_trail_remove( p->trail[g] );
3731 array_erase( &p->trail, array_begin(p->trail), array_end(p->trail) );
3732 /* All done. */
3733 persist_count++;
3734 }
3735 else /* rest get killed */
3737 }
3739
3740 /* Init AI on the remaining pilots, has to be done here so the pilot_stack is consistent. */
3741 for (int i=0; i<array_size(pilot_stack); i++) {
3742 Pilot *p = pilot_stack[i];
3744 ai_cleartasks(p);
3745 ai_init(p);
3746 }
3747
3748 /* Clear global hooks. */
3750}
3751
3756{
3757 double r = cur_system->radius * 1.1;
3758
3760 for (int i=0; i < array_size(pilot_stack); i++)
3762
3763 if (qt_init)
3764 qt_destroy( &pilot_quadtree );
3765 qt_create( &pilot_quadtree, -r, -r, r, r, qt_max_elem, qt_depth );
3766 qt_init = 1;
3767}
3768
3772void pilots_clear (void)
3773{
3774 for (int i=0; i < array_size(pilot_stack); i++)
3775 if (!pilot_isPlayer(pilot_stack[i])
3776 && !pilot_isFlag(pilot_stack[i], PILOT_NOCLEAR))
3778}
3779
3784{
3785 pilots_clean(0);
3786 if (player.p != NULL) {
3787 player_rmPlayerShip( &player.ps );
3788 player.p = NULL;
3789 memset( &player.ps, 0, sizeof(PlayerShip_t) );
3790 }
3792}
3793
3798{
3799 /* Delete loop - this should be atomic or we get hook fuckery! */
3800 for (int i=array_size(pilot_stack)-1; i>=0; i--) {
3801 Pilot *p = pilot_stack[i];
3802
3803 /* Clear target. */
3804 p->ptarget = NULL;
3805
3806 /* Destroy pilot and go on. */
3807 if (pilot_isFlag(p, PILOT_DELETE))
3808 pilot_erase( p );
3809 }
3810
3811 /* Second loop sets up quadtrees. */
3812 qt_clear( &pilot_quadtree ); /* Empty it. */
3813 for (int i=0; i<array_size(pilot_stack); i++) {
3814 Pilot *p = pilot_stack[i];
3815 int x, y, w2, h2, px, py;
3816
3817 /* Ignore pilots being deleted. */
3818 if (pilot_isFlag(p, PILOT_DELETE))
3819 continue;
3820
3821 /* Ignore hidden pilots. */
3822 if (pilot_isFlag(p, PILOT_HIDE))
3823 continue;
3824
3825 x = round(p->solid.pos.x);
3826 y = round(p->solid.pos.y);
3827 px = round(p->solid.pre.x);
3828 py = round(p->solid.pre.y);
3829 w2 = ceil(p->ship->gfx_space->sw * 0.5);
3830 h2 = ceil(p->ship->gfx_space->sh * 0.5);
3831 qt_insert( &pilot_quadtree, i, MIN(x,px)-w2, MIN(y,py)-h2, MAX(x,px)+w2, MAX(y,py)+h2 );
3832 }
3833}
3834
3840void pilots_update( double dt )
3841{
3842 /* Have all the pilots think. */
3843 for (int i=0; i<array_size(pilot_stack); i++) {
3844 Pilot *p = pilot_stack[i];
3845
3846 /* Invisible, not doing anything. */
3847 if (pilot_isFlag(p, PILOT_HIDE))
3848 continue;
3849
3850 /* See if should think. */
3851 if (pilot_isDisabled(p))
3852 continue;
3853 if (pilot_isFlag(p,PILOT_DEAD))
3854 continue;
3855
3856 /* Ignore persisting pilots during simulation since they don't get cleared. */
3857 if (space_isSimulation() && (pilot_isFlag(p,PILOT_PERSIST)))
3858 continue;
3859
3860 /* Hyperspace gets special treatment */
3861 if (pilot_isFlag(p, PILOT_HYP_PREP)) {
3862 if (!pilot_isFlag(p, PILOT_HYPERSPACE))
3863 ai_think( p, dt, 0 );
3864 pilot_hyperspace(p, dt);
3865 }
3866 /* Entering hyperspace. */
3867 else if (pilot_isFlag(p, PILOT_HYP_END)) {
3868 if ((VMOD(p->solid.vel) < 2*solid_maxspeed( &p->solid, p->speed, p->accel) ) && (p->ptimer < 0.))
3869 pilot_rmFlag(p, PILOT_HYP_END);
3870 }
3871 /* Must not be boarding to think. */
3872 else if (!pilot_isFlag(p, PILOT_BOARDING) &&
3873 !pilot_isFlag(p, PILOT_REFUELBOARDING) &&
3874 /* Must not be landing nor taking off. */
3875 !pilot_isFlag(p, PILOT_LANDING) &&
3876 !pilot_isFlag(p, PILOT_TAKEOFF) &&
3877 /* Must not be jumping in. */
3878 !pilot_isFlag(p, PILOT_HYP_END)) {
3879 if (pilot_isFlag(p, PILOT_PLAYER))
3880 player_think( p, dt );
3881 else
3882 ai_think( p, dt, 1 );
3883 }
3884 }
3885
3886 /* Now update all the pilots. */
3887 for (int i=0; i<array_size(pilot_stack); i++) {
3888 Pilot *p = pilot_stack[i];
3889
3890 /* Ignore. */
3891 if (pilot_isFlag(p, PILOT_DELETE))
3892 continue;
3893
3894 /* Invisible, not doing anything. */
3895 if (pilot_isFlag(p, PILOT_HIDE))
3896 continue;
3897
3898 /* Just update the pilot. */
3899 if (pilot_isFlag( p, PILOT_PLAYER ))
3900 player_update( p, dt );
3901 else
3902 pilot_update( p, dt );
3903 }
3904}
3905
3909void pilots_render (void)
3910{
3911 for (int i=0; i<array_size(pilot_stack); i++) {
3912 Pilot *p = pilot_stack[i];
3913
3914 /* Invisible, not doing anything. */
3915 if (pilot_isFlag(p, PILOT_HIDE) || pilot_isFlag(p, PILOT_DELETE))
3916 continue;
3917
3918 if (!pilot_isFlag( p, PILOT_PLAYER ))
3919 pilot_render( p );
3920 }
3921}
3922
3927{
3928 for (int i=0; i<array_size(pilot_stack); i++) {
3929 Pilot *p = pilot_stack[i];
3930
3931 /* Invisible, not doing anything. */
3932 if (pilot_isFlag(p, PILOT_HIDE) || pilot_isFlag(p, PILOT_DELETE))
3933 continue;
3934
3935 if (!pilot_isFlag( p, PILOT_PLAYER ))
3937 }
3938}
3939
3946{
3947 int n;
3948
3949 /* Clear outfits first to not leave some outfits in dangling states. */
3950 pilot_outfitOffAll(pilot);
3951
3952 pilot->ptimer = 0.; /* Pilot timer. */
3953 pilot->tcontrol = 0.; /* AI control timer. */
3954 pilot->stimer = 0.; /* Shield timer. */
3955 pilot->dtimer = 0.; /* Disable timer. */
3956 pilot->otimer = 0.; /* Outfit timer. */
3957 for (int i=0; i<MAX_AI_TIMERS; i++)
3958 pilot->timer[i] = 0.; /* Specific AI timers. */
3959 n = 0;
3960 for (int i=0; i<array_size(pilot->outfits); i++) {
3961 PilotOutfitSlot *o = pilot->outfits[i];
3962 o->timer = 0.; /* Last used timer. */
3963 o->stimer = 0.; /* State timer. */
3964 if (o->state != PILOT_OUTFIT_OFF) {
3965 o->state = PILOT_OUTFIT_OFF; /* Set off. */
3966 n++;
3967 }
3968 }
3969
3970 /* Must recalculate stats. */
3971 if (n > 0)
3972 pilot_calcStats( pilot );
3973}
3974
3982double pilot_relsize( const Pilot* cur_pilot, const Pilot* p )
3983{
3984 return (1. - 1./(1. + ((double)cur_pilot->solid.mass / (double)p->solid.mass)));
3985}
3986
3994void pilot_dpseps( const Pilot *p, double *pdps, double *peps )
3995{
3996 double shots, dps=0., eps=0.;
3997 for (int i=0; i<array_size(p->outfits); i++) {
3998 const Damage *dmg;
3999 double mod_energy, mod_damage, mod_shots;
4000 const Outfit *o = p->outfits[i]->outfit;
4001 if (o==NULL)
4002 continue;
4003 switch (o->type) {
4004 case OUTFIT_TYPE_BOLT:
4005 mod_energy = p->stats.fwd_energy;
4006 mod_damage = p->stats.fwd_damage;
4007 mod_shots = 1. / p->stats.fwd_firerate * (double)o->u.blt.shots;
4008 break;
4009 case OUTFIT_TYPE_TURRET_BOLT:
4010 mod_energy = p->stats.tur_energy;
4011 mod_damage = p->stats.tur_damage;
4012 mod_shots = 1. / p->stats.tur_firerate * (double)o->u.blt.shots;
4013 break;
4014 case OUTFIT_TYPE_LAUNCHER:
4015 case OUTFIT_TYPE_TURRET_LAUNCHER:
4016 mod_energy = 1.;
4017 mod_damage = p->stats.launch_damage;
4018 mod_shots = 1. / p->stats.launch_rate * (double)o->u.lau.shots;
4019 break;
4020 case OUTFIT_TYPE_BEAM:
4021 case OUTFIT_TYPE_TURRET_BEAM:
4022 /* Special case due to continuous fire. */
4023 if (o->type == OUTFIT_TYPE_BEAM) {
4024 mod_energy = p->stats.fwd_energy;
4025 mod_damage = p->stats.fwd_damage;
4026 mod_shots = 1. / p->stats.fwd_firerate;
4027 }
4028 else {
4029 mod_energy = p->stats.tur_energy;
4030 mod_damage = p->stats.tur_damage;
4031 mod_shots = 1. / p->stats.tur_firerate;
4032 }
4033 shots = outfit_duration(o);
4034 mod_shots = shots / (shots + mod_shots * outfit_delay(o));
4035 dps += mod_shots * mod_damage * outfit_damage(o)->damage;
4036 eps += mod_shots * mod_energy * outfit_energy(o);
4037 continue;
4038
4039 default:
4040 continue;
4041 }
4042 shots = 1. / (mod_shots * outfit_delay(o));
4043
4044 dmg = outfit_damage(o);
4045 dps += shots * mod_damage * dmg->damage;
4046 eps += shots * mod_energy * MAX( outfit_energy(o), 0. );
4047 }
4048 if (pdps != NULL)
4049 *pdps = dps;
4050 if (peps != NULL)
4051 *peps = eps;
4052}
4053
4061double pilot_reldps( const Pilot* cur_pilot, const Pilot* p )
4062{
4063 double DPSaccum_target, DPSaccum_pilot;
4064
4065 pilot_dpseps( p, &DPSaccum_target, NULL );
4066 pilot_dpseps( cur_pilot, &DPSaccum_pilot, NULL );
4067
4068 if ((DPSaccum_target > 1e-6) && (DPSaccum_pilot > 1e-6))
4069 return DPSaccum_pilot / (DPSaccum_target + DPSaccum_pilot);
4070 else if (DPSaccum_pilot > 0.)
4071 return 1.;
4072 return 0.;
4073}
4074
4082double pilot_relhp( const Pilot* cur_pilot, const Pilot* p )
4083{
4084 double c_hp = cur_pilot -> armour_max + cur_pilot -> shield_max;
4085 double p_hp = p -> armour_max + p -> shield_max;
4086 return c_hp / (p_hp + c_hp);
4087}
4088
4096credits_t pilot_worth( const Pilot *p, int count_unique )
4097{
4098 /* Ship price is base price + outfit prices. */
4099 credits_t price = ship_basePrice( p->ship );
4100 for (int i=0; i<array_size(p->outfits); i++) {
4101 if (p->outfits[i]->outfit == NULL)
4102 continue;
4103 /* Don't count unique outfits. */
4104 if (!count_unique && outfit_isProp(p->outfits[i]->outfit, OUTFIT_PROP_UNIQUE))
4105 continue;
4106 price += p->outfits[i]->outfit->price;
4107 }
4108
4109 return price;
4110}
4111
4120void pilot_msg( const Pilot *p, const Pilot *receiver, const char *type, unsigned int idx )
4121{
4122 if (idx != 0)
4123 lua_pushvalue(naevL, idx); /* data */
4124 else
4125 lua_pushnil(naevL); /* data */
4126
4127 lua_newtable(naevL); /* data, msg */
4128
4129 if (p != NULL) {
4130 lua_pushpilot(naevL, p->id); /* data, msg, sender */
4131 lua_rawseti(naevL, -2, 1); /* data, msg */
4132 }
4133
4134 lua_pushstring(naevL, type); /* data, msg, type */
4135 lua_rawseti(naevL, -2, 2); /* data, msg */
4136
4137 lua_pushvalue(naevL, -2); /* data, msg, data */
4138 lua_rawseti(naevL, -2, 3); /* data, msg */
4139
4140 lua_rawgeti(naevL, LUA_REGISTRYINDEX, receiver->messages); /* data, msg, messages */
4141 lua_pushvalue(naevL, -2); /* data, msg, messages, msg */
4142 lua_rawseti(naevL, -2, lua_objlen(naevL, -2)+1); /* data, msg, messages */
4143 lua_pop(naevL, 3); /* */
4144}
4145
4153int pilot_hasIllegal( const Pilot *p, int faction )
4154{
4155 /* Check commodities. */
4156 for (int i=0; i<array_size(p->commodities); i++) {
4157 const Commodity *c = p->commodities[i].commodity;
4158 if (commodity_checkIllegal( c, faction ))
4159 return 1;
4160 }
4161 /* Check outfits. */
4162 for (int i=0; i<array_size(p->outfits); i++) {
4163 const Outfit *o = p->outfits[i]->outfit;
4164 if ((o != NULL) && outfit_checkIllegal( o, faction ))
4165 return 1;
4166 }
4167 /* Nothing to see here sir. */
4168 return 0;
4169}
4170
4177void pilot_quadtreeParams( int max_elem, int depth )
4178{
4179 qt_max_elem = max_elem;
4180 qt_depth = depth;
4181}
void ai_cleartasks(Pilot *p)
Clears the pilot's tasks.
Definition ai.c:550
void ai_think(Pilot *pilot, double dt, int dotask)
Heart of the AI, brains of the pilot.
Definition ai.c:797
void ai_getDistress(const Pilot *p, const Pilot *distressed, const Pilot *attacker)
Sends a distress signal to a pilot.
Definition ai.c:1049
void ai_destroy(Pilot *p)
Destroys the ai part of the pilot.
Definition ai.c:563
Pilot * cur_pilot
Definition ai.c:338
void ai_init(Pilot *p)
Initializes the AI.
Definition ai.c:893
int ai_pinit(Pilot *p, const char *ai)
Initializes the pilot in the ai.
Definition ai.c:496
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:158
#define array_end(array)
Returns a pointer to the end of the reserved memory space.
Definition array.h:202
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
Definition array.h:102
#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_shrink(ptr_array)
Shrinks memory to fit only ‘size’ elements.
Definition array.h:149
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition array.h:129
#define array_begin(array)
Returns a pointer to the beginning of the reserved memory space.
Definition array.h:194
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
void pilot_boardComplete(Pilot *p)
Finishes the boarding.
Definition board.c:271
void cam_getPos(double *x, double *y)
Gets the camera position.
Definition camera.c:118
double cam_getZoom(void)
Gets the camera zoom.
Definition camera.c:97
int commodity_checkIllegal(const Commodity *com, int faction)
Checks to see if a commodity is illegal to a faction.
Definition commodity.c:384
void dtype_calcDamage(double *dshield, double *darmour, double absorb, double *knockback, const Damage *dmg, const ShipStats *s)
Gives the real shield damage, armour damage and knockback modifier.
Definition damagetype.c:276
int dtype_get(const char *name)
Gets the id of a dtype based on name.
Definition damagetype.c:159
void debris_add(double mass, double r, double px, double py, double vx, double vy)
Creates a cloud of debris.
Definition debris.c:80
void effect_cleanup(Effect *efxlist)
Cleans up an effect list freeing it.
Definition effect.c:528
int effect_update(Effect **efxlist, double dt)
Updates an effect list.
Definition effect.c:260
void escort_rmList(Pilot *p, unsigned int id)
Remove from escorts list.
Definition escort.c:85
void escort_freeList(Pilot *p)
Remove all escorts from a pilot.
Definition escort.c:60
void expl_explode(double x, double y, double vx, double vy, double radius, const Damage *dmg, const Pilot *parent, int mode)
Does explosion in a radius (damage and graphics).
Definition explosion.c:42
const char * faction_default_ai(int f)
Gets the name of the default AI profile for the faction's pilots.
Definition faction.c:399
const int * faction_getEnemies(int f)
Gets the list of enemies of a faction.
Definition faction.c:485
char faction_getColourChar(int f)
Gets the faction character associated to its standing with the player.
Definition faction.c:1052
int areEnemies(int a, int b)
Checks whether two factions are enemies.
Definition faction.c:1227
void faction_modPlayer(int f, double mod, const char *source)
Modifies the player's standing with a faction.
Definition faction.c:843
int areAllies(int a, int b)
Checks whether two factions are allies or not.
Definition faction.c:1253
void gl_printRaw(const glFont *ft_font, double x, double y, const glColour *c, double outlineR, const char *text)
Prints text on screen.
Definition font.c:617
int gl_printWidthRaw(const glFont *ft_font, const char *text)
Gets the width that it would take to print some text.
Definition font.c:961
glFont gl_defFont
Definition font.c:153
glTexture * gui_hailIcon(void)
Gets the hail icon texture.
Definition gui.c:2071
int gui_onScreenPilot(double *rx, double *ry, const Pilot *pilot)
Takes a pilot and returns whether it's on screen, plus its relative position.
Definition gui.c:624
void gui_cooldownEnd(void)
Notifies GUI scripts that the player broke out of cooldown.
Definition gui.c:856
void player_message(const char *fmt,...)
Adds a mesg to the queue to be displayed on screen.
Definition gui.c:335
void lvar_freeArray(lvar *arr)
Frees a variable array.
Definition lvar.c:146
void mat4_translate(mat4 *m, double x, double y, double z)
Translates a homogenous transformation matrix.
Definition mat4.c:99
mat4 mat4_identity(void)
Creates an identity matrix.
Definition mat4.c:195
void mat4_scale(mat4 *m, double x, double y, double z)
Scales a homogeneous transformation matrix.
Definition mat4.c:82
mat4 mat4_ortho(double left, double right, double bottom, double top, double nearVal, double farVal)
Creates an orthographic projection matrix.
Definition mat4.c:209
Header file with generic functions and naev-specifics.
#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 FABS(x)
Definition naev.h:37
#define MAX(x, y)
Definition naev.h:39
const Outfit ** lua_pushoutfit(lua_State *L, const Outfit *outfit)
Pushes a outfit on the stack.
LuaPilot * lua_pushpilot(lua_State *L, LuaPilot pilot)
Pushes a pilot on the stack.
Definition nlua_pilot.c:563
vec2 * lua_pushvector(lua_State *L, vec2 vec)
Pushes a vector on the stack.
Definition nlua_vec2.c:145
ntime_t ntime_create(int scu, int stp, int stu)
Creates a time structure.
Definition ntime.c:94
glInfo gl_screen
Definition opengl.c:51
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_renderRect(double x, double y, double w, double h, const glColour *c)
Renders a rectangle.
void gl_gameToScreenCoords(double *nx, double *ny, double bx, double by)
Converts in-game coordinates to screen coordinates.
void gl_renderTextureInterpolate(const glTexture *ta, const glTexture *tb, double inter, double x, double y, double w, double h, double tx, double ty, double tw, double th, const glColour *c)
Texture blitting backend for interpolated texture.
void gl_renderSprite(const glTexture *sprite, double bx, double by, int sx, int sy, const glColour *c)
Blits a sprite, position is relative to the player.
void gl_renderCross(double x, double y, double r, const glColour *c)
Renders a cross at a given position.
void gl_renderSpriteInterpolateScale(const glTexture *sa, const glTexture *sb, double inter, double bx, double by, double scalew, double scaleh, int sx, int sy, const glColour *c)
Blits a sprite interpolating, position is relative to the player.
void gl_getSpriteFromDir(int *x, int *y, const glTexture *t, const double dir)
Sets x and y to be the appropriate sprite for glTexture using dir.
Definition opengl_tex.c:967
void gl_vboActivateAttribOffset(gl_vbo *vbo, GLuint index, GLuint offset, GLint size, GLenum type, GLsizei stride)
Activates a VBO's offset.
Definition opengl_vbo.c:226
int outfit_isLauncher(const Outfit *o)
Checks if outfit is a weapon launcher.
Definition outfit.c:564
int outfit_checkIllegal(const Outfit *o, int fct)
Checks illegality of an outfit to a faction.
Definition outfit.c:3045
int outfit_isFighterBay(const Outfit *o)
Checks if outfit is a fighter bay.
Definition outfit.c:616
const Damage * outfit_damage(const Outfit *o)
Gets the outfit's damage.
Definition outfit.c:713
double outfit_duration(const Outfit *o)
Gets the outfit's duration.
Definition outfit.c:917
double outfit_energy(const Outfit *o)
Gets the outfit's energy usage.
Definition outfit.c:757
double outfit_delay(const Outfit *o)
Gets the outfit's delay.
Definition outfit.c:734
char pilot_getFactionColourChar(const Pilot *p)
Gets the faction colour char, works like faction_getColourChar but for a pilot.
Definition pilot.c:1080
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
static void pilot_hyperspace(Pilot *pilot, double dt)
Handles pilot's hyperspace states.
Definition pilot.c:2733
unsigned int pilot_getNearestEnemy_size(const Pilot *p, double target_mass_LB, double target_mass_UB)
Gets the nearest enemy to the pilot closest to the pilot whose mass is between LB and UB.
Definition pilot.c:352
static int pilot_trail_generated(Pilot *p, int generator)
Return true if the given trail_emitters index has a corresponding generated trail.
Definition pilot.c:2677
void pilot_choosePoint(vec2 *vp, Spob **spob, JumpPoint **jump, int lf, int ignore_rules, int guerilla)
Finds a spawn point for a pilot.
Definition pilot.c:3442
int pilot_isHostile(const Pilot *p)
Checks to see if pilot is hostile to the player.
Definition pilot.c:678
void pilot_updateDisable(Pilot *p, unsigned int shooter)
Handles pilot disabling. Set or unset the disable status depending on health and stress values.
Definition pilot.c:1550
void pilot_cooldown(Pilot *p, int dochecks)
Begins active cooldown, reducing hull and outfit temperatures.
Definition pilot.c:893
static IntList pilot_qtquery
Definition pilot.c:63
int pilot_brakeCheckReverseThrusters(const Pilot *p)
See if the pilot wants to use their reverse thrusters to brake.
Definition pilot.c:821
void pilot_rmHostile(Pilot *p)
Unmarks a pilot as hostile to player.
Definition pilot.c:1233
unsigned int pilot_addStack(Pilot *p)
Adds a pilot to the stack.
Definition pilot.c:3358
void pilots_updatePurge(void)
Purges pilots set for deletion.
Definition pilot.c:3797
void pilot_quadtreeParams(int max_elem, int depth)
Sets the quad tree parameters. Can have significant impact on performance.
Definition pilot.c:4177
double pilot_relhp(const Pilot *cur_pilot, const Pilot *p)
Gets the relative hp(combined shields and armour) between the current pilot and the specified target.
Definition pilot.c:4082
int pilot_validEnemy(const Pilot *p, const Pilot *target)
Checks to see if a pilot is a valid enemy for another pilot.
Definition pilot.c:277
double pilot_relsize(const Pilot *cur_pilot, const Pilot *p)
Gets the relative size(shipmass) between the current pilot and the specified target.
Definition pilot.c:3982
int pilot_areEnemies(const Pilot *p, const Pilot *target)
Like areEnemies but for pilots.
Definition pilot.c:745
void pilots_clear(void)
Clears all the pilots except the player and clear-exempt pilots.
Definition pilot.c:3772
static const double pilot_commFade
Definition pilot.c:71
unsigned int pilot_getNearestPilot(const Pilot *p)
Get the nearest pilot to a pilot.
Definition pilot.c:423
void pilots_clean(int persist)
Cleans up the pilot stack - leaves the player.
Definition pilot.c:3696
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
void pilot_clearTimers(Pilot *pilot)
Clears the pilot's timers.
Definition pilot.c:3945
double pilot_reldps(const Pilot *cur_pilot, const Pilot *p)
Gets the relative damage output(total DPS) between the current pilot and the specified target.
Definition pilot.c:4061
static void pilot_renderFramebufferBase(Pilot *p, GLuint fbo, double fw, double fh)
Renders a pilot to a framebuffer without effects.
Definition pilot.c:1739
void pilot_msg(const Pilot *p, const Pilot *receiver, const char *type, unsigned int idx)
Sends a message.
Definition pilot.c:4120
void pilot_dead(Pilot *p, unsigned int killer)
Pilot is dead, now will slowly explode.
Definition pilot.c:1628
static int pilot_cmp(const void *ptr1, const void *ptr2)
Compare id (for use with bsearch)
Definition pilot.c:102
Pilot * pilot_setPlayer(Pilot *after)
Replaces the player's pilot with an alternate ship with the same ID.
Definition pilot.c:3396
int pilot_validEnemyDist(const Pilot *p, const Pilot *target, double *dist)
Same as pilot_validEnemy, but able to store the distance too.
Definition pilot.c:285
static void pilot_refuel(Pilot *p, double dt)
Has the pilot refuel its target.
Definition pilot.c:2915
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
static void pilot_erase(Pilot *p)
Destroys pilot from stack.
Definition pilot.c:3630
void pilot_cooldownEnd(Pilot *p, const char *reason)
Terminates active cooldown.
Definition pilot.c:959
static void pilot_init(Pilot *dest, const Ship *ship, const char *name, int faction, const double dir, const vec2 *pos, const vec2 *vel, const PilotFlags flags, unsigned int dockpilot, int dockslot)
Initialize pilot.
Definition pilot.c:3045
static const double pilot_commTimeout
Definition pilot.c:70
credits_t pilot_modCredits(Pilot *p, credits_t amount)
Modifies the amount of credits the pilot has.
Definition pilot.c:3004
unsigned int pilot_getNearestEnemy(const Pilot *p)
Gets the nearest enemy to the pilot.
Definition pilot.c:323
void pilot_setFriendly(Pilot *p)
Marks pilot as friendly to player.
Definition pilot.c:1251
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_explode(double x, double y, double radius, const Damage *dmg, const Pilot *parent)
Makes the pilot explosion.
Definition pilot.c:1683
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
int pilot_refuelStart(Pilot *p)
Attempts to start refueling the pilot's target.
Definition pilot.c:2887
void pilots_renderOverlay(void)
Renders all the pilots overlays.
Definition pilot.c:3926
int pilot_isNeutral(const Pilot *p)
Checks to see if pilot is neutral to the player.
Definition pilot.c:695
PilotOutfitSlot * pilot_getDockSlot(Pilot *p)
Gets the dock slot of the pilot.
Definition pilot.c:776
void pilots_init(void)
Initializes pilot stuff.
Definition pilot.c:3654
int pilot_hasIllegal(const Pilot *p, int faction)
Checks to see if the pilot has illegal stuf to a faction.
Definition pilot.c:4153
void pilot_setCommMsg(Pilot *p, const char *s)
Sets the overhead communication message of the pilot.
Definition pilot.c:1096
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
void pilot_broadcast(Pilot *p, const char *msg, int ignore_int)
Has the pilot broadcast a message.
Definition pilot.c:1111
void pilot_setHostile(Pilot *p)
Marks pilot as hostile to player.
Definition pilot.c:1066
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
void pilot_dpseps(const Pilot *p, double *pdps, double *peps)
Calculates the dps and eps of a pilot.
Definition pilot.c:3994
const glColour * pilot_getColour(const Pilot *p)
Gets a pilot's colour.
Definition pilot.c:1284
static Pilot ** pilot_stack
Definition pilot.c:61
void pilot_distress(Pilot *p, Pilot *attacker, const char *msg)
Has the pilot broadcast a distress signal.
Definition pilot.c:1139
void pilot_render(Pilot *p)
Renders the pilot.
Definition pilot.c:1876
#define PILOT_SIZE_MIN
Definition pilot.c:55
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
unsigned int pilot_getNearestEnemy_heuristic(const Pilot *p, double mass_factor, double health_factor, double damage_factor, double range_factor)
Gets the nearest enemy to the pilot closest to the pilot whose mass is between LB and UB.
Definition pilot.c:387
static unsigned int pilot_id
Definition pilot.c:58
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
void pilots_newSystem(void)
Updates pilot state which depends on the system (sensor range, nebula trails...)
Definition pilot.c:3755
unsigned int pilot_getNextID(unsigned int id, int mode)
Gets the next pilot based on id.
Definition pilot.c:135
double pilot_minbrakedist(const Pilot *p, double dt)
Gets the minimum braking distance for the pilot.
Definition pilot.c:845
void pilot_rmFriendly(Pilot *p)
Unmarks a pilot as friendly to player.
Definition pilot.c:1262
void pilots_render(void)
Renders all the pilots.
Definition pilot.c:3909
int pilot_areAllies(const Pilot *p, const Pilot *target)
Like areAllies but for pilots.
Definition pilot.c:721
double pilot_getNearestAng(const Pilot *p, unsigned int *tp, double ang, int disabled)
Get the pilot closest to an angle extending from another pilot.
Definition pilot.c:567
void pilot_untargetAsteroid(int anchor, int asteroid)
Loops over pilot stack to remove an asteroid as target.
Definition pilot.c:2960
int pilot_getJumps(const Pilot *p)
Gets the amount of jumps the pilot has left.
Definition pilot.c:1273
void pilot_delete(Pilot *p)
Deletes a pilot.
Definition pilot.c:2687
void pilots_update(double dt)
Updates all the pilots.
Definition pilot.c:3840
void pilots_cleanAll(void)
Even cleans up the player.
Definition pilot.c:3783
void pilot_clearTrails(Pilot *p)
Resets the trails for a pilot.
Definition pilot.c:3383
unsigned int pilot_getBoss(const Pilot *p)
Get the strongest ally in a given range.
Definition pilot.c:436
static void pilot_init_trails(Pilot *p)
Initialize pilot's trails according to the ship type and current system characteristics.
Definition pilot.c:3228
void pilots_free(void)
Frees the pilot stack.
Definition pilot.c:3663
static Quadtree pilot_quadtree
Definition pilot.c:62
double pilot_hit(Pilot *p, const Solid *w, const Pilot *pshooter, const Damage *dmg, const Outfit *outfit, int lua_mem, int reset)
Damages the pilot.
Definition pilot.c:1338
static int pilot_getStackPos(unsigned int id)
Gets the pilot's position in the stack.
Definition pilot.c:116
void pilot_renderFramebuffer(Pilot *p, GLuint fbo, double fw, double fh)
Renders a pilot to a framebuffer.
Definition pilot.c:1792
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
void pilot_sample_trails(Pilot *p, int none)
Updates the given pilot's trail emissions.
Definition pilot.c:2601
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
int pilot_brake(Pilot *p, double dt)
Causes the pilot to turn around and brake.
Definition pilot.c:862
void pilot_setTarget(Pilot *p, unsigned int id)
Sets the target of the pilot.
Definition pilot.c:1308
unsigned int pilot_clone(const Pilot *ref)
Clones an existing pilot.
Definition pilot.c:3319
int pilot_cargoRmAll(Pilot *pilot, int cleanup)
Gets rid of all cargo from pilot. Can remove mission cargo.
int pilot_cargoJet(Pilot *p, const Commodity *cargo, int quantity, int simulate)
Tries to get rid of quantity cargo from pilot, jetting it into space.
void pilot_ewUpdateStealth(Pilot *p, double dt)
Updates the stealth mode and checks to see if it is getting broken.
Definition pilot_ew.c:468
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
void pilot_ewUpdateDynamic(Pilot *p, double dt)
Updates the pilot's dynamic electronic warfare properties.
Definition pilot_ew.c:106
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_updateSensorRange(void)
Updates the system's base sensor range.
Definition pilot_ew.c:198
void pilot_ewScanStart(Pilot *p)
Initializes the scan timer for a pilot.
Definition pilot_ew.c:51
double pilot_sensorRange(void)
Returns the default sensor range for the current system.
Definition pilot_ew.c:208
double pilot_heatEfficiencyMod(double T, double Tb, double Tc)
Returns a 0:1 modifier representing efficiency (1. being normal).
Definition pilot_heat.c:235
void pilot_heatUpdateCooldown(Pilot *p)
Overrides the usual heat model during active cooldown.
Definition pilot_heat.c:245
double pilot_heatFireRateMod(double T)
Returns a 0:1 modifier representing fire rate (1. being normal).
Definition pilot_heat.c:285
void pilot_heatReset(Pilot *p)
Resets a pilot's heat.
Definition pilot_heat.c:101
void pilot_heatUpdateShip(Pilot *p, double Q_cond, double dt)
Heats the pilot's ship.
Definition pilot_heat.c:213
double pilot_heatUpdateSlot(const Pilot *p, PilotOutfitSlot *o, double dt)
Heats the pilot's slot.
Definition pilot_heat.c:180
void pilot_heatAddSlotTime(const Pilot *p, PilotOutfitSlot *o, double dt)
Adds heat to an outfit slot over a period of time.
Definition pilot_heat.c:152
void pilots_clearGlobalHooks(void)
Removes all the pilot global hooks.
Definition pilot_hook.c:165
void pilot_clearHooks(Pilot *p)
Clears the pilots hooks.
Definition pilot_hook.c:206
void pilot_freeGlobalHooks(void)
Clears global pilot hooks.
Definition pilot_hook.c:221
int pilot_runHook(Pilot *p, int hook_type)
Tries to run a pilot hook if he has it.
Definition pilot_hook.c:106
int pilot_addOutfitIntrinsicRaw(Pilot *pilot, const Outfit *outfit)
Adds an outfit as an intrinsic slot.
void pilot_outfitLCooldown(Pilot *pilot, int done, int success, double timer)
Handle cooldown hooks for outfits.
void pilot_outfitLOutfofenergy(Pilot *pilot)
Handles when the pilot runs out of energy.
void pilot_healLanded(Pilot *pilot)
Cures the pilot as if he was landed.
void pilot_calcStats(Pilot *pilot)
Recalculates the pilot's stats based on his outfits.
void pilot_fillAmmo(Pilot *pilot)
Fills pilot's ammo completely.
int pilot_addAmmo(Pilot *pilot, PilotOutfitSlot *s, int quantity)
Adds some ammo to the pilot stock.
void pilot_lockClear(Pilot *p)
Clears pilot's missile lockon timers.
void pilot_outfitLCleanup(Pilot *pilot)
Handle cleanup hooks for outfits.
int pilot_reportSpaceworthy(const Pilot *p, char *buf, int bufSize)
Pilot safety report - makes sure stats are safe.
void pilot_lockUpdateSlot(Pilot *p, PilotOutfitSlot *o, Pilot *t, double *a, double dt)
Updates the lockons on the pilot's launchers.
void pilot_outfitLUpdate(Pilot *pilot, double dt)
Runs the pilot's Lua outfits update script.
int pilot_addOutfitRaw(Pilot *pilot, const Outfit *outfit, PilotOutfitSlot *s)
Adds an outfit to the pilot, ignoring CPU or other limits.
int pilot_addOutfitIntrinsic(Pilot *pilot, const Outfit *outfit)
Adds an outfit as an intrinsic slot.
void pilot_outfitLOnhit(Pilot *pilot, double armour, double shield, unsigned int attacker)
Runs the pilot's Lua outfits onhit script.
void pilot_outfitLInitAll(Pilot *pilot)
Runs the pilot's Lua outfits init script.
int pilot_shipLInit(Pilot *p)
Initializes the pilot ship Lua.
Definition pilot_ship.c:44
int pilot_shipLExplodeUpdate(Pilot *p, double dt)
Updates the pilot explosion Lua stuff.
Definition pilot_ship.c:171
int pilot_shipLUpdate(Pilot *p, double dt)
Updates the pilot Lua stuff.
Definition pilot_ship.c:108
int pilot_shipLCleanup(Pilot *p)
Cleans up the pilot ship Lua.
Definition pilot_ship.c:76
int pilot_shipLExplodeInit(Pilot *p)
Initializes the pilot explosion stuff.
Definition pilot_ship.c:144
void pilot_afterburnOver(Pilot *p)
Deactivates the afterburner.
void pilot_weapSetAIClear(Pilot *p)
Useful function for AI, clears activeness of all weapon sets.
void pilot_weapSetUpdate(Pilot *p)
Updates the pilot's weapon sets.
int pilot_outfitOffAll(Pilot *p)
Disables all active outfits for a pilot.
void pilot_weaponAuto(Pilot *p)
Tries to automatically set and create the pilot's weapon set.
void pilot_weapSetFree(Pilot *p)
Frees a pilot's weapon sets.
double pilot_weapSetSpeed(Pilot *p, int id, int level)
Gets the speed of the current pilot weapon set.
int pilot_outfitOff(Pilot *p, PilotOutfitSlot *o)
Disables a given active outfit.
void player_updateSpecific(Pilot *pplayer, const double dt)
Does a player specific update.
Definition player.c:1334
void player_dead(void)
Player got pwned.
Definition player.c:2536
void player_soundPlay(int sound, int once)
Plays a sound at the player.
Definition player.c:886
int snd_hypPowDown
Definition player.c:104
void player_update(Pilot *pplayer, const double dt)
Player update function.
Definition player.c:1318
void player_soundStop(void)
Stops playing player sounds.
Definition player.c:894
int snd_hypPowUpJump
Definition player.c:105
int snd_hypPowUp
Definition player.c:102
void player_think(Pilot *pplayer, const double dt)
Basically uses keyboard input instead of AI input. Used in pilot.c.
Definition player.c:1170
Player_t player
Definition player.c:74
void player_destroyed(void)
Player blew up in a fireball.
Definition player.c:2549
void player_autonavResetSpeed(void)
Resets the game speed.
static const double c[]
Definition rng.c:264
static const double d[]
Definition rng.c:273
credits_t ship_basePrice(const Ship *s)
Gets the ship's base price (no outfits).
Definition ship.c:266
void ss_free(ShipStatList *ll)
Frees a list of ship stats.
Definition shipstats.c:887
double sound_getLength(int sound)
Gets the length of the sound buffer.
Definition sound.c:775
int sound_playPos(int sound, double px, double py, double vx, double vy)
Plays a sound based on position.
Definition sound.c:827
int sound_get(const char *name)
Gets the buffer to sound of name.
Definition sound.c:756
void system_rmCurrentPresence(StarSystem *sys, int faction, double amount)
Removes active presence.
Definition space.c:4312
int space_canHyperspace(const Pilot *p)
Checks to make sure if pilot is far enough away to hyperspace.
Definition space.c:469
StarSystem * cur_system
Definition space.c:106
double system_getPresence(const StarSystem *sys, int faction)
Get the presence of a faction in a system.
Definition space.c:4181
int space_needsEffects(void)
returns whether or not we're simulating with effects.
Definition space.c:1538
int space_isSimulation(void)
returns whether we're just simulating.
Definition space.c:1530
void spfx_trail_sample(Trail_spfx *trail, double x, double y, TrailMode mode, int force)
Makes a trail grow.
Definition spfx.c:756
void spfx_shake(double mod)
Increases the current rumble level.
Definition spfx.c:898
int spfx_get(const char *name)
Gets the id of an spfx based on name.
Definition spfx.c:342
void spfx_trail_remove(Trail_spfx *trail)
Removes a trail.
Definition spfx.c:792
void spfx_add(int effect, const double px, const double py, const double vx, const double vy, int layer)
Creates a new special effect.
Definition spfx.c:475
void spfx_damage(double mod)
Increases the current damage level.
Definition spfx.c:918
Trail_spfx * spfx_trail_create(const TrailSpec *spec)
Initalizes a trail.
Definition spfx.c:688
void spfx_trail_draw(const Trail_spfx *trail)
Draws a trail on screen.
Definition spfx.c:811
Represents a commodity.
Definition commodity.h:43
Core damage that an outfit does.
Definition outfit.h:138
int type
Definition outfit.h:139
double disable
Definition outfit.h:142
double penetration
Definition outfit.h:140
double damage
Definition outfit.h:141
Pilot ship effect data.
Definition effect.h:16
Pilot ship effect.
Definition effect.h:46
double r
Definition effect.h:52
const EffectData * data
Definition effect.h:47
double elapsed
Definition effect.h:53
double timer
Definition effect.h:49
The actual hook parameter.
Definition hook.h:38
LuaPilot lp
Definition hook.h:44
HookParamType type
Definition hook.h:39
union HookParam::@25 u
LuaJump lj
Definition hook.h:50
int destid
Definition nlua_jump.h:16
int srcid
Definition nlua_jump.h:15
double reload_time
Definition outfit.h:214
A ship outfit, depends radically on the type.
Definition outfit.h:328
OutfitLauncherData lau
Definition outfit.h:406
OutfitBoltData blt
Definition outfit.h:404
double overheat_max
Definition outfit.h:358
OutfitType type
Definition outfit.h:402
int lua_onimpact
Definition outfit.h:394
union Outfit::@12 u
OutfitAfterburnerData afb
Definition outfit.h:408
OutfitFighterBayData bay
Definition outfit.h:409
nlua_env lua_env
Definition outfit.h:371
double overheat_min
Definition outfit.h:357
char * name
Definition outfit.h:329
const Commodity * commodity
Definition pilot.h:180
Stores an outfit the pilot has.
Definition pilot.h:108
PilotOutfitAmmo ammo
Definition pilot.h:135
double heat_C
Definition pilot.h:118
double stimer
Definition pilot.h:124
double rtimer
Definition pilot.h:126
double heat_start
Definition pilot.h:120
double heat_T
Definition pilot.h:117
PilotOutfitState state
Definition pilot.h:123
double timer
Definition pilot.h:125
ShipOutfitSlot * sslot
Definition pilot.h:114
const Outfit * outfit
Definition pilot.h:112
The representation of an in-game pilot.
Definition pilot.h:217
double engine_glow
Definition pilot.h:383
double dtimer
Definition pilot.h:373
double dtimer_accum
Definition pilot.h:374
double itimer
Definition pilot.h:369
ShipStats stats
Definition pilot.h:294
double accel
Definition pilot.h:242
double shield
Definition pilot.h:253
double otimer
Definition pilot.h:375
AI_Profile * ai
Definition pilot.h:350
unsigned int id
Definition pilot.h:218
PilotCommodity * commodities
Definition pilot.h:326
int aimLines
Definition pilot.h:322
PilotOutfitSlot * outfit_structure
Definition pilot.h:301
unsigned int parent
Definition pilot.h:333
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
int messages
Definition pilot.h:384
double armour_max
Definition pilot.h:254
double speed
Definition pilot.h:244
int tsy
Definition pilot.h:232
int tsx
Definition pilot.h:231
double timer[MAX_AI_TIMERS]
Definition pilot.h:353
double htimer
Definition pilot.h:370
const Ship * ship
Definition pilot.h:226
double sbonus
Definition pilot.h:372
double fuel_max
Definition pilot.h:259
double energy
Definition pilot.h:264
int nav_anchor
Definition pilot.h:346
double stress
Definition pilot.h:252
int hail_pos
Definition pilot.h:377
double ptimer
Definition pilot.h:368
int faction
Definition pilot.h:222
int autoweap
Definition pilot.h:321
double comm_msgTimer
Definition pilot.h:362
double stimer
Definition pilot.h:371
double energy_max
Definition pilot.h:265
double landing_delay
Definition pilot.h:366
unsigned int shoot_indicator
Definition pilot.h:355
Solid solid
Definition pilot.h:227
double fuel
Definition pilot.h:260
double energy_loss
Definition pilot.h:268
PilotOutfitSlot * afterburner
Definition pilot.h:316
char * name
Definition pilot.h:219
double tcontrol
Definition pilot.h:352
PilotFlags flags
Definition pilot.h:365
unsigned int dockpilot
Definition pilot.h:335
int lua_ship_mem
Definition pilot.h:358
double ctimer
Definition pilot.h:288
double energy_tau
Definition pilot.h:267
double shield_regen
Definition pilot.h:257
int cargo_free
Definition pilot.h:327
int nav_spob
Definition pilot.h:344
int dockslot
Definition pilot.h:339
int lua_mem
Definition pilot.h:351
double player_damage
Definition pilot.h:381
Effect * effects
Definition pilot.h:297
char * comm_msg
Definition pilot.h:364
PilotOutfitSlot * outfit_weapon
Definition pilot.h:303
double armour
Definition pilot.h:251
double shield_max
Definition pilot.h:255
int nav_asteroid
Definition pilot.h:347
double armour_regen
Definition pilot.h:256
int healthbars
Definition conf.h:97
double zoom_far
Definition conf.h:134
Player ship.
Definition player.h:73
double dmg_done_armour
Definition player.h:87
double dmg_taken_armour
Definition player.h:89
double dmg_taken_shield
Definition player.h:88
Pilot * p
Definition player.h:74
unsigned int ships_destroyed[SHIP_CLASS_TOTAL]
Definition player.h:90
char * acquired
Definition player.h:84
double dmg_done_shield
Definition player.h:86
Pilot * p
Definition player.h:101
double dmg_done_shield
Definition player.h:132
PlayerShip_t ps
Definition player.h:102
double dmg_done_armour
Definition player.h:133
unsigned int ships_destroyed[SHIP_CLASS_TOTAL]
Definition player.h:136
double dmg_taken_armour
Definition player.h:135
double dmg_taken_shield
Definition player.h:134
Ship outfit slot.
Definition ship.h:70
int required
Definition ship.h:74
const Outfit * data
Definition ship.h:76
double time_speedup
Definition shipstats.h:309
double ammo_capacity
Definition shipstats.h:260
double damage
Definition shipstats.h:224
double disable
Definition shipstats.h:225
double fuel_regen
Definition shipstats.h:304
double launch_reload
Definition shipstats.h:263
double fbay_capacity
Definition shipstats.h:269
double stress_dissipation
Definition shipstats.h:252
double fbay_reload
Definition shipstats.h:271
Ship trail emitter.
Definition ship.h:83
double y_engine
Definition ship.h:85
double h_engine
Definition ship.h:86
double x_engine
Definition ship.h:84
unsigned int always_under
Definition ship.h:87
Represents a space ship.
Definition ship.h:94
double dt_default
Definition ship.h:124
double cap_cargo
Definition ship.h:123
glTexture * gfx_space
Definition ship.h:138
char * name
Definition ship.h:95
ShipOutfitSlot * outfit_utility
Definition ship.h:155
Outfit const ** outfit_intrinsic
Definition ship.h:157
ShipOutfitSlot * outfit_weapon
Definition ship.h:156
double mass
Definition ship.h:119
ShipOutfitSlot * outfit_structure
Definition ship.h:154
int lua_explode_update
Definition ship.h:178
Represents a solid in the game.
Definition physics.h:44
double speed_max
Definition physics.h:52
void(* update)(struct Solid_ *, double)
Definition physics.h:53
vec2 vel
Definition physics.h:48
double dir
Definition physics.h:46
double mass
Definition physics.h:45
vec2 pos
Definition physics.h:49
double accel
Definition physics.h:51
int faction
Definition space.h:67
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition space.h:89
SpobPresence presence
Definition space.h:104
A trail generated by a ship or an ammo.
Definition spfx.h:64
int h
Definition font.h:18
GLuint fbo_tex[OPENGL_NUM_FBOS]
Definition opengl.h:72
GLuint fbo[OPENGL_NUM_FBOS]
Definition opengl.h:71
int nw
Definition opengl.h:47
int nh
Definition opengl.h:48
GLuint current_fbo
Definition opengl.h:70
Abstraction for rendering sprite sheets.
Definition opengl_tex.h:36
double sw
Definition opengl_tex.h:46
double sh
Definition opengl_tex.h:47
double w
Definition opengl_tex.h:40
double sx
Definition opengl_tex.h:44
double srh
Definition opengl_tex.h:49
double sy
Definition opengl_tex.h:45
double h
Definition opengl_tex.h:41
double srw
Definition opengl_tex.h:48
Definition mat4.h:10
Represents a 2d vector.
Definition vec2.h:32
double y
Definition vec2.h:34
double x
Definition vec2.h:33