79#include "gatherable.h"
84#include "nlua_asteroid.h"
85#include "nlua_pilot.h"
101#define ai_setFlag( f ) ( pilot_flags |= f )
102#define ai_isFlag( f ) ( pilot_flags & f )
104#define AI_DISTRESS ( 1 << 0 )
118static void ai_run( nlua_env env,
int nargs );
123static int ai_sort(
const void *p1,
const void *p2 );
171static int aiL_aim( lua_State *L );
172static int aiL_dir( lua_State *L );
350#define AI_STATUS_NORMAL 1
351#define AI_STATUS_CREATE 2
363 while ( t != NULL ) {
373 pointer->
next = NULL;
402 nlua_getenv(
naevL, env,
"mem" );
403 oldmem = luaL_ref(
naevL, LUA_REGISTRYINDEX );
406 nlua_setenv(
naevL, env,
"mem" );
431 lua_rawgeti(
naevL, LUA_REGISTRYINDEX, oldmem.
mem );
432 nlua_setenv(
naevL, env,
"mem" );
433 luaL_unref(
naevL, LUA_REGISTRYINDEX, oldmem.
mem );
457 pilot_acc =
CLAMP( -PILOT_REVERSE_THRUST * p->stats.misc_reverse_thrust, 1.,
476static void ai_run( nlua_env env,
int nargs )
478 if ( nlua_pcall( env, nargs, 0 ) ) {
479 WARN( _(
"Pilot '%s' ai '%s' error: %s" ),
cur_pilot->name,
499 strncpy( buf, ai,
sizeof( buf ) - 1 );
500 buf[
sizeof( buf ) - 1] =
'\0';
504 if ( prof == NULL ) {
505 WARN( _(
"AI Profile '%s' not found, using dummy fallback." ), buf );
508 if ( prof == NULL ) {
509 WARN( _(
"Dummy AI Profile not valid! Things are going to break." ) );
515 lua_newtable(
naevL );
519 lua_pushnil(
naevL );
520 while ( lua_next(
naevL, -2 ) != 0 ) {
521 lua_pushvalue(
naevL, -2 );
522 lua_pushvalue(
naevL, -2 );
523 lua_remove(
naevL, -3 );
524 lua_settable(
naevL, -5 );
527 p->lua_mem = luaL_ref(
naevL, LUA_REGISTRYINDEX );
531 pilot_setFlag( p, PILOT_CREATED_AI );
538 p->tcontrol = RNGF() * p->ai->control_rate;
567 if ( !pilot_isPlayer( p ) ) {
569 luaL_unref(
naevL, LUA_REGISTRYINDEX, p->lua_mem );
570 p->lua_mem = LUA_NOREF;
577static int ai_sort(
const void *p1,
const void *p2 )
581 return strcmp( ai1->
name, ai2->
name );
593 Uint32 time = SDL_GetTicks();
596 NTracingZone( _ctx, 1 );
599 files = PHYSFS_enumerateFiles( AI_PATH );
605 for (
size_t i = 0; files[i] != NULL; i++ ) {
613 snprintf( path,
sizeof( path ), AI_PATH
"%s", files[i] );
618 WARN( _(
"Error loading AI profile '%s'" ), path );
626 PHYSFS_freeList( files );
629 if ( conf.devmode ) {
630 time = SDL_GetTicks() - time;
631 DEBUG( n_(
"Loaded %d AI Profile in %.3f s",
635 DEBUG( n_(
"Loaded %d AI Profile",
"Loaded %d AI Profiles",
646 NTracingZoneEnd( _ctx );
658 const char *filename = AI_EQUIP_PATH;
660 NTracingZone( _ctx, 1 );
671 if ( nlua_dobufenv(
equip_env, buf, bufsize, filename ) != 0 ) {
672 WARN( _(
"Error loading file: %s\n"
674 "Most likely Lua file has improper syntax, please check" ),
675 filename, lua_tostring(
naevL, -1 ) );
676 NTracingZoneEnd( _ctx );
681 NTracingZoneEnd( _ctx );
686int nlua_loadAI( nlua_env env )
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';
714 env = nlua_newEnv( filename );
722 lua_pushboolean(
naevL, 1 );
723 nlua_setenv(
naevL, env,
"__ai" );
726 lua_newtable(
naevL );
727 lua_pushvalue(
naevL, -1 );
729 nlua_setenv(
naevL, env,
"mem" );
733 if ( nlua_dobufenv( env, buf, bufsize, filename ) != 0 ) {
734 WARN( _(
"Error loading AI file: %s\n"
736 "Most likely Lua file has improper syntax, please check" ),
737 filename, lua_tostring(
naevL, -1 ) );
746 str = _(
"AI Profile '%s' is missing '%s' function!" );
749 WARN( str, filename,
"control" );
753 WARN( str, filename,
"control_manual" );
756 WARN( str, filename,
"refuel" );
759 WARN( str, filename,
"create" );
762 nlua_getenv(
naevL, env,
"control_rate" );
777 const AI_Profile ai = { .name = (
char *)name };
781 WARN( _(
"AI Profile '%s' not found in AI stack" ), name );
819 if ( pilot->
ai == NULL )
822 NTracingZone( _ctx, 1 );
828 pilot_rmFlag( pilot, PILOT_SCANNING );
844 if ( (
cur_pilot->tcontrol < 0. ) || ( t == NULL ) ) {
845 NTracingZoneName( _ctx_control,
"ai_think[control]", 1 );
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,
855 lua_rawgeti(
naevL, LUA_REGISTRYINDEX,
cur_pilot->ai->ref_control );
860 cur_pilot->tcontrol = crate * ( 0.9 + 0.2 * RNGF() );
865 NTracingZoneEnd( _ctx_control );
870 NTracingZoneEnd( _ctx );
877 NTracingZoneName( _ctx_task,
"ai_think[task]", 1 );
881 lua_rawgeti(
naevL, LUA_REGISTRYINDEX, t->
subtask->func );
884 if ( data == LUA_NOREF )
887 lua_rawgeti(
naevL, LUA_REGISTRYINDEX, t->
func );
891 if ( data != LUA_NOREF ) {
892 lua_rawgeti(
naevL, LUA_REGISTRYINDEX, data );
898 if ( pilot_isFlag(
cur_pilot, PILOT_MANUAL_CONTROL ) ) {
905 NTracingZoneEnd( _ctx_task );
921 NTracingZoneEnd( _ctx );
931 NTracingZone( _ctx, 1 );
934 if ( ( p->ai == NULL ) || ( p->ai->ref_create == LUA_NOREF ) )
937 lua_rawgeti(
naevL, LUA_REGISTRYINDEX, p->ai->ref_create );
941 NTracingZoneEnd( _ctx );
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;
963 pilot_runHookParam( attacked, PILOT_HOOK_ATTACKED, hparam, 2 );
966 if ( attacked->
ai == NULL )
970 if ( pilot_isFlag( attacked, PILOT_MANUAL_CONTROL ) )
976 if ( nlua_pcall(
cur_pilot->ai->env, 1, 0 ) ) {
977 WARN( _(
"Pilot '%s' ai '%s' -> 'attacked': %s" ),
cur_pilot->name,
995 if ( pilot_isFlag( discovered, PILOT_MANUAL_CONTROL ) )
999 if ( discovered->
ai == NULL )
1006 if ( lua_isnil(
naevL, -1 ) ) {
1007 lua_pop(
naevL, 1 );
1012 if ( nlua_pcall(
cur_pilot->ai->env, 0, 0 ) ) {
1013 WARN( _(
"Pilot '%s' ai '%s' -> 'discovered': %s" ),
cur_pilot->name,
1015 lua_pop(
naevL, 1 );
1034 if ( recipient->
ai == NULL )
1041 if ( lua_isnil(
naevL, -1 ) ) {
1042 lua_pop(
naevL, 1 );
1047 if ( nlua_pcall(
cur_pilot->ai->env, 0, 0 ) ) {
1048 WARN( _(
"Pilot '%s' ai '%s' -> 'hail': %s" ),
cur_pilot->name,
1050 lua_pop(
naevL, 1 );
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!" ),
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 );
1078 t->
dat = luaL_ref(
naevL, LUA_REGISTRYINDEX );
1095 const Pilot *attacker )
1098 if ( pilot_isFlag( p, PILOT_MANUAL_CONTROL ) )
1105 if ( attacker != NULL )
1108 lua_pushnil(
naevL );
1109 pilot_msg( distressed, p,
"distress", -1 );
1110 lua_pop(
naevL, 1 );
1122 NTracingZone( _ctx, 1 );
1125 if ( !pilot_isFlag( pilot, PILOT_CREATED_AI ) )
1129 if ( !pilot_isFlag( pilot, PILOT_NO_OUTFITS ) &&
1130 !pilot_isFlag( pilot, PILOT_NO_EQUIP ) &&
1133 char *func =
"equip_generic";
1139 nlua_getenv(
naevL, env, func );
1141 if ( nlua_pcall( env, 1, 0 ) ) {
1142 WARN( _(
"Pilot '%s' equip '%s' -> '%s': %s" ), pilot->
name,
1143 pilot->
ai->
name, func, lua_tostring(
naevL, -1 ) );
1144 lua_pop(
naevL, 1 );
1152 if ( pilot->
ai == NULL ) {
1153 NTracingZoneEnd( _ctx );
1161 if ( !pilot_isFlag( pilot, PILOT_CREATED_AI ) )
1163 NTracingZoneEnd( _ctx );
1174 if ( p->ai == NULL ) {
1176 L, _(
"Trying to create new task for pilot '%s' that has no AI!" ),
1182 nlua_getenv( L, p->ai->env, func );
1183 luaL_checktype( L, -1, LUA_TFUNCTION );
1186 t = ncalloc( 1,
sizeof(
Task ) );
1187 t->
name = strdup( func );
1188 t->
func = luaL_ref( L, LUA_REGISTRYINDEX );
1193 if ( ( pos == 1 ) && ( p->task != NULL ) ) {
1194 for ( pointer = p->task; pointer->next != NULL;
1195 pointer = pointer->next )
1205 if ( curtask == NULL ) {
1207 NLUA_ERROR( L, _(
"Trying to add subtask '%s' to non-existent task." ),
1213 if ( ( pos == 1 ) && ( curtask->
subtask != NULL ) ) {
1214 for ( pointer = curtask->
subtask; pointer->next != NULL;
1215 pointer = pointer->next )
1234 if ( t->
func != LUA_NOREF )
1235 luaL_unref(
naevL, LUA_REGISTRYINDEX, t->
func );
1237 if ( t->
dat != LUA_NOREF )
1238 luaL_unref(
naevL, LUA_REGISTRYINDEX, t->
dat );
1247 if ( t->
next != NULL ) {
1262 const char *func = luaL_checkstring( L, 1 );
1265 !pilot_isFlag(
cur_pilot, PILOT_MANUAL_CONTROL ) )
1271 NLUA_ERROR( L, _(
"Failed to create new task for pilot '%s'." ),
1277 if ( lua_gettop( L ) > 1 ) {
1278 lua_pushvalue( L, 2 );
1279 t->
dat = luaL_ref( L, LUA_REGISTRYINDEX );
1290 if ( t->
dat == LUA_NOREF )
1292 lua_rawgeti( L, LUA_REGISTRYINDEX, t->
dat );
1333 L, _(
"Trying to pop task when there are no tasks on the stack." ) );
1352 lua_pushstring( L, t->
name );
1398 L, _(
"Trying to pop task when there are no tasks on the stack." ) );
1400 return NLUA_ERROR( L,
1401 _(
"Trying to pop subtask when there are no subtasks "
1402 "for the task '%s'." ),
1423 if ( ( t != NULL ) && ( t->
subtask != NULL ) )
1424 lua_pushstring( L, t->
subtask->name );
1441 if ( ( t == NULL ) || ( t->
subtask == NULL ) )
1495 int candidate_id = -1;
1510 if ( candidate_id == -1 )
1539 NLUA_INVALID_PARAMETER( L, 1 );
1541 lua_pushnumber( L, vec2_dist( v, &
cur_pilot->solid.pos ) );
1566 NLUA_INVALID_PARAMETER( L, 1 );
1568 lua_pushnumber( L, vec2_dist2( v, &
cur_pilot->solid.pos ) );
1583 vec2 perp_motion_unit, offset_vect;
1584 int offset_distance;
1597 NLUA_INVALID_PARAMETER( L, 1 );
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 );
1604 lua_pushnumber( L, offset_distance );
1626 if ( lua_gettop( L ) > 0 ) {
1627 double time, dist, vel;
1632 vec2_cset( &vv, p->solid.vel.
x -
cur_pilot->solid.vel.x,
1633 p->solid.vel.y -
cur_pilot->solid.vel.y );
1639 vel =
MIN(
cur_pilot->speed - VMOD( p->solid.vel ), VMOD( vv ) );
1644 dist = vel * (flytime)-0.5 * (
cur_pilot->accel ) * time * time;
1645 lua_pushnumber( L, dist );
1646 lua_pushnumber( L, flytime );
1650 lua_pushnumber( L, dist );
1651 lua_pushnumber( L, flytime );
1666 lua_pushboolean( L, pilot_isWithPlayer( p ) &&
1667 pilot_isFlag(
cur_pilot, PILOT_BRIBED ) );
1679 lua_pushboolean( L,
cur_pilot->stats.misc_instant_jump );
1693 lua_pushboolean( L, ( VMOD(
cur_pilot->solid.vel ) >
1708 lua_pushboolean( L, ( VMOD(
cur_pilot->solid.vel ) < MIN_VEL_ERR ) );
1724 if ( pilot_isWithPlayer( p ) ) {
1746 if ( pilot_isWithPlayer( p ) ) {
1765 lua_pushboolean( L,
cur_pilot->lockons > 0 );
1778 lua_pushboolean( L,
cur_pilot->projectiles > 0 );
1806 double n = luaL_optnumber( L, 1, 1. );
1840 double k_diff, k_vel, diff, vx, vy, dx, dy;
1848 if ( lua_toboolean( L, 2 ) )
1856 }
else if ( lua_isnumber( L, 1 ) ) {
1857 double d = lua_tonumber( L, 1 );
1858 diff = angle_diff(
cur_pilot->solid.dir,
d );
1862 lua_pushnumber( L,
ABS( diff ) );
1867 NLUA_INVALID_PARAMETER( L, 1 );
1870 vel = lua_toboolean( L, 3 );
1887 if ( vel && ( dx || dy ) ) {
1889 double d = ( vx * dx + vy * dy ) / ( dx * dx + dy * dy );
1900 diff = angle_diff(
cur_pilot->solid.dir, atan2( dy, dx ) );
1906 lua_pushnumber( L,
ABS( diff ) );
1931 double d, diff, dist;
1937 const double k_goal = 1.;
1938 const double k_enemy = 6e6;
1949 }
else if ( lua_isnumber( L, 1 ) ) {
1950 d = (double)lua_tonumber( L, 1 );
1954 NLUA_INVALID_PARAMETER( L, 1 );
1958 NLUA_INVALID_PARAMETER( L, 1 );
1961 vec2_csetmin( &F, 0., 0. );
1962 vec2_cset( &F1, tv->
x -
cur_pilot->solid.pos.x,
1964 dist = VMOD( F1 ) + 0.1;
1965 vec2_cset( &F1, F1.
x * k_goal / dist, F1.
y * k_goal / dist );
1974 pilot_collideQueryIL( &
ai_qtquery, x - r, y - r, x + r, y + r );
1975 for (
int i = 0; i < il_size( &
ai_qtquery ); i++ ) {
1982 if ( p_i->
id == p->id )
1984 if ( pilot_isDisabled( p_i ) )
1990 if ( dist <
pow2( 750. ) )
1992 dist = sqrt( dist );
1998 double factor = k_enemy * k_mult / ( dist * dist * dist );
2005 vec2_cset( &F, F.x + F1.
x, F.y + F1.
y );
2008 diff = angle_diff(
cur_pilot->solid.dir, VANGLE( F ) );
2014 lua_pushnumber( L,
ABS( diff ) );
2031 double diff, mod, angle;
2043 diff = angle_diff(
cur_pilot->solid.dir, angle );
2046 lua_pushnumber( L,
ABS( diff ) );
2061 vec2 *vec, drift, reference_vector;
2063 double diff, heading_offset_azimuth, drift_radial, drift_azimuthal;
2073 NLUA_INVALID_PARAMETER( L, 1 );
2075 if ( vec == NULL ) {
2080 vec2_cset( &drift, VX( p->solid.vel ) - VX(
cur_pilot->solid.vel ),
2081 VY( p->solid.vel ) - VY(
cur_pilot->solid.vel ) );
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 ) );
2088 vec2_cset( &drift, -VX(
cur_pilot->solid.vel ),
2091 vec2_cset( &reference_vector, VX( *vec ) - VX(
cur_pilot->solid.pos ),
2092 VY( *vec ) - VY(
cur_pilot->solid.pos ) );
2096 vec2_uv( &drift_radial, &drift_azimuthal, &drift, &reference_vector );
2097 heading_offset_azimuth =
2098 angle_diff(
cur_pilot->solid.dir, VANGLE( reference_vector ) );
2104 if (
FABS( heading_offset_azimuth ) < M_PI_2 ) {
2112 -copysign( 1. - 1. / (
FABS( drift_azimuthal / 200. ) + 1. ),
2115 diff = angle_diff( heading_offset_azimuth, speedmap );
2131 lua_pushnumber( L,
ABS( diff ) );
2152 vec2_cset( &tv, VX( p->solid.pos ), VY( p->solid.pos ) );
2153 diff = angle_diff(
cur_pilot->solid.dir, vec2_angle( &sv, &tv ) );
2156 diff = angle_diff(
cur_pilot->solid.dir,
2157 vec2_angle( &
cur_pilot->solid.pos, vec ) );
2159 NLUA_INVALID_PARAMETER( L, 1 );
2162 lua_pushnumber( L, diff );
2177 vec2 *vec, drift, reference_vector;
2179 double diff, heading_offset_azimuth, drift_radial, drift_azimuthal;
2189 NLUA_INVALID_PARAMETER( L, 1 );
2191 if ( vec == NULL ) {
2196 vec2_cset( &drift, VX( p->solid.vel ) - VX(
cur_pilot->solid.vel ),
2197 VY( p->solid.vel ) - VY(
cur_pilot->solid.vel ) );
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 ) );
2204 vec2_cset( &drift, -VX(
cur_pilot->solid.vel ),
2207 vec2_cset( &reference_vector, VX( *vec ) - VX(
cur_pilot->solid.pos ),
2208 VY( *vec ) - VY(
cur_pilot->solid.pos ) );
2212 vec2_uv( &drift_radial, &drift_azimuthal, &drift, &reference_vector );
2213 heading_offset_azimuth =
2214 angle_diff(
cur_pilot->solid.dir, VANGLE( reference_vector ) );
2220 if (
FABS( heading_offset_azimuth ) < M_PI_2 ) {
2228 -copysign( 1. - 1. / (
FABS( drift_azimuthal / 200. ) + 1. ),
2231 diff = -angle_diff( heading_offset_azimuth, speedmap );
2240 diff = heading_offset_azimuth;
2244 lua_pushnumber( L, diff );
2259 lua_pushnumber( L, drift );
2273 double dir, accel, diff;
2274 int isstopped = pilot_isStopped(
cur_pilot );
2276 lua_toboolean( L, 1 ) *
cur_pilot->stats.misc_reverse_thrust;
2279 lua_pushboolean( L, 1 );
2285 accel = -PILOT_REVERSE_THRUST;
2287 dir = VANGLE(
cur_pilot->solid.vel ) + M_PI;
2291 diff = angle_diff(
cur_pilot->solid.dir, dir );
2293 if (
ABS( diff ) < MIN_DIR_ERR )
2297 lua_pushboolean( L, 0 );
2317 if ( !spob_hasService(
cur_system->spobs[i], SPOB_SERVICE_INHABITED ) )
2321 cur_system->spobs[i]->presence.faction ) ) &&
2358 if ( !spob_hasService(
cur_system->spobs[i], SPOB_SERVICE_INHABITED ) )
2362 cur_system->spobs[i]->presence.faction ) ) &&
2421 if ( pilot_isFlag(
cur_pilot, PILOT_NOLAND ) )
2425 only_friend = lua_toboolean( L, 1 );
2434 if ( !spob_hasService( pnt, SPOB_SERVICE_LAND ) )
2436 if ( !spob_hasService( pnt, SPOB_SERVICE_INHABITED ) )
2479 if ( !lua_isnoneornil( L, 1 ) ) {
2490 return NLUA_ERROR( L, _(
"Spob '%s' not found in system '%s'" ),
2497 return NLUA_ERROR( L, _(
"Pilot '%s' (ai '%s') has no land target" ),
2505 !spob_hasService( spob, SPOB_SERVICE_LAND ) ) {
2506 lua_pushboolean( L, 0 );
2516 if ( pilot_isFlag(
cur_pilot, PILOT_NOLAND ) ) {
2517 lua_pushboolean( L, 0 );
2524 lua_pushboolean( L, 0 );
2529 if ( vec2_odist2( &
cur_pilot->solid.vel ) >
pow2( MAX_HYPERSPACE_VEL ) ) {
2530 lua_pushboolean( L, 0 );
2534 if ( spob->
lua_land == LUA_NOREF ) {
2536 PILOT_LANDING_DELAY *
cur_pilot->ship->dt_default;
2538 pilot_setFlag(
cur_pilot, PILOT_LANDING );
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 );
2550 hparam.
type = HOOK_PARAM_SPOB;
2551 hparam.
u.
la = spob->
id;
2553 pilot_runHookParam(
cur_pilot, PILOT_HOOK_LAND, &hparam, 1 );
2554 lua_pushboolean( L, 1 );
2570 if ( !lua_isnoneornil( L, 1 ) ) {
2574 return NLUA_ERROR( L, _(
"Jump point must be in current system." ) );
2579 lua_pushnumber( L, canjump );
2592 const JumpPoint *jp;
2601 return NLUA_ERROR( L, _(
"Jump point must be in current system." ) );
2607 a = RNGF() * M_PI * 2.;
2608 rad = RNGF() * 0.5 * jp->radius;
2609 vec2_cadd( &vec, rad * cos( a ), rad * sin( a ) );
2628 const JumpPoint *jp;
2629 double mindist, dist;
2636 const JumpPoint *jiter = &
cur_system->jumps[i];
2640 if ( jp_isFlag( jiter, JP_EXITONLY ) )
2644 if ( !useshidden && jp_isFlag( jiter, JP_HIDDEN ) )
2652 dist = vec2_dist2( &
cur_pilot->solid.pos, &jiter->pos );
2653 if ( dist < mindist ) {
2662 lj.
destid = jp->targetid;
2696 if ( ( !useshidden && jp_isFlag( jiter, JP_HIDDEN ) ) ||
2697 jp_isFlag( jiter, JP_EXITONLY ) )
2714 if ( ( !useshidden && jp_isFlag( jiter, JP_HIDDEN ) ) ||
2715 jp_isFlag( jiter, JP_EXITONLY ) )
2724 NLUA_WARN( L, _(
"Pilot '%s' can't find jump to leave system!" ),
2732 lj.
destid = jumps[r]->targetid;
2781 if ( lua_gettop( L ) > 1 )
2782 absolute = lua_toboolean( L, 2 );
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 );
2791 vec2_cset( &vv, p->solid.vel.
x, p->solid.vel.y );
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. );
2798 lua_pushnumber( L, dot / mod );
2819 vec2 point, cons, goal, pv;
2820 double radius, angle, Kp, Kd, angle2;
2821 const Pilot *p, *target;
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" );
2832 if ( strcmp( method,
"absolute" ) == 0 )
2834 else if ( strcmp( method,
"keepangle" ) == 0 ) {
2835 vec2_cset( &pv, p->solid.pos.
x - target->
solid.
pos.
x,
2837 angle2 = VANGLE( pv );
2839 angle2 = angle + VANGLE( target->
solid.
vel );
2841 vec2_cset( &point, VX( target->
solid.
pos ) + radius * cos( angle2 ),
2842 VY( target->
solid.
pos ) + radius * sin( angle2 ) );
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 );
2851 vec2_cset( &goal, cons.
x + p->solid.pos.x, cons.
y + p->solid.pos.y );
2875 vec2 point, cons, goal, *pos, *vel;
2876 double radius, angle, Kp, Kd;
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. );
2886 vec2_cset( &point, pos->
x + radius * cos( angle ),
2887 pos->
y + radius * sin( angle ) );
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 );
2895 vec2_cset( &goal, cons.
x + p->solid.pos.x, cons.
y + p->solid.pos.y );
2913 if ( VMOD(
cur_pilot->solid.vel ) < MIN_VEL_ERR )
2914 vec2_pset( &
cur_pilot->solid.vel, 0., 0. );
2941 if ( lua_gettop( L ) > 0 ) {
2942 int i = lua_toboolean( L, 1 );
2944 pilot_setFlag(
cur_pilot, PILOT_COMBAT );
2946 pilot_rmFlag(
cur_pilot, PILOT_COMBAT );
2948 pilot_setFlag(
cur_pilot, PILOT_COMBAT );
3000 if ( ( lua_gettop( L ) < 1 ) || lua_isnil( L, 1 ) )
3003 rad = lua_tonumber( L, 1 );
3008 lua_pushnumber( L, i );
3028 i = lua_tointeger( L, 1 );
3052 id = luaL_checkinteger( L, 1 ) - 1;
3054 if ( lua_gettop( L ) > 1 )
3055 type = lua_toboolean( L, 2 );
3075 lua_pushboolean( L,
cur_pilot->ncannons > 0 );
3087 lua_pushboolean( L,
cur_pilot->nturrets > 0 );
3099 lua_pushboolean( L,
cur_pilot->nfighterbays > 0 );
3111 lua_pushboolean( L,
cur_pilot->nafterburners > 0 );
3125 if ( lua_isnoneornil( L, 1 ) ) {
3132 double range = luaL_checknumber( L, 1 );
3133 double r2 =
pow2( range );
3134 unsigned int tp = 0;
3142 pilot_collideQueryIL( &
ai_qtquery, x - r, y - r, x + r, y + r );
3143 for (
int i = 0; i < il_size( &
ai_qtquery ); i++ ) {
3147 if ( vec2_dist2( &p->solid.pos, &
cur_pilot->solid.pos ) > r2 )
3154 td = vec2_dist2( &p->solid.pos, &
cur_pilot->solid.pos );
3155 if ( !tp || ( td <
d ) ) {
3173 if ( pilot_isWithPlayer( p ) )
3188 int id = luaL_checkinteger( L, 1 ) - 1;
3203 int id = luaL_checkinteger( L, 1 ) - 1;
3218 int id = luaL_checkinteger( L, 1 ) - 1;
3233 int id = luaL_checkinteger( L, 1 ) - 1;
3250 if ( !pilot_isDisabled( p ) ) {
3251 lua_pushboolean( L, 0 );
3256 lua_pushboolean( L, !pilot_isFlag( p, PILOT_BOARDED ) );
3338 int n = luaL_checkint( L, 1 );
3340 cur_pilot->timer[n] = luaL_optnumber( L, 2, 0. );
3354 int n = luaL_checkint( L, 1 );
3355 lua_pushboolean( L,
cur_pilot->timer[n] <= 0. );
3367 cur_pilot->shoot_indicator = lua_toboolean( L, 1 );
3380 lua_pushboolean( L,
cur_pilot->shoot_indicator );
3392 if ( lua_isstring( L, 1 ) )
3394 lua_tostring( L, 1 ) );
3395 else if ( lua_isnoneornil( L, 1 ) )
3398 NLUA_INVALID_PARAMETER( L, 1 );
3437 cur_pilot->credits = luaL_checklong( L, 1 );
3450 lua_rawgeti( L, LUA_REGISTRYINDEX,
cur_pilot->messages );
3452 lua_rawseti( L, LUA_REGISTRYINDEX,
cur_pilot->messages );
3468 if ( lua_gettop( L ) > 0 )
3469 b = lua_toboolean( L, 1 );
3473 lua_pushboolean( L, 1 );
3489 cur_pilot->outfits[i]->flags &= ~PILOTOUTFIT_ISON_TOGGLE;
static int ai_setMemory(void)
Sets the cur_pilot's ai.
Task * ai_newtask(lua_State *L, Pilot *p, const char *func, int subtask, int pos)
Creates a new AI task.
void ai_unsetPilot(AIMemory oldmem)
Finishes setting up a pilot.
static nlua_env equip_env
void ai_thinkApply(Pilot *p)
Applies the result of thinking.
static AI_Profile * profiles
static IntList ai_qtquery
Task * ai_curTask(Pilot *pilot)
Gets the current running task.
void ai_refuel(Pilot *refueler, unsigned int target)
Has a pilot attempt to refuel the other.
static const luaL_Reg aiL_methods[]
static int ai_loadProfile(AI_Profile *prof, const char *filename)
Initializes an AI_Profile and adds it to the stack.
static void ai_create(Pilot *pilot)
Runs the create() function in the pilot.
void ai_cleartasks(Pilot *p)
Clears the pilot's tasks.
static int ai_tasktarget(lua_State *L, const Task *t)
Pushes a task target.
void ai_freetask(Task *t)
Frees an AI task.
void ai_think(Pilot *pilot, double dt, int dotask)
Heart of the AI, brains of the pilot.
void ai_thinkSetup(double dt)
Sets up the pilot for thinking.
void ai_getDistress(const Pilot *p, const Pilot *distressed, const Pilot *attacker)
Sends a distress signal to a pilot.
AIMemory ai_setPilot(Pilot *p)
Sets the pilot for further AI calls.
static Task * ai_createTask(lua_State *L, int subtask)
Creates a new task based on stack information.
static void ai_run(nlua_env env, int nargs)
Attempts to run a function.
static char aiL_distressmsg[STRMAX_SHORT]
void ai_attacked(Pilot *attacked, const unsigned int attacker, double dmg)
Triggers the attacked() function in the pilot's AI.
void ai_destroy(Pilot *p)
Destroys the ai part of the pilot.
void ai_hail(Pilot *recipient)
Triggers the hail() function in the pilot's AI.
void ai_discovered(Pilot *discovered)
Triggers the discovered() function in the pilot's AI.
void ai_exit(void)
Cleans up global AI.
static int ai_loadEquip(void)
Loads the equipment selector script.
void ai_init(Pilot *p)
Initializes the AI.
static void ai_taskGC(Pilot *pilot)
Runs the garbage collector on the pilot's tasks.
int ai_pinit(Pilot *p, const char *ai)
Initializes the pilot in the ai.
int ai_load(void)
Initializes the AI stuff which is basically Lua.
AI_Profile * ai_getProfile(const char *name)
Gets the AI_Profile by name.
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
int pilot_board(Pilot *p)
Has a pilot attempt to board another pilot.
nlua_env faction_getEquipper(int f)
Gets the equipper state associated to the faction scheduler.
int areEnemies(int a, int b)
Checks whether two factions are enemies.
int faction_usesHiddenJumps(int f)
Checks to see if a faction uses hidden jumps.
int areAllies(int a, int b)
Checks whether two factions are allies or not.
int gatherable_getPos(vec2 *pos, vec2 *vel, int id)
Returns the position and velocity of a gatherable.
int gatherable_getClosest(const vec2 *pos, double rad)
Gets the closest gatherable from a given position, within a given radius.
static int aiL_getweaprangemin(lua_State *L)
Gets the minimum range of a weapon set.
static int aiL_ismaxvel(lua_State *L)
Checks to see if pilot is at maximum velocity.
static int aiL_follow_accurate(lua_State *L)
Computes the point to face in order to follow another pilot using a PD controller.
static int aiL_face_accurate(lua_State *L)
Computes the point to face in order to follow a moving object.
static int aiL_relhp(lua_State *L)
Gets the relative health (total shields and armour) between the current pilot and the specified targe...
static int aiL_sethyptarget(lua_State *L)
Sets hyperspace target.
static int aiL_getspobfrompos(lua_State *L)
Get the nearest friendly spob to a given position.
static int aiL_getlandspob(lua_State *L)
Get a random friendly spob.
static int aiL_accel(lua_State *L)
Starts accelerating the pilot.
static int aiL_weapSet(lua_State *L)
Sets the active weapon set, fires another weapon set or activate an outfit.
static int aiL_poptask(lua_State *L)
Pops the current running task.
static int aiL_iface(lua_State *L)
Maintains an intercept pursuit course.
static int aiL_settarget(lua_State *L)
Sets the pilot's target.
static int aiL_nearhyptarget(lua_State *L)
Gets the nearest hyperspace target.
static int aiL_getrndspob(lua_State *L)
Get a random spob.
static int aiL_pilot(lua_State *L)
Gets the AI's pilot. Lua return parameter: Pilot The AI's pilot.
static int aiL_minbrakedist(lua_State *L)
Gets the minimum braking distance.
static int aiL_gatherablePos(lua_State *L)
Gets the pos and vel of a given gatherable.
static int aiL_relvel(lua_State *L)
Gets the relative velocity of a pilot.
static int aiL_haslockon(lua_State *L)
Checks to see if pilot has a missile lockon.
static int aiL_refuel(lua_State *L)
Attempts to refuel the pilot's target.
static int aiL_getdistance2(lua_State *L)
Gets the squared distance from the pointer.
static int aiL_getdistance(lua_State *L)
Gets the distance from the pointer.
static int aiL_instantJump(lua_State *L)
Checks to see if pilot can instant jump.
static int aiL_land(lua_State *L)
Lands on a spob.
static int aiL_isenemy(lua_State *L)
Checks to see if target is an enemy.
static int aiL_messages(lua_State *L)
Returns and clears the pilots message queue.
static int aiL_turn(lua_State *L)
Starts turning the pilot.
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...
static int aiL_rndhyptarget(lua_State *L)
Gets a random hyperspace target.
static int aiL_dir(lua_State *L)
calculates the direction that the target is relative to the current pilot facing.
static int aiL_careful_face(lua_State *L)
Gives the direction to follow in order to reach the target while minimizating risk.
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...
static int aiL_hasturrets(lua_State *L)
Does the pilot have turrets?
static int aiL_isally(lua_State *L)
Checks to see if target is an ally.
static int aiL_hyperspaceAbort(lua_State *L)
Has the AI abandon hyperspace if applicable.
static int aiL_relsize(lua_State *L)
Gets the relative size (ship mass) between the current pilot and the specified target.
static int aiL_aim(lua_State *L)
Aims at a pilot, trying to hit it rather than move to it.
static int aiL_credits(lua_State *L)
Sets the pilots credits. Only call in create().
static int aiL_reldps(lua_State *L)
Gets the relative damage output (total DPS) between the current pilot and the specified target.
static int aiL_canboard(lua_State *L)
Checks to see if pilot can board the target.
static int aiL_idir(lua_State *L)
Calculates angle between pilot facing and intercept-course to target.
static int aiL_getnearestpilot(lua_State *L)
gets the nearest pilot to the current pilot
static int aiL_hostile(lua_State *L)
Sets the enemy hostile (basically notifies of an impending attack).
static int aiL_hascannons(lua_State *L)
Does the pilot have cannons?
static int aiL_getBoss(lua_State *L)
Picks a pilot that will command the current pilot.
static int aiL_isbribed(lua_State *L)
Checks to see if target has bribed pilot.
static int aiL_getGatherable(lua_State *L)
Gets the closest gatherable within a radius.
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 ...
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...
static int aiL_hasprojectile(lua_State *L)
Checks to see if pilot has a projectile after him.
static int aiL_getweapammo(lua_State *L)
Gets the ammo of a weapon.
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.
static int aiL_shoot_indicator(lua_State *L)
Access the seeker shoot indicator (that is put to true each time a seeker is shot).
static int aiL_combat(lua_State *L)
Sets the combat flag.
static int aiL_distress(lua_State *L)
Sends a distress signal.
static int aiL_settimer(lua_State *L)
Sets a timer.
static int aiL_setasterotarget(lua_State *L)
Sets the pilot's asteroid target.
static int aiL_getweapspeed(lua_State *L)
Gets the speed of a weapon.
static int aiL_getrndpilot(lua_State *L)
Gets a random pilot in the system. Lua return parameter: Pilot|nil.
static int aiL_set_shoot_indicator(lua_State *L)
Set the seeker shoot indicator.
static int aiL_getenemy(lua_State *L)
Gets the nearest enemy.
static int aiL_stealth(lua_State *L)
Tries to stealth or destealth the pilot.
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...
static int aiL_stop(lua_State *L)
Completely stops the pilot if it is below minimum vel error (no insta-stops).
static int aiL_getflybydistance(lua_State *L)
Gets the distance from the pointer perpendicular to the current pilot's flight vector.
static int aiL_canHyperspace(lua_State *L)
Gets whether or not the pilot can hyperspace.
static int aiL_popsubtask(lua_State *L)
Pops the current running task.
static int aiL_face(lua_State *L)
Faces the target.
static int aiL_timeup(lua_State *L)
Checks a timer.
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...
static int aiL_scandone(lua_State *L)
Checks to see if pilot has finished scanning their target.
static int aiL_getweaprange(lua_State *L)
Gets the range of a weapon set.
static int aiL_dock(lua_State *L)
Docks the ship.
static int aiL_outfitOffAll(lua_State *L)
Tries to turn off all outfits.
static int aiL_hyperspace(lua_State *L)
Tries to enter hyperspace.
static int aiL_hasafterburner(lua_State *L)
Does the pilot have afterburners?
static int aiL_board(lua_State *L)
Attempts to board the pilot's target.
static int aiL_hasfighterbays(lua_State *L)
Does the pilot have fighter bays?
static int aiL_brake(lua_State *L)
Brakes the pilot.
static int aiL_getnearestspob(lua_State *L)
Get the nearest friendly spob to the pilot.
static int aiL_isstopped(lua_State *L)
Checks to see if pilot is stopped.
void naev_renderLoadscreen(void)
Renders the loadscreen if necessary.
Header file with generic functions and naev-specifics.
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
int ndata_matchExt(const char *path, const char *ext)
Sees if a file matches an extension.
int nlua_loadStandard(nlua_env env)
Loads the standard Naev Lua API.
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.
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.
LuaJump * lua_pushjump(lua_State *L, LuaJump jump)
Pushes a jump on the stack.
JumpPoint * luaL_validjump(lua_State *L, int ind)
Gets a jump directly.
LuaPilot * lua_pushpilot(lua_State *L, LuaPilot pilot)
Pushes a pilot on the stack.
Pilot * luaL_validpilot(lua_State *L, int ind)
Makes sure the pilot is valid or raises a Lua error.
int lua_ispilot(lua_State *L, int ind)
Checks to see if ind is a pilot.
LuaSpob * lua_pushspob(lua_State *L, LuaSpob spob)
Pushes a spob on the stack.
Spob * luaL_validspob(lua_State *L, int ind)
Gets a spob directly.
int lua_isvector(lua_State *L, int ind)
Checks to see if ind is a vector.
vec2 * luaL_checkvector(lua_State *L, int ind)
Gets vector at index making sure type is valid.
vec2 * lua_tovector(lua_State *L, int ind)
Represents a 2D vector in Lua.
vec2 * lua_pushvector(lua_State *L, vec2 vec)
Pushes a vector on the stack.
int pilot_isHostile(const Pilot *p)
Checks to see if pilot is hostile to the player.
int pilot_brakeCheckReverseThrusters(const Pilot *p)
See if the pilot wants to use their reverse thrusters to brake.
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.
int pilot_validEnemy(const Pilot *p, const Pilot *target)
Checks to see if a pilot is a valid enemy for another pilot.
double pilot_relsize(const Pilot *cur_pilot, const Pilot *p)
Gets the relative size(shipmass) between the current pilot and the specified target.
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.
void pilot_msg(const Pilot *p, const Pilot *receiver, const char *type, unsigned int idx)
Sends a message.
void pilot_setAccel(Pilot *p, double accel)
Sets the pilot's accel.
unsigned int pilot_getNearestEnemy(const Pilot *p)
Gets the nearest enemy to the pilot.
void pilot_hyperspaceAbort(Pilot *p)
Stops the pilot from hyperspacing.
void pilot_setTurn(Pilot *p, double turn)
Sets the pilot's turn.
int pilot_isFriendly(const Pilot *p)
Checks to see if pilot is friendly to the player.
int pilot_refuelStart(Pilot *p)
Attempts to start refueling the pilot's target.
double pilot_minbrakedist(const Pilot *p, double dt, double *flytime)
Gets the minimum braking distance for the pilot.
void pilot_setHostile(Pilot *p)
Marks pilot as hostile to player.
static Pilot ** pilot_stack
void pilot_distress(Pilot *p, Pilot *attacker, const char *msg)
Has the pilot broadcast a distress signal.
Pilot *const * pilot_getAll(void)
Gets the pilot stack.
int pilot_canTarget(const Pilot *p)
Same as pilot_validTarget but without the range check.
double pilot_aimAngle(Pilot *p, const vec2 *pos, const vec2 *vel)
Returns the angle for a pilot to aim at another pilot.
unsigned int pilot_getBoss(const Pilot *p)
Get the strongest ally in a given range.
void pilot_setTarget(Pilot *p, unsigned int id)
Sets the target of the pilot.
int pilot_inRangePilot(const Pilot *p, const Pilot *target, double *dist2)
Check to see if a pilot is in sensor range of another.
int pilot_ewScanCheck(const Pilot *p)
Checks to see if a scan is done.
void pilot_destealth(Pilot *p)
Destealths a pilot.
int pilot_stealth(Pilot *p)
Stealths a pilot.
int pilot_runHook(Pilot *p, int hook_type)
Tries to run a pilot hook if he has it.
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.
int space_canHyperspace(const Pilot *p)
Checks to make sure if pilot is far enough away to hyperspace.
int spob_index(const Spob *p)
Gets the ID of a spob.
double system_getPresence(const StarSystem *sys, int faction)
Get the presence of a faction in a system.
int space_hyperspace(Pilot *p)
Tries to get the pilot into hyperspace.
Represents a temporary pilot memory. For use with ai_setPilot and ai_unsetPilot.
Represents a single asteroid.
The actual hook parameter.
union HookParam::@065274143236224234262250043114351136253171035204 u
The representation of an in-game pilot.
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...