naev 0.11.5
pilot_outfit.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include "naev.h"
13#include "array.h"
14#include "escort.h"
15#include "gui.h"
16#include "log.h"
17#include "difficulty.h"
18#include "nstring.h"
19#include "nxml.h"
20#include "outfit.h"
21#include "pause.h"
22#include "pilot.h"
23#include "player.h"
24#include "slots.h"
25#include "space.h"
26#include "nlua.h"
27#include "nlua_pilot.h"
28#include "nlua_pilotoutfit.h"
29#include "nlua_outfit.h"
30
31static int stealth_break = 0;
33/*
34 * Prototypes.
35 */
36static void pilot_calcStatsSlot( Pilot *pilot, PilotOutfitSlot *slot );
37static const char *outfitkeytostr( OutfitKey key );
38
48void pilot_lockUpdateSlot( Pilot *p, PilotOutfitSlot *o, Pilot *t, double *a, double dt )
49{
50 double arc, max;
51 int locked;
52
53 /* No target. */
54 if (t == NULL)
55 return;
56
57 /* Nota seeker. */
58 if (!outfit_isSeeker(o->outfit))
59 return;
60
61 /* Check arc. */
62 arc = o->outfit->u.lau.arc;
63 if (arc > 0.) {
64
65 /* We use an external variable to set and update the angle if necessary. */
66 if (*a < 0.) {
67 double x, y, ang;
68 x = t->solid.pos.x - p->solid.pos.x;
69 y = t->solid.pos.y - p->solid.pos.y;
70 ang = ANGLE( x, y );
71 *a = FABS( angle_diff( ang, p->solid.dir ) );
72 }
73
74 /* Decay if not in arc. */
75 if (*a > arc) {
76 /* When a lock is lost, immediately gain half the lock timer.
77 * This is meant as an incentive for the aggressor not to lose the lock,
78 * and for the target to try and break the lock. */
79 double old = o->u.ammo.lockon_timer;
80 /* Limit decay to the lockon time for this launcher. */
81 max = o->outfit->u.lau.lockon;
82 o->u.ammo.lockon_timer += dt;
83 if ((old <= 0.) && (o->u.ammo.lockon_timer > 0.))
84 o->u.ammo.lockon_timer += o->outfit->u.lau.lockon / 2.;
85
86 /* Cap at max. */
87 if (o->u.ammo.lockon_timer > max)
88 o->u.ammo.lockon_timer = max;
89
90 /* Out of arc. */
91 o->u.ammo.in_arc = 0;
92 return;
93 }
94 }
95
96 /* In arc. */
97 o->u.ammo.in_arc = 1;
98 locked = (o->u.ammo.lockon_timer < 0.);
99
100 /* Lower timer. When the timer reaches zero, the lock is established. */
101 max = -o->outfit->u.lau.lockon/3.;
102 if (o->u.ammo.lockon_timer > max) {
103 /* Targetting is linear and can't be faster than the time specified (can be slower though). */
104 double mod = pilot_ewWeaponTrack( p, t, o->outfit->u.lau.trackmin, o->outfit->u.lau.trackmax );
105 o->u.ammo.lockon_timer -= dt * mod / p->stats.launch_lockon;
106
107 /* Cap at -max/3. */
108 if (o->u.ammo.lockon_timer < max)
109 o->u.ammo.lockon_timer = max;
110
111 /* Trigger lockon hook. */
112 if (!locked && (o->u.ammo.lockon_timer < 0.))
113 pilot_runHook( p, PILOT_HOOK_LOCKON );
114 }
115}
116
123{
124 for (int i=0; i<array_size(p->outfits); i++) {
125 PilotOutfitSlot *o = p->outfits[i];
126 if (o->outfit == NULL)
127 continue;
128 if (!outfit_isSeeker(o->outfit))
129 continue;
130
131 /* Clear timer. */
132 o->u.ammo.lockon_timer = o->outfit->u.lau.lockon;
133
134 /* Clear arc. */
135 o->u.ammo.in_arc = 0;
136 }
137}
138
149int pilot_getMount( const Pilot *p, const PilotOutfitSlot *w, vec2 *v )
150{
151 double a, x, y;
152 double cm, sm;
153 const ShipMount *m;
154
155 /* Calculate the sprite angle. */
156 a = (double)(p->tsy * p->ship->gfx_space->sx + p->tsx);
157 a *= p->ship->mangle;
158
159 /* 2d rotation matrix
160 * [ x' ] [ cos sin ] [ x ]
161 * [ y' ] = [ -sin cos ] * [ y ]
162 *
163 * dir is inverted so that rotation is counter-clockwise.
164 */
165 m = &w->sslot->mount;
166 cm = cos(-a);
167 sm = sin(-a);
168 x = m->x * cm + m->y * sm;
169 y = m->x *-sm + m->y * cm;
170
171 /* Correction for ortho perspective. */
172 y *= M_SQRT1_2;
173
174 /* Don't forget to add height. */
175 y += m->h;
176
177 /* Get the mount and add the player.p offset. */
178 vec2_cset( v, x, y );
179
180 return 0;
181}
182
190int pilot_dock( Pilot *p, Pilot *target )
191{
192 int i;
193 PilotOutfitSlot* dockslot;
194
195 /* Must belong to target */
196 if (p->dockpilot != target->id)
197 return -1;
198
199 /* Must have a dockslot */
200 dockslot = pilot_getDockSlot( p );
201 if (dockslot == NULL)
202 return -1;
203
204 /* Must be close. */
205 if (vec2_dist(&p->solid.pos, &target->solid.pos) >
206 target->ship->gfx_space->sw * PILOT_SIZE_APPROX )
207 return -1;
208
209 /* Cannot be going much faster. */
210 if (vec2_dist2( &p->solid.vel, &target->solid.vel ) > pow2(MAX_HYPERSPACE_VEL))
211 return -1;
212
213 /* Grab dock ammo */
214 i = p->dockslot;
215
216 /* Try to add fighter. */
217 dockslot->u.ammo.deployed--;
218 p->dockpilot = 0;
219 p->dockslot = -1;
220
221 /* Add the pilot's outfit. */
222 if (pilot_addAmmo(target, target->outfits[i], 1) != 1)
223 WARN(_("Unable to add ammo to '%s' from docking pilot '%s'!"),target->name,p->name);
224
225 /* Remove from pilot's escort list. */
226 for (i=0; i<array_size(target->escorts); i++) {
227 if ((target->escorts[i].type == ESCORT_TYPE_BAY) &&
228 (target->escorts[i].id == p->id))
229 break;
230 }
231 /* Not found as pilot's escorts. */
232 if (i >= array_size(target->escorts))
233 WARN(_("Docking pilot '%s' not found in pilot '%s's escort list!"),target->name,p->name);
234 /* Remove escort pilot. */
235 escort_rmListIndex(target, i);
236
237 /* Destroy the pilot. */
238 pilot_delete(p);
239
240 return 0;
241}
242
250{
251 for (int i=0; i<array_size(p->outfits); i++) {
252 if (p->outfits[i]->outfit == NULL)
253 continue;
254 if (outfit_isFighterBay(p->outfits[i]->outfit))
255 if (p->outfits[i]->u.ammo.deployed > 0)
256 return 1;
257 }
258 return 0;
259}
260
271int pilot_addOutfitRaw( Pilot* pilot, const Outfit* outfit, PilotOutfitSlot *s )
272{
273 const Outfit *o;
274
275 /* Set the outfit. */
276 s->state = PILOT_OUTFIT_OFF;
277 s->outfit = outfit;
278
279 /* Set some default parameters. */
280 s->timer = 0.;
281
282 /* Some per-case scenarios. */
283 if (outfit_isFighterBay(outfit)) {
284 s->u.ammo.quantity = 0;
285 s->u.ammo.deployed = 0;
286 pilot->nfighterbays++;
287 }
288 else if (outfit_isTurret(outfit)) /* used to speed up AI */
289 pilot->nturrets++;
290 else if (outfit_isBolt(outfit))
291 pilot->ncannons++;
292 else if (outfit_isAfterburner(outfit))
293 pilot->nafterburners++;
294 if (outfit_isLauncher(outfit)) {
295 s->u.ammo.quantity = 0;
296 s->u.ammo.deployed = 0; /* Just in case. */
297 }
298
299 if (outfit_isBeam(outfit)) { /* Used to speed up some calculations. */
300 s->u.beamid = 0;
301 pilot->nbeams++;
302 }
303
304 /* Check if active. */
305 o = s->outfit;
306 s->active = outfit_isActive(o);
307
308 /* Update heat. */
310
311 /* Disable lua for now. */
312 s->lua_mem = LUA_NOREF;
313 ss_free( s->lua_stats ); /* Just in case. */
314 s->lua_stats = NULL;
315
316 /* Initialize if active thingy if necessary. */
317 pilot_outfitLAdd( pilot, s );
318
319 return 0;
320}
321
331int pilot_addOutfitTest( Pilot* pilot, const Outfit* outfit, const PilotOutfitSlot *s, int warn )
332{
333 const char *str;
334
335 /* See if slot has space. */
336 if (s->outfit != NULL) {
337 if (warn)
338 WARN( _("Pilot '%s': trying to add outfit '%s' to slot that already has an outfit"),
339 pilot->name, outfit->name );
340 return -1;
341 }
342 else if ((outfit_cpu(outfit) < 0) &&
343 (pilot->cpu < ABS( outfit_cpu(outfit) ))) {
344 if (warn)
345 WARN( _("Pilot '%s': Not enough CPU to add outfit '%s'"),
346 pilot->name, outfit->name );
347 return -1;
348 }
349 else if ((str = pilot_canEquip( pilot, s, outfit)) != NULL) {
350 if (warn)
351 WARN( _("Pilot '%s': Trying to add outfit but %s"),
352 pilot->name, str );
353 return -1;
354 }
355 return 0;
356}
357
366int pilot_addOutfit( Pilot* pilot, const Outfit* outfit, PilotOutfitSlot *s )
367{
368 /* Test to see if outfit can be added. */
369 int ret = pilot_addOutfitTest( pilot, outfit, s, 1 );
370 if (ret != 0)
371 return -1;
372
373 /* Add outfit. */
374 ret = pilot_addOutfitRaw( pilot, outfit, s );
375
376 /* Recalculate the stats */
377 pilot_calcStats(pilot);
378
379 return ret;
380}
381
385int pilot_addOutfitIntrinsicRaw( Pilot *pilot, const Outfit *outfit )
386{
388
389 if (!outfit_isMod(outfit)) {
390 WARN(_("Instrinsic outfits must be modifiers!"));
391 return -1;
392 }
393
394 if (pilot->outfit_intrinsic==NULL)
396
397 s = &array_grow( &pilot->outfit_intrinsic );
398 memset( s, 0, sizeof(PilotOutfitSlot) );
399 return pilot_addOutfitRaw( pilot, outfit, s );
400}
401
405int pilot_addOutfitIntrinsic( Pilot *pilot, const Outfit *outfit )
406{
408 int ret;
409
410 if (!outfit_isMod(outfit)) {
411 WARN(_("Instrinsic outfits must be modifiers!"));
412 return -1;
413 }
414
415 if (pilot->outfit_intrinsic==NULL)
417
418 s = &array_grow( &pilot->outfit_intrinsic );
419 memset( s, 0, sizeof(PilotOutfitSlot) );
420 ret = pilot_addOutfitRaw( pilot, outfit, s );
421 if (pilot->id > 0)
422 pilot_outfitLInit( pilot, s );
423
424 return ret;
425}
426
430int pilot_rmOutfitIntrinsic( Pilot *pilot, const Outfit *outfit )
431{
432 int ret = 0;
433 for (int i=0; i<array_size(pilot->outfit_intrinsic); i++) {
434 PilotOutfitSlot *s = &pilot->outfit_intrinsic[i];
435 if (s->outfit != outfit)
436 continue;
437 ret = pilot_rmOutfitRaw( pilot, s );
438 array_erase( &pilot->outfit_intrinsic, s, s+1 );
439 break;
440 }
441 /* Recalculate the stats */
442 if (ret)
443 pilot_calcStats(pilot);
444 return ret;
445}
446
450int pilot_hasIntrinsic( const Pilot *pilot, const Outfit *outfit )
451{
452 int ret = 0;
453 for (int i=0; i<array_size(pilot->outfit_intrinsic); i++) {
454 const PilotOutfitSlot *s = &pilot->outfit_intrinsic[i];
455 if (s->outfit != outfit)
456 continue;
457 ret++;
458 }
459 return ret;
460}
461
472{
473 int ret;
474
475 /* Force turn off if necessary. */
476 if (s->state==PILOT_OUTFIT_ON)
477 pilot_outfitOff( pilot, s );
478
479 /* Run remove hook if necessary. */
480 pilot_outfitLRemove( pilot, s );
481
482 /* Decrement counters if necessary. */
483 if (s->outfit != NULL) {
484 if (outfit_isTurret(s->outfit))
485 pilot->nturrets--;
486 else if (outfit_isBolt(s->outfit))
487 pilot->ncannons--;
488 else if (outfit_isAfterburner(s->outfit))
489 pilot->nafterburners--;
490 else if (outfit_isFighterBay(s->outfit))
491 pilot->nfighterbays--;
492 if (outfit_isBeam(s->outfit))
493 pilot->nbeams--;
494 }
495
496 /* Remove the outfit. */
497 ret = (s->outfit==NULL);
498 s->outfit = NULL;
499 //s->weapset = -1;
500
501 /* Remove secondary and such if necessary. */
502 if (pilot->afterburner == s)
503 pilot->afterburner = NULL;
504
505 /* Clear Lua if necessary. */
506 if (s->lua_mem != LUA_NOREF) {
507 luaL_unref( naevL, LUA_REGISTRYINDEX, s->lua_mem );
508 s->lua_mem = LUA_NOREF;
509 }
510
511 /* Clean up stats. */
512 ss_free( s->lua_stats );
513 s->lua_stats = NULL;
514
515 return ret;
516}
517
518
527{
528 int ret;
529 const char *str = pilot_canEquip( pilot, s, NULL );
530 if (str != NULL) {
531 WARN(_("Pilot '%s': Trying to remove outfit but %s"),
532 pilot->name, str );
533 return -1;
534 }
535
536 ret = pilot_rmOutfitRaw( pilot, s );
537
538 /* recalculate the stats */
539 pilot_calcStats(pilot);
540
541 return ret;
542}
543
551{
552 for (int i=0; i<array_size(p->outfits); i++)
553 if ((p->outfits[i]->outfit != NULL) &&
554 !outfit_fitsSlot( p->outfits[i]->outfit, &p->outfits[i]->sslot->slot ))
555 return 0;
556 return 1;
557}
558
566{
567 for (int i=0; i<array_size(p->outfits); i++)
568 if (p->outfits[i]->sslot->required && p->outfits[i]->outfit == NULL)
569 return 0;
570 return 1;
571}
572
580{
581 return !pilot_reportSpaceworthy( p, NULL, 0 );
582}
583
592int pilot_reportSpaceworthy( const Pilot *p, char *buf, int bufSize )
593{
594#define SPACEWORTHY_CHECK(cond,msg) \
595 if (cond) { ret++; \
596 if (buf != NULL) { \
597 if (pos > 0) \
598 pos += scnprintf( &buf[pos], bufSize-pos, "\n" ); \
599 pos += scnprintf( &buf[pos], bufSize-pos, (msg) ); } }
600 int pos = 0;
601 int ret = 0;
602
603 /* Core Slots */
604 SPACEWORTHY_CHECK( !pilot_slotsCheckRequired(p), _("!! Not All Core Slots are equipped") );
605 /* CPU. */
606 SPACEWORTHY_CHECK( p->cpu < 0, _("!! Insufficient CPU") );
607
608 /* Movement. */
609 SPACEWORTHY_CHECK( p->accel < 0, _("!! Insufficient Accel") );
610 SPACEWORTHY_CHECK( p->speed < 0, _("!! Insufficient Speed") );
611 SPACEWORTHY_CHECK( p->turn < 0, _("!! Insufficient Turn") );
612
613 /* Health. */
614 SPACEWORTHY_CHECK( p->armour < 0., _("!! Insufficient Armour") );
615 SPACEWORTHY_CHECK( p->armour_regen < 0., _("!! Insufficient Armour Regeneration") );
616 SPACEWORTHY_CHECK( p->shield < 0., _("!! Insufficient Shield") );
617 SPACEWORTHY_CHECK( p->shield_regen < 0., _("!! Insufficient Shield Regeneration") );
618 SPACEWORTHY_CHECK( p->energy_max < 0., _("!! Insufficient Energy") );
619 SPACEWORTHY_CHECK( (p->energy_regen <= 0.) && (p->energy_max > 0.), _("!! Insufficient Energy Regeneration") );
620
621 /* Misc. */
622 SPACEWORTHY_CHECK( p->fuel_max < 0, _("!! Insufficient Fuel Maximum") );
623 SPACEWORTHY_CHECK( p->fuel_consumption < 0, _("!! Insufficient Fuel Consumption") );
624 SPACEWORTHY_CHECK( p->cargo_free < 0, _("!! Insufficient Free Cargo Space") );
625 SPACEWORTHY_CHECK( p->crew < 0, _("!! Insufficient Crew") );
626
627 /* No need to mess with the string. */
628 if (buf==NULL)
629 return ret;
630
631 /* Buffer is full, lets write that there is more then what's copied */
632 if (pos > bufSize-1) {
633 buf[bufSize-4]='.';
634 buf[bufSize-3]='.';
635 buf[bufSize-2]='.';
636 /* buf[bufSize-1]='\0'; already done for us */
637 }
638 else if (pos == 0) {
639 /* String is empty so no errors encountered */
640 pos += scnprintf( buf, bufSize, _("Spaceworthy"));
641 if (ship_isFlag(p->ship, SHIP_NOPLAYER))
642 pos += scnprintf( &buf[pos], bufSize-pos, "\n#o%s#0", _("Escort only") );
643 if (ship_isFlag(p->ship, SHIP_NOESCORT))
644 /* pos +=*/ scnprintf( &buf[pos], bufSize-pos, "\n#o%s#0", _("Lead ship only") );
645 }
646
647 return ret;
648}
649#undef SPACEWORTHY_CHECK
650
658int pilot_hasOutfitLimit( const Pilot *p, const char *limit )
659{
660 if (limit==NULL)
661 return 0;
662 for (int i = 0; i<array_size(p->outfits); i++) {
663 const Outfit *o = p->outfits[i]->outfit;
664 if (o == NULL)
665 continue;
666 if ((o->limit != NULL) && (strcmp(o->limit,limit)==0))
667 return 1;
668 }
669 for (int i=0; i<array_size(p->outfit_intrinsic); i++) {
670 const Outfit *o = p->outfit_intrinsic[i].outfit;
671 if ((o->limit != NULL) && (strcmp(o->limit,limit)==0))
672 return 1;
673 }
674 return 0;
675}
676
685const char* pilot_canEquip( const Pilot *p, const PilotOutfitSlot *s, const Outfit *o )
686{
687 /* Just in case. */
688 if ((p==NULL) || (s==NULL))
689 return _("Nothing selected.");
690
691 if (o!=NULL) {
692 /* Check slot type. */
693 if (!outfit_fitsSlot( o, &s->sslot->slot ))
694 return _("Does not fit slot.");
695 /* Check outfit limit. */
696 if ((o->limit != NULL) && pilot_hasOutfitLimit( p, o->limit ))
697 return _("Already have an outfit of this type installed");
698 /* Check to see if already equipped unique. */
699 if (outfit_isProp(o,OUTFIT_PROP_UNIQUE) && (pilot_numOutfit(p,o)>0))
700 return _("Can only install unique outfit once.");
701 }
702 else {
703 /* Check fighter bay. */
704 if ((o==NULL) && (s!=NULL) && (s->u.ammo.deployed > 0))
705 return _("Recall the fighters first");
706 }
707
708 return NULL;
709}
710
719int pilot_addAmmo( Pilot* pilot, PilotOutfitSlot *s, int quantity )
720{
721 int q, max;
722
723 /* Failure cases. */
724 if (s->outfit == NULL) {
725 WARN(_("Pilot '%s': Trying to add ammo to unequipped slot."), pilot->name );
726 return 0;
727 }
729 return 0;
730
731 /* Add the ammo. */
732 max = pilot_maxAmmoO(pilot,s->outfit) - s->u.ammo.deployed;
733 q = s->u.ammo.quantity; /* Amount have. */
734 s->u.ammo.quantity += quantity;
735 s->u.ammo.quantity = MIN( max, s->u.ammo.quantity );
736 q = s->u.ammo.quantity - q; /* Amount actually added. */
737 pilot->mass_outfit += q * outfit_ammoMass( s->outfit );
738 pilot_updateMass( pilot );
739
740 return q;
741}
742
751int pilot_rmAmmo( Pilot* pilot, PilotOutfitSlot *s, int quantity )
752{
753 int q;
754
755 /* Failure cases. */
757 return 0;
758 else if (s->outfit == NULL) {
759 WARN(_("Pilot '%s': Trying to remove ammo from unequipped slot."), pilot->name );
760 return 0;
761 }
762
763 /* Remove ammo. */
764 q = MIN( quantity, s->u.ammo.quantity );
765 s->u.ammo.quantity -= q;
766 pilot->mass_outfit -= q * outfit_ammoMass( s->outfit );
767 pilot_updateMass( pilot );
768 /* We don't set the outfit to null so it "remembers" old ammo. */
769
770 return q;
771}
772
779int pilot_countAmmo( const Pilot *pilot )
780{
781 int nammo = 0;
782 for (int i=0; i<array_size(pilot->outfits); i++) {
783 const Outfit* outfit;
784 PilotOutfitSlot* po = pilot->outfits[i];
785 if (po == NULL)
786 continue;
787 outfit = po->outfit;
788 if (outfit == NULL)
789 continue;
790 if (!outfit_isLauncher(po->outfit))
791 continue;
792 nammo += po->u.ammo.quantity;
793 }
794 return nammo;
795}
796
803int pilot_maxAmmo( const Pilot *pilot )
804{
805 int max = 0;
806 for (int i=0; i<array_size(pilot->outfits); i++) {
807 const Outfit* outfit;
808 PilotOutfitSlot* po = pilot->outfits[i];
809 if (po == NULL)
810 continue;
811 outfit = po->outfit;
812 if (outfit == NULL)
813 continue;
814 if (!outfit_isLauncher(outfit))
815 continue;
816 max += outfit->u.lau.amount;
817 }
818 max = round( (double)max * pilot->stats.ammo_capacity );
819 return max;
820}
821
825int pilot_maxAmmoO( const Pilot *p, const Outfit *o )
826{
827 int max;
828 if (o==NULL)
829 return 0;
830 else if (outfit_isLauncher(o))
831 max = round( (double)o->u.lau.amount * p->stats.ammo_capacity );
832 else if (outfit_isFighterBay(o))
833 max = round( (double)o->u.bay.amount * p->stats.fbay_capacity );
834 else
835 max = 0;
836 return max;
837}
838
844void pilot_fillAmmo( Pilot* pilot )
845{
846 for (int i=0; i<array_size(pilot->outfits); i++) {
847 int ammo_threshold;
848 const Outfit *o = pilot->outfits[i]->outfit;
849
850 /* Must be valid outfit. */
851 if (o == NULL)
852 continue;
853
854 /* Initial (raw) ammo threshold */
855 ammo_threshold = pilot_maxAmmoO( pilot, o );
856
857 /* Adjust for deployed fighters if needed */
858 if (outfit_isFighterBay( o ))
859 ammo_threshold -= pilot->outfits[i]->u.ammo.deployed;
860
861 /* Add ammo. */
862 pilot_addAmmo( pilot, pilot->outfits[i],
863 ammo_threshold - pilot->outfits[i]->u.ammo.quantity );
864 }
865}
866
867double pilot_outfitRange( const Pilot *p, const Outfit *o )
868{
869 if (outfit_isBolt(o))
870 return o->u.blt.falloff + (o->u.blt.range - o->u.blt.falloff)/2.;
871 else if (outfit_isBeam(o))
872 return o->u.bem.range;
873 else if (outfit_isLauncher(o)) {
874 double duration = o->u.lau.duration;
875 if (p!=NULL)
876 duration *= p->stats.launch_range;
877 if (o->u.lau.accel) {
878 double speedinc;
879 if (o->u.lau.speed > 0.) /* Ammo that don't start stopped don't have max speed. */
880 speedinc = INFINITY;
881 else
882 speedinc = o->u.lau.speed_max - o->u.lau.speed;
883 double at = speedinc / o->u.lau.accel;
884 if (at < duration)
885 return speedinc * (duration - at / 2.) + o->u.lau.speed * duration;
886
887 /* Maximum speed will never be reached. */
888 return pow2(duration) * o->u.lau.accel / 2. + duration * o->u.lau.speed;
889 }
890 return o->u.lau.speed * duration;
891 }
892 else if (outfit_isFighterBay(o))
893 return INFINITY;
894 return -1.;
895}
896
900static void pilot_calcStatsSlot( Pilot *pilot, PilotOutfitSlot *slot )
901{
902 const Outfit *o = slot->outfit;
903 ShipStats *s = &pilot->stats;
904
905 /* Outfit must exist. */
906 if (o==NULL)
907 return;
908
909 /* Modify CPU. */
910 pilot->cpu += outfit_cpu(o);
911
912 /* Add mass. */
913 pilot->mass_outfit += o->mass;
914
915 /* Keep a separate counter for required (core) outfits. */
916 if (sp_required( o->slot.spid ))
917 pilot->base_mass += o->mass;
918
919 /* Add ammo mass. */
920 if (outfit_isLauncher(o))
921 pilot->mass_outfit += slot->u.ammo.quantity * o->u.lau.ammo_mass;
922 else if (outfit_isFighterBay(o))
923 pilot->mass_outfit += slot->u.ammo.quantity * o->u.bay.ship_mass;
924
925 if (outfit_isAfterburner(o)) /* Afterburner */
926 pilot->afterburner = slot; /* Set afterburner */
927
928 /* Lua mods apply their stats. */
929 if (slot->lua_mem != LUA_NOREF)
930 ss_statsMergeFromList( &pilot->stats, slot->lua_stats );
931
932 /* Has update function. */
933 if (o->lua_update != LUA_NOREF)
934 pilot->outfitlupdate = 1;
935
936 /* Apply modifications. */
937 if (outfit_isMod(o)) { /* Modification */
938 /* Active outfits must be on to affect stuff. */
939 if (slot->active && !(slot->state==PILOT_OUTFIT_ON))
940 return;
941 /* Add stats. */
943
944 }
945 else if (outfit_isAfterburner(o)) { /* Afterburner */
946 /* Active outfits must be on to affect stuff. */
947 if (slot->active && !(slot->state==PILOT_OUTFIT_ON))
948 return;
949 /* Add stats. */
951 pilot_setFlag( pilot, PILOT_AFTERBURNER ); /* We use old school flags for this still... */
952 pilot->energy_loss += pilot->afterburner->outfit->u.afb.energy; /* energy loss */
953 }
954 else {
955 /* Always add stats for non mod/afterburners. */
957 }
958}
959
965void pilot_calcStats( Pilot* pilot )
966{
967 double ac, sc, ec, tm; /* temporary health coefficients to set */
968 ShipStats *s;
969
970 /*
971 * Set up the basic stuff
972 */
973 /* mass */
974 pilot->solid.mass = pilot->ship->mass;
975 pilot->base_mass = pilot->solid.mass;
976 /* cpu */
977 pilot->cpu = 0.;
978 /* movement */
979 pilot->accel_base = pilot->ship->accel;
980 pilot->turn_base = pilot->ship->turn;
981 pilot->speed_base = pilot->ship->speed;
982 /* crew */
983 pilot->crew = pilot->ship->crew;
984 /* cargo */
985 pilot->cap_cargo = pilot->ship->cap_cargo;
986 /* fuel_consumption. */
987 pilot->fuel_consumption = pilot->ship->fuel_consumption;
988 /* health */
989 ac = (pilot->armour_max > 0.) ? pilot->armour / pilot->armour_max : 0.;
990 sc = (pilot->shield_max > 0.) ? pilot->shield / pilot->shield_max : 0.;
991 ec = (pilot->energy_max > 0.) ? pilot->energy / pilot->energy_max : 0.;
992 pilot->armour_max = pilot->ship->armour;
993 pilot->shield_max = pilot->ship->shield;
994 pilot->fuel_max = pilot->ship->fuel;
995 pilot->armour_regen = pilot->ship->armour_regen;
996 pilot->shield_regen = pilot->ship->shield_regen;
997 /* Absorption. */
998 pilot->dmg_absorb = pilot->ship->dmg_absorb;
999 /* Energy. */
1000 pilot->energy_max = pilot->ship->energy;
1001 pilot->energy_regen = pilot->ship->energy_regen;
1002 pilot->energy_loss = 0.; /* Initially no net loss. */
1003 /* Misc. */
1004 pilot->outfitlupdate = 0;
1005 /* Stats. */
1006 s = &pilot->stats;
1007 tm = s->time_mod;
1008 *s = pilot->ship->stats_array;
1009
1010 /* Player gets difficulty applied. */
1011 if (pilot_isPlayer(pilot))
1012 difficulty_apply( s );
1013
1014 /* Now add outfit changes */
1015 pilot->mass_outfit = 0.;
1016 for (int i=0; i<array_size(pilot->outfit_intrinsic); i++)
1017 pilot_calcStatsSlot( pilot, &pilot->outfit_intrinsic[i] );
1018 for (int i=0; i<array_size(pilot->outfits); i++)
1019 pilot_calcStatsSlot( pilot, pilot->outfits[i] );
1020
1021 /* Merge stats. */
1022 ss_statsMergeFromList( &pilot->stats, pilot->ship_stats );
1023 ss_statsMergeFromList( &pilot->stats, pilot->intrinsic_stats );
1024
1025 /* Compute effects. */
1026 effect_compute( &pilot->stats, pilot->effects );
1027
1028 /* Apply system effects. */
1029 ss_statsMergeFromList( &pilot->stats, cur_system->stats );
1030
1031 /* Apply stealth malus. */
1032 if (pilot_isFlag(pilot, PILOT_STEALTH)) {
1033 s->accel_mod *= 0.8;
1034 s->turn_mod *= 0.8;
1035 s->speed_mod *= 0.5;
1036 }
1037
1038 /*
1039 * Absolute increases.
1040 */
1041 /* Movement. */
1042 pilot->accel_base += s->accel;
1043 pilot->turn_base += s->turn * M_PI / 180.;
1044 pilot->speed_base += s->speed;
1045 /* Health. */
1046 pilot->armour_max += s->armour;
1047 pilot->armour_regen += s->armour_regen;
1048 pilot->shield_max += s->shield;
1049 pilot->shield_regen += s->shield_regen;
1050 pilot->energy_max += s->energy;
1051 pilot->energy_regen += s->energy_regen;
1052 /* Misc. */
1053 pilot->fuel_max += s->fuel;
1054 pilot->cap_cargo += s->cargo;
1055
1056 /*
1057 * Relative increases.
1058 */
1059 /* Movement. */
1060 pilot->accel_base *= s->accel_mod;
1061 pilot->turn_base *= s->turn_mod;
1062 pilot->speed_base *= s->speed_mod;
1063 /* Health. */
1064 pilot->armour_max *= s->armour_mod;
1065 pilot->armour_regen *= s->armour_regen_mod;
1066 pilot->shield_max *= s->shield_mod;
1067 pilot->shield_regen *= s->shield_regen_mod;
1068 pilot->energy_max *= s->energy_mod;
1069 pilot->energy_regen *= s->energy_regen_mod;
1070 /* Enforce health to be at least 0 after mods, so that something like -1000% would just set it to 0 instead of negative. */
1071 pilot->armour_regen = MAX( 0., pilot->armour_regen );
1072 pilot->shield_regen = MAX( 0., pilot->shield_regen );
1073 pilot->energy_regen = MAX( 0., pilot->energy_regen );
1074 /* cpu */
1075 pilot->cpu_max = (int)floor((float)(pilot->ship->cpu + s->cpu_max)*s->cpu_mod);
1076 pilot->cpu += pilot->cpu_max; /* CPU is negative, this just sets it so it's based off of cpu_max. */
1077 /* Misc. */
1078 pilot->crew = pilot->crew * s->crew_mod + s->crew;
1079 pilot->fuel_max *= s->fuel_mod;
1080 pilot->cap_cargo *= s->cargo_mod;
1082
1083 /*
1084 * Flat increases.
1085 */
1086 pilot->armour_regen -= s->armour_regen_malus;
1087 pilot->shield_regen -= s->shield_regen_malus;
1088 pilot->energy_regen -= s->energy_regen_malus;
1089 pilot->energy_loss += s->energy_loss;
1090 pilot->dmg_absorb = CLAMP( 0., 1., pilot->dmg_absorb + s->absorb );
1091
1092 /* Give the pilot his health proportion back */
1093 pilot->armour = ac * pilot->armour_max;
1094 pilot->shield = sc * pilot->shield_max;
1095 pilot->energy = ec * pilot->energy_max;
1096
1097 /* Dump excess fuel */
1098 pilot->fuel = MIN( pilot->fuel, pilot->fuel_max );
1099
1100 /* Set final energy tau. */
1101 if (pilot->energy_regen > 0.)
1102 pilot->energy_tau = pilot->energy_max / pilot->energy_regen;
1103 else
1104 pilot->energy_tau = 1.;
1105
1106 /* Cargo has to be reset. */
1107 pilot_cargoCalc(pilot); /* Calls pilot_updateMass. */
1108
1109 /* Calculate the heat. */
1110 pilot_heatCalc( pilot );
1111
1112 /* Update GUI as necessary. */
1113 gui_setGeneric( pilot );
1114
1115 /* Update weapon set range. */
1116 pilot_weapSetUpdateStats( pilot );
1117
1118 /* In case the time_mod has changed. */
1119 if (pilot_isPlayer(pilot) && (tm != s->time_mod))
1121}
1122
1127{
1128 pilot->armour = pilot->armour_max;
1129 pilot->shield = pilot->shield_max;
1130 pilot->energy = pilot->energy_max;
1131
1132 pilot->stress = 0.;
1133 pilot->stimer = 0.;
1134 pilot->sbonus = 0.;
1135
1136 pilot_fillAmmo( pilot );
1137
1138 for (int i=0; i<array_size(pilot->escorts); i++) {
1139 const Escort_t *e = &pilot->escorts[i];
1140 Pilot *pe = pilot_get( e->id );
1141
1142 if (pe != NULL)
1143 pilot_healLanded( pe );
1144 }
1145}
1146
1150PilotOutfitSlot *pilot_getSlotByName( Pilot *pilot, const char *name )
1151{
1152 for (int i=0; i<array_size(pilot->outfits); i++) {
1153 PilotOutfitSlot *s = pilot->outfits[i];
1154 if ((s->sslot->name!=NULL) && (strcmp(s->sslot->name,name)==0))
1155 return s;
1156 }
1157 return NULL;
1158}
1159
1163double pilot_massFactor( const Pilot *pilot )
1164{
1165 double mass = pilot->solid.mass;
1166 if ((pilot->stats.engine_limit > 0.) && (mass > pilot->stats.engine_limit)) {
1167 double f = (mass-pilot->stats.engine_limit) / pilot->stats.engine_limit;
1168 return 1./(1.+f+f+4.*pow(f,3.));
1169 }
1170 return 1.;
1171}
1172
1179{
1180 double factor;
1181
1182 /* Recompute effective mass if something changed. */
1183 pilot->solid.mass = MAX( pilot->stats.mass_mod*pilot->ship->mass + pilot->stats.cargo_inertia*pilot->mass_cargo + pilot->mass_outfit, 0.);
1184
1185 /* Set and apply limit. */
1186 factor = pilot_massFactor( pilot );
1187 pilot->accel = factor * pilot->accel_base;
1188 pilot->turn = factor * pilot->turn_base;
1189 pilot->speed = factor * pilot->speed_base;
1190
1191 /* limit the maximum speed if limiter is active */
1192 if (pilot_isFlag(pilot, PILOT_HASSPEEDLIMIT)) {
1193 pilot->speed = pilot->speed_limit - pilot->accel / 3.;
1194 /* Speed must never go negative. */
1195 if (pilot->speed < 0.) {
1196 /* If speed DOES go negative, we have to lower accel. */
1197 pilot->accel = 3. * pilot->speed_limit;
1198 pilot->speed = 0.;
1199 }
1200 }
1201 /* Need to recalculate electronic warfare mass change. */
1202 pilot_ewUpdateStatic( pilot );
1203
1204 /* Update ship stuff. */
1205 if (pilot_isPlayer(pilot))
1206 gui_setShip();
1207}
1208
1216{
1217 const Outfit *oo;
1218 if (!o->active)
1219 return 0;
1220
1221 oo = o->outfit;
1222 if (oo == NULL)
1223 return 0;
1224 if (!outfit_isToggleable(oo))
1225 return 0;
1226
1227 return 1;
1228}
1229
1233static void pilot_outfitLRun( Pilot *p, void (*const func)( const Pilot *p, PilotOutfitSlot *po, const void *data ), const void *data )
1234{
1235 pilotoutfit_modified = 0;
1236 for (int i=0; i<array_size(p->outfits); i++) {
1237 PilotOutfitSlot *po = p->outfits[i];
1238 if (po->outfit==NULL)
1239 continue;
1240 func( p, po, data );
1241 }
1242 for (int i=0; i<array_size(p->outfit_intrinsic); i++) {
1243 PilotOutfitSlot *po = &p->outfit_intrinsic[i];
1244 if (po->outfit==NULL)
1245 continue;
1246 func( p, po, data );
1247 }
1248 /* Recalculate if anything changed. */
1249 if (pilotoutfit_modified)
1250 pilot_calcStats( p );
1251}
1252static void outfitLRunWarning( const Pilot *p, const Outfit *o, const char *name, const char *error )
1253{
1254 WARN( _("Pilot '%s''s outfit '%s' -> '%s':\n%s"), p->name, o->name, name, error );
1255}
1256
1260static int pilot_outfitLmem( PilotOutfitSlot *po, nlua_env env )
1261{
1262 int oldmem;
1263 /* Create the memory if necessary and initialize stats. */
1264 if (po->lua_mem == LUA_NOREF) {
1265 lua_newtable(naevL); /* mem */
1266 po->lua_mem = luaL_ref(naevL,LUA_REGISTRYINDEX); /* */
1267 }
1268 /* Get old memory. */
1269 nlua_getenv( naevL, env, "mem" ); /* oldmem */
1270 oldmem = luaL_ref( naevL, LUA_REGISTRYINDEX ); /* */
1271 /* Set the memory. */
1272 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->lua_mem); /* mem */
1273 nlua_setenv( naevL, env, "mem" ); /* */
1274 return oldmem;
1275}
1276
1280static void pilot_outfitLunmem( nlua_env env, int oldmem )
1281{
1282 lua_rawgeti( naevL, LUA_REGISTRYINDEX, oldmem );
1283 nlua_setenv( naevL, env, "mem"); /* pm */
1284 luaL_unref( naevL, LUA_REGISTRYINDEX, oldmem );
1285}
1286
1287static const char* pilot_outfitLDescExtra( const Pilot *p, const Outfit *o )
1288{
1289 static char descextra[STRMAX];
1290 const char *de;
1291 if (o->lua_descextra == LUA_NOREF)
1292 return (o->desc_extra != NULL) ? _(o->desc_extra) : NULL;
1293
1294 /* Set up the function: init( p, po ) */
1295 lua_rawgeti(naevL, LUA_REGISTRYINDEX, o->lua_descextra); /* f */
1296 if ((p != NULL) && (p->id > 0)) /* Needs valid ID. */
1297 lua_pushpilot( naevL, p->id ); /* f, p */
1298 else
1299 lua_pushnil( naevL ); /* f, p */
1300 lua_pushoutfit( naevL, o ); /* f, p, o */
1301 if (nlua_pcall( o->lua_env, 2, 1 )) { /* */
1302 outfitLRunWarning( p, o, "descextra", lua_tostring(naevL,-1) );
1303 lua_pop(naevL, 1);
1304 descextra[0] = '\0';
1305 return descextra;
1306 }
1307 /* Case no return we just pass nothing. */
1308 if (lua_isnoneornil( naevL, -1 )) {
1309 lua_pop( naevL, 1 );
1310 return NULL;
1311 }
1312 de = luaL_checkstring( naevL, -1 );
1313 strncpy( descextra, de, sizeof(descextra)-1 );
1314 lua_pop( naevL, 1 );
1315 return descextra;
1316}
1317
1327const char* pilot_outfitDescription( const Pilot *p, const Outfit *o )
1328{
1329 static char o_description[STRMAX];
1330 const char *de = pilot_outfitLDescExtra( p, o );
1331 if (de == NULL)
1332 return _(o->desc_raw);
1333 snprintf( o_description, sizeof(o_description), "%s\n%s", _(o->desc_raw), de );
1334 return o_description;
1335
1336}
1337
1348const char* pilot_outfitSummary( const Pilot *p, const Outfit *o, int withname )
1349{
1350 static char o_summary[STRMAX];
1351 const char *de = pilot_outfitLDescExtra( p, o );
1352 if (de == NULL) {
1353 if (withname)
1354 snprintf( o_summary, sizeof(o_summary), "%s\n%s", _(o->name), o->summary_raw );
1355 else
1356 snprintf( o_summary, sizeof(o_summary), "%s", o->summary_raw );
1357 }
1358 else {
1359 if (withname)
1360 snprintf( o_summary, sizeof(o_summary), "%s\n%s\n%s", _(o->name), o->summary_raw, de );
1361 else
1362 snprintf( o_summary, sizeof(o_summary), "%s\n%s", o->summary_raw, de );
1363 }
1364 return o_summary;
1365}
1366
1373{
1374 pilotoutfit_modified = 0;
1375 for (int i=0; i<array_size(pilot->outfits); i++)
1376 pilot_outfitLInit( pilot, pilot->outfits[i] );
1377 for (int i=0; i<array_size(pilot->outfit_intrinsic); i++)
1378 pilot_outfitLInit( pilot, &pilot->outfit_intrinsic[i] );
1379 /* Recalculate if anything changed. */
1380 if (pilotoutfit_modified)
1381 pilot_calcStats( pilot );
1382}
1383
1388{
1389 int oldmem;
1390
1391 if (po->outfit==NULL)
1392 return 0;
1393 if (po->outfit->lua_onadd == LUA_NOREF)
1394 return 0;
1395
1396 /* Create the memory if necessary and initialize stats. */
1397 oldmem = pilot_outfitLmem( po, po->outfit->lua_env );
1398
1399 /* Set up the function: init( p, po ) */
1400 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->outfit->lua_onadd); /* f */
1401 lua_pushpilot(naevL, pilot->id); /* f, p */
1402 lua_pushpilotoutfit(naevL, po); /* f, p, po */
1403 if (nlua_pcall( po->outfit->lua_env, 2, 0 )) { /* */
1404 outfitLRunWarning( pilot, po->outfit, "onadd", lua_tostring(naevL,-1) );
1405 lua_pop(naevL, 1);
1406 pilot_outfitLunmem( po->outfit->lua_env, oldmem );
1407 return -1;
1408 }
1409 pilot_outfitLunmem( po->outfit->lua_env, oldmem );
1410 return 1;
1411}
1412
1417{
1418 int oldmem;
1419
1420 if (po->outfit==NULL)
1421 return 0;
1422 if (po->outfit->lua_onremove == LUA_NOREF)
1423 return 0;
1424
1425 /* Create the memory if necessary and initialize stats. */
1426 oldmem = pilot_outfitLmem( po, po->outfit->lua_env );
1427
1428 /* Set up the function: init( p, po ) */
1429 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->outfit->lua_onremove); /* f */
1430 lua_pushpilot(naevL, pilot->id); /* f, p */
1431 lua_pushpilotoutfit(naevL, po); /* f, p, po */
1432 if (nlua_pcall( po->outfit->lua_env, 2, 0 )) { /* */
1433 outfitLRunWarning( pilot, po->outfit, "onremove", lua_tostring(naevL,-1) );
1434 lua_pop(naevL, 1);
1435 pilot_outfitLunmem( po->outfit->lua_env, oldmem );
1436 return -1;
1437 }
1438 pilot_outfitLunmem( po->outfit->lua_env, oldmem );
1439 return 1;
1440}
1441
1450{
1451 int lua_oinit, oldmem;
1452 nlua_env lua_env;
1453
1454 if (po->outfit==NULL)
1455 return 0;
1456
1457 if (po->outfit->lua_env==LUA_NOREF)
1458 return 0;
1459
1460 lua_oinit = po->outfit->lua_init;
1461 lua_env = po->outfit->lua_env;
1462
1463 /* Create the memory if necessary and initialize stats. */
1464 oldmem = pilot_outfitLmem( po, lua_env );
1465
1466 if (lua_oinit == LUA_NOREF) {
1467 pilot_outfitLunmem( po->outfit->lua_env, oldmem );
1468 return 0;
1469 }
1470
1471 /* Set up the function: init( p, po ) */
1472 lua_rawgeti(naevL, LUA_REGISTRYINDEX, lua_oinit); /* f */
1473 lua_pushpilot(naevL, pilot->id); /* f, p */
1474 lua_pushpilotoutfit(naevL, po); /* f, p, po */
1475 if (nlua_pcall( lua_env, 2, 0 )) { /* */
1476 outfitLRunWarning( pilot, po->outfit, "init", lua_tostring(naevL,-1) );
1477 lua_pop(naevL, 1);
1478 pilot_outfitLunmem( po->outfit->lua_env, oldmem );
1479 return -1;
1480 }
1481 pilot_outfitLunmem( po->outfit->lua_env, oldmem );
1482 return 1;
1483}
1484
1485static void outfitLUpdate( const Pilot *pilot, PilotOutfitSlot *po, const void *data )
1486{
1487 double dt;
1488 int oldmem;
1489 if (po->outfit->lua_update == LUA_NOREF)
1490 return;
1491
1492 nlua_env env = po->outfit->lua_env;
1493
1494 /* The data. */
1495 dt = *(double*)data;
1496
1497 /* Set the memory. */
1498 oldmem = pilot_outfitLmem( po, env );
1499
1500 /* Set up the function: update( p, po, dt ) */
1501 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->outfit->lua_update); /* f */
1502 lua_pushpilot(naevL, pilot->id); /* f, p */
1503 lua_pushpilotoutfit(naevL, po); /* f, p, po */
1504 lua_pushnumber(naevL, dt); /* f, p, po, dt */
1505 if (nlua_pcall( env, 3, 0 )) { /* */
1506 outfitLRunWarning( pilot, po->outfit, "update", lua_tostring(naevL,-1) );
1507 lua_pop(naevL, 1);
1508 }
1509 pilot_outfitLunmem( env, oldmem );
1510}
1517void pilot_outfitLUpdate( Pilot *pilot, double dt )
1518{
1519 if (!pilot->outfitlupdate)
1520 return;
1521 pilot_outfitLRun( pilot, outfitLUpdate, &dt );
1522}
1523
1524static void outfitLOutofenergy( const Pilot *pilot, PilotOutfitSlot *po, const void *data )
1525{
1526 (void) data;
1527 int oldmem;
1528
1529 if (po->outfit->lua_outofenergy == LUA_NOREF)
1530 return;
1531
1532 nlua_env env = po->outfit->lua_env;
1533
1534 /* Set the memory. */
1535 oldmem = pilot_outfitLmem( po, env );
1536
1537 /* Set up the function: outofenergy( p, po ) */
1538 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->outfit->lua_outofenergy); /* f */
1539 lua_pushpilot(naevL, pilot->id); /* f, p */
1540 lua_pushpilotoutfit(naevL, po); /* f, p, po */
1541 if (nlua_pcall( env, 2, 0 )) { /* */
1542 outfitLRunWarning( pilot, po->outfit, "outofenergy", lua_tostring(naevL,-1) );
1543 lua_pop(naevL, 1);
1544 }
1545 pilot_outfitLunmem( env, oldmem );
1546}
1553{
1554 pilot_outfitLRun( pilot, outfitLOutofenergy, NULL );
1555}
1556
1558 double armour;
1559 double shield;
1560 unsigned int attacker;
1561};
1562static void outfitLOnhit( const Pilot *pilot, PilotOutfitSlot *po, const void *data )
1563{
1564 double armour, shield;
1565 unsigned int attacker;
1566 const struct OnhitData *odat;
1567 int oldmem;
1568
1569 if (po->outfit->lua_onhit == LUA_NOREF)
1570 return;
1571
1572 nlua_env env = po->outfit->lua_env;
1573
1574 /* Data. */
1575 odat = (const struct OnhitData*)data;
1576 armour = odat->armour;
1577 shield = odat->shield;
1578 attacker = odat->attacker;
1579
1580 /* Set the memory. */
1581 oldmem = pilot_outfitLmem( po, env );
1582
1583 /* Set up the function: onhit( p, po, armour, shield ) */
1584 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->outfit->lua_onhit); /* f */
1585 lua_pushpilot(naevL, pilot->id); /* f, p */
1586 lua_pushpilotoutfit(naevL, po); /* f, p, po */
1587 lua_pushnumber(naevL, armour ); /* f, p, po, a */
1588 lua_pushnumber(naevL, shield ); /* f, p, po, a, s */
1589 lua_pushpilot(naevL, attacker); /* f, p, po, a, s, attacker */
1590 if (nlua_pcall( env, 5, 0 )) { /* */
1591 outfitLRunWarning( pilot, po->outfit, "onhit", lua_tostring(naevL,-1) );
1592 lua_pop(naevL, 1);
1593 }
1594 pilot_outfitLunmem( env, oldmem );
1595}
1604void pilot_outfitLOnhit( Pilot *pilot, double armour, double shield, unsigned int attacker )
1605{
1606 const struct OnhitData data = { .armour = armour, .shield = shield, .attacker = attacker };
1607 pilot_outfitLRun( pilot, outfitLOnhit, &data );
1608}
1609
1618int pilot_outfitLOntoggle( const Pilot *pilot, PilotOutfitSlot *po, int on )
1619{
1620 nlua_env env = po->outfit->lua_env;
1621 int ret, oldmem;
1622 pilotoutfit_modified = 0;
1623
1624 /* Set the memory. */
1625 oldmem = pilot_outfitLmem( po, env );
1626
1627 /* Set up the function: ontoggle( p, po, armour, shield ) */
1628 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->outfit->lua_ontoggle); /* f */
1629 lua_pushpilot(naevL, pilot->id); /* f, p */
1630 lua_pushpilotoutfit(naevL, po); /* f, p, po */
1631 lua_pushboolean(naevL, on); /* f, p, po, on */
1632 if (nlua_pcall( env, 3, 1 )) { /* */
1633 outfitLRunWarning( pilot, po->outfit, "ontoggle", lua_tostring(naevL,-1) );
1634 lua_pop(naevL, 1);
1635 pilot_outfitLunmem( env, oldmem );
1636 return 0;
1637 }
1638
1639 /* Handle return boolean. */
1640 ret = lua_toboolean(naevL, -1);
1641 lua_pop(naevL, 1);
1642 pilot_outfitLunmem( env, oldmem );
1643 return ret || pilotoutfit_modified; /* Even if the script says it didn't change, it may have been modified. */
1644}
1645
1654{
1655 nlua_env env = po->outfit->lua_env;
1656 int ret, oldmem;
1657 pilotoutfit_modified = 0;
1658
1659 /* Set the memory. */
1660 oldmem = pilot_outfitLmem( po, env );
1661
1662 /* Set up the function: onshoot( p, po, armour, shield ) */
1663 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->outfit->lua_onshoot); /* f */
1664 lua_pushpilot(naevL, pilot->id); /* f, p */
1665 lua_pushpilotoutfit(naevL, po); /* f, p, po */
1666 if (nlua_pcall( env, 2, 1 )) { /* */
1667 outfitLRunWarning( pilot, po->outfit, "onshoot", lua_tostring(naevL,-1) );
1668 lua_pop(naevL, 1);
1669 pilot_outfitLunmem( env, oldmem );
1670 return 0;
1671 }
1672
1673 /* Handle return boolean. */
1674 ret = lua_toboolean(naevL, -1);
1675 lua_pop(naevL, 1);
1676 pilot_outfitLunmem( env, oldmem );
1677 return ret || pilotoutfit_modified; /* Even if the script says it didn't change, it may have been modified. */
1678}
1679
1681 int done;
1682 int success;
1683 double timer;
1684};
1685static void outfitLCooldown( const Pilot *pilot, PilotOutfitSlot *po, const void *data )
1686{
1687 int done, success, oldmem;
1688 double timer;
1689 const struct CooldownData *cdat;
1690
1691 if (po->outfit->lua_cooldown == LUA_NOREF)
1692 return;
1693
1694 nlua_env env = po->outfit->lua_env;
1695
1696 cdat = (const struct CooldownData*) data;
1697 done = cdat->done;
1698 success = cdat->success;
1699 timer = cdat->timer;
1700
1701 /* Set the memory. */
1702 oldmem = pilot_outfitLmem( po, env );
1703
1704 /* Set up the function: cooldown( p, po, done, success/timer ) */
1705 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->outfit->lua_cooldown); /* f */
1706 lua_pushpilot(naevL, pilot->id); /* f, p */
1707 lua_pushpilotoutfit(naevL, po); /* f, p, po */
1708 lua_pushboolean(naevL, done); /* f, p, po, done */
1709 if (done)
1710 lua_pushboolean(naevL, success); /* f, p, po, done, success */
1711 else
1712 lua_pushnumber(naevL, timer); /* f, p, po, done, timer */
1713 if (nlua_pcall( env, 4, 0 )) { /* */
1714 outfitLRunWarning( pilot, po->outfit, "cooldown", lua_tostring(naevL,-1) );
1715 lua_pop(naevL, 1);
1716 }
1717 pilot_outfitLunmem( env, oldmem );
1718}
1727void pilot_outfitLCooldown( Pilot *pilot, int done, int success, double timer )
1728{
1729 const struct CooldownData data = { .done = done, .success = success, .timer = timer };
1730 pilot_outfitLRun( pilot, outfitLCooldown, &data );
1731}
1732
1733static void outfitLOnshootany( const Pilot *pilot, PilotOutfitSlot *po, const void *data )
1734{
1735 (void) data;
1736 int oldmem;
1737 if (po->outfit->lua_onshootany == LUA_NOREF)
1738 return;
1739
1740 nlua_env env = po->outfit->lua_env;
1741
1742 /* Set the memory. */
1743 oldmem = pilot_outfitLmem( po, env );
1744
1745 /* Set up the function: onshootany( p, po ) */
1746 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->outfit->lua_onshootany); /* f */
1747 lua_pushpilot(naevL, pilot->id); /* f, p */
1748 lua_pushpilotoutfit(naevL, po); /* f, p, po */
1749 if (nlua_pcall( env, 2, 0 )) { /* */
1750 outfitLRunWarning( pilot, po->outfit, "onshootany", lua_tostring(naevL,-1) );
1751 lua_pop(naevL, 1);
1752 }
1753 pilot_outfitLunmem( env, oldmem );
1754}
1761{
1762 pilot_outfitLRun( pilot, outfitLOnshootany, NULL );
1763}
1764
1765static void outfitLOnstealth( const Pilot *pilot, PilotOutfitSlot *po, const void *data )
1766{
1767 (void) data;
1768 int oldmem;
1769 if (po->outfit->lua_onstealth == LUA_NOREF)
1770 return;
1771
1772 nlua_env env = po->outfit->lua_env;
1773
1774 /* Set the memory. */
1775 oldmem = pilot_outfitLmem( po, env );
1776
1777 /* Set up the function: onstealth( p, po, stealthed ) */
1778 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->outfit->lua_onstealth); /* f */
1779 lua_pushpilot(naevL, pilot->id); /* f, p */
1780 lua_pushpilotoutfit(naevL, po); /* f, p, po */
1781 lua_pushboolean(naevL, pilot_isFlag(pilot,PILOT_STEALTH) ); /* f, p, po, steathed */
1782 if (nlua_pcall( env, 3, 0 )) { /* */
1783 outfitLRunWarning( pilot, po->outfit, "onstealth", lua_tostring(naevL,-1) );
1784 lua_pop(naevL, 1);
1785 }
1786 pilot_outfitLunmem( env, oldmem );
1787}
1795{
1796 pilot_outfitLRun( pilot, outfitLOnstealth, NULL );
1797 return pilotoutfit_modified;
1798}
1799
1800static void outfitLOnscan( const Pilot *pilot, PilotOutfitSlot *po, const void *data )
1801{
1802 (void) data;
1803 int oldmem;
1804 if (po->outfit->lua_onscan == LUA_NOREF)
1805 return;
1806
1807 nlua_env env = po->outfit->lua_env;
1808
1809 /* Set the memory. */
1810 oldmem = pilot_outfitLmem( po, env );
1811
1812 /* Set up the function: onscan( p, po, target ) */
1813 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->outfit->lua_onscan); /* f */
1814 lua_pushpilot(naevL, pilot->id); /* f, p */
1815 lua_pushpilotoutfit(naevL, po); /* f, p, po */
1816 lua_pushpilot(naevL, pilot->target); /* f, p, po, t */
1817 if (nlua_pcall( env, 3, 0 )) { /* */
1818 outfitLRunWarning( pilot, po->outfit, "onscan", lua_tostring(naevL,-1) );
1819 lua_pop(naevL, 1);
1820 }
1821 pilot_outfitLunmem( env, oldmem );
1822}
1829{
1830 pilot_outfitLRun( pilot, outfitLOnscan, NULL );
1831}
1832
1833static void outfitLOnscanned( const Pilot *pilot, PilotOutfitSlot *po, const void *data )
1834{
1835 const Pilot *scanner;
1836 int oldmem;
1837 if (po->outfit->lua_onscanned == LUA_NOREF)
1838 return;
1839
1840 nlua_env env = po->outfit->lua_env;
1841 scanner = (const Pilot*) data;
1842
1843 /* Set the memory. */
1844 oldmem = pilot_outfitLmem( po, env );
1845
1846 /* Set up the function: onscanned( p, po, stealthed ) */
1847 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->outfit->lua_onscanned); /* f */
1848 lua_pushpilot(naevL, pilot->id); /* f, p */
1849 lua_pushpilotoutfit(naevL, po); /* f, p, po */
1850 lua_pushpilot(naevL, scanner->id); /* f, p, po, scanner */
1851 if (nlua_pcall( env, 3, 0 )) { /* */
1852 outfitLRunWarning( pilot, po->outfit, "onscanned", lua_tostring(naevL,-1) );
1853 lua_pop(naevL, 1);
1854 }
1855 pilot_outfitLunmem( env, oldmem );
1856}
1863void pilot_outfitLOnscanned( Pilot *pilot, const Pilot *scanner )
1864{
1865 pilot_outfitLRun( pilot, outfitLOnscanned, scanner );
1866}
1867
1868static void outfitLOnland( const Pilot *pilot, PilotOutfitSlot *po, const void *data )
1869{
1870 (void) data;
1871 int oldmem;
1872 if (po->outfit->lua_land == LUA_NOREF)
1873 return;
1874
1875 nlua_env env = po->outfit->lua_env;
1876
1877 /* Set the memory. */
1878 oldmem = pilot_outfitLmem( po, env );
1879
1880 /* Set up the function: land( p, po ) */
1881 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->outfit->lua_land); /* f */
1882 lua_pushpilot(naevL, pilot->id); /* f, p */
1883 lua_pushpilotoutfit(naevL, po); /* f, p, po */
1884 if (nlua_pcall( env, 2, 0 )) { /* */
1885 outfitLRunWarning( pilot, po->outfit, "land", lua_tostring(naevL,-1) );
1886 lua_pop(naevL, 1);
1887 }
1888 pilot_outfitLunmem( env, oldmem );
1889}
1896{
1897 pilot_outfitLRun( pilot, outfitLOnland, NULL );
1898}
1899
1900static void outfitLOntakeoff( const Pilot *pilot, PilotOutfitSlot *po, const void *data )
1901{
1902 (void) data;
1903 int oldmem;
1904 if (po->outfit->lua_takeoff == LUA_NOREF)
1905 return;
1906
1907 nlua_env env = po->outfit->lua_env;
1908
1909 /* Set the memory. */
1910 oldmem = pilot_outfitLmem( po, env );
1911
1912 /* Set up the function: takeoff( p, po ) */
1913 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->outfit->lua_takeoff); /* f */
1914 lua_pushpilot(naevL, pilot->id); /* f, p */
1915 lua_pushpilotoutfit(naevL, po); /* f, p, po */
1916 if (nlua_pcall( env, 2, 0 )) { /* */
1917 outfitLRunWarning( pilot, po->outfit, "takeoff", lua_tostring(naevL,-1) );
1918 lua_pop(naevL, 1);
1919 }
1920 pilot_outfitLunmem( env, oldmem );
1921}
1928{
1929 pilot_outfitLRun( pilot, outfitLOntakeoff, NULL );
1930}
1931
1932static void outfitLOnjumpin( const Pilot *pilot, PilotOutfitSlot *po, const void *data )
1933{
1934 (void) data;
1935 int oldmem;
1936 if (po->outfit->lua_jumpin == LUA_NOREF)
1937 return;
1938
1939 nlua_env env = po->outfit->lua_env;
1940
1941 /* Set the memory. */
1942 oldmem = pilot_outfitLmem( po, env );
1943
1944 /* Set up the function: takeoff( p, po ) */
1945 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->outfit->lua_jumpin); /* f */
1946 lua_pushpilot(naevL, pilot->id); /* f, p */
1947 lua_pushpilotoutfit(naevL, po); /* f, p, po */
1948 if (nlua_pcall( env, 2, 0 )) { /* */
1949 outfitLRunWarning( pilot, po->outfit, "jumpin", lua_tostring(naevL,-1) );
1950 lua_pop(naevL, 1);
1951 }
1952 pilot_outfitLunmem( env, oldmem );
1953}
1960{
1961 pilot_outfitLRun( pilot, outfitLOnjumpin, NULL );
1962}
1963
1964static void outfitLOnboard( const Pilot *pilot, PilotOutfitSlot *po, const void *data )
1965{
1966 const Pilot *target;
1967 int oldmem;
1968 if (po->outfit->lua_board == LUA_NOREF)
1969 return;
1970
1971 nlua_env env = po->outfit->lua_env;
1972 target = (const Pilot*) data;
1973
1974 /* Set the memory. */
1975 oldmem = pilot_outfitLmem( po, env );
1976
1977 /* Set up the function: board( p, po, stealthed ) */
1978 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->outfit->lua_board); /* f */
1979 lua_pushpilot(naevL, pilot->id); /* f, p */
1980 lua_pushpilotoutfit(naevL, po); /* f, p, po */
1981 lua_pushpilot(naevL, target->id); /* f, p, po, target */
1982 if (nlua_pcall( env, 3, 0 )) { /* */
1983 outfitLRunWarning( pilot, po->outfit, "board", lua_tostring(naevL,-1) );
1984 lua_pop(naevL, 1);
1985 }
1986 pilot_outfitLunmem( env, oldmem );
1987}
1994void pilot_outfitLOnboard( Pilot *pilot, const Pilot *target )
1995{
1996 pilot_outfitLRun( pilot, outfitLOnboard, target );
1997}
1998
1999static const char *outfitkeytostr( OutfitKey key )
2000{
2001 switch (key) {
2002 case OUTFIT_KEY_ACCEL:
2003 return "accel";
2004 case OUTFIT_KEY_LEFT:
2005 return "left";
2006 case OUTFIT_KEY_RIGHT:
2007 return "right";
2008 }
2009 return NULL;
2010}
2011
2012static void outfitLOnkeydoubletap( const Pilot *pilot, PilotOutfitSlot *po, const void *data )
2013{
2014 int oldmem;
2015 OutfitKey key;
2016 if (po->outfit->lua_keydoubletap == LUA_NOREF)
2017 return;
2018 key = *((const OutfitKey*) data);
2019
2020 nlua_env env = po->outfit->lua_env;
2021
2022 /* Set the memory. */
2023 oldmem = pilot_outfitLmem( po, env );
2024
2025 /* Set up the function: takeoff( p, po ) */
2026 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->outfit->lua_keydoubletap); /* f */
2027 lua_pushpilot(naevL, pilot->id); /* f, p */
2028 lua_pushpilotoutfit(naevL, po); /* f, p, po */
2029 lua_pushstring(naevL, outfitkeytostr(key) );
2030 if (nlua_pcall( env, 3, 1 )) { /* */
2031 outfitLRunWarning( pilot, po->outfit, "keydoubletap", lua_tostring(naevL,-1) );
2032 lua_pop(naevL, 1);
2033 }
2034 pilot_outfitLunmem( env, oldmem );
2035
2036 /* Broke stealth. */
2037 if ((po->state==PILOT_OUTFIT_ON) || lua_toboolean(naevL,-1))
2038 stealth_break = 1;
2039 lua_pop( naevL, 1 );
2040}
2041void pilot_outfitLOnkeydoubletap( Pilot *pilot, OutfitKey key )
2042{
2043 stealth_break = 0;
2044 pilot_outfitLRun( pilot, outfitLOnkeydoubletap, &key );
2045 if (stealth_break && pilot_isFlag( pilot, PILOT_STEALTH ))
2046 pilot_destealth( pilot );
2047}
2048
2049static void outfitLOnkeyrelease( const Pilot *pilot, PilotOutfitSlot *po, const void *data )
2050{
2051 int oldmem;
2052 OutfitKey key;
2053 if (po->outfit->lua_keyrelease == LUA_NOREF)
2054 return;
2055 key = *((const OutfitKey*) data);
2056
2057 nlua_env env = po->outfit->lua_env;
2058
2059 /* Set the memory. */
2060 oldmem = pilot_outfitLmem( po, env );
2061
2062 /* Set up the function: takeoff( p, po ) */
2063 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->outfit->lua_keyrelease); /* f */
2064 lua_pushpilot(naevL, pilot->id); /* f, p */
2065 lua_pushpilotoutfit(naevL, po); /* f, p, po */
2066 lua_pushstring(naevL, outfitkeytostr(key) );
2067 if (nlua_pcall( env, 3, 0 )) { /* */
2068 outfitLRunWarning( pilot, po->outfit, "keyrelease", lua_tostring(naevL,-1) );
2069 lua_pop(naevL, 1);
2070 }
2071 pilot_outfitLunmem( env, oldmem );
2072}
2073void pilot_outfitLOnkeyrelease( Pilot *pilot, OutfitKey key )
2074{
2075 pilot_outfitLRun( pilot, outfitLOnkeyrelease, &key );
2076}
2077
2084{
2085 /* TODO we might want to run this on intrinsic outfits too... */
2086 pilotoutfit_modified = 0;
2087 for (int i=0; i<array_size(pilot->outfits); i++) {
2088 int oldmem;
2089 PilotOutfitSlot *po = pilot->outfits[i];
2090 if (po->outfit==NULL)
2091 continue;
2092 if (po->outfit->lua_cleanup == LUA_NOREF)
2093 continue;
2094 /* Pilot could be created and then erased without getting properly
2095 * initialized. */
2096 if (po->lua_mem == LUA_NOREF)
2097 continue;
2098
2099 nlua_env env = po->outfit->lua_env;
2100
2101 /* Set the memory. */
2102 oldmem = pilot_outfitLmem( po, env );
2103
2104 /* Set up the function: cleanup( p, po ) */
2105 lua_rawgeti(naevL, LUA_REGISTRYINDEX, po->outfit->lua_cleanup); /* f */
2106 lua_pushpilot(naevL, pilot->id); /* f, p */
2107 lua_pushpilotoutfit(naevL, po); /* f, p, po */
2108 if (nlua_pcall( env, 2, 0 )) { /* */
2109 outfitLRunWarning( pilot, po->outfit, "cleanup", lua_tostring(naevL,-1) );
2110 lua_pop(naevL, 1);
2111 }
2112 pilot_outfitLunmem( env, oldmem );
2113 }
2114 /* Pilot gets cleaned up so no need to recalculate stats. */
2115}
Provides macros to work with dynamic arrays.
#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_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
void effect_compute(ShipStats *s, const Effect *efxlist)
Updates shipstats from effect list.
Definition effect.c:515
void escort_rmListIndex(Pilot *p, int i)
Remove from escorts list.
Definition escort.c:73
void gui_setShip(void)
Player just upgraded their ship or modified it.
Definition gui.c:1791
void gui_setGeneric(const Pilot *pilot)
Calls trigger functions depending on who the pilot is.
Definition gui.c:1824
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
PilotOutfitSlot ** lua_pushpilotoutfit(lua_State *L, PilotOutfitSlot *po)
Pushes a pilot outfit on the stack.
int scnprintf(char *text, size_t maxlen, const char *fmt,...)
Like snprintf(), but returns the number of characters ACTUALLY "printed" into the buffer....
Definition nstring.c:99
int outfit_isBeam(const Outfit *o)
Checks if outfit is a beam type weapon.
Definition outfit.c:554
double outfit_cpu(const Outfit *o)
Gets the outfit's cpu usage.
Definition outfit.c:779
int outfit_isActive(const Outfit *o)
Checks if outfit is an active outfit.
Definition outfit.c:484
int outfit_isLauncher(const Outfit *o)
Checks if outfit is a weapon launcher.
Definition outfit.c:564
int outfit_isSeeker(const Outfit *o)
Checks if outfit is a seeking weapon.
Definition outfit.c:574
int outfit_isToggleable(const Outfit *o)
Checks if outfit can be toggled.
Definition outfit.c:500
int outfit_fitsSlot(const Outfit *o, const OutfitSlot *s)
Checks to see if an outfit fits a slot.
Definition outfit.c:1047
int outfit_isFighterBay(const Outfit *o)
Checks if outfit is a fighter bay.
Definition outfit.c:616
int outfit_isAfterburner(const Outfit *o)
Checks if outfit is an afterburner.
Definition outfit.c:607
int outfit_isTurret(const Outfit *o)
Checks if outfit is a turret class weapon.
Definition outfit.c:587
double outfit_ammoMass(const Outfit *o)
Gets the outfit's ammunition mass.
Definition outfit.c:906
int outfit_isMod(const Outfit *o)
Checks if outfit is a ship modification.
Definition outfit.c:598
int outfit_isBolt(const Outfit *o)
Checks if outfit is bolt type weapon.
Definition outfit.c:544
PilotOutfitSlot * pilot_getDockSlot(Pilot *p)
Gets the dock slot of the pilot.
Definition pilot.c:776
Pilot * pilot_get(unsigned int id)
Pulls a pilot out of the pilot_stack based on ID.
Definition pilot.c:620
void pilot_delete(Pilot *p)
Deletes a pilot.
Definition pilot.c:2687
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_cargoCalc(Pilot *pilot)
Calculates how much cargo ship has left and such.
void pilot_destealth(Pilot *p)
Destealths a pilot.
Definition pilot_ew.c:552
double pilot_ewWeaponTrack(const Pilot *p, const Pilot *t, double trackmin, double trackmax)
Calculates the weapon lead (1. is 100%, 0. is 0%)..
Definition pilot_ew.c:389
void pilot_ewUpdateStatic(Pilot *p)
Updates the pilot's static electronic warfare properties.
Definition pilot_ew.c:94
void pilot_heatCalcSlot(PilotOutfitSlot *o)
Calculates the heat parameters for a pilot's slot.
Definition pilot_heat.c:83
void pilot_heatCalc(Pilot *p)
Calculates the heat parameters for a pilot.
Definition pilot_heat.c:33
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_getMount(const Pilot *p, const PilotOutfitSlot *w, vec2 *v)
Gets the mount position of a pilot.
static int stealth_break
int pilot_rmOutfit(Pilot *pilot, PilotOutfitSlot *s)
Removes an outfit from the pilot.
void pilot_updateMass(Pilot *pilot)
Updates the pilot stats after mass change.
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.
int pilot_hasOutfitLimit(const Pilot *p, const char *limit)
Checks to see if a pilot has an outfit with a specific outfit type.
void pilot_outfitLOutfofenergy(Pilot *pilot)
Handles when the pilot runs out of energy.
const char * pilot_outfitDescription(const Pilot *p, const Outfit *o)
Gets the description of an outfit for a given pilot.
void pilot_healLanded(Pilot *pilot)
Cures the pilot as if he was landed.
int pilot_slotsCheckRequired(const Pilot *p)
Pilot required (core) slot filled check - makes sure they are filled.
int pilot_slotsCheckSafety(const Pilot *p)
Pilot slot safety check - makes sure stats are safe.
int pilot_outfitLAdd(const Pilot *pilot, PilotOutfitSlot *po)
Outfit is added to a ship.
int pilot_maxAmmoO(const Pilot *p, const Outfit *o)
Gets the maximum available ammo for a pilot for a specific outfit.
int pilot_hasDeployed(const Pilot *p)
Checks to see if the pilot has deployed ships.
static void pilot_outfitLunmem(nlua_env env, int oldmem)
Cleans up the outfit memory for a slot.
int pilot_addOutfit(Pilot *pilot, const Outfit *outfit, PilotOutfitSlot *s)
Adds an outfit to the pilot.
void pilot_outfitLOnjumpin(Pilot *pilot)
Runs Lua outfits when pilot jumps into a system.
int pilot_slotIsToggleable(const PilotOutfitSlot *o)
Checks to see if a slot has an active outfit that can be toggleable.
void pilot_outfitLOntakeoff(Pilot *pilot)
Runs Lua outfits when pilot takes off from a spob.
int pilot_outfitLOntoggle(const Pilot *pilot, PilotOutfitSlot *po, int on)
Handle the manual toggle of an outfit.
void pilot_calcStats(Pilot *pilot)
Recalculates the pilot's stats based on his outfits.
double pilot_massFactor(const Pilot *pilot)
Gets the factor at which speed gets worse.
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.
int pilot_hasIntrinsic(const Pilot *pilot, const Outfit *outfit)
Gets how many copies of an intrinsic a pilot has.
const char * pilot_outfitSummary(const Pilot *p, const Outfit *o, int withname)
Gets the summary of an outfit for a give pilot.
int pilot_rmOutfitRaw(Pilot *pilot, PilotOutfitSlot *s)
Removes an outfit from the pilot without doing any checks.
static void pilot_calcStatsSlot(Pilot *pilot, PilotOutfitSlot *slot)
Computes the stats for a pilot's slot.
int pilot_outfitLInit(const Pilot *pilot, PilotOutfitSlot *po)
Runs the pilot's Lua outfits init script for an outfit.
int pilot_countAmmo(const Pilot *pilot)
Gets the number of ammo units on the ship.
void pilot_lockClear(Pilot *p)
Clears pilot's missile lockon timers.
int pilot_outfitLOnstealth(Pilot *pilot)
Runs the pilot's Lua outfits onhit script.
void pilot_outfitLCleanup(Pilot *pilot)
Handle cleanup hooks for outfits.
PilotOutfitSlot * pilot_getSlotByName(Pilot *pilot, const char *name)
Gets the outfit slot by name.
static int pilot_outfitLmem(PilotOutfitSlot *po, nlua_env env)
Sets up the outfit memory for a slot.
int pilot_maxAmmo(const Pilot *pilot)
The maximum amount of ammo the pilot's current ship can hold.
void pilot_outfitLOnscan(Pilot *pilot)
Runs Lua outfits when pilot scanned their target.
int pilot_reportSpaceworthy(const Pilot *p, char *buf, int bufSize)
Pilot safety report - makes sure stats are safe.
int pilot_addOutfitTest(Pilot *pilot, const Outfit *outfit, const PilotOutfitSlot *s, int warn)
Tests to see if an outfit can be added.
int pilot_outfitLOnshoot(const Pilot *pilot, PilotOutfitSlot *po)
Handle the manual shoot of an outfit.
void pilot_outfitLOnboard(Pilot *pilot, const Pilot *target)
Runs Lua outfits when pilot boards a target.
int pilot_outfitLRemove(const Pilot *pilot, PilotOutfitSlot *po)
Outfit is removed froma ship.
int pilot_rmAmmo(Pilot *pilot, PilotOutfitSlot *s, int quantity)
Removes some ammo from the pilot stock.
void pilot_outfitLOnland(Pilot *pilot)
Runs Lua outfits when pilot lands on a spob.
int pilot_dock(Pilot *p, Pilot *target)
Docks the pilot on its target pilot.
void pilot_outfitLOnscanned(Pilot *pilot, const Pilot *scanner)
Runs Lua outfits when pilot was scanned by scanner.
const char * pilot_canEquip(const Pilot *p, const PilotOutfitSlot *s, const Outfit *o)
Checks to see if can equip/remove an outfit from a slot.
void pilot_lockUpdateSlot(Pilot *p, PilotOutfitSlot *o, Pilot *t, double *a, double dt)
Updates the lockons on the pilot's launchers.
void pilot_outfitLOnshootany(Pilot *pilot)
Runs the pilot's Lua outfits onshootany script.
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.
static void pilot_outfitLRun(Pilot *p, void(*const func)(const Pilot *p, PilotOutfitSlot *po, const void *data), const void *data)
Wrapper that does all the work for us.
int pilot_rmOutfitIntrinsic(Pilot *pilot, const Outfit *outfit)
Removes an outfit from an intrinsic slot.
int pilot_isSpaceworthy(const Pilot *p)
Pilot safety check - makes sure stats are safe.
int pilot_addOutfitIntrinsic(Pilot *pilot, const Outfit *outfit)
Adds an outfit as an intrinsic slot.
void pilot_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_outfitOff(Pilot *p, PilotOutfitSlot *o)
Disables a given active outfit.
void pilot_weapSetUpdateStats(Pilot *p)
Update the weapon sets given pilot stat changes.
void player_resetSpeed(void)
Resets the player speed stuff.
Definition player.c:1448
void ss_free(ShipStatList *ll)
Frees a list of ship stats.
Definition shipstats.c:887
int ss_statsMergeFromList(ShipStats *stats, const ShipStatList *list)
Updates a stat structure from a stat list.
Definition shipstats.c:627
int sp_required(unsigned int spid)
Gets whether or not a slot property is required.
Definition slots.c:179
StarSystem * cur_system
Definition space.c:106
Stores an escort.
Definition pilot.h:206
unsigned int id
Definition pilot.h:209
EscortType_t type
Definition pilot.h:208
double range
Definition outfit.h:186
double falloff
Definition outfit.h:152
double range
Definition outfit.h:151
unsigned int spid
Definition outfit.h:110
A ship outfit, depends radically on the type.
Definition outfit.h:328
int lua_ontoggle
Definition outfit.h:378
int lua_onscan
Definition outfit.h:385
char * limit
Definition outfit.h:342
int lua_jumpin
Definition outfit.h:389
OutfitLauncherData lau
Definition outfit.h:406
int lua_cooldown
Definition outfit.h:386
char * desc_raw
Definition outfit.h:348
OutfitBeamData bem
Definition outfit.h:405
OutfitBoltData blt
Definition outfit.h:404
int lua_keyrelease
Definition outfit.h:392
int lua_takeoff
Definition outfit.h:388
int lua_outofenergy
Definition outfit.h:381
int lua_land
Definition outfit.h:387
int lua_onscanned
Definition outfit.h:384
int lua_onshootany
Definition outfit.h:382
int lua_update
Definition outfit.h:377
int lua_descextra
Definition outfit.h:372
union Outfit::@12 u
OutfitSlot slot
Definition outfit.h:336
int lua_onhit
Definition outfit.h:380
char * summary_raw
Definition outfit.h:349
OutfitAfterburnerData afb
Definition outfit.h:408
int lua_onshoot
Definition outfit.h:379
OutfitFighterBayData bay
Definition outfit.h:409
int lua_cleanup
Definition outfit.h:376
ShipStatList * stats
Definition outfit.h:364
nlua_env lua_env
Definition outfit.h:371
int lua_onstealth
Definition outfit.h:383
int lua_onadd
Definition outfit.h:373
int lua_board
Definition outfit.h:390
int lua_keydoubletap
Definition outfit.h:391
int lua_onremove
Definition outfit.h:374
double mass
Definition outfit.h:340
char * desc_extra
Definition outfit.h:350
char * name
Definition outfit.h:329
int lua_init
Definition outfit.h:375
double lockon_timer
Definition pilot.h:101
Stores an outfit the pilot has.
Definition pilot.h:108
unsigned int beamid
Definition pilot.h:134
PilotOutfitAmmo ammo
Definition pilot.h:135
PilotOutfitState state
Definition pilot.h:123
ShipStatList * lua_stats
Definition pilot.h:140
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
int nturrets
Definition pilot.h:308
ShipStatList * ship_stats
Definition pilot.h:292
ShipStats stats
Definition pilot.h:294
double accel
Definition pilot.h:242
double shield
Definition pilot.h:253
double speed_limit
Definition pilot.h:246
unsigned int id
Definition pilot.h:218
double turn_base
Definition pilot.h:248
int cpu_max
Definition pilot.h:237
double crew
Definition pilot.h:238
double energy_regen
Definition pilot.h:266
PilotOutfitSlot ** outfits
Definition pilot.h:300
PilotOutfitSlot * outfit_intrinsic
Definition pilot.h:304
int outfitlupdate
Definition pilot.h:312
double armour_max
Definition pilot.h:254
double speed
Definition pilot.h:244
double speed_base
Definition pilot.h:245
const Ship * ship
Definition pilot.h:226
double sbonus
Definition pilot.h:372
double fuel_max
Definition pilot.h:259
ShipStatList * intrinsic_stats
Definition pilot.h:293
int ncannons
Definition pilot.h:307
double energy
Definition pilot.h:264
double stress
Definition pilot.h:252
double mass_cargo
Definition pilot.h:229
double stimer
Definition pilot.h:371
double energy_max
Definition pilot.h:265
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
double accel_base
Definition pilot.h:243
char * name
Definition pilot.h:219
int nbeams
Definition pilot.h:309
double mass_outfit
Definition pilot.h:230
Escort_t * escorts
Definition pilot.h:334
int cpu
Definition pilot.h:236
double fuel_consumption
Definition pilot.h:261
double base_mass
Definition pilot.h:228
int nfighterbays
Definition pilot.h:310
double energy_tau
Definition pilot.h:267
double shield_regen
Definition pilot.h:257
unsigned int target
Definition pilot.h:342
int nafterburners
Definition pilot.h:311
Effect * effects
Definition pilot.h:297
double cap_cargo
Definition pilot.h:239
double turn
Definition pilot.h:247
double armour
Definition pilot.h:251
double shield_max
Definition pilot.h:255
double dmg_absorb
Definition pilot.h:258
double armour_regen
Definition pilot.h:256
Represents a ship weapon mount point.
Definition ship.h:61
double x
Definition ship.h:62
double y
Definition ship.h:63
double h
Definition ship.h:64
char * name
Definition ship.h:72
OutfitSlot slot
Definition ship.h:71
Represents ship statistics, properties ship can use.
Definition shipstats.h:198
double energy
Definition shipstats.h:208
double armour_regen
Definition shipstats.h:220
double armour
Definition shipstats.h:219
double crew_mod
Definition shipstats.h:253
double ammo_capacity
Definition shipstats.h:260
double engine_limit
Definition shipstats.h:293
double cargo_inertia
Definition shipstats.h:238
double shield_regen_malus
Definition shipstats.h:218
double shield_regen
Definition shipstats.h:215
double mass_mod
Definition shipstats.h:254
double energy_regen_malus
Definition shipstats.h:212
double energy_loss
Definition shipstats.h:213
double absorb
Definition shipstats.h:232
double energy_regen
Definition shipstats.h:209
double turn_mod
Definition shipstats.h:204
double armour_regen_mod
Definition shipstats.h:222
double shield
Definition shipstats.h:214
double accel_mod
Definition shipstats.h:205
double accel
Definition shipstats.h:202
double shield_regen_mod
Definition shipstats.h:217
double speed
Definition shipstats.h:200
double speed_mod
Definition shipstats.h:203
double engine_limit_rel
Definition shipstats.h:292
double cpu_max
Definition shipstats.h:231
double shield_mod
Definition shipstats.h:216
double armour_regen_malus
Definition shipstats.h:223
double fuel_mod
Definition shipstats.h:229
double cpu_mod
Definition shipstats.h:230
double energy_regen_mod
Definition shipstats.h:211
double time_mod
Definition shipstats.h:308
double energy_mod
Definition shipstats.h:210
double turn
Definition shipstats.h:201
double armour_mod
Definition shipstats.h:221
double cargo_mod
Definition shipstats.h:228
double shield_regen
Definition ship.h:130
double cap_cargo
Definition ship.h:123
glTexture * gfx_space
Definition ship.h:138
ShipStats stats_array
Definition ship.h:165
int fuel
Definition ship.h:121
double energy_regen
Definition ship.h:132
double armour
Definition ship.h:127
int fuel_consumption
Definition ship.h:122
double armour_regen
Definition ship.h:128
int crew
Definition ship.h:118
double dmg_absorb
Definition ship.h:133
double cpu
Definition ship.h:120
double speed
Definition ship.h:115
double turn
Definition ship.h:114
double accel
Definition ship.h:113
double energy
Definition ship.h:131
double shield
Definition ship.h:129
double mass
Definition ship.h:119
vec2 vel
Definition physics.h:48
double mass
Definition physics.h:45
vec2 pos
Definition physics.h:49
double sw
Definition opengl_tex.h:46
Represents a 2d vector.
Definition vec2.h:32
double y
Definition vec2.h:34
double x
Definition vec2.h:33