naev 0.12.5
ai.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
61#include <lauxlib.h>
62#include <lualib.h>
63#include <math.h>
64#include <stdio.h>
65#include <stdlib.h>
66
67#include "SDL_timer.h"
68#include "physfs.h"
69
70#include "naev.h"
72
73#include "ai.h"
74
75#include "array.h"
76#include "board.h"
77#include "conf.h"
78#include "faction.h"
79#include "gatherable.h"
80#include "hook.h"
81#include "log.h"
82#include "ndata.h"
83#include "nlua.h"
84#include "nlua_asteroid.h"
85#include "nlua_pilot.h"
86#include "nlua_spob.h"
87#include "nlua_vec2.h"
88#include "nluadef.h"
89#include "ntracing.h"
90#include "physics.h"
91#include "pilot.h"
92#include "rng.h"
93#include "space.h"
94
95/*
96 * ai flags
97 *
98 * They can be used for stuff like movement or for pieces of code which might
99 * run AI stuff when the AI module is not reentrant.
100 */
101#define ai_setFlag( f ) ( pilot_flags |= f )
102#define ai_isFlag( f ) ( pilot_flags & f )
103/* flags */
104#define AI_DISTRESS ( 1 << 0 )
105
106/*
107 * all the AI profiles
108 */
109static AI_Profile *profiles = NULL;
110static nlua_env equip_env = LUA_NOREF;
112static double ai_dt = 0.;
113
114/*
115 * prototypes
116 */
117/* Internal C routines */
118static void ai_run( nlua_env env, int nargs );
119static int ai_loadProfile( AI_Profile *prof, const char *filename );
120static int ai_setMemory( void );
121static void ai_create( Pilot *pilot );
122static int ai_loadEquip( void );
123static int ai_sort( const void *p1, const void *p2 );
124/* Task management. */
125static void ai_taskGC( Pilot *pilot );
126static Task *ai_createTask( lua_State *L, int subtask );
127static int ai_tasktarget( lua_State *L, const Task *t );
128
129/*
130 * AI routines for Lua
131 */
132/* tasks */
133static int
134aiL_pushtask( lua_State *L ); /* pushtask( string, number/pointer ) */
135static int aiL_poptask( lua_State *L ); /* poptask() */
136static int aiL_taskname( lua_State *L ); /* string taskname() */
137static int aiL_taskdata( lua_State *L ); /* pointer subtaskdata() */
138static int aiL_pushsubtask(
139 lua_State *L ); /* pushsubtask( string, number/pointer, number ) */
140static int aiL_popsubtask( lua_State *L ); /* popsubtask() */
141static int aiL_subtaskname( lua_State *L ); /* string subtaskname() */
142static int aiL_subtaskdata( lua_State *L ); /* pointer subtaskdata() */
143
144/* consult values */
145static int aiL_pilot( lua_State *L ); /* number pilot() */
146static int aiL_getrndpilot( lua_State *L ); /* number getrndpilot() */
147static int aiL_getnearestpilot( lua_State *L ); /* number getnearestpilot() */
148static int aiL_getdistance( lua_State *L ); /* number getdist(vec2) */
149static int aiL_getdistance2( lua_State *L ); /* number getdist(vec2) */
150static int aiL_getflybydistance( lua_State *L ); /* number getflybydist(vec2) */
151static int
152aiL_minbrakedist( lua_State *L ); /* number minbrakedist( [number] ) */
153static int aiL_isbribed( lua_State *L ); /* bool isbribed( number ) */
154static int
155aiL_getGatherable( lua_State *L ); /* integer getgatherable( radius ) */
156static int aiL_instantJump( lua_State *L ); /* bool instantJump() */
157
158/* boolean expressions */
159static int aiL_ismaxvel( lua_State *L ); /* boolean ismaxvel() */
160static int aiL_isstopped( lua_State *L ); /* boolean isstopped() */
161static int aiL_isenemy( lua_State *L ); /* boolean isenemy( number ) */
162static int aiL_isally( lua_State *L ); /* boolean isally( number ) */
163static int aiL_haslockon( lua_State *L ); /* boolean haslockon() */
164static int aiL_hasprojectile( lua_State *L ); /* boolean hasprojectile() */
165static int aiL_scandone( lua_State *L );
166
167/* movement */
168static int aiL_accel( lua_State *L ); /* accel(number); number <= 1. */
169static int aiL_turn( lua_State *L ); /* turn(number); abs(number) <= 1. */
170static int aiL_careful_face( lua_State *L ); /* face( number/pointer, bool) */
171static int aiL_aim( lua_State *L ); /* aim(number) */
172static int aiL_dir( lua_State *L ); /* dir(number/pointer) */
173static int aiL_face( lua_State *L ); /* face( number/pointer, bool) */
174static int aiL_iface( lua_State *L ); /* iface(number/pointer) */
175static int aiL_idir( lua_State *L ); /* idir(number/pointer) */
176static int aiL_follow_accurate( lua_State *L ); /* follow_accurate() */
177static int aiL_face_accurate( lua_State *L ); /* face_accurate() */
178static int aiL_drift_facing( lua_State *L ); /* drift_facing(number/pointer) */
179static int aiL_brake( lua_State *L ); /* brake() */
180static int aiL_getnearestspob( lua_State *L ); /* Vec2 getnearestspob() */
181static int aiL_getspobfrompos( lua_State *L ); /* Vec2 getspobfrompos() */
182static int aiL_getrndspob( lua_State *L ); /* Vec2 getrndspob() */
183static int aiL_getlandspob( lua_State *L ); /* Vec2 getlandspob() */
184static int aiL_land( lua_State *L ); /* bool land() */
185static int aiL_stop( lua_State *L ); /* stop() */
186static int aiL_relvel( lua_State *L ); /* relvel( number ) */
187
188/* Hyperspace. */
189static int aiL_sethyptarget( lua_State *L );
190static int aiL_nearhyptarget( lua_State *L ); /* pointer rndhyptarget() */
191static int aiL_rndhyptarget( lua_State *L ); /* pointer rndhyptarget() */
192static int aiL_hyperspace( lua_State *L ); /* [number] hyperspace() */
193static int aiL_canHyperspace( lua_State *L );
194static int aiL_hyperspaceAbort( lua_State *L );
195
196/* escorts */
197static int aiL_dock( lua_State *L ); /* dock( number ) */
198
199/* combat */
200static int aiL_combat( lua_State *L ); /* combat( number ) */
201static int aiL_settarget( lua_State *L ); /* settarget( number ) */
202static int aiL_weapSet( lua_State *L ); /* weapset( number ) */
203static int aiL_hascannons( lua_State *L ); /* bool hascannons() */
204static int aiL_hasturrets( lua_State *L ); /* bool hasturrets() */
205static int aiL_hasfighterbays( lua_State *L ); /* bool hasfighterbays() */
206static int aiL_hasafterburner( lua_State *L ); /* bool hasafterburner() */
207static int aiL_getenemy( lua_State *L ); /* number getenemy() */
208static int aiL_hostile( lua_State *L ); /* hostile( number ) */
209static int aiL_getweaprangemin( lua_State *L ); /* number getweaprangemin() */
210static int aiL_getweaprange( lua_State *L ); /* number getweaprange() */
211static int aiL_getweapspeed( lua_State *L ); /* number getweapspeed() */
212static int aiL_getweapammo( lua_State *L );
213static int aiL_canboard( lua_State *L ); /* boolean canboard( number ) */
214static int aiL_relsize( lua_State *L ); /* boolean relsize( number ) */
215static int aiL_reldps( lua_State *L ); /* boolean reldps( number ) */
216static int aiL_relhp( lua_State *L ); /* boolean relhp( number ) */
217
218/* timers */
219static int aiL_settimer( lua_State *L ); /* settimer( number, number ) */
220static int aiL_timeup( lua_State *L ); /* boolean timeup( number ) */
221
222/* messages */
223static int aiL_distress( lua_State *L ); /* distress( string [, bool] ) */
224static int aiL_getBoss( lua_State *L ); /* number getBoss() */
225
226/* loot */
227static int aiL_credits( lua_State *L ); /* credits( number ) */
228
229/* misc */
230static int aiL_board( lua_State *L ); /* boolean board() */
231static int aiL_refuel( lua_State *L ); /* boolean, boolean refuel() */
232static int aiL_messages( lua_State *L );
233static int
234aiL_setasterotarget( lua_State *L ); /* setasterotarget( Asteroid ) */
235static int aiL_gatherablePos( lua_State *L ); /* gatherablepos( number ) */
236static int aiL_shoot_indicator( lua_State *L ); /* get shoot indicator */
237static int aiL_set_shoot_indicator( lua_State *L ); /* set shoot indicator */
238static int aiL_stealth( lua_State *L );
239static int aiL_outfitOffAll( lua_State *L );
240
241static const luaL_Reg aiL_methods[] = {
242 /* tasks */
243 { "pushtask", aiL_pushtask },
244 { "poptask", aiL_poptask },
245 { "taskname", aiL_taskname },
246 { "taskdata", aiL_taskdata },
247 { "pushsubtask", aiL_pushsubtask },
248 { "popsubtask", aiL_popsubtask },
249 { "subtaskname", aiL_subtaskname },
250 { "subtaskdata", aiL_subtaskdata },
251 /* is */
252 { "ismaxvel", aiL_ismaxvel },
253 { "isstopped", aiL_isstopped },
254 { "isenemy", aiL_isenemy },
255 { "isally", aiL_isally },
256 { "haslockon", aiL_haslockon },
257 { "hasprojectile", aiL_hasprojectile },
258 { "scandone", aiL_scandone },
259 /* get */
260 { "pilot", aiL_pilot },
261 { "rndpilot", aiL_getrndpilot },
262 { "nearestpilot", aiL_getnearestpilot },
263 { "dist", aiL_getdistance },
264 { "dist2", aiL_getdistance2 },
265 { "flyby_dist", aiL_getflybydistance },
266 { "minbrakedist", aiL_minbrakedist },
267 { "isbribed", aiL_isbribed },
268 { "getgatherable", aiL_getGatherable },
269 { "instantJump", aiL_instantJump },
270 /* movement */
271 { "nearestspob", aiL_getnearestspob },
272 { "spobfrompos", aiL_getspobfrompos },
273 { "rndspob", aiL_getrndspob },
274 { "landspob", aiL_getlandspob },
275 { "land", aiL_land },
276 { "accel", aiL_accel },
277 { "turn", aiL_turn },
278 { "face", aiL_face },
279 { "careful_face", aiL_careful_face },
280 { "iface", aiL_iface },
281 { "dir", aiL_dir },
282 { "idir", aiL_idir },
283 { "drift_facing", aiL_drift_facing },
284 { "brake", aiL_brake },
285 { "stop", aiL_stop },
286 { "relvel", aiL_relvel },
287 { "follow_accurate", aiL_follow_accurate },
288 { "face_accurate", aiL_face_accurate },
289 /* Hyperspace. */
290 { "sethyptarget", aiL_sethyptarget },
291 { "nearhyptarget", aiL_nearhyptarget },
292 { "rndhyptarget", aiL_rndhyptarget },
293 { "hyperspace", aiL_hyperspace },
294 { "canHyperspace", aiL_canHyperspace },
295 { "hyperspaceAbort", aiL_hyperspaceAbort },
296 { "dock", aiL_dock },
297 /* combat */
298 { "aim", aiL_aim },
299 { "combat", aiL_combat },
300 { "settarget", aiL_settarget },
301 { "weapset", aiL_weapSet },
302 { "hascannons", aiL_hascannons },
303 { "hasturrets", aiL_hasturrets },
304 { "hasfighterbays", aiL_hasfighterbays },
305 { "hasafterburner", aiL_hasafterburner },
306 { "getenemy", aiL_getenemy },
307 { "hostile", aiL_hostile },
308 { "getweaprangemin", aiL_getweaprangemin },
309 { "getweaprange", aiL_getweaprange },
310 { "getweapspeed", aiL_getweapspeed },
311 { "getweapammo", aiL_getweapammo },
312 { "canboard", aiL_canboard },
313 { "relsize", aiL_relsize },
314 { "reldps", aiL_reldps },
315 { "relhp", aiL_relhp },
316 /* timers */
317 { "settimer", aiL_settimer },
318 { "timeup", aiL_timeup },
319 /* messages */
320 { "distress", aiL_distress },
321 { "getBoss", aiL_getBoss },
322 /* loot */
323 { "setcredits", aiL_credits },
324 /* misc */
325 { "board", aiL_board },
326 { "refuel", aiL_refuel },
327 { "messages", aiL_messages },
328 { "setasterotarget", aiL_setasterotarget },
329 { "gatherablepos", aiL_gatherablePos },
330 { "shoot_indicator", aiL_shoot_indicator },
331 { "set_shoot_indicator", aiL_set_shoot_indicator },
332 { "stealth", aiL_stealth },
333 { "outfitOffAll", aiL_outfitOffAll },
334 { 0, 0 } /* end */
335};
336
337/*
338 * current pilot "thinking" and assorted variables
339 */
341static double pilot_acc = 0.;
342static double pilot_turn = 0.;
343static int pilot_flags = 0;
344static char
345 aiL_distressmsg[STRMAX_SHORT];
346
347/*
348 * ai status, used so that create functions can't be used elsewhere
349 */
350#define AI_STATUS_NORMAL 1
351#define AI_STATUS_CREATE 2
353
359static void ai_taskGC( Pilot *pilot )
360{
361 Task *prev = NULL;
362 Task *t = pilot->task;
363 while ( t != NULL ) {
364 if ( t->done ) {
365 Task *pointer = t;
366 /* Unattach pointer. */
367 t = t->next;
368 if ( prev == NULL )
369 pilot->task = t;
370 else
371 prev->next = t;
372 /* Free pointer. */
373 pointer->next = NULL;
374 ai_freetask( pointer );
375 } else {
376 prev = t;
377 t = t->next;
378 }
379 }
380}
381
386{
387 /* Get last task. */
388 for ( Task *t = pilot->task; t != NULL; t = t->next )
389 if ( !t->done )
390 return t;
391 return NULL;
392}
393
397static int ai_setMemory( void )
398{
399 int oldmem;
400 nlua_env env = cur_pilot->ai->env;
401
402 nlua_getenv( naevL, env, "mem" ); /* oldmem */
403 oldmem = luaL_ref( naevL, LUA_REGISTRYINDEX ); /* */
404
405 lua_rawgeti( naevL, LUA_REGISTRYINDEX, cur_pilot->lua_mem );
406 nlua_setenv( naevL, env, "mem" ); /* pm */
407
408 return oldmem;
409}
410
417{
418 AIMemory oldmem;
419 cur_pilot = p;
420 oldmem.p = cur_pilot;
421 oldmem.mem = ai_setMemory();
422 return oldmem;
423}
424
429{
430 nlua_env env = cur_pilot->ai->env;
431 lua_rawgeti( naevL, LUA_REGISTRYINDEX, oldmem.mem );
432 nlua_setenv( naevL, env, "mem" ); /* pm */
433 luaL_unref( naevL, LUA_REGISTRYINDEX, oldmem.mem );
434 cur_pilot = oldmem.p;
435}
436
440void ai_thinkSetup( double dt )
441{
442 /* Clean up some variables */
443 pilot_acc = 0.;
444 pilot_turn = 0.;
445 pilot_flags = 0;
446 ai_dt = MAX( dt, DOUBLE_TOL );
447}
448
455{
456 /* Make sure pilot_acc and pilot_turn are legal */
457 pilot_acc = CLAMP( -PILOT_REVERSE_THRUST * p->stats.misc_reverse_thrust, 1.,
458 pilot_acc );
459 pilot_turn = CLAMP( -1., 1., pilot_turn );
460
461 /* Set turn and accel. */
464
465 /* other behaviours. */
466 if ( ai_isFlag( AI_DISTRESS ) )
468}
469
476static void ai_run( nlua_env env, int nargs )
477{
478 if ( nlua_pcall( env, nargs, 0 ) ) { /* error has occurred */
479 WARN( _( "Pilot '%s' ai '%s' error: %s" ), cur_pilot->name,
480 cur_pilot->ai->name, lua_tostring( naevL, -1 ) );
481 lua_pop( naevL, 1 );
482 }
483}
484
494int ai_pinit( Pilot *p, const char *ai )
495{
496 AI_Profile *prof;
497 char buf[PATH_MAX];
498
499 strncpy( buf, ai, sizeof( buf ) - 1 );
500 buf[sizeof( buf ) - 1] = '\0';
501
502 /* Set up the profile. */
503 prof = ai_getProfile( buf );
504 if ( prof == NULL ) {
505 WARN( _( "AI Profile '%s' not found, using dummy fallback." ), buf );
506 prof = ai_getProfile( "dummy" );
507 }
508 if ( prof == NULL ) {
509 WARN( _( "Dummy AI Profile not valid! Things are going to break." ) );
510 return -1;
511 }
512 p->ai = prof;
513
514 /* Adds a new pilot memory in the memory table. */
515 lua_newtable( naevL ); /* m */
516
517 /* Copy defaults over from the global memory table. */
518 lua_rawgeti( naevL, LUA_REGISTRYINDEX, prof->lua_mem ); /* m, d */
519 lua_pushnil( naevL ); /* m, d, nil */
520 while ( lua_next( naevL, -2 ) != 0 ) { /* m, d, k, v */
521 lua_pushvalue( naevL, -2 ); /* m, d, k, v, k */
522 lua_pushvalue( naevL, -2 ); /* m, d, k, v, k, v */
523 lua_remove( naevL, -3 ); /* m, d, k, k, v */
524 lua_settable( naevL, -5 ); /* m, d, k */
525 } /* m, d */
526 lua_pop( naevL, 1 ); /* m */
527 p->lua_mem = luaL_ref( naevL, LUA_REGISTRYINDEX ); /* */
528
529 /* Create the pilot. */
530 ai_create( p );
531 pilot_setFlag( p, PILOT_CREATED_AI );
532
533 /* Initialize randomly within a control tick. */
534 /* This doesn't work as nicely as one would expect because the pilot
535 * has no initial task and control ticks get synchronized if you
536 * spawn a bunch at the same time, which is why we add randomness
537 * elsewhere. */
538 p->tcontrol = RNGF() * p->ai->control_rate;
539
540 return 0;
541}
542
549{
550 /* Clean up tasks. */
551 if ( p->task )
552 ai_freetask( p->task );
553 p->task = NULL;
554}
555
562{
563 if ( p->ai == NULL )
564 return;
565
566 /* Get rid of pilot's memory. */
567 if ( !pilot_isPlayer( p ) ) { /* Player is an exception as more than one ship
568 shares pilot id. */
569 luaL_unref( naevL, LUA_REGISTRYINDEX, p->lua_mem );
570 p->lua_mem = LUA_NOREF;
571 }
572
573 /* Clear the tasks. */
574 ai_cleartasks( p );
575}
576
577static int ai_sort( const void *p1, const void *p2 )
578{
579 const AI_Profile *ai1 = p1;
580 const AI_Profile *ai2 = p2;
581 return strcmp( ai1->name, ai2->name );
582}
583
589int ai_load( void )
590{
591 char **files;
592#if DEBUGGING
593 Uint32 time = SDL_GetTicks();
594#endif /* DEBUGGING */
595
596 NTracingZone( _ctx, 1 );
597
598 /* get the file list */
599 files = PHYSFS_enumerateFiles( AI_PATH );
600
601 /* Create array. */
603
604 /* load the profiles */
605 for ( size_t i = 0; files[i] != NULL; i++ ) {
606 AI_Profile prof;
607 char path[PATH_MAX];
608 int ret;
609
610 if ( !ndata_matchExt( files[i], "lua" ) )
611 continue;
612
613 snprintf( path, sizeof( path ), AI_PATH "%s", files[i] );
614 ret = ai_loadProfile( &prof, path ); /* Load the profile */
615 if ( ret == 0 )
616 array_push_back( &profiles, prof );
617 else
618 WARN( _( "Error loading AI profile '%s'" ), path );
619
620 /* Render if necessary. */
622 }
623 qsort( profiles, array_size( profiles ), sizeof( AI_Profile ), ai_sort );
624
625 /* More clean up. */
626 PHYSFS_freeList( files );
627
628#if DEBUGGING
629 if ( conf.devmode ) {
630 time = SDL_GetTicks() - time;
631 DEBUG( n_( "Loaded %d AI Profile in %.3f s",
632 "Loaded %d AI Profiles in %.3f s", array_size( profiles ) ),
633 array_size( profiles ), time / 1000. );
634 } else
635 DEBUG( n_( "Loaded %d AI Profile", "Loaded %d AI Profiles",
636 array_size( profiles ) ),
637 array_size( profiles ) );
638#endif /* DEBUGGING */
639
640 /* Create collision stuff. */
641 il_create( &ai_qtquery, 1 );
642
643 /* Load equipment thingy. */
644 ai_loadEquip();
645
646 NTracingZoneEnd( _ctx );
647
648 return 0;
649}
650
654static int ai_loadEquip( void )
655{
656 char *buf;
657 size_t bufsize;
658 const char *filename = AI_EQUIP_PATH;
659
660 NTracingZone( _ctx, 1 );
661
662 /* Make sure doesn't already exist. */
663 nlua_freeEnv( equip_env );
664
665 /* Create new state. */
666 equip_env = nlua_newEnv( "ai_equip" );
668
669 /* Load the file. */
670 buf = ndata_read( filename, &bufsize );
671 if ( nlua_dobufenv( equip_env, buf, bufsize, filename ) != 0 ) {
672 WARN( _( "Error loading file: %s\n"
673 "%s\n"
674 "Most likely Lua file has improper syntax, please check" ),
675 filename, lua_tostring( naevL, -1 ) );
676 NTracingZoneEnd( _ctx );
677 return -1;
678 }
679 free( buf );
680
681 NTracingZoneEnd( _ctx );
682
683 return 0;
684}
685
686int nlua_loadAI( nlua_env env )
687{
688 nlua_register( env, "ai", aiL_methods, 0 );
689 return 0;
690}
691
699static int ai_loadProfile( AI_Profile *prof, const char *filename )
700{
701 char *buf = NULL;
702 size_t bufsize = 0;
703 nlua_env env;
704 size_t len;
705 const char *str;
706
707 /* Set name. */
708 len = strlen( filename ) - strlen( AI_PATH ) - strlen( ".lua" );
709 prof->name = malloc( len + 1 );
710 strncpy( prof->name, &filename[strlen( AI_PATH )], len );
711 prof->name[len] = '\0';
712
713 /* Create Lua. */
714 env = nlua_newEnv( filename );
715 nlua_loadStandard( env );
716 prof->env = env;
717
718 /* Register C functions in Lua */
719 nlua_register( env, "ai", aiL_methods, 0 );
720
721 /* Mark as an ai. */
722 lua_pushboolean( naevL, 1 );
723 nlua_setenv( naevL, env, "__ai" );
724
725 /* Set "mem" to be default template. */
726 lua_newtable( naevL ); /* m */
727 lua_pushvalue( naevL, -1 ); /* m, m */
728 prof->lua_mem = luaL_ref( naevL, LUA_REGISTRYINDEX ); /* m */
729 nlua_setenv( naevL, env, "mem" ); /* */
730
731 /* Now load the file since all the functions have been previously loaded */
732 buf = ndata_read( filename, &bufsize );
733 if ( nlua_dobufenv( env, buf, bufsize, filename ) != 0 ) {
734 WARN( _( "Error loading AI file: %s\n"
735 "%s\n"
736 "Most likely Lua file has improper syntax, please check" ),
737 filename, lua_tostring( naevL, -1 ) );
738 free( prof->name );
739 nlua_freeEnv( env );
740 free( buf );
741 return -1;
742 }
743 free( buf );
744
745 /* Find and set up the necessary references. */
746 str = _( "AI Profile '%s' is missing '%s' function!" );
747 prof->ref_control = nlua_refenvtype( env, "control", LUA_TFUNCTION );
748 if ( prof->ref_control == LUA_NOREF )
749 WARN( str, filename, "control" );
750 prof->ref_control_manual =
751 nlua_refenvtype( env, "control_manual", LUA_TFUNCTION );
752 if ( prof->ref_control_manual == LUA_NOREF )
753 WARN( str, filename, "control_manual" );
754 prof->ref_refuel = nlua_refenvtype( env, "refuel", LUA_TFUNCTION );
755 if ( prof->ref_refuel == LUA_NOREF )
756 WARN( str, filename, "refuel" );
757 prof->ref_create = nlua_refenvtype( env, "create", LUA_TFUNCTION );
758 if ( prof->ref_create == LUA_NOREF )
759 WARN( str, filename, "create" );
760
761 /* Get the control rate. */
762 nlua_getenv( naevL, env, "control_rate" );
763 prof->control_rate = lua_tonumber( naevL, -1 );
764 lua_pop( naevL, 1 );
765
766 return 0;
767}
768
775AI_Profile *ai_getProfile( const char *name )
776{
777 const AI_Profile ai = { .name = (char *)name };
778 AI_Profile *ret = bsearch( &ai, profiles, array_size( profiles ),
779 sizeof( AI_Profile ), ai_sort );
780 if ( ret == NULL )
781 WARN( _( "AI Profile '%s' not found in AI stack" ), name );
782 return ret;
783}
784
788void ai_exit( void )
789{
790 /* Free AI profiles. */
791 for ( int i = 0; i < array_size( profiles ); i++ ) {
792 free( profiles[i].name );
793 nlua_freeEnv( profiles[i].env );
794 }
796
797 /* Free equipment Lua. */
798 nlua_freeEnv( equip_env );
799 equip_env = LUA_NOREF;
800
801 /* Clean up query stuff. */
802 il_destroy( &ai_qtquery );
803}
804
812void ai_think( Pilot *pilot, double dt, int dotask )
813{
814 nlua_env env;
815 AIMemory oldmem;
816 Task *t;
817
818 /* Must have AI. */
819 if ( pilot->ai == NULL )
820 return;
821
822 NTracingZone( _ctx, 1 );
823
824 oldmem = ai_setPilot( pilot );
825 env = cur_pilot->ai->env; /* set the AI profile to the current pilot's */
826
827 ai_thinkSetup( dt );
828 pilot_rmFlag( pilot, PILOT_SCANNING ); /* Reset each frame, only set if the
829 pilot is checking ai.scandone. */
830 /* So the way this works is that, for other than the player, we reset all
831 * the weapon sets every frame, so that the AI has to redo them over and
832 * over. Now, this is a horrible hack so shit works and needs a proper fix.
833 * TODO fix. */
834
835 /* Mark weapon sets as off, and the AI will activate as necessary. */
836 if ( !pilot_isPlayer( cur_pilot ) )
837 /* Turn off HOLD groups. */
839
840 /* Get current task. */
841 t = ai_curTask( cur_pilot );
842
843 /* control function if pilot is idle or tick is up */
844 if ( ( cur_pilot->tcontrol < 0. ) || ( t == NULL ) ) {
845 NTracingZoneName( _ctx_control, "ai_think[control]", 1 );
846
847 double crate = cur_pilot->ai->control_rate;
848 if ( pilot_isFlag( pilot, PILOT_PLAYER ) ||
849 pilot_isFlag( cur_pilot, PILOT_MANUAL_CONTROL ) ) {
850 lua_rawgeti( naevL, LUA_REGISTRYINDEX,
851 cur_pilot->ai->ref_control_manual );
852 lua_pushnumber( naevL, crate - cur_pilot->tcontrol );
853 ai_run( env, 1 );
854 } else {
855 lua_rawgeti( naevL, LUA_REGISTRYINDEX, cur_pilot->ai->ref_control );
856 lua_pushnumber( naevL, crate - cur_pilot->tcontrol );
857 ai_run( env, 1 ); /* run control */
858 }
859 /* Try to desync control ticks when possible by adding randomness. */
860 cur_pilot->tcontrol = crate * ( 0.9 + 0.2 * RNGF() );
861
862 /* Task may have changed due to control tick. */
863 t = ai_curTask( cur_pilot );
864
865 NTracingZoneEnd( _ctx_control );
866 }
867
868 if ( !dotask ) {
869 ai_unsetPilot( oldmem );
870 NTracingZoneEnd( _ctx );
871 return;
872 }
873
874 /* pilot has a currently running task */
875 if ( t != NULL ) {
876 int data;
877 NTracingZoneName( _ctx_task, "ai_think[task]", 1 );
878
879 /* Run subtask if available, otherwise run main task. */
880 if ( t->subtask != NULL ) {
881 lua_rawgeti( naevL, LUA_REGISTRYINDEX, t->subtask->func );
882 /* Use subtask data or task data if subtask is not set. */
883 data = t->subtask->dat;
884 if ( data == LUA_NOREF )
885 data = t->dat;
886 } else {
887 lua_rawgeti( naevL, LUA_REGISTRYINDEX, t->func );
888 data = t->dat;
889 }
890 /* Function should be on the stack. */
891 if ( data != LUA_NOREF ) {
892 lua_rawgeti( naevL, LUA_REGISTRYINDEX, data );
893 ai_run( env, 1 );
894 } else
895 ai_run( env, 0 );
896
897 /* Manual control must check if IDLE hook has to be run. */
898 if ( pilot_isFlag( cur_pilot, PILOT_MANUAL_CONTROL ) ) {
899 /* We must yet check again to see if there still is a current task
900 * running. */
901 if ( ai_curTask( cur_pilot ) == NULL )
902 pilot_runHook( cur_pilot, PILOT_HOOK_IDLE );
903 }
904
905 NTracingZoneEnd( _ctx_task );
906 }
907
908 /* Have to update potential outfit state changes here. */
909 if ( !pilot_isPlayer( cur_pilot ) )
911
912 /* Applies local variables to the pilot. */
914
915 /* Restore memory. */
916 ai_unsetPilot( oldmem );
917
918 /* Clean up if necessary. */
920
921 NTracingZoneEnd( _ctx );
922}
923
929void ai_init( Pilot *p )
930{
931 NTracingZone( _ctx, 1 );
932
933 AIMemory oldmem;
934 if ( ( p->ai == NULL ) || ( p->ai->ref_create == LUA_NOREF ) )
935 return;
936 oldmem = ai_setPilot( p );
937 lua_rawgeti( naevL, LUA_REGISTRYINDEX, p->ai->ref_create );
938 ai_run( p->ai->env, 0 ); /* run control */
939 ai_unsetPilot( oldmem );
940
941 NTracingZoneEnd( _ctx );
942}
943
951void ai_attacked( Pilot *attacked, const unsigned int attacker, double dmg )
952{
953 AIMemory oldmem;
954 HookParam hparam[2];
955
956 /* Custom hook parameters. */
957 hparam[0].type = HOOK_PARAM_PILOT;
958 hparam[0].u.lp = attacker;
959 hparam[1].type = HOOK_PARAM_NUMBER;
960 hparam[1].u.num = dmg;
961
962 /* Behaves differently if manually overridden. */
963 pilot_runHookParam( attacked, PILOT_HOOK_ATTACKED, hparam, 2 );
964
965 /* Must have an AI profile. */
966 if ( attacked->ai == NULL )
967 return;
968
969 oldmem = ai_setPilot( attacked ); /* Sets cur_pilot. */
970 if ( pilot_isFlag( attacked, PILOT_MANUAL_CONTROL ) )
971 nlua_getenv( naevL, cur_pilot->ai->env, "attacked_manual" );
972 else
973 nlua_getenv( naevL, cur_pilot->ai->env, "attacked" );
974
975 lua_pushpilot( naevL, attacker );
976 if ( nlua_pcall( cur_pilot->ai->env, 1, 0 ) ) {
977 WARN( _( "Pilot '%s' ai '%s' -> 'attacked': %s" ), cur_pilot->name,
978 cur_pilot->ai->name, lua_tostring( naevL, -1 ) );
979 lua_pop( naevL, 1 );
980 }
981 ai_unsetPilot( oldmem );
982}
983
989void ai_discovered( Pilot *discovered )
990{
991 AIMemory oldmem;
992
993 /* Behaves differently if manually overridden. */
994 pilot_runHook( discovered, PILOT_HOOK_DISCOVERED );
995 if ( pilot_isFlag( discovered, PILOT_MANUAL_CONTROL ) )
996 return;
997
998 /* Must have an AI profile and not be player. */
999 if ( discovered->ai == NULL )
1000 return;
1001
1002 oldmem = ai_setPilot( discovered ); /* Sets cur_pilot. */
1003
1004 /* Only run if discovered function exists. */
1005 nlua_getenv( naevL, cur_pilot->ai->env, "discovered" );
1006 if ( lua_isnil( naevL, -1 ) ) {
1007 lua_pop( naevL, 1 );
1008 ai_unsetPilot( oldmem );
1009 return;
1010 }
1011
1012 if ( nlua_pcall( cur_pilot->ai->env, 0, 0 ) ) {
1013 WARN( _( "Pilot '%s' ai '%s' -> 'discovered': %s" ), cur_pilot->name,
1014 cur_pilot->ai->name, lua_tostring( naevL, -1 ) );
1015 lua_pop( naevL, 1 );
1016 }
1017 ai_unsetPilot( oldmem );
1018}
1019
1025void ai_hail( Pilot *recipient )
1026{
1027 AIMemory oldmem;
1028
1029 /* Make sure it's getable. */
1030 if ( !pilot_canTarget( recipient ) )
1031 return;
1032
1033 /* Must have an AI profile and not be player. */
1034 if ( recipient->ai == NULL )
1035 return;
1036
1037 oldmem = ai_setPilot( recipient ); /* Sets cur_pilot. */
1038
1039 /* Only run if hail function exists. */
1040 nlua_getenv( naevL, cur_pilot->ai->env, "hail" );
1041 if ( lua_isnil( naevL, -1 ) ) {
1042 lua_pop( naevL, 1 );
1043 ai_unsetPilot( oldmem );
1044 return;
1045 }
1046
1047 if ( nlua_pcall( cur_pilot->ai->env, 0, 0 ) ) {
1048 WARN( _( "Pilot '%s' ai '%s' -> 'hail': %s" ), cur_pilot->name,
1049 cur_pilot->ai->name, lua_tostring( naevL, -1 ) );
1050 lua_pop( naevL, 1 );
1051 }
1052 ai_unsetPilot( oldmem );
1053}
1054
1061void ai_refuel( Pilot *refueler, unsigned int target )
1062{
1063 Task *t;
1064
1065 if ( cur_pilot->ai->ref_refuel == LUA_NOREF ) {
1066 WARN( _( "Pilot '%s' (ai '%s') is trying to refuel when no 'refuel' "
1067 "function is defined!" ),
1068 cur_pilot->name, cur_pilot->ai->name );
1069 return;
1070 }
1071
1072 /* Create the task. */
1073 t = ncalloc( 1, sizeof( Task ) );
1074 t->name = strdup( "refuel" );
1075 lua_rawgeti( naevL, LUA_REGISTRYINDEX, cur_pilot->ai->ref_refuel );
1076 t->func = luaL_ref( naevL, LUA_REGISTRYINDEX );
1077 lua_pushpilot( naevL, target );
1078 t->dat = luaL_ref( naevL, LUA_REGISTRYINDEX );
1079
1080 /* Prepend the task. */
1081 t->next = refueler->task;
1082 refueler->task = t;
1083
1084 return;
1085}
1086
1094void ai_getDistress( const Pilot *p, const Pilot *distressed,
1095 const Pilot *attacker )
1096{
1097 /* Ignore distress signals when under manual control. */
1098 if ( pilot_isFlag( p, PILOT_MANUAL_CONTROL ) )
1099 return;
1100
1101 /* Must have AI. */
1102 if ( cur_pilot->ai == NULL )
1103 return;
1104
1105 if ( attacker != NULL )
1106 lua_pushpilot( naevL, attacker->id );
1107 else
1108 lua_pushnil( naevL );
1109 pilot_msg( distressed, p, "distress", -1 );
1110 lua_pop( naevL, 1 );
1111}
1112
1120static void ai_create( Pilot *pilot )
1121{
1122 NTracingZone( _ctx, 1 );
1123
1124 /* Set creation mode. */
1125 if ( !pilot_isFlag( pilot, PILOT_CREATED_AI ) )
1127
1128 /* Create equipment first - only if creating for the first time. */
1129 if ( !pilot_isFlag( pilot, PILOT_NO_OUTFITS ) &&
1130 !pilot_isFlag( pilot, PILOT_NO_EQUIP ) &&
1131 ( aiL_status == AI_STATUS_CREATE ) ) {
1132 nlua_env env = equip_env;
1133 char *func = "equip_generic";
1134
1135 if ( faction_getEquipper( pilot->faction ) != LUA_NOREF ) {
1136 env = faction_getEquipper( pilot->faction );
1137 func = "equip";
1138 }
1139 nlua_getenv( naevL, env, func );
1140 lua_pushpilot( naevL, pilot->id );
1141 if ( nlua_pcall( env, 1, 0 ) ) { /* Error has occurred. */
1142 WARN( _( "Pilot '%s' equip '%s' -> '%s': %s" ), pilot->name,
1143 pilot->ai->name, func, lua_tostring( naevL, -1 ) );
1144 lua_pop( naevL, 1 );
1145 }
1146
1147 /* Since the pilot changes outfits and cores, we must heal him up. */
1148 pilot_healLanded( pilot );
1149 }
1150
1151 /* Must have AI. */
1152 if ( pilot->ai == NULL ) {
1153 NTracingZoneEnd( _ctx );
1154 return;
1155 }
1156
1157 /* Set up. */
1158 ai_init( pilot );
1159
1160 /* Recover normal mode. */
1161 if ( !pilot_isFlag( pilot, PILOT_CREATED_AI ) )
1163 NTracingZoneEnd( _ctx );
1164}
1165
1169Task *ai_newtask( lua_State *L, Pilot *p, const char *func, int subtask,
1170 int pos )
1171{
1172 Task *t, *pointer;
1173
1174 if ( p->ai == NULL ) {
1175 NLUA_ERROR(
1176 L, _( "Trying to create new task for pilot '%s' that has no AI!" ),
1177 p->name );
1178 return NULL;
1179 }
1180
1181 /* Check if the function is good. */
1182 nlua_getenv( L, p->ai->env, func );
1183 luaL_checktype( L, -1, LUA_TFUNCTION );
1184
1185 /* Create the new task. */
1186 t = ncalloc( 1, sizeof( Task ) );
1187 t->name = strdup( func );
1188 t->func = luaL_ref( L, LUA_REGISTRYINDEX );
1189 t->dat = LUA_NOREF;
1190
1191 /* Handle subtask and general task. */
1192 if ( !subtask ) {
1193 if ( ( pos == 1 ) && ( p->task != NULL ) ) { /* put at the end */
1194 for ( pointer = p->task; pointer->next != NULL;
1195 pointer = pointer->next )
1196 ;
1197 pointer->next = t;
1198 } else {
1199 t->next = p->task;
1200 p->task = t;
1201 }
1202 } else {
1203 /* Must have valid task. */
1204 Task *curtask = ai_curTask( p );
1205 if ( curtask == NULL ) {
1206 ai_freetask( t );
1207 NLUA_ERROR( L, _( "Trying to add subtask '%s' to non-existent task." ),
1208 func );
1209 return NULL;
1210 }
1211
1212 /* Add the subtask. */
1213 if ( ( pos == 1 ) && ( curtask->subtask != NULL ) ) { /* put at the end */
1214 for ( pointer = curtask->subtask; pointer->next != NULL;
1215 pointer = pointer->next )
1216 ;
1217 pointer->next = t;
1218 } else {
1219 t->next = curtask->subtask;
1220 curtask->subtask = t;
1221 }
1222 }
1223
1224 return t;
1225}
1226
1233{
1234 if ( t->func != LUA_NOREF )
1235 luaL_unref( naevL, LUA_REGISTRYINDEX, t->func );
1236
1237 if ( t->dat != LUA_NOREF )
1238 luaL_unref( naevL, LUA_REGISTRYINDEX, t->dat );
1239
1240 /* Recursive subtask freeing. */
1241 if ( t->subtask != NULL ) {
1242 ai_freetask( t->subtask );
1243 t->subtask = NULL;
1244 }
1245
1246 /* Free next task in the chain. */
1247 if ( t->next != NULL ) {
1248 ai_freetask( t->next ); /* yay recursive freeing */
1249 t->next = NULL;
1250 }
1251
1252 free( t->name );
1253 nfree( t );
1254}
1255
1259static Task *ai_createTask( lua_State *L, int subtask )
1260{
1261 /* Parse basic parameters. */
1262 const char *func = luaL_checkstring( L, 1 );
1263
1264 if ( pilot_isPlayer( cur_pilot ) &&
1265 !pilot_isFlag( cur_pilot, PILOT_MANUAL_CONTROL ) )
1266 return NULL;
1267
1268 /* Creates a new AI task. */
1269 Task *t = ai_newtask( L, cur_pilot, func, subtask, 0 );
1270 if ( t == NULL ) {
1271 NLUA_ERROR( L, _( "Failed to create new task for pilot '%s'." ),
1272 cur_pilot->name );
1273 return NULL;
1274 }
1275
1276 /* Set the data. */
1277 if ( lua_gettop( L ) > 1 ) {
1278 lua_pushvalue( L, 2 );
1279 t->dat = luaL_ref( L, LUA_REGISTRYINDEX );
1280 }
1281
1282 return t;
1283}
1284
1288static int ai_tasktarget( lua_State *L, const Task *t )
1289{
1290 if ( t->dat == LUA_NOREF )
1291 return 0;
1292 lua_rawgeti( L, LUA_REGISTRYINDEX, t->dat );
1293 return 1;
1294}
1295
1315static int aiL_pushtask( lua_State *L )
1316{
1317 ai_createTask( L, 0 );
1318 aiL_outfitOffAll( L );
1319 return 0;
1320}
1321
1326static int aiL_poptask( lua_State *L )
1327{
1328 (void)L;
1329 Task *t = ai_curTask( cur_pilot );
1330 /* Tasks must exist. */
1331 if ( t == NULL ) {
1332 NLUA_WARN(
1333 L, _( "Trying to pop task when there are no tasks on the stack." ) );
1334 return 0;
1335 }
1336 t->done = 1;
1337 aiL_outfitOffAll( L );
1338 return 0;
1339}
1340
1347static int aiL_taskname( lua_State *L )
1348{
1349 const Task *t = ai_curTask( cur_pilot );
1350 if ( t == NULL )
1351 return 0;
1352 lua_pushstring( L, t->name );
1353 return 1;
1354}
1355
1363static int aiL_taskdata( lua_State *L )
1364{
1365 const Task *t = ai_curTask( cur_pilot );
1366 /* Must have a task. */
1367 if ( t == NULL )
1368 return 0;
1369 return ai_tasktarget( L, t );
1370}
1371
1379static int aiL_pushsubtask( lua_State *L )
1380{
1381 ai_createTask( L, 1 );
1382 return 0;
1383}
1384
1390static int aiL_popsubtask( lua_State *L )
1391{
1392 Task *t, *st;
1393 t = ai_curTask( cur_pilot );
1394
1395 /* Tasks must exist. */
1396 if ( t == NULL )
1397 return NLUA_ERROR(
1398 L, _( "Trying to pop task when there are no tasks on the stack." ) );
1399 if ( t->subtask == NULL )
1400 return NLUA_ERROR( L,
1401 _( "Trying to pop subtask when there are no subtasks "
1402 "for the task '%s'." ),
1403 t->name );
1404
1405 /* Exterminate, annihilate destroy. */
1406 st = t->subtask;
1407 t->subtask = st->next;
1408 st->next = NULL;
1409 ai_freetask( st );
1410 return 0;
1411}
1412
1420static int aiL_subtaskname( lua_State *L )
1421{
1422 const Task *t = ai_curTask( cur_pilot );
1423 if ( ( t != NULL ) && ( t->subtask != NULL ) )
1424 lua_pushstring( L, t->subtask->name );
1425 else
1426 lua_pushnil( L );
1427 return 1;
1428}
1429
1437static int aiL_subtaskdata( lua_State *L )
1438{
1439 const Task *t = ai_curTask( cur_pilot );
1440 /* Must have a subtask. */
1441 if ( ( t == NULL ) || ( t->subtask == NULL ) )
1442 return 0;
1443
1444 return ai_tasktarget( L, t->subtask );
1445}
1446
1453static int aiL_pilot( lua_State *L )
1454{
1455 lua_pushpilot( L, cur_pilot->id );
1456 return 1;
1457}
1458
1465static int aiL_getrndpilot( lua_State *L )
1466{
1467 Pilot *const *pilot_stack = pilot_getAll();
1468 int p = RNG( 0, array_size( pilot_stack ) - 1 );
1469 /* Make sure it can't be the same pilot. */
1470 if ( pilot_stack[p]->id == cur_pilot->id ) {
1471 p++;
1472 if ( p >= array_size( pilot_stack ) )
1473 p = 0;
1474 }
1475 /* Last check. */
1476 if ( pilot_stack[p]->id == cur_pilot->id )
1477 return 0;
1478 /* Actually found a pilot. */
1479 lua_pushpilot( L, pilot_stack[p]->id );
1480 return 1;
1481}
1482
1489static int aiL_getnearestpilot( lua_State *L )
1490{
1491 /* dist will be initialized to a number */
1492 /* this will only seek out pilots closer than dist */
1493 Pilot *const *pilot_stack = pilot_getAll();
1494 int dist = 1e6;
1495 int candidate_id = -1;
1496
1497 /*cycle through all the pilots and find the closest one that is not the pilot
1498 */
1499 for ( int i = 0; i < array_size( pilot_stack ); i++ ) {
1500 if ( pilot_stack[i]->id == cur_pilot->id )
1501 continue;
1502 if ( vec2_dist( &pilot_stack[i]->solid.pos, &cur_pilot->solid.pos ) >
1503 dist )
1504 continue;
1505 dist = vec2_dist( &pilot_stack[i]->solid.pos, &cur_pilot->solid.pos );
1506 candidate_id = i;
1507 }
1508
1509 /* Last check. */
1510 if ( candidate_id == -1 )
1511 return 0;
1512
1513 /* Actually found a pilot. */
1514 lua_pushpilot( L, pilot_stack[candidate_id]->id );
1515 return 1;
1516}
1517
1525static int aiL_getdistance( lua_State *L )
1526{
1527 const vec2 *v;
1528
1529 /* vector as a parameter */
1530 if ( lua_isvector( L, 1 ) )
1531 v = lua_tovector( L, 1 );
1532 /* pilot as parameter */
1533 else if ( lua_ispilot( L, 1 ) ) {
1534 const Pilot *p = luaL_validpilot( L, 1 );
1535 v = &p->solid.pos;
1536 }
1537 /* wrong parameter */
1538 else
1539 NLUA_INVALID_PARAMETER( L, 1 );
1540
1541 lua_pushnumber( L, vec2_dist( v, &cur_pilot->solid.pos ) );
1542 return 1;
1543}
1544
1552static int aiL_getdistance2( lua_State *L )
1553{
1554 const vec2 *v;
1555
1556 /* vector as a parameter */
1557 if ( lua_isvector( L, 1 ) )
1558 v = lua_tovector( L, 1 );
1559 /* pilot as parameter */
1560 else if ( lua_ispilot( L, 1 ) ) {
1561 const Pilot *p = luaL_validpilot( L, 1 );
1562 v = &p->solid.pos;
1563 }
1564 /* wrong parameter */
1565 else
1566 NLUA_INVALID_PARAMETER( L, 1 );
1567
1568 lua_pushnumber( L, vec2_dist2( v, &cur_pilot->solid.pos ) );
1569 return 1;
1570}
1571
1580static int aiL_getflybydistance( lua_State *L )
1581{
1582 const vec2 *v;
1583 vec2 perp_motion_unit, offset_vect;
1584 int offset_distance;
1585
1586 /* vector as a parameter */
1587 if ( lua_isvector( L, 1 ) )
1588 v = lua_tovector( L, 1 );
1589 /* pilot id as parameter */
1590 else if ( lua_ispilot( L, 1 ) ) {
1591 const Pilot *p = luaL_validpilot( L, 1 );
1592 v = &p->solid.pos;
1593
1594 /*vec2_cset(&v, VX(pilot->solid.pos) - VX(cur_pilot->solid.pos),
1595 * VY(pilot->solid.pos) - VY(cur_pilot->solid.pos) );*/
1596 } else
1597 NLUA_INVALID_PARAMETER( L, 1 );
1598
1599 vec2_cset( &offset_vect, VX( *v ) - VX( cur_pilot->solid.pos ),
1600 VY( *v ) - VY( cur_pilot->solid.pos ) );
1601 vec2_pset( &perp_motion_unit, 1, VANGLE( cur_pilot->solid.vel ) + M_PI_2 );
1602 offset_distance = vec2_dot( &perp_motion_unit, &offset_vect );
1603
1604 lua_pushnumber( L, offset_distance );
1605 return 1;
1606}
1607
1623static int aiL_minbrakedist( lua_State *L )
1624{
1625 /* More complicated calculation based on relative velocity. */
1626 if ( lua_gettop( L ) > 0 ) {
1627 double time, dist, vel;
1628 vec2 vv;
1629 const Pilot *p = luaL_validpilot( L, 1 );
1630
1631 /* Set up the vectors. */
1632 vec2_cset( &vv, p->solid.vel.x - cur_pilot->solid.vel.x,
1633 p->solid.vel.y - cur_pilot->solid.vel.y );
1634
1635 /* Run the same calculations. */
1636 time = VMOD( vv ) / cur_pilot->accel + ai_dt;
1637
1638 /* Get relative velocity. */
1639 vel = MIN( cur_pilot->speed - VMOD( p->solid.vel ), VMOD( vv ) );
1640 if ( vel < 0. )
1641 vel = 0.;
1642 /* Get distance to brake. */
1643 double flytime = time + M_PI / cur_pilot->turn + ai_dt;
1644 dist = vel * (flytime)-0.5 * ( cur_pilot->accel ) * time * time;
1645 lua_pushnumber( L, dist );
1646 lua_pushnumber( L, flytime );
1647 } else {
1648 double flytime;
1649 double dist = pilot_minbrakedist( cur_pilot, ai_dt, &flytime );
1650 lua_pushnumber( L, dist );
1651 lua_pushnumber( L, flytime );
1652 }
1653 return 2;
1654}
1655
1663static int aiL_isbribed( lua_State *L )
1664{
1665 const Pilot *p = luaL_validpilot( L, 1 );
1666 lua_pushboolean( L, pilot_isWithPlayer( p ) &&
1667 pilot_isFlag( cur_pilot, PILOT_BRIBED ) );
1668 return 1;
1669}
1670
1677static int aiL_instantJump( lua_State *L )
1678{
1679 lua_pushboolean( L, cur_pilot->stats.misc_instant_jump );
1680 return 1;
1681}
1682
1689static int aiL_ismaxvel( lua_State *L )
1690{
1691 // lua_pushboolean(L,(VMOD(cur_pilot->solid.vel) >
1692 // (cur_pilot->speed-MIN_VEL_ERR)));
1693 lua_pushboolean( L, ( VMOD( cur_pilot->solid.vel ) >
1694 ( solid_maxspeed( &cur_pilot->solid, cur_pilot->speed,
1695 cur_pilot->accel ) -
1696 MIN_VEL_ERR ) ) );
1697 return 1;
1698}
1699
1706static int aiL_isstopped( lua_State *L )
1707{
1708 lua_pushboolean( L, ( VMOD( cur_pilot->solid.vel ) < MIN_VEL_ERR ) );
1709 return 1;
1710}
1711
1719static int aiL_isenemy( lua_State *L )
1720{
1721 const Pilot *p = luaL_validpilot( L, 1 );
1722
1723 /* Player needs special handling in case of hostility. */
1724 if ( pilot_isWithPlayer( p ) ) {
1725 lua_pushboolean( L, pilot_isHostile( cur_pilot ) );
1726 return 1;
1727 }
1728
1729 /* Check if is ally. */
1730 lua_pushboolean( L, areEnemies( cur_pilot->faction, p->faction ) );
1731 return 1;
1732}
1733
1741static int aiL_isally( lua_State *L )
1742{
1743 const Pilot *p = luaL_validpilot( L, 1 );
1744
1745 /* Player needs special handling in case of friendliness. */
1746 if ( pilot_isWithPlayer( p ) ) {
1747 lua_pushboolean( L, pilot_isFriendly( cur_pilot ) );
1748 return 1;
1749 }
1750
1751 /* Check if is ally. */
1752 lua_pushboolean( L, areAllies( cur_pilot->faction, p->faction ) );
1753 return 1;
1754}
1755
1762
1763static int aiL_haslockon( lua_State *L )
1764{
1765 lua_pushboolean( L, cur_pilot->lockons > 0 );
1766 return 1;
1767}
1768
1775
1776static int aiL_hasprojectile( lua_State *L )
1777{
1778 lua_pushboolean( L, cur_pilot->projectiles > 0 );
1779 return 1;
1780}
1781
1788
1789static int aiL_scandone( lua_State *L )
1790{
1791 pilot_setFlag(
1792 cur_pilot, PILOT_SCANNING ); /*< Indicate pilot is scanning this frame. */
1793 lua_pushboolean( L, pilot_ewScanCheck( cur_pilot ) );
1794 return 1;
1795}
1796
1804static int aiL_accel( lua_State *L )
1805{
1806 double n = luaL_optnumber( L, 1, 1. );
1807 pilot_acc = CLAMP( 0., 1., n );
1808 return 0;
1809}
1810
1817static int aiL_turn( lua_State *L )
1818{
1819 pilot_turn = luaL_checknumber( L, 1 );
1820 return 0;
1821}
1822
1837static int aiL_face( lua_State *L )
1838{
1839 const vec2 *tv; /* get the position to face */
1840 double k_diff, k_vel, diff, vx, vy, dx, dy;
1841 int vel;
1842
1843 /* Default gain. */
1844 k_diff = 1. / ( cur_pilot->turn * ai_dt );
1845 k_vel = 100.; /* overkill gain! */
1846
1847 /* Check if must invert. */
1848 if ( lua_toboolean( L, 2 ) )
1849 k_diff *= -1;
1850
1851 /* Get first parameter, aka what to face. */
1852 if ( lua_ispilot( L, 1 ) ) {
1853 Pilot *p = luaL_validpilot( L, 1 );
1854 /* Target vector. */
1855 tv = &p->solid.pos;
1856 } else if ( lua_isnumber( L, 1 ) ) {
1857 double d = lua_tonumber( L, 1 );
1858 diff = angle_diff( cur_pilot->solid.dir, d );
1859 /* Make pilot turn. */
1860 pilot_turn = k_diff * diff;
1861 /* Return angle away from target. */
1862 lua_pushnumber( L, ABS( diff ) );
1863 return 1;
1864 } else if ( lua_isvector( L, 1 ) )
1865 tv = lua_tovector( L, 1 );
1866 else
1867 NLUA_INVALID_PARAMETER( L, 1 );
1868
1869 /* Third parameter. */
1870 vel = lua_toboolean( L, 3 );
1871
1872 /* Tangential component of velocity vector
1873 *
1874 * v: velocity vector
1875 * d: direction vector
1876 *
1877 * d d d
1878 * v_t = v - ( v . --- ) * --- = v - ( v . ----- ) * d
1879 * |d| |d| |d|^2
1880 */
1881 /* Velocity vector. */
1882 vx = cur_pilot->solid.vel.x;
1883 vy = cur_pilot->solid.vel.y;
1884 /* Direction vector. */
1885 dx = tv->x - cur_pilot->solid.pos.x;
1886 dy = tv->y - cur_pilot->solid.pos.y;
1887 if ( vel && ( dx || dy ) ) {
1888 /* Calculate dot product. */
1889 double d = ( vx * dx + vy * dy ) / ( dx * dx + dy * dy );
1890 /* Calculate tangential velocity. */
1891 vx = vx - d * dx;
1892 vy = vy - d * dy;
1893
1894 /* Add velocity compensation. */
1895 dx += -k_vel * vx;
1896 dy += -k_vel * vy;
1897 }
1898
1899 /* Compensate error and rotate. */
1900 diff = angle_diff( cur_pilot->solid.dir, atan2( dy, dx ) );
1901
1902 /* Make pilot turn. */
1903 pilot_turn = k_diff * diff;
1904
1905 /* Return angle away from target. */
1906 lua_pushnumber( L, ABS( diff ) );
1907 return 1;
1908}
1909
1927static int aiL_careful_face( lua_State *L )
1928{
1929 vec2 *tv, F, F1;
1930 Pilot *p;
1931 double d, diff, dist;
1932 Pilot *const *pilot_stack;
1933 int x, y, r;
1934
1935 /* Default gains. */
1936 const double k_diff = 1. / ( cur_pilot->turn * ai_dt );
1937 const double k_goal = 1.;
1938 const double k_enemy = 6e6;
1939
1940 /* Init some variables */
1942 p = cur_pilot;
1943
1944 /* Get first parameter, aka what to face. */
1945 if ( lua_ispilot( L, 1 ) ) {
1946 p = luaL_validpilot( L, 1 );
1947 /* Target vector. */
1948 tv = &p->solid.pos;
1949 } else if ( lua_isnumber( L, 1 ) ) {
1950 d = (double)lua_tonumber( L, 1 );
1951 if ( d < 0. )
1952 tv = &cur_pilot->solid.pos;
1953 else
1954 NLUA_INVALID_PARAMETER( L, 1 );
1955 } else if ( lua_isvector( L, 1 ) )
1956 tv = lua_tovector( L, 1 );
1957 else
1958 NLUA_INVALID_PARAMETER( L, 1 );
1959
1960 /* Init the force, where F1 is roughly normalized to norm 1. */
1961 vec2_csetmin( &F, 0., 0. );
1962 vec2_cset( &F1, tv->x - cur_pilot->solid.pos.x,
1963 tv->y - cur_pilot->solid.pos.y );
1964 dist = VMOD( F1 ) + 0.1; /* Avoid / 0 */
1965 vec2_cset( &F1, F1.x * k_goal / dist, F1.y * k_goal / dist );
1966
1967 /* Cycle through all the pilots in order to compute the force */
1968 x = round( cur_pilot->solid.pos.x );
1969 y = round( cur_pilot->solid.pos.y );
1970 /* It's modulated by k_enemy * k_mult / dist^2, where k_mult<1 and
1971 * k_enemy=6e6 A distance of 5000 should give a maximum factor of 0.24, but
1972 * it should be far away enough to not matter (hopefully).. */
1973 r = 5000;
1974 pilot_collideQueryIL( &ai_qtquery, x - r, y - r, x + r, y + r );
1975 for ( int i = 0; i < il_size( &ai_qtquery ); i++ ) {
1976 const Pilot *p_i = pilot_stack[il_get( &ai_qtquery, i, 0 )];
1977
1978 /* Valid pilot isn't self, is in range, isn't the target and isn't
1979 * disabled */
1980 if ( p_i->id == cur_pilot->id )
1981 continue;
1982 if ( p_i->id == p->id )
1983 continue;
1984 if ( pilot_isDisabled( p_i ) )
1985 continue;
1986 if ( pilot_inRangePilot( cur_pilot, p_i, &dist ) != 1 )
1987 continue;
1988
1989 /* If the enemy is too close, ignore it*/
1990 if ( dist < pow2( 750. ) )
1991 continue;
1992 dist = sqrt( dist ); /* Have to undo the square. */
1993
1994 /* Check if friendly or not */
1995 if ( areEnemies( cur_pilot->faction, p_i->faction ) ) {
1996 double k_mult =
1997 pilot_relhp( p_i, cur_pilot ) * pilot_reldps( p_i, cur_pilot );
1998 double factor = k_enemy * k_mult / ( dist * dist * dist );
1999 vec2_csetmin(
2000 &F, F.x + factor * ( cur_pilot->solid.pos.x - p_i->solid.pos.x ),
2001 F.y + factor * ( cur_pilot->solid.pos.y - p_i->solid.pos.y ) );
2002 }
2003 }
2004
2005 vec2_cset( &F, F.x + F1.x, F.y + F1.y );
2006
2007 /* Rotate. */
2008 diff = angle_diff( cur_pilot->solid.dir, VANGLE( F ) );
2009
2010 /* Make pilot turn. */
2011 pilot_turn = k_diff * diff;
2012
2013 /* Return angle away from target. */
2014 lua_pushnumber( L, ABS( diff ) );
2015 return 1;
2016}
2017
2029static int aiL_aim( lua_State *L )
2030{
2031 double diff, mod, angle;
2032
2033 if ( lua_isasteroid( L, 1 ) ) {
2034 const Asteroid *a = luaL_validasteroid( L, 1 );
2035 angle = pilot_aimAngle( cur_pilot, &a->sol.pos, &a->sol.vel );
2036 } else {
2037 const Pilot *p = luaL_validpilot( L, 1 );
2038 angle = pilot_aimAngle( cur_pilot, &p->solid.pos, &p->solid.vel );
2039 }
2040
2041 /* Calculate what we need to turn */
2042 mod = 1. / ( cur_pilot->turn * ai_dt );
2043 diff = angle_diff( cur_pilot->solid.dir, angle );
2044 pilot_turn = mod * diff;
2045
2046 lua_pushnumber( L, ABS( diff ) );
2047 return 1;
2048}
2049
2058static int aiL_iface( lua_State *L )
2059{
2060 NLUA_MIN_ARGS( 1 );
2061 vec2 *vec, drift, reference_vector; /* get the position to face */
2062 Pilot *p;
2063 double diff, heading_offset_azimuth, drift_radial, drift_azimuthal;
2064
2065 /* Get first parameter, aka what to face. */
2066 p = NULL;
2067 vec = NULL;
2068 if ( lua_ispilot( L, 1 ) )
2069 p = luaL_validpilot( L, 1 );
2070 else if ( lua_isvector( L, 1 ) )
2071 vec = lua_tovector( L, 1 );
2072 else
2073 NLUA_INVALID_PARAMETER( L, 1 );
2074
2075 if ( vec == NULL ) {
2076 if ( p == NULL )
2077 return 0; /* Return silently when attempting to face an invalid pilot.
2078 */
2079 /* Establish the current pilot velocity and position vectors */
2080 vec2_cset( &drift, VX( p->solid.vel ) - VX( cur_pilot->solid.vel ),
2081 VY( p->solid.vel ) - VY( cur_pilot->solid.vel ) );
2082 /* Establish the in-line coordinate reference */
2083 vec2_cset( &reference_vector,
2084 VX( p->solid.pos ) - VX( cur_pilot->solid.pos ),
2085 VY( p->solid.pos ) - VY( cur_pilot->solid.pos ) );
2086 } else {
2087 /* Establish the current pilot velocity and position vectors */
2088 vec2_cset( &drift, -VX( cur_pilot->solid.vel ),
2089 -VY( cur_pilot->solid.vel ) );
2090 /* Establish the in-line coordinate reference */
2091 vec2_cset( &reference_vector, VX( *vec ) - VX( cur_pilot->solid.pos ),
2092 VY( *vec ) - VY( cur_pilot->solid.pos ) );
2093 }
2094
2095 /* Break down the the velocity vectors of both craft into UV coordinates */
2096 vec2_uv( &drift_radial, &drift_azimuthal, &drift, &reference_vector );
2097 heading_offset_azimuth =
2098 angle_diff( cur_pilot->solid.dir, VANGLE( reference_vector ) );
2099
2100 /* Now figure out what to do...
2101 * Are we pointing anywhere inside the correct UV quadrant?
2102 * if we're outside the correct UV quadrant, we need to get into it ASAP
2103 * Otherwise match velocities and approach */
2104 if ( FABS( heading_offset_azimuth ) < M_PI_2 ) {
2105 /* This indicates we're in the correct plane*/
2106 /* 1 - 1/(|x|+1) does a pretty nice job of mapping the reals to the
2107 * interval (0...1). That forms the core of this angle calculation */
2108 /* There is nothing special about the scaling parameter of 200; it can be
2109 tuned to get any behavior desired. A lower number will give a more
2110 dramatic 'lead' */
2111 double speedmap =
2112 -copysign( 1. - 1. / ( FABS( drift_azimuthal / 200. ) + 1. ),
2113 drift_azimuthal ) *
2114 M_PI_2;
2115 diff = angle_diff( heading_offset_azimuth, speedmap );
2116 pilot_turn = -diff / ( ai_dt * cur_pilot->turn );
2117 }
2118 /* turn most efficiently to face the target. If we intercept the correct
2119 quadrant in the UV plane first, then the code above will kick in */
2120 /* some special case logic is added to optimize turn time. Reducing this to
2121 only the else cases would speed up the operation but cause the pilot to
2122 turn in the less-than-optimal direction sometimes when between 135 and 225
2123 degrees off from the target */
2124 else {
2125 /* signal that we're not in a productive direction for accelerating */
2126 diff = M_PI;
2127 pilot_turn = heading_offset_azimuth / ( ai_dt * cur_pilot->turn );
2128 }
2129
2130 /* Return angle in degrees away from target. */
2131 lua_pushnumber( L, ABS( diff ) );
2132 return 1;
2133}
2134
2143static int aiL_dir( lua_State *L )
2144{
2145 vec2 sv, tv; /* get the position to face */
2146 double diff;
2147
2148 /* Get first parameter, aka what to face. */
2149 vec2_cset( &sv, VX( cur_pilot->solid.pos ), VY( cur_pilot->solid.pos ) );
2150 if ( lua_ispilot( L, 1 ) ) {
2151 const Pilot *p = luaL_validpilot( L, 1 );
2152 vec2_cset( &tv, VX( p->solid.pos ), VY( p->solid.pos ) );
2153 diff = angle_diff( cur_pilot->solid.dir, vec2_angle( &sv, &tv ) );
2154 } else if ( lua_isvector( L, 1 ) ) {
2155 const vec2 *vec = lua_tovector( L, 1 );
2156 diff = angle_diff( cur_pilot->solid.dir,
2157 vec2_angle( &cur_pilot->solid.pos, vec ) );
2158 } else
2159 NLUA_INVALID_PARAMETER( L, 1 );
2160
2161 /* Return angle in degrees away from target. */
2162 lua_pushnumber( L, diff );
2163 return 1;
2164}
2165
2174static int aiL_idir( lua_State *L )
2175{
2176 NLUA_MIN_ARGS( 1 );
2177 vec2 *vec, drift, reference_vector; /* get the position to face */
2178 Pilot *p;
2179 double diff, heading_offset_azimuth, drift_radial, drift_azimuthal;
2180
2181 /* Get first parameter, aka what to face. */
2182 p = NULL;
2183 vec = NULL;
2184 if ( lua_ispilot( L, 1 ) )
2185 p = luaL_validpilot( L, 1 );
2186 else if ( lua_isvector( L, 1 ) )
2187 vec = lua_tovector( L, 1 );
2188 else
2189 NLUA_INVALID_PARAMETER( L, 1 );
2190
2191 if ( vec == NULL ) {
2192 if ( p == NULL )
2193 return 0; /* Return silently when attempting to face an invalid pilot.
2194 */
2195 /* Establish the current pilot velocity and position vectors */
2196 vec2_cset( &drift, VX( p->solid.vel ) - VX( cur_pilot->solid.vel ),
2197 VY( p->solid.vel ) - VY( cur_pilot->solid.vel ) );
2198 /* Establish the in-line coordinate reference */
2199 vec2_cset( &reference_vector,
2200 VX( p->solid.pos ) - VX( cur_pilot->solid.pos ),
2201 VY( p->solid.pos ) - VY( cur_pilot->solid.pos ) );
2202 } else {
2203 /* Establish the current pilot velocity and position vectors */
2204 vec2_cset( &drift, -VX( cur_pilot->solid.vel ),
2205 -VY( cur_pilot->solid.vel ) );
2206 /* Establish the in-line coordinate reference */
2207 vec2_cset( &reference_vector, VX( *vec ) - VX( cur_pilot->solid.pos ),
2208 VY( *vec ) - VY( cur_pilot->solid.pos ) );
2209 }
2210
2211 /* Break down the the velocity vectors of both craft into UV coordinates */
2212 vec2_uv( &drift_radial, &drift_azimuthal, &drift, &reference_vector );
2213 heading_offset_azimuth =
2214 angle_diff( cur_pilot->solid.dir, VANGLE( reference_vector ) );
2215
2216 /* Now figure out what to do...
2217 * Are we pointing anywhere inside the correct UV quadrant?
2218 * if we're outside the correct UV quadrant, we need to get into it ASAP
2219 * Otherwise match velocities and approach */
2220 if ( FABS( heading_offset_azimuth ) < M_PI_2 ) {
2221 /* This indicates we're in the correct plane*/
2222 /* 1 - 1/(|x|+1) does a pretty nice job of mapping the reals to the
2223 * interval (0...1). That forms the core of this angle calculation */
2224 /* There is nothing special about the scaling parameter of 200; it can be
2225 tuned to get any behavior desired. A lower number will give a more
2226 dramatic 'lead' */
2227 double speedmap =
2228 -copysign( 1. - 1. / ( FABS( drift_azimuthal / 200. ) + 1. ),
2229 drift_azimuthal ) *
2230 M_PI_2;
2231 diff = -angle_diff( heading_offset_azimuth, speedmap );
2232 }
2233 /* turn most efficiently to face the target. If we intercept the correct
2234 quadrant in the UV plane first, then the code above will kick in */
2235 /* some special case logic is added to optimize turn time. Reducing this to
2236 only the else cases would speed up the operation but cause the pilot to
2237 turn in the less-than-optimal direction sometimes when between 135 and 225
2238 degrees off from the target */
2239 else {
2240 diff = heading_offset_azimuth;
2241 }
2242
2243 /* Return angle in degrees away from target. */
2244 lua_pushnumber( L, diff );
2245 return 1;
2246}
2247
2255static int aiL_drift_facing( lua_State *L )
2256{
2257 double drift =
2258 angle_diff( VANGLE( cur_pilot->solid.vel ), cur_pilot->solid.dir );
2259 lua_pushnumber( L, drift );
2260 return 1;
2261}
2262
2271static int aiL_brake( lua_State *L )
2272{
2273 double dir, accel, diff;
2274 int isstopped = pilot_isStopped( cur_pilot );
2275 int prefer_rev =
2276 lua_toboolean( L, 1 ) * cur_pilot->stats.misc_reverse_thrust;
2277
2278 if ( isstopped ) {
2279 lua_pushboolean( L, 1 );
2280 return 1;
2281 }
2282
2283 if ( prefer_rev || pilot_brakeCheckReverseThrusters( cur_pilot ) ) {
2284 dir = VANGLE( cur_pilot->solid.vel );
2285 accel = -PILOT_REVERSE_THRUST;
2286 } else {
2287 dir = VANGLE( cur_pilot->solid.vel ) + M_PI;
2288 accel = 1.;
2289 }
2290
2291 diff = angle_diff( cur_pilot->solid.dir, dir );
2292 pilot_turn = diff / ( cur_pilot->turn * ai_dt );
2293 if ( ABS( diff ) < MIN_DIR_ERR )
2294 pilot_acc = accel;
2295 else
2296 pilot_acc = 0.;
2297 lua_pushboolean( L, 0 );
2298 return 1;
2299}
2300
2307static int aiL_getnearestspob( lua_State *L )
2308{
2309 double dist, d;
2310 int j;
2311 LuaSpob spob;
2312
2313 /* cycle through spobs */
2314 dist = HUGE_VAL;
2315 j = -1;
2316 for ( int i = 0; i < array_size( cur_system->spobs ); i++ ) {
2317 if ( !spob_hasService( cur_system->spobs[i], SPOB_SERVICE_INHABITED ) )
2318 continue;
2319 d = vec2_dist( &cur_system->spobs[i]->pos, &cur_pilot->solid.pos );
2320 if ( ( !areEnemies( cur_pilot->faction,
2321 cur_system->spobs[i]->presence.faction ) ) &&
2322 ( d < dist ) ) { /* closer friendly spob */
2323 j = i;
2324 dist = d;
2325 }
2326 }
2327
2328 /* no friendly spob found */
2329 if ( j == -1 )
2330 return 0;
2331
2332 cur_pilot->nav_spob = j;
2333 spob = cur_system->spobs[j]->id;
2334 lua_pushspob( L, spob );
2335
2336 return 1;
2337}
2338
2346static int aiL_getspobfrompos( lua_State *L )
2347{
2348 int j;
2349 double dist;
2350 LuaSpob spob;
2351 const vec2 *pos = luaL_checkvector( L, 1 );
2352
2353 /* cycle through spobs */
2354 dist = HUGE_VAL;
2355 j = -1;
2356 for ( int i = 0; i < array_size( cur_system->spobs ); i++ ) {
2357 double d;
2358 if ( !spob_hasService( cur_system->spobs[i], SPOB_SERVICE_INHABITED ) )
2359 continue;
2360 d = vec2_dist( &cur_system->spobs[i]->pos, pos );
2361 if ( ( !areEnemies( cur_pilot->faction,
2362 cur_system->spobs[i]->presence.faction ) ) &&
2363 ( d < dist ) ) { /* closer friendly spob */
2364 j = i;
2365 dist = d;
2366 }
2367 }
2368
2369 /* no friendly spob found */
2370 if ( j == -1 )
2371 return 0;
2372
2373 cur_pilot->nav_spob = j;
2374 spob = cur_system->spobs[j]->id;
2375 lua_pushspob( L, spob );
2376
2377 return 1;
2378}
2379
2386static int aiL_getrndspob( lua_State *L )
2387{
2388 LuaSpob spob;
2389 int p;
2390
2391 /* No spobs. */
2392 if ( array_size( cur_system->spobs ) == 0 )
2393 return 0;
2394
2395 /* get a random spob */
2396 p = RNG( 0, array_size( cur_system->spobs ) - 1 );
2397
2398 /* Copy the data into a vector */
2399 spob = cur_system->spobs[p]->id;
2400 lua_pushspob( L, spob );
2401
2402 return 1;
2403}
2404
2412static int aiL_getlandspob( lua_State *L )
2413{
2414 int *ind;
2415 int id;
2416 LuaSpob spob;
2417 const Spob *p;
2418 int only_friend;
2419
2420 /* If pilot can't land ignore. */
2421 if ( pilot_isFlag( cur_pilot, PILOT_NOLAND ) )
2422 return 0;
2423
2424 /* Check if we should get only friendlies. */
2425 only_friend = lua_toboolean( L, 1 );
2426
2427 /* Allocate memory. */
2428 ind = array_create_size( int, array_size( cur_system->spobs ) );
2429
2430 /* Copy friendly spob.s */
2431 for ( int i = 0; i < array_size( cur_system->spobs ); i++ ) {
2432 Spob *pnt = cur_system->spobs[i];
2433
2434 if ( !spob_hasService( pnt, SPOB_SERVICE_LAND ) )
2435 continue;
2436 if ( !spob_hasService( pnt, SPOB_SERVICE_INHABITED ) )
2437 continue;
2438
2439 /* Check conditions. */
2440 if ( only_friend &&
2441 !areAllies( cur_pilot->faction, pnt->presence.faction ) )
2442 continue;
2443 if ( areEnemies( cur_pilot->faction, pnt->presence.faction ) )
2444 continue;
2445
2446 /* Add it. */
2447 array_push_back( &ind, i );
2448 }
2449
2450 /* no spob to land on found */
2451 if ( array_size( ind ) == 0 ) {
2452 array_free( ind );
2453 return 0;
2454 }
2455
2456 /* we can actually get a random spob now */
2457 id = RNG( 0, array_size( ind ) - 1 );
2458 p = cur_system->spobs[ind[id]];
2459 spob = p->id;
2460 lua_pushspob( L, spob );
2461 cur_pilot->nav_spob = ind[id];
2462 array_free( ind );
2463
2464 return 1;
2465}
2466
2474static int aiL_land( lua_State *L )
2475{
2476 const Spob *spob;
2477 HookParam hparam;
2478
2479 if ( !lua_isnoneornil( L, 1 ) ) {
2480 int i;
2481 const Spob *pnt = luaL_validspob( L, 1 );
2482
2483 /* Find the spob. */
2484 for ( i = 0; i < array_size( cur_system->spobs ); i++ ) {
2485 if ( cur_system->spobs[i] == pnt ) {
2486 break;
2487 }
2488 }
2489 if ( i >= array_size( cur_system->spobs ) )
2490 return NLUA_ERROR( L, _( "Spob '%s' not found in system '%s'" ),
2491 pnt->name, cur_system->name );
2492
2493 cur_pilot->nav_spob = i;
2494 }
2495
2496 if ( cur_pilot->nav_spob < 0 )
2497 return NLUA_ERROR( L, _( "Pilot '%s' (ai '%s') has no land target" ),
2498 cur_pilot->name, cur_pilot->ai->name );
2499
2500 /* Get spob. */
2501 spob = cur_system->spobs[cur_pilot->nav_spob];
2502
2503 /* Check landability. */
2504 if ( ( spob->lua_can_land == LUA_NOREF ) &&
2505 !spob_hasService( spob, SPOB_SERVICE_LAND ) ) { /* Basic services */
2506 lua_pushboolean( L, 0 );
2507 return 1;
2508 }
2509 /* TODO can_land is player-specific, we need to implement this on a pilot
2510 level... if ((!pilot_isFlag(cur_pilot, PILOT_MANUAL_CONTROL) &&
2511 !spob->can_land)) { lua_pushboolean(L,0); return 1;
2512 }
2513 */
2514
2515 /* Check landing functionality. */
2516 if ( pilot_isFlag( cur_pilot, PILOT_NOLAND ) ) {
2517 lua_pushboolean( L, 0 );
2518 return 1;
2519 }
2520
2521 /* Check distance. */
2522 if ( vec2_dist2( &cur_pilot->solid.pos, &spob->pos ) >
2523 pow2( spob->radius ) ) {
2524 lua_pushboolean( L, 0 );
2525 return 1;
2526 }
2527
2528 /* Check velocity. */
2529 if ( vec2_odist2( &cur_pilot->solid.vel ) > pow2( MAX_HYPERSPACE_VEL ) ) {
2530 lua_pushboolean( L, 0 );
2531 return 1;
2532 }
2533
2534 if ( spob->lua_land == LUA_NOREF ) {
2535 cur_pilot->landing_delay =
2536 PILOT_LANDING_DELAY * cur_pilot->ship->dt_default;
2537 cur_pilot->ptimer = cur_pilot->landing_delay;
2538 pilot_setFlag( cur_pilot, PILOT_LANDING );
2539 } else {
2540 lua_rawgeti( naevL, LUA_REGISTRYINDEX, spob->lua_land ); /* f */
2541 lua_pushspob( naevL, spob_index( spob ) );
2543 if ( nlua_pcall( spob->lua_env, 2, 0 ) ) {
2544 NLUA_WARN( L, _( "Spob '%s' failed to run '%s':\n%s" ), spob->name,
2545 "land", lua_tostring( naevL, -1 ) );
2546 lua_pop( naevL, 1 );
2547 }
2548 }
2549
2550 hparam.type = HOOK_PARAM_SPOB;
2551 hparam.u.la = spob->id;
2552
2553 pilot_runHookParam( cur_pilot, PILOT_HOOK_LAND, &hparam, 1 );
2554 lua_pushboolean( L, 1 );
2555 return 1;
2556}
2557
2565static int aiL_hyperspace( lua_State *L )
2566{
2567 int canjump;
2568
2569 /* Find the target jump. */
2570 if ( !lua_isnoneornil( L, 1 ) ) {
2571 const JumpPoint *jp = luaL_validjump( L, 1 );
2572 const LuaJump *lj = luaL_checkjump( L, 1 );
2573 if ( lj->srcid != cur_system->id )
2574 return NLUA_ERROR( L, _( "Jump point must be in current system." ) );
2575 cur_pilot->nav_hyperspace = jp - cur_system->jumps;
2576 }
2577
2578 canjump = space_hyperspace( cur_pilot );
2579 lua_pushnumber( L, canjump );
2580 return 1;
2581}
2582
2590static int aiL_sethyptarget( lua_State *L )
2591{
2592 const JumpPoint *jp;
2593 const LuaJump *lj;
2594 vec2 vec;
2595 double a, rad;
2596
2597 lj = luaL_checkjump( L, 1 );
2598 jp = luaL_validjump( L, 1 );
2599
2600 if ( lj->srcid != cur_system->id )
2601 return NLUA_ERROR( L, _( "Jump point must be in current system." ) );
2602
2603 /* Copy vector. */
2604 vec = jp->pos;
2605
2606 /* Introduce some error. */
2607 a = RNGF() * M_PI * 2.;
2608 rad = RNGF() * 0.5 * jp->radius;
2609 vec2_cadd( &vec, rad * cos( a ), rad * sin( a ) );
2610
2611 /* Set up target. */
2612 cur_pilot->nav_hyperspace = jp - cur_system->jumps;
2613
2614 /* Return vector. */
2615 lua_pushvector( L, vec );
2616
2617 return 1;
2618}
2619
2626static int aiL_nearhyptarget( lua_State *L )
2627{
2628 const JumpPoint *jp;
2629 double mindist, dist;
2630 LuaJump lj;
2631
2632 /* Find nearest jump .*/
2633 mindist = INFINITY;
2634 jp = NULL;
2635 for ( int i = 0; i < array_size( cur_system->jumps ); i++ ) {
2636 const JumpPoint *jiter = &cur_system->jumps[i];
2637 int useshidden = faction_usesHiddenJumps( cur_pilot->faction );
2638
2639 /* Ignore exit only. */
2640 if ( jp_isFlag( jiter, JP_EXITONLY ) )
2641 continue;
2642
2643 /* We want only standard jump points to be used. */
2644 if ( !useshidden && jp_isFlag( jiter, JP_HIDDEN ) )
2645 continue;
2646
2647 /* Only jump if there is presence there. */
2648 if ( system_getPresence( jiter->target, cur_pilot->faction ) <= 0. )
2649 continue;
2650
2651 /* Get nearest distance. */
2652 dist = vec2_dist2( &cur_pilot->solid.pos, &jiter->pos );
2653 if ( dist < mindist ) {
2654 jp = jiter;
2655 mindist = dist;
2656 }
2657 }
2658 /* None available. */
2659 if ( jp == NULL )
2660 return 0;
2661
2662 lj.destid = jp->targetid;
2663 lj.srcid = cur_system->id;
2664
2665 /* Return Jump. */
2666 lua_pushjump( L, lj );
2667 return 1;
2668}
2669
2676static int aiL_rndhyptarget( lua_State *L )
2677{
2678 JumpPoint **jumps;
2679 int r, useshidden;
2680 int *id;
2681 LuaJump lj;
2682
2683 /* No jumps in the system. */
2684 if ( array_size( cur_system->jumps ) == 0 )
2685 return 0;
2686
2687 useshidden = faction_usesHiddenJumps( cur_pilot->faction );
2688
2689 /* Find usable jump points. */
2690 jumps = array_create_size( JumpPoint *, array_size( cur_system->jumps ) );
2691 id = array_create_size( int, array_size( cur_system->jumps ) );
2692 for ( int i = 0; i < array_size( cur_system->jumps ); i++ ) {
2693 JumpPoint *jiter = &cur_system->jumps[i];
2694
2695 /* We want only standard jump points to be used. */
2696 if ( ( !useshidden && jp_isFlag( jiter, JP_HIDDEN ) ) ||
2697 jp_isFlag( jiter, JP_EXITONLY ) )
2698 continue;
2699
2700 /* Only jump if there is presence there. */
2701 if ( system_getPresence( jiter->target, cur_pilot->faction ) <= 0. )
2702 continue;
2703
2704 array_push_back( &id, i );
2705 array_push_back( &jumps, jiter );
2706 }
2707
2708 /* Try to be more lax. */
2709 if ( array_size( jumps ) <= 0 ) {
2710 for ( int i = 0; i < array_size( cur_system->jumps ); i++ ) {
2711 JumpPoint *jiter = &cur_system->jumps[i];
2712
2713 /* We want only standard jump points to be used. */
2714 if ( ( !useshidden && jp_isFlag( jiter, JP_HIDDEN ) ) ||
2715 jp_isFlag( jiter, JP_EXITONLY ) )
2716 continue;
2717
2718 array_push_back( &id, i );
2719 array_push_back( &jumps, jiter );
2720 }
2721 }
2722
2723 if ( array_size( jumps ) <= 0 ) {
2724 NLUA_WARN( L, _( "Pilot '%s' can't find jump to leave system!" ),
2725 cur_pilot->name );
2726 return 0;
2727 }
2728
2729 /* Choose random jump point. */
2730 r = RNG( 0, MAX( array_size( jumps ) - 1, 0 ) );
2731
2732 lj.destid = jumps[r]->targetid;
2733 lj.srcid = cur_system->id;
2734
2735 /* Clean up. */
2736 array_free( jumps );
2737 array_free( id );
2738
2739 /* Return Jump. */
2740 lua_pushjump( L, lj );
2741 return 1;
2742}
2743
2750static int aiL_canHyperspace( lua_State *L )
2751{
2752 lua_pushboolean( L, space_canHyperspace( cur_pilot ) );
2753 return 1;
2754}
2755
2761static int aiL_hyperspaceAbort( lua_State *L )
2762{
2763 (void)L;
2765 return 0;
2766}
2767
2774static int aiL_relvel( lua_State *L )
2775{
2776 double dot, mod;
2777 vec2 vv, pv;
2778 int absolute;
2779 const Pilot *p = luaL_validpilot( L, 1 );
2780
2781 if ( lua_gettop( L ) > 1 )
2782 absolute = lua_toboolean( L, 2 );
2783 else
2784 absolute = 0;
2785
2786 /* Get the projection of target on current velocity. */
2787 if ( absolute == 0 )
2788 vec2_cset( &vv, p->solid.vel.x - cur_pilot->solid.vel.x,
2789 p->solid.vel.y - cur_pilot->solid.vel.y );
2790 else
2791 vec2_cset( &vv, p->solid.vel.x, p->solid.vel.y );
2792
2793 vec2_cset( &pv, p->solid.pos.x - cur_pilot->solid.pos.x,
2794 p->solid.pos.y - cur_pilot->solid.pos.y );
2795 dot = vec2_dot( &pv, &vv );
2796 mod = MAX( VMOD( pv ), 1. ); /* Avoid /0. */
2797
2798 lua_pushnumber( L, dot / mod );
2799 return 1;
2800}
2801
2817static int aiL_follow_accurate( lua_State *L )
2818{
2819 vec2 point, cons, goal, pv;
2820 double radius, angle, Kp, Kd, angle2;
2821 const Pilot *p, *target;
2822 const char *method;
2823
2824 p = cur_pilot;
2825 target = luaL_validpilot( L, 1 );
2826 radius = luaL_optnumber( L, 2, 0. );
2827 angle = luaL_optnumber( L, 3, 0. );
2828 Kp = luaL_optnumber( L, 4, 10. );
2829 Kd = luaL_optnumber( L, 5, 20. );
2830 method = luaL_optstring( L, 6, "velocity" );
2831
2832 if ( strcmp( method, "absolute" ) == 0 )
2833 angle2 = angle;
2834 else if ( strcmp( method, "keepangle" ) == 0 ) {
2835 vec2_cset( &pv, p->solid.pos.x - target->solid.pos.x,
2836 p->solid.pos.y - target->solid.pos.y );
2837 angle2 = VANGLE( pv );
2838 } else /* method == "velocity" */
2839 angle2 = angle + VANGLE( target->solid.vel );
2840
2841 vec2_cset( &point, VX( target->solid.pos ) + radius * cos( angle2 ),
2842 VY( target->solid.pos ) + radius * sin( angle2 ) );
2843
2844 /* Compute the direction using a pd controller */
2845 vec2_cset( &cons,
2846 ( point.x - p->solid.pos.x ) * Kp +
2847 ( target->solid.vel.x - p->solid.vel.x ) * Kd,
2848 ( point.y - p->solid.pos.y ) * Kp +
2849 ( target->solid.vel.y - p->solid.vel.y ) * Kd );
2850
2851 vec2_cset( &goal, cons.x + p->solid.pos.x, cons.y + p->solid.pos.y );
2852
2853 /* Push info */
2854 lua_pushvector( L, goal );
2855
2856 return 1;
2857}
2858
2873static int aiL_face_accurate( lua_State *L )
2874{
2875 vec2 point, cons, goal, *pos, *vel;
2876 double radius, angle, Kp, Kd;
2877 const Pilot *p = cur_pilot;
2878
2879 pos = lua_tovector( L, 1 );
2880 vel = lua_tovector( L, 2 );
2881 radius = luaL_optnumber( L, 3, 0. );
2882 angle = luaL_optnumber( L, 4, 0. );
2883 Kp = luaL_optnumber( L, 5, 10. );
2884 Kd = luaL_optnumber( L, 6, 20. );
2885
2886 vec2_cset( &point, pos->x + radius * cos( angle ),
2887 pos->y + radius * sin( angle ) );
2888
2889 /* Compute the direction using a pd controller */
2890 vec2_cset(
2891 &cons,
2892 ( point.x - p->solid.pos.x ) * Kp + ( vel->x - p->solid.vel.x ) * Kd,
2893 ( point.y - p->solid.pos.y ) * Kp + ( vel->y - p->solid.vel.y ) * Kd );
2894
2895 vec2_cset( &goal, cons.x + p->solid.pos.x, cons.y + p->solid.pos.y );
2896
2897 /* Push info */
2898 lua_pushvector( L, goal );
2899
2900 return 1;
2901}
2902
2909static int aiL_stop( lua_State *L )
2910{
2911 (void)L; /* avoid gcc warning */
2912
2913 if ( VMOD( cur_pilot->solid.vel ) < MIN_VEL_ERR )
2914 vec2_pset( &cur_pilot->solid.vel, 0., 0. );
2915
2916 return 0;
2917}
2918
2925static int aiL_dock( lua_State *L )
2926{
2927 /* Target is another ship. */
2928 Pilot *p = luaL_validpilot( L, 1 );
2929 pilot_dock( cur_pilot, p );
2930 return 0;
2931}
2932
2939static int aiL_combat( lua_State *L )
2940{
2941 if ( lua_gettop( L ) > 0 ) {
2942 int i = lua_toboolean( L, 1 );
2943 if ( i == 1 )
2944 pilot_setFlag( cur_pilot, PILOT_COMBAT );
2945 else if ( i == 0 )
2946 pilot_rmFlag( cur_pilot, PILOT_COMBAT );
2947 } else
2948 pilot_setFlag( cur_pilot, PILOT_COMBAT );
2949
2950 return 0;
2951}
2952
2959static int aiL_settarget( lua_State *L )
2960{
2961 const Pilot *p = luaL_validpilot( L, 1 );
2962 pilot_setTarget( cur_pilot, p->id );
2963 return 0;
2964}
2965
2973static int aiL_setasterotarget( lua_State *L )
2974{
2975 const LuaAsteroid_t *la = luaL_checkasteroid( L, 1 );
2976
2977 /* Set the target asteroid. */
2978 cur_pilot->nav_anchor = la->parent;
2979 cur_pilot->nav_asteroid = la->id;
2980
2981 /* Untarget pilot. */
2982 cur_pilot->target = cur_pilot->id;
2983 cur_pilot->ptarget = NULL;
2984
2985 return 0;
2986}
2987
2995static int aiL_getGatherable( lua_State *L )
2996{
2997 int i;
2998 double rad;
2999
3000 if ( ( lua_gettop( L ) < 1 ) || lua_isnil( L, 1 ) )
3001 rad = INFINITY;
3002 else
3003 rad = lua_tonumber( L, 1 );
3004
3005 i = gatherable_getClosest( &cur_pilot->solid.pos, rad );
3006
3007 if ( i != -1 )
3008 lua_pushnumber( L, i );
3009 else
3010 lua_pushnil( L );
3011
3012 return 1;
3013}
3014
3023static int aiL_gatherablePos( lua_State *L )
3024{
3025 int i, did;
3026 vec2 pos, vel;
3027
3028 i = lua_tointeger( L, 1 );
3029
3030 did = gatherable_getPos( &pos, &vel, i );
3031
3032 if ( did == 0 ) /* No gatherable matching this ID. */
3033 return 0;
3034
3035 lua_pushvector( L, pos );
3036 lua_pushvector( L, vel );
3037
3038 return 2;
3039}
3040
3049static int aiL_weapSet( lua_State *L )
3050{
3051 int id, type;
3052 id = luaL_checkinteger( L, 1 ) - 1;
3053
3054 if ( lua_gettop( L ) > 1 )
3055 type = lua_toboolean( L, 2 );
3056 else
3057 type = 1;
3058
3059 /* weapset type is weapon or change */
3060 if ( type )
3061 pilot_weapSetPress( cur_pilot, id, +1 );
3062 else
3063 pilot_weapSetPress( cur_pilot, id, -1 );
3064 return 0;
3065}
3066
3073static int aiL_hascannons( lua_State *L )
3074{
3075 lua_pushboolean( L, cur_pilot->ncannons > 0 );
3076 return 1;
3077}
3078
3085static int aiL_hasturrets( lua_State *L )
3086{
3087 lua_pushboolean( L, cur_pilot->nturrets > 0 );
3088 return 1;
3089}
3090
3097static int aiL_hasfighterbays( lua_State *L )
3098{
3099 lua_pushboolean( L, cur_pilot->nfighterbays > 0 );
3100 return 1;
3101}
3102
3109static int aiL_hasafterburner( lua_State *L )
3110{
3111 lua_pushboolean( L, cur_pilot->nafterburners > 0 );
3112 return 1;
3113}
3114
3123static int aiL_getenemy( lua_State *L )
3124{
3125 if ( lua_isnoneornil( L, 1 ) ) {
3126 unsigned int id = pilot_getNearestEnemy( cur_pilot );
3127 if ( id == 0 ) /* No enemy found */
3128 return 0;
3129 lua_pushpilot( L, id );
3130 return 1;
3131 } else {
3132 double range = luaL_checknumber( L, 1 );
3133 double r2 = pow2( range );
3134 unsigned int tp = 0;
3135 double d = 0.;
3136 int x, y, r;
3137 Pilot *const *pilot_stack = pilot_getAll();
3138
3139 r = ceil( range );
3140 x = round( cur_pilot->solid.pos.x );
3141 y = round( cur_pilot->solid.pos.y );
3142 pilot_collideQueryIL( &ai_qtquery, x - r, y - r, x + r, y + r );
3143 for ( int i = 0; i < il_size( &ai_qtquery ); i++ ) {
3144 const Pilot *p = pilot_stack[il_get( &ai_qtquery, i, 0 )];
3145 double td;
3146
3147 if ( vec2_dist2( &p->solid.pos, &cur_pilot->solid.pos ) > r2 )
3148 continue;
3149
3150 if ( !pilot_validEnemy( cur_pilot, p ) )
3151 continue;
3152
3153 /* Check distance. */
3154 td = vec2_dist2( &p->solid.pos, &cur_pilot->solid.pos );
3155 if ( !tp || ( td < d ) ) {
3156 d = td;
3157 tp = p->id;
3158 }
3159 }
3160 return tp;
3161 }
3162}
3163
3170static int aiL_hostile( lua_State *L )
3171{
3172 const Pilot *p = luaL_validpilot( L, 1 );
3173 if ( pilot_isWithPlayer( p ) )
3175 return 0;
3176}
3177
3186static int aiL_getweaprangemin( lua_State *L )
3187{
3188 int id = luaL_checkinteger( L, 1 ) - 1;
3189 lua_pushnumber( L, pilot_weapSetRangeMin( cur_pilot, id ) );
3190 return 1;
3191}
3192
3201static int aiL_getweaprange( lua_State *L )
3202{
3203 int id = luaL_checkinteger( L, 1 ) - 1;
3204 lua_pushnumber( L, pilot_weapSetRange( cur_pilot, id ) );
3205 return 1;
3206}
3207
3216static int aiL_getweapspeed( lua_State *L )
3217{
3218 int id = luaL_checkinteger( L, 1 ) - 1;
3219 lua_pushnumber( L, pilot_weapSetSpeed( cur_pilot, id ) );
3220 return 1;
3221}
3222
3231static int aiL_getweapammo( lua_State *L )
3232{
3233 int id = luaL_checkinteger( L, 1 ) - 1;
3234 lua_pushnumber( L, pilot_weapSetAmmo( cur_pilot, id ) );
3235 return 1;
3236}
3237
3245static int aiL_canboard( lua_State *L )
3246{
3247 const Pilot *p = luaL_validpilot( L, 1 );
3248
3249 /* Must be disabled. */
3250 if ( !pilot_isDisabled( p ) ) {
3251 lua_pushboolean( L, 0 );
3252 return 1;
3253 }
3254
3255 /* Check if can be boarded. */
3256 lua_pushboolean( L, !pilot_isFlag( p, PILOT_BOARDED ) );
3257 return 1;
3258}
3259
3268static int aiL_relsize( lua_State *L )
3269{
3270 const Pilot *p = luaL_validpilot( L, 1 );
3271 lua_pushnumber( L, pilot_relsize( cur_pilot, p ) );
3272 return 1;
3273}
3274
3283static int aiL_reldps( lua_State *L )
3284{
3285 const Pilot *p = luaL_validpilot( L, 1 );
3286 lua_pushnumber( L, pilot_reldps( cur_pilot, p ) );
3287 return 1;
3288}
3289
3298static int aiL_relhp( lua_State *L )
3299{
3300 const Pilot *p = luaL_validpilot( L, 1 );
3301 lua_pushnumber( L, pilot_relhp( cur_pilot, p ) );
3302 return 1;
3303}
3304
3311static int aiL_board( lua_State *L )
3312{
3313 lua_pushboolean( L, pilot_board( cur_pilot ) );
3314 return 1;
3315}
3316
3323static int aiL_refuel( lua_State *L )
3324{
3325 lua_pushboolean( L, pilot_refuelStart( cur_pilot ) );
3326 return 1;
3327}
3328
3336static int aiL_settimer( lua_State *L )
3337{
3338 int n = luaL_checkint( L, 1 );
3339 /* Set timer. */
3340 cur_pilot->timer[n] = luaL_optnumber( L, 2, 0. );
3341 return 0;
3342}
3343
3351
3352static int aiL_timeup( lua_State *L )
3353{
3354 int n = luaL_checkint( L, 1 );
3355 lua_pushboolean( L, cur_pilot->timer[n] <= 0. );
3356 return 1;
3357}
3358
3365static int aiL_set_shoot_indicator( lua_State *L )
3366{
3367 cur_pilot->shoot_indicator = lua_toboolean( L, 1 );
3368 return 0;
3369}
3370
3378static int aiL_shoot_indicator( lua_State *L )
3379{
3380 lua_pushboolean( L, cur_pilot->shoot_indicator );
3381 return 1;
3382}
3383
3390static int aiL_distress( lua_State *L )
3391{
3392 if ( lua_isstring( L, 1 ) )
3393 snprintf( aiL_distressmsg, sizeof( aiL_distressmsg ), "%s",
3394 lua_tostring( L, 1 ) );
3395 else if ( lua_isnoneornil( L, 1 ) )
3396 aiL_distressmsg[0] = '\0';
3397 else
3398 NLUA_INVALID_PARAMETER( L, 1 );
3399
3400 /* Set flag because code isn't reentrant. */
3402
3403 return 0;
3404}
3405
3412static int aiL_getBoss( lua_State *L )
3413{
3414 unsigned int id = pilot_getBoss( cur_pilot );
3415
3416 if ( id == 0 ) /* No boss found */
3417 return 0;
3418
3419 lua_pushpilot( L, id );
3420
3421 return 1;
3422}
3423
3430static int aiL_credits( lua_State *L )
3431{
3432 if ( aiL_status != AI_STATUS_CREATE ) {
3433 /*NLUA_ERROR(L, "This function must be called in \"create\" only.");*/
3434 return 0;
3435 }
3436
3437 cur_pilot->credits = luaL_checklong( L, 1 );
3438
3439 return 0;
3440}
3441
3448static int aiL_messages( lua_State *L )
3449{
3450 lua_rawgeti( L, LUA_REGISTRYINDEX, cur_pilot->messages );
3451 lua_newtable( L );
3452 lua_rawseti( L, LUA_REGISTRYINDEX, cur_pilot->messages );
3453 return 1;
3454}
3455
3465static int aiL_stealth( lua_State *L )
3466{
3467 int b = 1;
3468 if ( lua_gettop( L ) > 0 )
3469 b = lua_toboolean( L, 1 );
3470
3471 if ( !b ) {
3473 lua_pushboolean( L, 1 ); /* always succeeds */
3474 return 1;
3475 }
3476
3477 lua_pushboolean( L, pilot_stealth( cur_pilot ) );
3478 return 1;
3479}
3480
3485static int aiL_outfitOffAll( lua_State *L )
3486{
3487 (void)L;
3488 for ( int i = 0; i < array_size( cur_pilot->outfits ); i++ )
3489 cur_pilot->outfits[i]->flags &= ~PILOTOUTFIT_ISON_TOGGLE;
3491 return 0;
3492}
3493
static int ai_setMemory(void)
Sets the cur_pilot's ai.
Definition ai.c:397
Task * ai_newtask(lua_State *L, Pilot *p, const char *func, int subtask, int pos)
Creates a new AI task.
Definition ai.c:1169
void ai_unsetPilot(AIMemory oldmem)
Finishes setting up a pilot.
Definition ai.c:428
static double pilot_turn
Definition ai.c:342
static nlua_env equip_env
Definition ai.c:110
void ai_thinkApply(Pilot *p)
Applies the result of thinking.
Definition ai.c:454
static AI_Profile * profiles
Definition ai.c:109
static int aiL_status
Definition ai.c:352
static IntList ai_qtquery
Definition ai.c:111
static double ai_dt
Definition ai.c:112
Task * ai_curTask(Pilot *pilot)
Gets the current running task.
Definition ai.c:385
void ai_refuel(Pilot *refueler, unsigned int target)
Has a pilot attempt to refuel the other.
Definition ai.c:1061
static const luaL_Reg aiL_methods[]
Definition ai.c:241
static int ai_loadProfile(AI_Profile *prof, const char *filename)
Initializes an AI_Profile and adds it to the stack.
Definition ai.c:699
static void ai_create(Pilot *pilot)
Runs the create() function in the pilot.
Definition ai.c:1120
void ai_cleartasks(Pilot *p)
Clears the pilot's tasks.
Definition ai.c:548
static int ai_tasktarget(lua_State *L, const Task *t)
Pushes a task target.
Definition ai.c:1288
void ai_freetask(Task *t)
Frees an AI task.
Definition ai.c:1232
void ai_think(Pilot *pilot, double dt, int dotask)
Heart of the AI, brains of the pilot.
Definition ai.c:812
void ai_thinkSetup(double dt)
Sets up the pilot for thinking.
Definition ai.c:440
void ai_getDistress(const Pilot *p, const Pilot *distressed, const Pilot *attacker)
Sends a distress signal to a pilot.
Definition ai.c:1094
static double pilot_acc
Definition ai.c:341
AIMemory ai_setPilot(Pilot *p)
Sets the pilot for further AI calls.
Definition ai.c:416
static Task * ai_createTask(lua_State *L, int subtask)
Creates a new task based on stack information.
Definition ai.c:1259
static void ai_run(nlua_env env, int nargs)
Attempts to run a function.
Definition ai.c:476
static char aiL_distressmsg[STRMAX_SHORT]
Definition ai.c:345
void ai_attacked(Pilot *attacked, const unsigned int attacker, double dmg)
Triggers the attacked() function in the pilot's AI.
Definition ai.c:951
#define ai_isFlag(f)
Definition ai.c:102
void ai_destroy(Pilot *p)
Destroys the ai part of the pilot.
Definition ai.c:561
Pilot * cur_pilot
Definition ai.c:340
void ai_hail(Pilot *recipient)
Triggers the hail() function in the pilot's AI.
Definition ai.c:1025
#define ai_setFlag(f)
Definition ai.c:101
void ai_discovered(Pilot *discovered)
Triggers the discovered() function in the pilot's AI.
Definition ai.c:989
void ai_exit(void)
Cleans up global AI.
Definition ai.c:788
static int ai_loadEquip(void)
Loads the equipment selector script.
Definition ai.c:654
void ai_init(Pilot *p)
Initializes the AI.
Definition ai.c:929
#define AI_DISTRESS
Definition ai.c:104
#define AI_STATUS_NORMAL
Definition ai.c:350
static void ai_taskGC(Pilot *pilot)
Runs the garbage collector on the pilot's tasks.
Definition ai.c:359
int ai_pinit(Pilot *p, const char *ai)
Initializes the pilot in the ai.
Definition ai.c:494
#define AI_STATUS_CREATE
Definition ai.c:351
static int pilot_flags
Definition ai.c:343
int ai_load(void)
Initializes the AI stuff which is basically Lua.
Definition ai.c:589
AI_Profile * ai_getProfile(const char *name)
Gets the AI_Profile by name.
Definition ai.c:775
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:170
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
Definition array.h:102
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:179
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition array.h:134
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
int pilot_board(Pilot *p)
Has a pilot attempt to board another pilot.
Definition board.c:221
nlua_env faction_getEquipper(int f)
Gets the equipper state associated to the faction scheduler.
Definition faction.c:770
int areEnemies(int a, int b)
Checks whether two factions are enemies.
Definition faction.c:1450
int faction_usesHiddenJumps(int f)
Checks to see if a faction uses hidden jumps.
Definition faction.c:2356
int areAllies(int a, int b)
Checks whether two factions are allies or not.
Definition faction.c:1476
int gatherable_getPos(vec2 *pos, vec2 *vel, int id)
Returns the position and velocity of a gatherable.
Definition gatherable.c:197
int gatherable_getClosest(const vec2 *pos, double rad)
Gets the closest gatherable from a given position, within a given radius.
Definition gatherable.c:173
static int aiL_getweaprangemin(lua_State *L)
Gets the minimum range of a weapon set.
Definition ai.c:3186
static int aiL_ismaxvel(lua_State *L)
Checks to see if pilot is at maximum velocity.
Definition ai.c:1689
static int aiL_follow_accurate(lua_State *L)
Computes the point to face in order to follow another pilot using a PD controller.
Definition ai.c:2817
static int aiL_face_accurate(lua_State *L)
Computes the point to face in order to follow a moving object.
Definition ai.c:2873
static int aiL_relhp(lua_State *L)
Gets the relative health (total shields and armour) between the current pilot and the specified targe...
Definition ai.c:3298
static int aiL_sethyptarget(lua_State *L)
Sets hyperspace target.
Definition ai.c:2590
static int aiL_getspobfrompos(lua_State *L)
Get the nearest friendly spob to a given position.
Definition ai.c:2346
static int aiL_getlandspob(lua_State *L)
Get a random friendly spob.
Definition ai.c:2412
static int aiL_accel(lua_State *L)
Starts accelerating the pilot.
Definition ai.c:1804
static int aiL_weapSet(lua_State *L)
Sets the active weapon set, fires another weapon set or activate an outfit.
Definition ai.c:3049
static int aiL_poptask(lua_State *L)
Pops the current running task.
Definition ai.c:1326
static int aiL_iface(lua_State *L)
Maintains an intercept pursuit course.
Definition ai.c:2058
static int aiL_settarget(lua_State *L)
Sets the pilot's target.
Definition ai.c:2959
static int aiL_nearhyptarget(lua_State *L)
Gets the nearest hyperspace target.
Definition ai.c:2626
static int aiL_getrndspob(lua_State *L)
Get a random spob.
Definition ai.c:2386
static int aiL_pilot(lua_State *L)
Gets the AI's pilot. Lua return parameter: Pilot The AI's pilot.
Definition ai.c:1453
static int aiL_minbrakedist(lua_State *L)
Gets the minimum braking distance.
Definition ai.c:1623
static int aiL_gatherablePos(lua_State *L)
Gets the pos and vel of a given gatherable.
Definition ai.c:3023
static int aiL_relvel(lua_State *L)
Gets the relative velocity of a pilot.
Definition ai.c:2774
static int aiL_haslockon(lua_State *L)
Checks to see if pilot has a missile lockon.
Definition ai.c:1763
static int aiL_refuel(lua_State *L)
Attempts to refuel the pilot's target.
Definition ai.c:3323
static int aiL_getdistance2(lua_State *L)
Gets the squared distance from the pointer.
Definition ai.c:1552
static int aiL_getdistance(lua_State *L)
Gets the distance from the pointer.
Definition ai.c:1525
static int aiL_instantJump(lua_State *L)
Checks to see if pilot can instant jump.
Definition ai.c:1677
static int aiL_land(lua_State *L)
Lands on a spob.
Definition ai.c:2474
static int aiL_isenemy(lua_State *L)
Checks to see if target is an enemy.
Definition ai.c:1719
static int aiL_messages(lua_State *L)
Returns and clears the pilots message queue.
Definition ai.c:3448
static int aiL_turn(lua_State *L)
Starts turning the pilot.
Definition ai.c:1817
static int aiL_subtaskname(lua_State *L)
Gets the current subtask's name. Lua return parameter: string The current subtask name or nil if ther...
Definition ai.c:1420
static int aiL_rndhyptarget(lua_State *L)
Gets a random hyperspace target.
Definition ai.c:2676
static int aiL_dir(lua_State *L)
calculates the direction that the target is relative to the current pilot facing.
Definition ai.c:2143
static int aiL_careful_face(lua_State *L)
Gives the direction to follow in order to reach the target while minimizating risk.
Definition ai.c:1927
static int aiL_taskdata(lua_State *L)
Gets the pilot's task data. Lua return parameter: The pilot's task data or nil if there is no task da...
Definition ai.c:1363
static int aiL_hasturrets(lua_State *L)
Does the pilot have turrets?
Definition ai.c:3085
static int aiL_isally(lua_State *L)
Checks to see if target is an ally.
Definition ai.c:1741
static int aiL_hyperspaceAbort(lua_State *L)
Has the AI abandon hyperspace if applicable.
Definition ai.c:2761
static int aiL_relsize(lua_State *L)
Gets the relative size (ship mass) between the current pilot and the specified target.
Definition ai.c:3268
static int aiL_aim(lua_State *L)
Aims at a pilot, trying to hit it rather than move to it.
Definition ai.c:2029
static int aiL_credits(lua_State *L)
Sets the pilots credits. Only call in create().
Definition ai.c:3430
static int aiL_reldps(lua_State *L)
Gets the relative damage output (total DPS) between the current pilot and the specified target.
Definition ai.c:3283
static int aiL_canboard(lua_State *L)
Checks to see if pilot can board the target.
Definition ai.c:3245
static int aiL_idir(lua_State *L)
Calculates angle between pilot facing and intercept-course to target.
Definition ai.c:2174
static int aiL_getnearestpilot(lua_State *L)
gets the nearest pilot to the current pilot
Definition ai.c:1489
static int aiL_hostile(lua_State *L)
Sets the enemy hostile (basically notifies of an impending attack).
Definition ai.c:3170
static int aiL_hascannons(lua_State *L)
Does the pilot have cannons?
Definition ai.c:3073
static int aiL_getBoss(lua_State *L)
Picks a pilot that will command the current pilot.
Definition ai.c:3412
static int aiL_isbribed(lua_State *L)
Checks to see if target has bribed pilot.
Definition ai.c:1663
static int aiL_getGatherable(lua_State *L)
Gets the closest gatherable within a radius.
Definition ai.c:2995
static int aiL_taskname(lua_State *L)
Gets the current task's name. Lua return parameter: string The current task name or nil if there are ...
Definition ai.c:1347
static int aiL_subtaskdata(lua_State *L)
Gets the pilot's subtask target. Lua return parameter: The pilot's target ship identifier or nil if n...
Definition ai.c:1437
static int aiL_hasprojectile(lua_State *L)
Checks to see if pilot has a projectile after him.
Definition ai.c:1776
static int aiL_getweapammo(lua_State *L)
Gets the ammo of a weapon.
Definition ai.c:3231
static int aiL_drift_facing(lua_State *L)
Calculate the offset between the pilot's current direction of travel and the pilot's current facing.
Definition ai.c:2255
static int aiL_shoot_indicator(lua_State *L)
Access the seeker shoot indicator (that is put to true each time a seeker is shot).
Definition ai.c:3378
static int aiL_combat(lua_State *L)
Sets the combat flag.
Definition ai.c:2939
static int aiL_distress(lua_State *L)
Sends a distress signal.
Definition ai.c:3390
static int aiL_settimer(lua_State *L)
Sets a timer.
Definition ai.c:3336
static int aiL_setasterotarget(lua_State *L)
Sets the pilot's asteroid target.
Definition ai.c:2973
static int aiL_getweapspeed(lua_State *L)
Gets the speed of a weapon.
Definition ai.c:3216
static int aiL_getrndpilot(lua_State *L)
Gets a random pilot in the system. Lua return parameter: Pilot|nil.
Definition ai.c:1465
static int aiL_set_shoot_indicator(lua_State *L)
Set the seeker shoot indicator.
Definition ai.c:3365
static int aiL_getenemy(lua_State *L)
Gets the nearest enemy.
Definition ai.c:3123
static int aiL_stealth(lua_State *L)
Tries to stealth or destealth the pilot.
Definition ai.c:3465
static int aiL_pushsubtask(lua_State *L)
Pushes a subtask onto the pilot's task's subtask list. Lua function parameter: string func Name of fu...
Definition ai.c:1379
static int aiL_stop(lua_State *L)
Completely stops the pilot if it is below minimum vel error (no insta-stops).
Definition ai.c:2909
static int aiL_getflybydistance(lua_State *L)
Gets the distance from the pointer perpendicular to the current pilot's flight vector.
Definition ai.c:1580
static int aiL_canHyperspace(lua_State *L)
Gets whether or not the pilot can hyperspace.
Definition ai.c:2750
static int aiL_popsubtask(lua_State *L)
Pops the current running task.
Definition ai.c:1390
static int aiL_face(lua_State *L)
Faces the target.
Definition ai.c:1837
static int aiL_timeup(lua_State *L)
Checks a timer.
Definition ai.c:3352
static int aiL_pushtask(lua_State *L)
Pushes a task onto the pilot's task list. Lua function parameter: string func Name of function to cal...
Definition ai.c:1315
static int aiL_scandone(lua_State *L)
Checks to see if pilot has finished scanning their target.
Definition ai.c:1789
static int aiL_getweaprange(lua_State *L)
Gets the range of a weapon set.
Definition ai.c:3201
static int aiL_dock(lua_State *L)
Docks the ship.
Definition ai.c:2925
static int aiL_outfitOffAll(lua_State *L)
Tries to turn off all outfits.
Definition ai.c:3485
static int aiL_hyperspace(lua_State *L)
Tries to enter hyperspace.
Definition ai.c:2565
static int aiL_hasafterburner(lua_State *L)
Does the pilot have afterburners?
Definition ai.c:3109
static int aiL_board(lua_State *L)
Attempts to board the pilot's target.
Definition ai.c:3311
static int aiL_hasfighterbays(lua_State *L)
Does the pilot have fighter bays?
Definition ai.c:3097
static int aiL_brake(lua_State *L)
Brakes the pilot.
Definition ai.c:2271
static int aiL_getnearestspob(lua_State *L)
Get the nearest friendly spob to the pilot.
Definition ai.c:2307
static int aiL_isstopped(lua_State *L)
Checks to see if pilot is stopped.
Definition ai.c:1706
void naev_renderLoadscreen(void)
Renders the loadscreen if necessary.
Definition naev.c:640
Header file with generic functions and naev-specifics.
#define MIN(x, y)
Definition naev.h:39
#define CLAMP(a, b, x)
Definition naev.h:41
#define ABS(x)
Definition naev.h:32
#define pow2(x)
Definition naev.h:53
#define FABS(x)
Definition naev.h:34
#define MAX(x, y)
Definition naev.h:37
#define PATH_MAX
Definition naev.h:57
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
Definition ndata.c:207
int ndata_matchExt(const char *path, const char *ext)
Sees if a file matches an extension.
Definition ndata.c:420
int nlua_loadStandard(nlua_env env)
Loads the standard Naev Lua API.
Definition nlua.c:914
int nlua_refenvtype(nlua_env env, const char *name, int type)
Gets the reference of a global in a lua environment if it matches a type.
Definition nlua.c:1047
lua_State * naevL
Definition nlua.c:54
int lua_isasteroid(lua_State *L, int ind)
Checks to see if ind is a asteroid.
LuaAsteroid_t * luaL_checkasteroid(lua_State *L, int ind)
Gets asteroid at index or raises error if there is no asteroid at index.
Asteroid * luaL_validasteroid(lua_State *L, int ind)
Gets asteroid at index raising an error if type doesn't match.
LuaJump * luaL_checkjump(lua_State *L, int ind)
Gets jump at index raising an error if isn't a jump.
Definition nlua_jump.c:106
LuaJump * lua_pushjump(lua_State *L, LuaJump jump)
Pushes a jump on the stack.
Definition nlua_jump.c:186
JumpPoint * luaL_validjump(lua_State *L, int ind)
Gets a jump directly.
Definition nlua_jump.c:174
LuaPilot * lua_pushpilot(lua_State *L, LuaPilot pilot)
Pushes a pilot on the stack.
Definition nlua_pilot.c:576
Pilot * luaL_validpilot(lua_State *L, int ind)
Makes sure the pilot is valid or raises a Lua error.
Definition nlua_pilot.c:560
int lua_ispilot(lua_State *L, int ind)
Checks to see if ind is a pilot.
Definition nlua_pilot.c:591
LuaSpob * lua_pushspob(lua_State *L, LuaSpob spob)
Pushes a spob on the stack.
Definition nlua_spob.c:203
Spob * luaL_validspob(lua_State *L, int ind)
Gets a spob directly.
Definition nlua_spob.c:177
int lua_isvector(lua_State *L, int ind)
Checks to see if ind is a vector.
Definition nlua_vec2.c:161
vec2 * luaL_checkvector(lua_State *L, int ind)
Gets vector at index making sure type is valid.
Definition nlua_vec2.c:130
vec2 * lua_tovector(lua_State *L, int ind)
Represents a 2D vector in Lua.
Definition nlua_vec2.c:119
vec2 * lua_pushvector(lua_State *L, vec2 vec)
Pushes a vector on the stack.
Definition nlua_vec2.c:145
int pilot_isHostile(const Pilot *p)
Checks to see if pilot is hostile to the player.
Definition pilot.c:699
int pilot_brakeCheckReverseThrusters(const Pilot *p)
See if the pilot wants to use their reverse thrusters to brake.
Definition pilot.c:838
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:4468
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:291
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:4364
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:4445
void pilot_msg(const Pilot *p, const Pilot *receiver, const char *type, unsigned int idx)
Sends a message.
Definition pilot.c:4531
void pilot_setAccel(Pilot *p, double accel)
Sets the pilot's accel.
Definition pilot.c:680
unsigned int pilot_getNearestEnemy(const Pilot *p)
Gets the nearest enemy to the pilot.
Definition pilot.c:331
void pilot_hyperspaceAbort(Pilot *p)
Stops the pilot from hyperspacing.
Definition pilot.c:3140
void pilot_setTurn(Pilot *p, double turn)
Sets the pilot's turn.
Definition pilot.c:688
int pilot_isFriendly(const Pilot *p)
Checks to see if pilot is friendly to the player.
Definition pilot.c:728
int pilot_refuelStart(Pilot *p)
Attempts to start refueling the pilot's target.
Definition pilot.c:3170
double pilot_minbrakedist(const Pilot *p, double dt, double *flytime)
Gets the minimum braking distance for the pilot.
Definition pilot.c:862
void pilot_setHostile(Pilot *p)
Marks pilot as hostile to player.
Definition pilot.c:1105
static Pilot ** pilot_stack
Definition pilot.c:51
void pilot_distress(Pilot *p, Pilot *attacker, const char *msg)
Has the pilot broadcast a distress signal.
Definition pilot.c:1180
Pilot *const * pilot_getAll(void)
Gets the pilot stack.
Definition pilot.c:93
int pilot_canTarget(const Pilot *p)
Same as pilot_validTarget but without the range check.
Definition pilot.c:270
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:1025
unsigned int pilot_getBoss(const Pilot *p)
Get the strongest ally in a given range.
Definition pilot.c:450
void pilot_setTarget(Pilot *p, unsigned int id)
Sets the target of the pilot.
Definition pilot.c:1352
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:256
int pilot_ewScanCheck(const Pilot *p)
Checks to see if a scan is done.
Definition pilot_ew.c:74
void pilot_destealth(Pilot *p)
Destealths a pilot.
Definition pilot_ew.c:585
int pilot_stealth(Pilot *p)
Stealths a pilot.
Definition pilot_ew.c:543
int pilot_runHook(Pilot *p, int hook_type)
Tries to run a pilot hook if he has it.
Definition pilot_hook.c:104
void pilot_healLanded(Pilot *pilot)
Cures the pilot as if he was landed.
double pilot_weapSetRangeMin(Pilot *p, int id)
Gets the minimum range of the current pilot weapon set.
void pilot_weapSetAIClear(Pilot *p)
Useful function for AI, clears activeness of all weapon sets.
double pilot_weapSetSpeed(Pilot *p, int id)
Gets the speed of the current pilot weapon set.
double pilot_weapSetAmmo(Pilot *p, int id)
Gets the ammo of the current pilot weapon set.
void pilot_weapSetUpdateOutfitState(Pilot *p)
Updates the local state of all the pilot's outfits based on the weapon sets.
double pilot_weapSetRange(Pilot *p, int id)
Gets the range of the current pilot weapon set.
int pilot_weapSetPress(Pilot *p, int id, int type)
Handles a weapon set press.
static const double d[]
Definition rng.c:263
int space_canHyperspace(const Pilot *p)
Checks to make sure if pilot is far enough away to hyperspace.
Definition space.c:494
int spob_index(const Spob *p)
Gets the ID of a spob.
Definition space.c:1158
StarSystem * cur_system
Definition space.c:110
double system_getPresence(const StarSystem *sys, int faction)
Get the presence of a faction in a system.
Definition space.c:4537
int space_hyperspace(Pilot *p)
Tries to get the pilot into hyperspace.
Definition space.c:529
Represents a temporary pilot memory. For use with ai_setPilot and ai_unsetPilot.
Definition ai.h:59
Pilot * p
Definition ai.h:61
int mem
Definition ai.h:60
Basic AI profile.
Definition ai.h:39
int lua_mem
Definition ai.h:43
int ref_refuel
Definition ai.h:46
nlua_env env
Definition ai.h:41
int ref_control
Definition ai.h:44
char * name
Definition ai.h:40
double control_rate
Definition ai.h:42
int ref_create
Definition ai.h:47
int ref_control_manual
Definition ai.h:45
Represents a single asteroid.
Definition asteroid.h:88
The actual hook parameter.
Definition hook.h:40
LuaPilot lp
Definition hook.h:46
HookParamType type
Definition hook.h:41
LuaSpob la
Definition hook.h:52
union HookParam::@065274143236224234262250043114351136253171035204 u
double num
Definition hook.h:43
Lua jump Wrapper.
Definition nlua_jump.h:14
int destid
Definition nlua_jump.h:16
int srcid
Definition nlua_jump.h:15
The representation of an in-game pilot.
Definition pilot.h:263
AI_Profile * ai
Definition pilot.h:408
unsigned int id
Definition pilot.h:264
int faction
Definition pilot.h:269
Solid solid
Definition pilot.h:275
char * name
Definition pilot.h:265
Task * task
Definition pilot.h:412
vec2 vel
Definition physics.h:48
vec2 pos
Definition physics.h:49
int faction
Definition space.h:79
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition space.h:102
int lua_land
Definition space.h:170
double radius
Definition space.h:110
nlua_env lua_env
Definition space.h:164
char * name
Definition space.h:105
vec2 pos
Definition space.h:109
int id
Definition space.h:104
int lua_can_land
Definition space.h:169
SpobPresence presence
Definition space.h:121
Basic AI task.
Definition ai.h:23
int func
Definition ai.h:26
char * name
Definition ai.h:25
struct Task_ * subtask
Definition ai.h:29
struct Task_ * next
Definition ai.h:24
int done
Definition ai.h:27
int dat
Definition ai.h:31
Definition msgcat.c:196
Represents a 2d vector.
Definition vec2.h:45
double y
Definition vec2.h:47
double x
Definition vec2.h:46