naev 0.12.5
nlua_pilotoutfit.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <lauxlib.h>
11
12#include "naev.h"
14
15#include "nlua_pilotoutfit.h"
16
17#include "array.h"
18#include "nlua_asteroid.h"
19#include "nlua_munition.h"
20#include "nlua_outfit.h"
21#include "nlua_pilot.h"
22#include "nlua_vec2.h"
23#include "nluadef.h"
24#include "slots.h"
25#include "weapon.h"
26
27int pilotoutfit_modified = 0;
28
29/* Pilot outfit metatable methods. */
30static int poL_slot( lua_State *L );
31static int poL_outfit( lua_State *L );
32static int poL_state( lua_State *L );
33static int poL_progress( lua_State *L );
34static int poL_set( lua_State *L );
35static int poL_clear( lua_State *L );
36static int poL_munition( lua_State *L );
37static int poL_shoot( lua_State *L );
38static int poL_heat( lua_State *L );
39static int poL_heatup( lua_State *L );
40
41static const luaL_Reg poL_methods[] = {
42 { "slot", poL_slot },
43 { "outfit", poL_outfit },
44 { "state", poL_state },
45 { "progress", poL_progress },
46 { "set", poL_set },
47 { "clear", poL_clear },
48 { "munition", poL_munition },
49 { "shoot", poL_shoot },
50 { "heat", poL_heat },
51 { "heatup", poL_heatup },
52 { 0, 0 } };
53
60int nlua_loadPilotOutfit( nlua_env env )
61{
62 nlua_register( env, PILOTOUTFIT_METATABLE, poL_methods, 1 );
63 return 0;
64}
65
78PilotOutfitSlot *lua_topilotoutfit( lua_State *L, int ind )
79{
80 return *( (PilotOutfitSlot **)lua_touserdata( L, ind ) );
81}
82
89PilotOutfitSlot *luaL_checkpilotoutfit( lua_State *L, int ind )
90{
91 if ( lua_ispilotoutfit( L, ind ) )
92 return lua_topilotoutfit( L, ind );
93 luaL_typerror( L, ind, PILOTOUTFIT_METATABLE );
94 return NULL;
95}
96
103PilotOutfitSlot *luaL_validpilotoutfit( lua_State *L, int ind )
104{
106
107 if ( lua_ispilotoutfit( L, ind ) )
108 o = luaL_checkpilotoutfit( L, ind );
109 else {
110 luaL_typerror( L, ind, PILOTOUTFIT_METATABLE );
111 return NULL;
112 }
113
114 if ( o == NULL )
115 NLUA_ERROR( L, _( "Pilot Outfit is invalid." ) );
116
117 return o;
118}
119
127{
128 PilotOutfitSlot **lpo =
129 (PilotOutfitSlot **)lua_newuserdata( L, sizeof( PilotOutfitSlot * ) );
130 *lpo = po;
131 luaL_getmetatable( L, PILOTOUTFIT_METATABLE );
132 lua_setmetatable( L, -2 );
133 return lpo;
134}
135
142int lua_ispilotoutfit( lua_State *L, int ind )
143{
144 int ret;
145
146 if ( lua_getmetatable( L, ind ) == 0 )
147 return 0;
148 lua_getfield( L, LUA_REGISTRYINDEX, PILOTOUTFIT_METATABLE );
149
150 ret = 0;
151 if ( lua_rawequal( L, -1, -2 ) ) /* does it have the correct mt? */
152 ret = 1;
153
154 lua_pop( L, 2 ); /* remove both metatables */
155 return ret;
156}
157
167static int poL_slot( lua_State *L )
168{
170 const ShipOutfitSlot *sslot = po->sslot;
171 const OutfitSlot *slot = &sslot->slot;
172
173 /* make the slot table and put it in */
174 lua_newtable( L );
175
176 lua_pushstring( L, "type" ); /* key */
177 lua_pushstring( L, slotName( slot->type ) ); /* value */
178 lua_rawset( L, -3 ); /* table[key = value ]*/
179
180 lua_pushstring( L, "size" ); /* key */
181 lua_pushstring( L, slotSize( slot->size ) );
182 lua_rawset( L, -3 ); /* table[key] = value */
183
184 lua_pushstring( L, "property" ); /* key */
185 lua_pushstring( L, sp_display( slot->spid ) ); /* value */
186 lua_rawset( L, -3 ); /* table[key] = value */
187
188 lua_pushstring( L, "required" ); /* key */
189 lua_pushboolean( L, sslot->required ); /* value */
190 lua_rawset( L, -3 ); /* table[key] = value */
191
192 lua_pushstring( L, "exclusive" ); /* key */
193 lua_pushboolean( L, sslot->exclusive ); /* value */
194 lua_rawset( L, -3 ); /* table[key] = value */
195
196 lua_pushstring( L, "locked" ); /* key */
197 lua_pushboolean( L, sslot->locked ); /* value */
198 lua_rawset( L, -3 ); /* table[key] = value */
199
200 return 1;
201}
202
210static int poL_outfit( lua_State *L )
211{
212 const PilotOutfitSlot *po = luaL_validpilotoutfit( L, 1 );
213 lua_pushoutfit( L, po->outfit );
214 return 1;
215}
216
232static int poL_state( lua_State *L )
233{
235 const char *state = luaL_optstring( L, 2, NULL );
236 PilotOutfitState pos = po->state;
237
238 if ( !outfit_isMod( po->outfit ) ) {
239 if ( outfit_isWeapon( po->outfit ) ) {
240 if ( state == NULL || strcmp( state, "off" ) == 0 ) {
241 po->flags &= ~( PILOTOUTFIT_DYNAMIC_FLAGS |
242 PILOTOUTFIT_ISON ); /* Clear toggles. */
243 } else if ( strcmp( state, "on" ) == 0 ) {
244 po->state = PILOT_OUTFIT_ON;
245 po->flags |=
246 PILOTOUTFIT_ISON |
247 PILOTOUTFIT_ISON_TOGGLE; /* Gets disabled if ontoggle is set. */
248 } else
249 return NLUA_ERROR( L,
250 _( "'pilotoutfit.%s' only works with \"on\" and "
251 "\"off\" for weapon outfits!" ),
252 "state" );
253 } else
254 return NLUA_ERROR(
255 L,
256 _( "'pilotoutfit.%s' only works with modifier or weapon outfits!" ),
257 "state" );
258 }
259
260 if ( state == NULL || strcmp( state, "off" ) == 0 ) {
261 po->state = PILOT_OUTFIT_OFF;
262 po->flags &=
263 ~( PILOTOUTFIT_DYNAMIC_FLAGS | PILOTOUTFIT_ISON ); /* Clear toggles. */
264 } else if ( strcmp( state, "warmup" ) == 0 ) {
265 po->state = PILOT_OUTFIT_WARMUP;
266 } else if ( strcmp( state, "on" ) == 0 ) {
267 if ( po->state != PILOT_OUTFIT_ON )
268 po->flags |= PILOTOUTFIT_ISON | PILOTOUTFIT_ISON_TOGGLE;
269 po->state = PILOT_OUTFIT_ON;
270 } else if ( strcmp( state, "cooldown" ) == 0 ) {
271 po->state = PILOT_OUTFIT_COOLDOWN;
272 po->flags &=
273 ~( PILOTOUTFIT_DYNAMIC_FLAGS | PILOTOUTFIT_ISON ); /* Clear toggles. */
274 } else
275 return NLUA_ERROR( L, _( "Unknown PilotOutfit state '%s'!" ), state );
276
277 /* Mark as modified if state changed. */
278 if ( pos != po->state )
279 pilotoutfit_modified = 1;
280
281 return 0;
282}
283
292static int poL_progress( lua_State *L )
293{
295
296 if ( !outfit_isMod( po->outfit ) )
297 return NLUA_ERROR(
298 L, _( "'pilotoutfit.%s' only works with modifier outfits!" ),
299 "progress" );
300
301 po->progress = CLAMP( 0., 1., luaL_checknumber( L, 2 ) );
302 return 0;
303}
304
315static int poL_set( lua_State *L )
316{
318 const char *name = luaL_checkstring( L, 2 );
319 double value = luaL_checknumber( L, 3 );
320 po->lua_stats =
321 ss_statsSetList( po->lua_stats, ss_typeFromName( name ), value, 1, 0 );
322 pilotoutfit_modified = 1;
323 return 0;
324}
325
332static int poL_clear( lua_State *L )
333{
335 ss_free( po->lua_stats );
336 po->lua_stats = NULL;
337 pilotoutfit_modified = 1;
338 return 0;
339}
340
341static Target lua_totarget( lua_State *L, int idx )
342{
343 Target t;
344 /* Handle target. */
345 if ( lua_isnoneornil( L, idx ) )
346 t.type = TARGET_NONE;
347 else if ( lua_ispilot( L, idx ) ) {
348 t.type = TARGET_PILOT;
349 t.u.id = lua_topilot( L, idx );
350 } else if ( lua_isasteroid( L, idx ) ) {
351 const LuaAsteroid_t *ast = lua_toasteroid( L, idx );
352 t.type = TARGET_ASTEROID;
353 t.u.ast.anchor = ast->parent;
354 t.u.ast.asteroid = ast->id;
355 } else if ( lua_ismunition( L, idx ) ) {
356 const LuaMunition *lm = lua_tomunition( L, idx );
357 t.type = TARGET_WEAPON;
358 t.u.id = lm->id;
359 } else {
360 NLUA_INVALID_PARAMETER_NORET( L, idx );
361 t.type = TARGET_NONE;
362 }
363 return t;
364}
365
385static int poL_munition( lua_State *L )
386{
388 Pilot *p = luaL_validpilot( L, 2 );
389 const Outfit *o = luaL_optoutfit( L, 3, po->outfit );
390 Target t = lua_totarget( L, 4 );
391 double dir = luaL_optnumber( L, 5, p->solid.dir );
392 const vec2 *vp = luaL_optvector( L, 6, &p->solid.pos );
393 const vec2 *vv = luaL_optvector( L, 7, &p->solid.vel );
394 int noaim = lua_toboolean( L, 8 );
395 const Weapon *w = weapon_add( po, o, dir, vp, vv, p, &t, 0., !noaim );
396 lua_pushmunition( L, w );
397 return 1;
398}
399
412static int poL_shoot( lua_State *L )
413{
415 Pilot *p = luaL_validpilot( L, 2 );
416 Target t = lua_totarget( L, 3 );
417 int stagger = lua_toboolean( L, 4 );
418 double time;
419 int ret;
420 int has_ammo;
421
422 /* The particular weapon can't fire, so ignore. */
423 if ( po->timer > 0. ) {
424 lua_pushboolean( L, 0 );
425 return 1;
426 }
427
428 /* Out of ammo. */
429 has_ammo =
431 if ( has_ammo && ( po->u.ammo.quantity <= 0 ) ) {
432 lua_pushboolean( L, 0 );
433 return 1;
434 }
435
436 /* See if we should stagger the outfits. */
437 if ( stagger ) {
438 double q, maxt, rate_mod, energy_mod;
439 int maxp, minh;
440
441 /* Calculate rate modifier. */
442 pilot_getRateMod( &rate_mod, &energy_mod, p, po->outfit );
443
444 /* Find optimal outfit, coolest that can fire. */
445 minh = -1;
446 maxt = 0.;
447 maxp = -1;
448 q = 0.;
449 for ( int i = 0; i < array_size( p->outfits ); i++ ) {
450 PilotOutfitSlot *pos = p->outfits[i];
451 if ( pos->outfit != po->outfit )
452 continue;
453 /* Launcher only counts with ammo. */
454 if ( has_ammo && ( pos->u.ammo.quantity <= 0 ) )
455 continue;
456 /* Get coolest that can fire. */
457 if ( pos->timer <= 0. ) {
458 if ( has_ammo ) {
459 if ( ( minh < 0 ) || ( p->outfits[minh]->u.ammo.quantity <
460 pos->u.ammo.quantity ) )
461 minh = i;
462 } else {
463 if ( ( minh < 0 ) || ( p->outfits[minh]->heat_T > pos->heat_T ) )
464 minh = i;
465 }
466 }
467
468 /* Save some stuff. */
469 if ( ( maxp < 0 ) || ( pos->timer > maxt ) ) {
470 maxp = i;
471 maxt = pos->timer;
472 }
473 q += 1.;
474 }
475
476 /* Only fire if the last weapon to fire fired more than (q-1)/q ago. */
477 if ( ( minh < 0 ) || ( maxt > rate_mod * outfit_delay( po->outfit ) *
478 ( ( q - 1. ) / q ) ) ) {
479 lua_pushboolean( L, 0 );
480 return 1;
481 }
482 }
483
484 time = weapon_targetFlyTime( po->outfit, p, &t );
485 ret = pilot_shootWeapon( p, po, &t, time, -1 );
486
487 lua_pushboolean( L, ret );
488 return 1;
489}
490
501static int poL_heat( lua_State *L )
502{
504 if ( lua_isboolean( L, 2 ) )
505 lua_pushnumber( L, po->heat_T );
506 else
507 lua_pushnumber( L, pilot_heatEfficiencyMod( po->heat_T,
508 po->outfit->overheat_min,
509 po->outfit->overheat_max ) );
510 return 1;
511}
512
526static int poL_heatup( lua_State *L )
527{
529 double heat = luaL_checknumber( L, 2 );
530 po->heat_T += heat / po->heat_C;
531 /* Enforce a minimum value as a safety measure. */
532 po->heat_T = MAX( po->heat_T, CONST_SPACE_STAR_TEMP );
533 return 0;
534}
Provides macros to work with dynamic arrays.
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:179
Header file with generic functions and naev-specifics.
#define CLAMP(a, b, x)
Definition naev.h:41
#define MAX(x, y)
Definition naev.h:37
int lua_isasteroid(lua_State *L, int ind)
Checks to see if ind is a asteroid.
LuaAsteroid_t * lua_toasteroid(lua_State *L, int ind)
Gets asteroid at index.
int lua_ismunition(lua_State *L, int ind)
Checks to see if ind is a munition.
LuaMunition * lua_tomunition(lua_State *L, int ind)
Lua bindings to interact with munitions.
LuaMunition * lua_pushmunition(lua_State *L, const Weapon *w)
Pushes a weapon as a munition on the stack.
const Outfit ** lua_pushoutfit(lua_State *L, const Outfit *outfit)
Pushes a outfit on the stack.
LuaPilot lua_topilot(lua_State *L, int ind)
Lua bindings to interact with pilots.
Definition nlua_pilot.c:535
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
static const luaL_Reg poL_methods[]
int nlua_loadPilotOutfit(nlua_env env)
Loads the pilot outfit library.
PilotOutfitSlot * luaL_validpilotoutfit(lua_State *L, int ind)
Makes sure the outfit is valid or raises a Lua error.
static int poL_progress(lua_State *L)
Sets the state progress of the PilotOutfit.
static int poL_heat(lua_State *L)
Gets the heat status of the pilot outfit.
PilotOutfitSlot * luaL_checkpilotoutfit(lua_State *L, int ind)
Gets outfit at index or raises error if there is no outfit at index.
static int poL_munition(lua_State *L)
Creates a munition.
PilotOutfitSlot ** lua_pushpilotoutfit(lua_State *L, PilotOutfitSlot *po)
Pushes a pilot outfit on the stack.
static int poL_set(lua_State *L)
Sets a temporary ship stat modifier of the pilot outfit.
static int poL_outfit(lua_State *L)
Gets the outfit of the PilotOutfit.
PilotOutfitSlot * lua_topilotoutfit(lua_State *L, int ind)
Lua bindings to interact with pilot outfits.
static int poL_heatup(lua_State *L)
Heats up a pilot outfit.
int lua_ispilotoutfit(lua_State *L, int ind)
Checks to see if ind is a pilot outfit.
static int poL_shoot(lua_State *L)
Shoots at an object.
static int poL_state(lua_State *L)
Sets the state of the PilotOutfit.
static int poL_clear(lua_State *L)
Clears all the temporary ship stat modifiers of the pilot outfit.
static int poL_slot(lua_State *L)
Gets the properties of the outfit slot.
int outfit_isLauncher(const Outfit *o)
Checks if outfit is a weapon launcher.
Definition outfit.c:649
int outfit_isWeapon(const Outfit *o)
Checks to see if an outfit is a weapon.
Definition outfit.c:603
int outfit_isFighterBay(const Outfit *o)
Checks if outfit is a fighter bay.
Definition outfit.c:701
const char * slotName(const OutfitSlotType type)
Definition outfit.c:413
int outfit_isMod(const Outfit *o)
Checks if outfit is a ship modification.
Definition outfit.c:683
const char * slotSize(const OutfitSlotSize o)
Gets the slot size as a string.
Definition outfit.c:436
double outfit_delay(const Outfit *o)
Gets the outfit's delay.
Definition outfit.c:834
double pilot_heatEfficiencyMod(double T, double Tb, double Tc)
Returns a 0:1 modifier representing efficiency (1. being normal).
Definition pilot_heat.c:237
void pilot_getRateMod(double *rate_mod, double *energy_mod, const Pilot *p, const Outfit *o)
Gets applicable fire rate and energy modifications for a pilot's weapon.
int pilot_shootWeapon(Pilot *p, PilotOutfitSlot *w, const Target *target, double time, int aim)
Actually handles the shooting, how often the player.p can shoot and such.
void ss_free(ShipStatList *ll)
Frees a list of ship stats.
Definition shipstats.c:934
ShipStatsType ss_typeFromName(const char *name)
Gets the type from the name.
Definition shipstats.c:725
const char * sp_display(unsigned int spid)
Gets the display name of a slot property (in English).
Definition slots.c:165
Lua Munition wrapper.
unsigned int id
Pilot slot that can contain outfits.
Definition outfit.h:139
OutfitSlotSize size
Definition outfit.h:143
unsigned int spid
Definition outfit.h:140
OutfitSlotType type
Definition outfit.h:142
A ship outfit, depends radically on the type.
Definition outfit.h:372
double overheat_max
Definition outfit.h:404
double overheat_min
Definition outfit.h:402
Stores an outfit the pilot has.
Definition pilot.h:145
PilotOutfitAmmo ammo
Definition pilot.h:174
double heat_C
Definition pilot.h:155
double heat_T
Definition pilot.h:154
double progress
Definition pilot.h:165
PilotOutfitState state
Definition pilot.h:160
ShipStatList * lua_stats
Definition pilot.h:180
double timer
Definition pilot.h:162
ShipOutfitSlot * sslot
Definition pilot.h:151
const Outfit * outfit
Definition pilot.h:149
The representation of an in-game pilot.
Definition pilot.h:263
Ship outfit slot.
Definition ship.h:71
int exclusive
Definition ship.h:74
int required
Definition ship.h:75
OutfitSlot slot
Definition ship.h:72
int locked
Definition ship.h:76
Represents a weapon target.
Definition target.h:19
In-game representation of a weapon.
Definition weapon.h:48
Represents a 2d vector.
Definition vec2.h:45
double weapon_targetFlyTime(const Outfit *o, const Pilot *p, const Target *t)
Gets the fly time for a weapon target.
Definition weapon.c:2715
Weapon * weapon_add(PilotOutfitSlot *po, const Outfit *ref, double dir, const vec2 *pos, const vec2 *vel, const Pilot *parent, const Target *target, double time, int aim)
Creates a new weapon.
Definition weapon.c:2689