Files
fs2open.github.com/code/scripting/api/objs/ship.cpp
T
2020-05-13 20:15:36 -04:00

1705 lines
49 KiB
C++

//
//
#include "ship.h"
#include "texture.h"
#include "object.h"
#include "subsystem.h"
#include "shipclass.h"
#include "cockpit_display.h"
#include "weaponclass.h"
#include "ship_bank.h"
#include "team.h"
#include "order.h"
#include "enums.h"
#include "wing.h"
#include "ship/shiphit.h"
#include "hud/hudshield.h"
#include "playerman/player.h"
#include "mission/missionlog.h"
#include "ai/aigoals.h"
#include "ship/shipfx.h"
#include "hud/hudets.h"
#include "object/object.h"
#include "model/model.h"
#include "ship/ship.h"
#include "parse/parselo.h"
extern void ship_reset_disabled_physics(object *objp, int ship_class);
namespace scripting {
namespace api {
//**********HANDLE: shiptextures
ADE_OBJ(l_ShipTextures, object_h, "shiptextures", "Ship textures handle");
ADE_FUNC(__len, l_ShipTextures, NULL, "Number of textures on ship", "number", "Number of textures on ship, or 0 if handle is invalid")
{
object_h *objh;
if(!ade_get_args(L, "o", l_ShipTextures.GetPtr(&objh)))
return ade_set_error(L, "i", 0);
if(!objh->IsValid())
return ade_set_error(L, "i", 0);
polymodel *pm = model_get(Ship_info[Ships[objh->objp->instance].ship_info_index].model_num);
if(pm == NULL)
return ade_set_error(L, "i", 0);
return ade_set_args(L, "i", pm->n_textures*TM_NUM_TYPES);
}
ADE_INDEXER(l_ShipTextures, "number Index/string TextureFilename", "Array of ship textures", "texture", "Texture, or invalid texture handle on failure")
{
object_h *oh;
const char* s;
texture_h* tdx = nullptr;
if (!ade_get_args(L, "os|o", l_ShipTextures.GetPtr(&oh), &s, l_Texture.GetPtr(&tdx)))
return ade_set_error(L, "o", l_Texture.Set(texture_h()));
if (!oh->IsValid() || s==NULL)
return ade_set_error(L, "o", l_Texture.Set(texture_h()));
ship *shipp = &Ships[oh->objp->instance];
polymodel *pm = model_get(Ship_info[shipp->ship_info_index].model_num);
int final_index = -1;
int i;
char fname[MAX_FILENAME_LEN];
if (shipp->ship_replacement_textures != NULL)
{
for(i = 0; i < MAX_REPLACEMENT_TEXTURES; i++)
{
bm_get_filename(shipp->ship_replacement_textures[i], fname);
if(!strextcmp(fname, s)) {
final_index = i;
break;
}
}
}
if(final_index < 0)
{
for (i = 0; i < pm->n_textures; i++)
{
int tm_num = pm->maps[i].FindTexture(s);
if(tm_num > -1)
{
final_index = i*TM_NUM_TYPES+tm_num;
break;
}
}
}
if (final_index < 0)
{
final_index = atoi(s) - 1; //Lua->FS2
if (final_index < 0 || final_index >= MAX_REPLACEMENT_TEXTURES)
return ade_set_error(L, "o", l_Texture.Set(texture_h()));
}
if (ADE_SETTING_VAR) {
if (shipp->ship_replacement_textures == NULL) {
shipp->ship_replacement_textures = (int *) vm_malloc(MAX_REPLACEMENT_TEXTURES * sizeof(int));
for (i = 0; i < MAX_REPLACEMENT_TEXTURES; i++)
shipp->ship_replacement_textures[i] = -1;
}
if (tdx != nullptr) {
if (tdx->isValid())
shipp->ship_replacement_textures[final_index] = tdx->handle;
else
shipp->ship_replacement_textures[final_index] = -1;
}
}
if (shipp->ship_replacement_textures != NULL && shipp->ship_replacement_textures[final_index] >= 0)
return ade_set_args(L, "o", l_Texture.Set(texture_h(shipp->ship_replacement_textures[final_index])));
else
return ade_set_args(L, "o", l_Texture.Set(texture_h(pm->maps[final_index / TM_NUM_TYPES].textures[final_index % TM_NUM_TYPES].GetTexture())));
}
ADE_FUNC(isValid, l_ShipTextures, NULL, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs")
{
object_h *oh;
if(!ade_get_args(L, "o", l_ShipTextures.GetPtr(&oh)))
return ADE_RETURN_NIL;
return ade_set_args(L, "b", oh->IsValid());
}
//**********HANDLE: Ship
ADE_OBJ_DERIV(l_Ship, object_h, "ship", "Ship handle", l_Object);
ADE_INDEXER(l_Ship, "string Name/number Index", "Array of ship subsystems", "subsystem", "Subsystem handle, or invalid subsystem handle if index or ship handle is invalid")
{
object_h *objh;
const char* s = nullptr;
ship_subsys_h *sub = nullptr;
if(!ade_get_args(L, "o|so", l_Ship.GetPtr(&objh), &s, l_Subsystem.GetPtr(&sub)))
return ade_set_error(L, "o", l_Subsystem.Set(ship_subsys_h()));
if(!objh->IsValid())
return ade_set_error(L, "o", l_Subsystem.Set(ship_subsys_h()));
ship *shipp = &Ships[objh->objp->instance];
ship_subsys *ss = ship_get_subsys(shipp, s);
if(ss == NULL)
{
int idx = atoi(s);
if(idx > 0 && idx <= ship_get_num_subsys(shipp))
{
idx--; //Lua->FS2
ss = ship_get_indexed_subsys(shipp, idx);
}
}
if(ss == NULL)
return ade_set_error(L, "o", l_Subsystem.Set(ship_subsys_h()));
return ade_set_args(L, "o", l_Subsystem.Set(ship_subsys_h(objh->objp, ss)));
}
ADE_FUNC(__len, l_Ship, NULL, "Number of subsystems on ship", "number", "Subsystem number, or 0 if handle is invalid")
{
object_h *objh;
if(!ade_get_args(L, "o", l_Ship.GetPtr(&objh)))
return ade_set_error(L, "i", 0);
if(!objh->IsValid())
return ade_set_error(L, "i", 0);
return ade_set_args(L, "i", ship_get_num_subsys(&Ships[objh->objp->instance]));
}
ADE_VIRTVAR(ShieldArmorClass, l_Ship, "string", "Current Armor class of the ships' shield", "string", "Armor class name, or empty string if none is set")
{
object_h *objh;
const char* s = nullptr;
const char *name = NULL;
if(!ade_get_args(L, "o|s", l_Ship.GetPtr(&objh), &s))
return ade_set_error(L, "s", "");
if(!objh->IsValid())
return ade_set_error(L, "s", "");
ship *shipp = &Ships[objh->objp->instance];
int atindex = -1;
if (ADE_SETTING_VAR && s != NULL) {
atindex = armor_type_get_idx(s);
shipp->shield_armor_type_idx = atindex;
}
if (atindex != -1)
name = Armor_types[atindex].GetNamePtr();
else
name = "";
return ade_set_args(L, "s", name);
}
ADE_VIRTVAR(ArmorClass, l_Ship, "string", "Current Armor class", "string", "Armor class name, or empty string if none is set")
{
object_h *objh;
const char* s = nullptr;
const char *name = NULL;
if(!ade_get_args(L, "o|s", l_Ship.GetPtr(&objh), &s))
return ade_set_error(L, "s", "");
if(!objh->IsValid())
return ade_set_error(L, "s", "");
ship *shipp = &Ships[objh->objp->instance];
int atindex = -1;
if (ADE_SETTING_VAR && s != NULL) {
atindex = armor_type_get_idx(s);
shipp->armor_type_idx = atindex;
}
if (atindex != -1)
name = Armor_types[atindex].GetNamePtr();
else
name = "";
return ade_set_args(L, "s", name);
}
ADE_VIRTVAR(Name, l_Ship, "string", "Ship name. This is the actual name of the ship. Use <i>getDisplayString</i> to get the string which should be displayed to the player.", "string", "Ship name, or empty string if handle is invalid")
{
object_h *objh;
const char* s = nullptr;
if(!ade_get_args(L, "o|s", l_Ship.GetPtr(&objh), &s))
return ade_set_error(L, "s", "");
if(!objh->IsValid())
return ade_set_error(L, "s", "");
ship *shipp = &Ships[objh->objp->instance];
if(ADE_SETTING_VAR && s != NULL) {
strncpy(shipp->ship_name, s, sizeof(shipp->ship_name)-1);
}
return ade_set_args(L, "s", shipp->ship_name);
}
ADE_VIRTVAR(DisplayName, l_Ship, "string", "Ship display name", "string", "The display name of the ship or empty if there is no display string")
{
object_h *objh;
const char* s = nullptr;
if(!ade_get_args(L, "o|s", l_Ship.GetPtr(&objh), &s))
return ade_set_error(L, "s", "");
if(!objh->IsValid())
return ade_set_error(L, "s", "");
ship *shipp = &Ships[objh->objp->instance];
if(ADE_SETTING_VAR && s != nullptr) {
shipp->display_name = s;
}
return ade_set_args(L, "s", shipp->display_name.c_str());
}
ADE_VIRTVAR(AfterburnerFuelLeft, l_Ship, "number", "Afterburner fuel left", "number", "Afterburner fuel left, or 0 if handle is invalid")
{
object_h *objh;
float fuel = -1.0f;
if(!ade_get_args(L, "o|f", l_Ship.GetPtr(&objh), &fuel))
return ade_set_error(L, "f", 0.0f);
if(!objh->IsValid())
return ade_set_error(L, "f", 0.0f);
ship *shipp = &Ships[objh->objp->instance];
if(ADE_SETTING_VAR && fuel >= 0.0f)
shipp->afterburner_fuel = fuel;
return ade_set_args(L, "f", shipp->afterburner_fuel);
}
ADE_VIRTVAR(AfterburnerFuelMax, l_Ship, "number", "Afterburner fuel capacity", "number", "Afterburner fuel capacity, or 0 if handle is invalid")
{
object_h *objh;
float fuel = -1.0f;
if(!ade_get_args(L, "o|f", l_Ship.GetPtr(&objh), &fuel))
return ade_set_error(L, "f", 0.0f);
if(!objh->IsValid())
return ade_set_error(L, "f", 0.0f);
ship_info *sip = &Ship_info[Ships[objh->objp->instance].ship_info_index];
if(ADE_SETTING_VAR && fuel >= 0.0f)
sip->afterburner_fuel_capacity = fuel;
return ade_set_args(L, "f", sip->afterburner_fuel_capacity);
}
ADE_VIRTVAR(Class, l_Ship, "shipclass", "Ship class", "shipclass", "Ship class, or invalid shipclass handle if ship handle is invalid")
{
object_h *objh;
int idx=-1;
if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&objh), l_Shipclass.Get(&idx)))
return ade_set_error(L, "o", l_Shipclass.Set(-1));
if(!objh->IsValid())
return ade_set_error(L, "o", l_Shipclass.Set(-1));
ship *shipp = &Ships[objh->objp->instance];
if(ADE_SETTING_VAR && idx > -1) {
change_ship_type(objh->objp->instance, idx, 1);
if (shipp == Player_ship) {
set_current_hud();
}
}
if(shipp->ship_info_index < 0)
return ade_set_error(L, "o", l_Shipclass.Set(-1));
return ade_set_args(L, "o", l_Shipclass.Set(shipp->ship_info_index));
}
ADE_VIRTVAR(CountermeasuresLeft, l_Ship, "number", "Number of countermeasures left", "number", "Countermeasures left, or 0 if ship handle is invalid")
{
object_h *objh;
int newcm = -1;
if(!ade_get_args(L, "o|i", l_Ship.GetPtr(&objh), &newcm))
return ade_set_error(L, "i", 0);
if(!objh->IsValid())
return ade_set_error(L, "i", 0);
ship *shipp = &Ships[objh->objp->instance];
if(ADE_SETTING_VAR && newcm > -1)
shipp->cmeasure_count = newcm;
return ade_set_args(L, "i", shipp->cmeasure_count);
}
ADE_VIRTVAR(CockpitDisplays, l_Ship, "displays", "An array of the cockpit displays on this ship.<br>NOTE: Only the ship of the player has these", "displays", "displays handle or invalid handle on error")
{
object_h *objh;
cockpit_displays_h *cdh = NULL;
if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&objh), l_CockpitDisplays.GetPtr(&cdh)))
return ade_set_error(L, "o", l_CockpitDisplays.Set(cockpit_displays_h()));
if(!objh->IsValid())
return ade_set_error(L, "o", l_CockpitDisplays.Set(cockpit_displays_h()));
if(ADE_SETTING_VAR)
{
LuaError(L, "Attempted to use incomplete feature: Cockpit displays copy");
}
return ade_set_args(L, "o", l_CockpitDisplays.Set(cockpit_displays_h(objh->objp)));
}
ADE_VIRTVAR(CountermeasureClass, l_Ship, "weaponclass", "Weapon class mounted on this ship's countermeasure point", "weaponclass", "Countermeasure hardpoint weapon class, or invalid weaponclass handle if no countermeasure class or ship handle is invalid")
{
object_h *objh;
int newcm = -1;
if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&objh), l_Weaponclass.Get(&newcm)))
return ade_set_error(L, "o", l_Weaponclass.Set(-1));;
if(!objh->IsValid())
return ade_set_error(L, "o", l_Weaponclass.Set(-1));;
ship *shipp = &Ships[objh->objp->instance];
if(ADE_SETTING_VAR) {
shipp->current_cmeasure = newcm;
}
if(shipp->current_cmeasure > -1)
return ade_set_args(L, "o", l_Weaponclass.Set(shipp->current_cmeasure));
else
return ade_set_error(L, "o", l_Weaponclass.Set(-1));;
}
ADE_VIRTVAR(HitpointsMax, l_Ship, "number", "Total hitpoints", "number", "Ship maximum hitpoints, or 0 if handle is invalid")
{
object_h *objh;
float newhits = -1;
if(!ade_get_args(L, "o|f", l_Ship.GetPtr(&objh), &newhits))
return ade_set_error(L, "f", 0.0f);
if(!objh->IsValid())
return ade_set_error(L, "f", 0.0f);
ship *shipp = &Ships[objh->objp->instance];
if(ADE_SETTING_VAR && newhits > -1)
shipp->ship_max_hull_strength = newhits;
return ade_set_args(L, "f", shipp->ship_max_hull_strength);
}
ADE_VIRTVAR(WeaponEnergyLeft, l_Ship, "number", "Current weapon energy reserves", "number", "Ship current weapon energy reserve level, or 0 if invalid")
{
object_h *objh;
float neweng = -1;
if(!ade_get_args(L, "o|f", l_Ship.GetPtr(&objh), &neweng))
return ade_set_error(L, "f", 0.0f);
if(!objh->IsValid())
return ade_set_error(L, "f", 0.0f);
ship *shipp = &Ships[objh->objp->instance];
if(ADE_SETTING_VAR && neweng > -1)
shipp->weapon_energy = neweng;
return ade_set_args(L, "f", shipp->weapon_energy);
}
ADE_VIRTVAR(WeaponEnergyMax, l_Ship, "number", "Maximum weapon energy", "number", "Ship maximum weapon energy reserve level, or 0 if invalid")
{
object_h *objh;
float neweng = -1;
if(!ade_get_args(L, "o|f", l_Ship.GetPtr(&objh), &neweng))
return ade_set_error(L, "f", 0.0f);
if(!objh->IsValid())
return ade_set_error(L, "f", 0.0f);
ship_info *sip = &Ship_info[Ships[objh->objp->instance].ship_info_index];
if(ADE_SETTING_VAR && neweng > -1)
sip->max_weapon_reserve = neweng;
return ade_set_args(L, "f", sip->max_weapon_reserve);
}
ADE_VIRTVAR(AutoaimFOV, l_Ship, "number", "FOV of ship's autoaim, if any", "number", "FOV (in degrees), or 0 if ship uses no autoaim or if handle is invalid")
{
object_h *objh;
float fov = -1;
if(!ade_get_args(L, "o|f", l_Ship.GetPtr(&objh), &fov))
return ade_set_error(L, "f", 0.0f);
if(!objh->IsValid())
return ade_set_error(L, "f", 0.0f);
ship *shipp = &Ships[objh->objp->instance];
if(ADE_SETTING_VAR && fov >= 0.0f) {
if (fov > 180.0)
fov = 180.0;
shipp->autoaim_fov = fov * PI / 180.0f;
}
return ade_set_args(L, "f", shipp->autoaim_fov * 180.0f / PI);
}
ADE_VIRTVAR(PrimaryTriggerDown, l_Ship, "boolean", "Determines if primary trigger is pressed or not", "boolean", "True if pressed, false if not, nil if ship handle is invalid")
{
object_h *objh;
bool trig = false;
if(!ade_get_args(L, "o|b", l_Ship.GetPtr(&objh), &trig))
return ADE_RETURN_NIL;
if(!objh->IsValid())
return ADE_RETURN_NIL;
ship *shipp = &Ships[objh->objp->instance];
if(ADE_SETTING_VAR)
{
if(trig)
shipp->flags.set(Ship::Ship_Flags::Trigger_down);
else
shipp->flags.remove(Ship::Ship_Flags::Trigger_down);
}
if (shipp->flags[Ship::Ship_Flags::Trigger_down])
return ADE_RETURN_TRUE;
else
return ADE_RETURN_FALSE;
}
ADE_VIRTVAR(PrimaryBanks, l_Ship, "weaponbanktype", "Array of primary weapon banks", "weaponbanktype", "Primary weapon banks, or invalid weaponbanktype handle if ship handle is invalid")
{
object_h *objh;
ship_banktype_h *swh = nullptr;
if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&objh), l_WeaponBankType.GetPtr(&swh)))
return ade_set_error(L, "o", l_WeaponBankType.Set(ship_banktype_h()));
if(!objh->IsValid())
return ade_set_error(L, "o", l_WeaponBankType.Set(ship_banktype_h()));
ship_weapon *dst = &Ships[objh->objp->instance].weapons;
if(ADE_SETTING_VAR && swh && swh->IsValid()) {
ship_weapon *src = &Ships[swh->objp->instance].weapons;
dst->current_primary_bank = src->current_primary_bank;
dst->num_primary_banks = src->num_primary_banks;
memcpy(dst->next_primary_fire_stamp, src->next_primary_fire_stamp, sizeof(dst->next_primary_fire_stamp));
memcpy(dst->primary_animation_done_time, src->primary_animation_done_time, sizeof(dst->primary_animation_done_time));
memcpy(dst->primary_animation_position, src->primary_animation_position, sizeof(dst->primary_animation_position));
memcpy(dst->primary_bank_ammo, src->primary_bank_ammo, sizeof(dst->primary_bank_ammo));
memcpy(dst->primary_bank_capacity, src->primary_bank_capacity, sizeof(dst->primary_bank_capacity));
memcpy(dst->primary_bank_rearm_time, src->primary_bank_rearm_time, sizeof(dst->primary_bank_rearm_time));
memcpy(dst->primary_bank_start_ammo, src->primary_bank_start_ammo, sizeof(dst->primary_bank_start_ammo));
memcpy(dst->primary_bank_weapons, src->primary_bank_weapons, sizeof(dst->primary_bank_weapons));
}
return ade_set_args(L, "o", l_WeaponBankType.Set(ship_banktype_h(objh->objp, dst, SWH_PRIMARY)));
}
ADE_VIRTVAR(SecondaryBanks, l_Ship, "weaponbanktype", "Array of secondary weapon banks", "weaponbanktype", "Secondary weapon banks, or invalid weaponbanktype handle if ship handle is invalid")
{
object_h *objh;
ship_banktype_h *swh = nullptr;
if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&objh), l_WeaponBankType.GetPtr(&swh)))
return ade_set_error(L, "o", l_WeaponBankType.Set(ship_banktype_h()));
if(!objh->IsValid())
return ade_set_error(L, "o", l_WeaponBankType.Set(ship_banktype_h()));
ship_weapon *dst = &Ships[objh->objp->instance].weapons;
if(ADE_SETTING_VAR && swh && swh->IsValid()) {
ship_weapon *src = &Ships[swh->objp->instance].weapons;
dst->current_secondary_bank = src->current_secondary_bank;
dst->num_secondary_banks = src->num_secondary_banks;
memcpy(dst->next_secondary_fire_stamp, src->next_secondary_fire_stamp, sizeof(dst->next_secondary_fire_stamp));
memcpy(dst->secondary_animation_done_time, src->secondary_animation_done_time, sizeof(dst->secondary_animation_done_time));
memcpy(dst->secondary_animation_position, src->secondary_animation_position, sizeof(dst->secondary_animation_position));
memcpy(dst->secondary_bank_ammo, src->secondary_bank_ammo, sizeof(dst->secondary_bank_ammo));
memcpy(dst->secondary_bank_capacity, src->secondary_bank_capacity, sizeof(dst->secondary_bank_capacity));
memcpy(dst->secondary_bank_rearm_time, src->secondary_bank_rearm_time, sizeof(dst->secondary_bank_rearm_time));
memcpy(dst->secondary_bank_start_ammo, src->secondary_bank_start_ammo, sizeof(dst->secondary_bank_start_ammo));
memcpy(dst->secondary_bank_weapons, src->secondary_bank_weapons, sizeof(dst->secondary_bank_weapons));
memcpy(dst->secondary_next_slot, src->secondary_next_slot, sizeof(dst->secondary_next_slot));
}
return ade_set_args(L, "o", l_WeaponBankType.Set(ship_banktype_h(objh->objp, dst, SWH_SECONDARY)));
}
ADE_VIRTVAR(TertiaryBanks, l_Ship, "weaponbanktype", "Array of tertiary weapon banks", "weaponbanktype", "Tertiary weapon banks, or invalid weaponbanktype handle if ship handle is invalid")
{
object_h *objh;
ship_banktype_h *swh = nullptr;
if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&objh), l_WeaponBankType.GetPtr(&swh)))
return ade_set_error(L, "o", l_WeaponBankType.Set(ship_banktype_h()));
if(!objh->IsValid())
return ade_set_error(L, "o", l_WeaponBankType.Set(ship_banktype_h()));
ship_weapon *dst = &Ships[objh->objp->instance].weapons;
if(ADE_SETTING_VAR && swh && swh->IsValid()) {
ship_weapon *src = &Ships[swh->objp->instance].weapons;
dst->current_tertiary_bank = src->current_tertiary_bank;
dst->num_tertiary_banks = src->num_tertiary_banks;
dst->next_tertiary_fire_stamp = src->next_tertiary_fire_stamp;
dst->tertiary_bank_ammo = src->tertiary_bank_ammo;
dst->tertiary_bank_capacity = src->tertiary_bank_capacity;
dst->tertiary_bank_rearm_time = src->tertiary_bank_rearm_time;
dst->tertiary_bank_start_ammo = src->tertiary_bank_start_ammo;
}
return ade_set_args(L, "o", l_WeaponBankType.Set(ship_banktype_h(objh->objp, dst, SWH_TERTIARY)));
}
ADE_VIRTVAR(Target, l_Ship, "object", "Target of ship. Value may also be a deriviative of the 'object' class, such as 'ship'.", "object", "Target object, or invalid object handle if no target or ship handle is invalid")
{
object_h *objh;
object_h *newh = nullptr;
//WMC - Maybe use two argument return capabilities of Lua to set/return subsystem?
if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&objh), l_Object.GetPtr(&newh)))
return ade_set_error(L, "o", l_Object.Set(object_h()));
if(!objh->IsValid())
return ade_set_error(L, "o", l_Object.Set(object_h()));
ai_info *aip = NULL;
if(Ships[objh->objp->instance].ai_index > -1)
aip = &Ai_info[Ships[objh->objp->instance].ai_index];
else
return ade_set_error(L, "o", l_Object.Set(object_h()));
if(ADE_SETTING_VAR && newh)
{
if(aip->target_signature != newh->sig)
{
if(newh->IsValid())
{
aip->target_objnum = OBJ_INDEX(newh->objp);
aip->target_signature = newh->sig;
aip->target_time = 0.0f;
if (aip == Player_ai)
hud_shield_hit_reset(newh->objp);
}
else
{
aip->target_objnum = -1;
aip->target_signature = -1;
aip->target_time = 0.0f;
}
set_targeted_subsys(aip, NULL, -1);
}
}
return ade_set_object_with_breed(L, aip->target_objnum);
}
ADE_VIRTVAR(TargetSubsystem, l_Ship, "subsystem", "Target subsystem of ship.", "subsystem", "Target subsystem, or invalid subsystem handle if no target or ship handle is invalid")
{
object_h *oh;
ship_subsys_h *newh = nullptr;
//WMC - Maybe use two argument return capabilities of Lua to set/return subsystem?
if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&oh), l_Subsystem.GetPtr(&newh)))
return ade_set_error(L, "o", l_Subsystem.Set(ship_subsys_h()));
if(!oh->IsValid())
return ade_set_error(L, "o", l_Subsystem.Set(ship_subsys_h()));
ai_info *aip = NULL;
if(Ships[oh->objp->instance].ai_index > -1)
aip = &Ai_info[Ships[oh->objp->instance].ai_index];
else
return ade_set_error(L, "o", l_Subsystem.Set(ship_subsys_h()));
if(ADE_SETTING_VAR)
{
if(newh && newh->isSubsystemValid())
{
if (aip == Player_ai) {
if (aip->target_signature != newh->sig)
hud_shield_hit_reset(newh->objp);
Ships[Objects[newh->ss->parent_objnum].instance].last_targeted_subobject[Player_num] = newh->ss;
}
aip->target_objnum = OBJ_INDEX(newh->objp);
aip->target_signature = newh->sig;
aip->target_time = 0.0f;
set_targeted_subsys(aip, newh->ss, aip->target_objnum);
}
else
{
aip->target_objnum = -1;
aip->target_signature = -1;
aip->target_time = 0.0f;
set_targeted_subsys(aip, NULL, -1);
}
}
return ade_set_args(L, "o", l_Subsystem.Set(ship_subsys_h(&Objects[aip->target_objnum], aip->targeted_subsys)));
}
ADE_VIRTVAR(Team, l_Ship, "team", "Ship's team", "team", "Ship team, or invalid team handle if ship handle is invalid")
{
object_h *oh=NULL;
int nt=-1;
if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&oh), l_Team.Get(&nt)))
return ade_set_error(L, "o", l_Team.Set(-1));
if(!oh->IsValid())
return ade_set_error(L, "o", l_Team.Set(-1));
ship *shipp = &Ships[oh->objp->instance];
if(ADE_SETTING_VAR && nt > -1) {
shipp->team = nt;
}
return ade_set_args(L, "o", l_Team.Set(shipp->team));
}
ADE_VIRTVAR(Textures, l_Ship, "shiptextures", "Gets ship textures", "shiptextures", "Ship textures, or invalid shiptextures handle if ship handle is invalid")
{
object_h *sh = nullptr;
object_h *dh;
if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&dh), l_Ship.GetPtr(&sh)))
return ade_set_error(L, "o", l_ShipTextures.Set(object_h()));
if(!dh->IsValid())
return ade_set_error(L, "o", l_ShipTextures.Set(object_h()));
if(ADE_SETTING_VAR && sh && sh->IsValid()) {
ship *src = &Ships[sh->objp->instance];
ship *dest = &Ships[dh->objp->instance];
if (src->ship_replacement_textures != NULL)
{
if (dest->ship_replacement_textures == NULL)
dest->ship_replacement_textures = (int *) vm_malloc(MAX_REPLACEMENT_TEXTURES * sizeof(int));
memcpy(dest->ship_replacement_textures, src->ship_replacement_textures, MAX_REPLACEMENT_TEXTURES * sizeof(int));
}
}
return ade_set_args(L, "o", l_ShipTextures.Set(object_h(dh->objp)));
}
ADE_VIRTVAR(FlagAffectedByGravity, l_Ship, "boolean", "Checks for the \"affected-by-gravity\" flag", "boolean", "True if flag is set, false if flag is not set and nil on error")
{
object_h *objh=NULL;
bool set = false;
if (!ade_get_args(L, "o|b", l_Ship.GetPtr(&objh), &set))
return ADE_RETURN_NIL;
if (!objh->IsValid())
return ADE_RETURN_NIL;
ship *shipp = &Ships[objh->objp->instance];
if(ADE_SETTING_VAR)
{
shipp->flags.set(Ship::Ship_Flags::Affected_by_gravity, set);
}
if (shipp->flags[Ship::Ship_Flags::Affected_by_gravity])
return ADE_RETURN_TRUE;
else
return ADE_RETURN_FALSE;
}
ADE_VIRTVAR(Disabled, l_Ship, "boolean", "The disabled state of this ship", "boolean", "true if ship is diabled, false otherwise")
{
object_h *objh=NULL;
bool set = false;
if (!ade_get_args(L, "o|b", l_Ship.GetPtr(&objh), &set))
return ADE_RETURN_FALSE;
if (!objh->IsValid())
return ADE_RETURN_FALSE;
ship *shipp = &Ships[objh->objp->instance];
if(ADE_SETTING_VAR)
{
shipp->flags.set(Ship::Ship_Flags::Disabled, set);
if(set)
{
mission_log_add_entry(LOG_SHIP_DISABLED, shipp->ship_name, NULL );
}
else
{
ship_reset_disabled_physics( &Objects[shipp->objnum], shipp->ship_info_index );
}
}
if (shipp->flags[Ship::Ship_Flags::Disabled])
return ADE_RETURN_TRUE;
else
return ADE_RETURN_FALSE;
}
ADE_VIRTVAR(Stealthed, l_Ship, "boolean", "Stealth status of this ship", "boolean", "true if stealthed, false otherwise or on error")
{
object_h *objh=NULL;
bool stealthed = false;
if (!ade_get_args(L, "o|b", l_Ship.GetPtr(&objh), &stealthed))
return ADE_RETURN_FALSE;
if (!objh->IsValid())
return ADE_RETURN_FALSE;
ship *shipp = &Ships[objh->objp->instance];
if(ADE_SETTING_VAR)
{
shipp->flags.set(Ship::Ship_Flags::Stealth, stealthed);
}
if (shipp->flags[Ship::Ship_Flags::Stealth])
return ADE_RETURN_TRUE;
else
return ADE_RETURN_FALSE;
}
ADE_VIRTVAR(HiddenFromSensors, l_Ship, "boolean", "Hidden from sensors status of this ship", "boolean", "true if invisible to hidden from sensors, false otherwise or on error")
{
object_h *objh=NULL;
bool hidden = false;
if (!ade_get_args(L, "o|b", l_Ship.GetPtr(&objh), &hidden))
return ADE_RETURN_FALSE;
if (!objh->IsValid())
return ADE_RETURN_FALSE;
ship *shipp = &Ships[objh->objp->instance];
if(ADE_SETTING_VAR)
{
shipp->flags.set(Ship::Ship_Flags::Hidden_from_sensors, hidden);
}
if (shipp->flags[Ship::Ship_Flags::Hidden_from_sensors])
return ADE_RETURN_TRUE;
else
return ADE_RETURN_FALSE;
}
ADE_VIRTVAR(Gliding, l_Ship, "boolean", "Specifies whether this ship is currently gliding or not.", "boolean", "true if gliding, false otherwise or in case of error")
{
object_h *objh=NULL;
bool gliding = false;
if (!ade_get_args(L, "o|b", l_Ship.GetPtr(&objh), &gliding))
return ADE_RETURN_FALSE;
if (!objh->IsValid())
return ADE_RETURN_FALSE;
ship *shipp = &Ships[objh->objp->instance];
if(ADE_SETTING_VAR)
{
if (Ship_info[shipp->ship_info_index].can_glide)
{
object_set_gliding(&Objects[shipp->objnum], gliding, true);
}
}
if (objh->objp->phys_info.flags & PF_GLIDING || objh->objp->phys_info.flags & PF_FORCE_GLIDE)
return ADE_RETURN_TRUE;
else
return ADE_RETURN_FALSE;
}
ADE_VIRTVAR(EtsEngineIndex, l_Ship, "number", "(SET not implemented, see EtsSetIndexes)", "number", "Ships ETS Engine index value, 0 to MAX_ENERGY_INDEX")
{
object_h *objh=NULL;
int ets_idx = 0;
if (!ade_get_args(L, "o|i", l_Ship.GetPtr(&objh), &ets_idx))
return ade_set_error(L, "i", 0);
if (!objh->IsValid())
return ade_set_error(L, "i", 0);
if(ADE_SETTING_VAR)
LuaError(L, "Attempted to set incomplete feature: ETS Engine Index (see EtsSetIndexes)");
return ade_set_args(L, "i", Ships[objh->objp->instance].engine_recharge_index);
}
ADE_VIRTVAR(EtsShieldIndex, l_Ship, "number", "(SET not implemented, see EtsSetIndexes)", "number", "Ships ETS Shield index value, 0 to MAX_ENERGY_INDEX")
{
object_h *objh=NULL;
int ets_idx = 0;
if (!ade_get_args(L, "o|i", l_Ship.GetPtr(&objh), &ets_idx))
return ade_set_error(L, "i", 0);
if (!objh->IsValid())
return ade_set_error(L, "i", 0);
if(ADE_SETTING_VAR)
LuaError(L, "Attempted to set incomplete feature: ETS Shield Index (see EtsSetIndexes)");
return ade_set_args(L, "i", Ships[objh->objp->instance].shield_recharge_index);
}
ADE_VIRTVAR(EtsWeaponIndex, l_Ship, "number", "(SET not implemented, see EtsSetIndexes)", "number", "Ships ETS Weapon index value, 0 to MAX_ENERGY_INDEX")
{
object_h *objh=NULL;
int ets_idx = 0;
if (!ade_get_args(L, "o|i", l_Ship.GetPtr(&objh), &ets_idx))
return ade_set_error(L, "i", 0);
if (!objh->IsValid())
return ade_set_error(L, "i", 0);
if(ADE_SETTING_VAR)
LuaError(L, "Attempted to set incomplete feature: ETS Weapon Index (see EtsSetIndexes)");
return ade_set_args(L, "i", Ships[objh->objp->instance].weapon_recharge_index);
}
ADE_VIRTVAR(Orders, l_Ship, "shiporders", "Array of ship orders", "shiporders", "Ship orders, or invalid handle if ship handle is invalid")
{
object_h *objh = NULL;
object_h *newh = NULL;
if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&objh), l_ShipOrders.GetPtr(&newh)))
return ade_set_error(L, "o", l_ShipOrders.Set(object_h()));
if(!objh->IsValid())
return ade_set_error(L, "o", l_ShipOrders.Set(object_h()));;
if(ADE_SETTING_VAR)
{
LuaError(L, "Attempted to use incomplete feature: Ai orders copy. Use giveOrder instead");
}
return ade_set_args(L, "o", l_ShipOrders.Set(object_h(objh->objp)));
}
ADE_FUNC(kill, l_Ship, "[object Killer]", "Kills the ship. Set \"Killer\" to the ship you are killing to self-destruct", "boolean", "True if successful, false or nil otherwise")
{
object_h *victim,*killer=NULL;
if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&victim), l_Ship.GetPtr(&killer)))
return ADE_RETURN_NIL;
if(!victim->IsValid())
return ADE_RETURN_NIL;
if(!killer || !killer->IsValid())
return ADE_RETURN_NIL;
//Ripped straight from shiphit.cpp
float percent_killed = -get_hull_pct(victim->objp);
if (percent_killed > 1.0f){
percent_killed = 1.0f;
}
ship_hit_kill(victim->objp, killer->objp, percent_killed, (victim->sig == killer->sig) ? 1 : 0);
return ADE_RETURN_TRUE;
}
ADE_FUNC(addShipEffect, l_Ship, "string name, int duration (in milliseconds)", "Activates an effect for this ship. Effect names are defined in Post_processing.tbl, and need to be implemented in the main shader. This functions analogous to the ship-effect sexp. NOTE: only one effect can be active at any time, adding new effects will override effects already in progress.\n", "boolean", "Returns true if the effect was successfully added, false otherwise") {
object_h *shiph;
const char* effect = nullptr;
int duration;
int effect_num;
if (!ade_get_args(L, "o|si", l_Ship.GetPtr(&shiph), &effect, &duration))
return ade_set_error(L, "b", false);
if (!shiph->IsValid())
return ade_set_error(L, "b", false);
effect_num = get_effect_from_name(effect);
if (effect_num == -1)
return ade_set_error(L, "b", false);
ship* shipp = &Ships[shiph->objp->instance];
shipp->shader_effect_active = true;
shipp->shader_effect_num = effect_num;
shipp->shader_effect_duration = duration;
shipp->shader_effect_start_time = timer_get_milliseconds();
return ade_set_args(L, "b", true);
}
ADE_FUNC(hasShipExploded, l_Ship, NULL, "Checks if the ship explosion event has already happened", "number", "Returns 1 if first explosion timestamp is passed, 2 if second is passed, 0 otherwise")
{
object_h *shiph;
if(!ade_get_args(L, "o", l_Ship.GetPtr(&shiph)))
return ade_set_error(L, "i", 0);
if(!shiph->IsValid())
return ade_set_error(L, "i", 0);
ship *shipp = &Ships[shiph->objp->instance];
if (shipp->flags[Ship::Ship_Flags::Dying]) {
if (shipp->final_death_time == 0) {
return ade_set_args(L, "i", 2);
}
if (shipp->pre_death_explosion_happened == 1) {
return ade_set_args(L, "i", 1);
}
return ade_set_args(L, "i", 3);
}
return ade_set_args(L, "i", 0);
}
ADE_FUNC(fireCountermeasure, l_Ship, NULL, "Launches a countermeasure from the ship", "boolean", "Whether countermeasure was launched or not")
{
object_h *objh;
if(!ade_get_args(L, "o", l_Ship.GetPtr(&objh)))
return ade_set_error(L, "b", false);
if(!objh->IsValid())
return ade_set_error(L, "b", false);
return ade_set_args(L, "b", ship_launch_countermeasure(objh->objp) != 0);
}
ADE_FUNC(firePrimary, l_Ship, NULL, "Fires ship primary bank(s)", "number", "Number of primary banks fired")
{
object_h *objh;
if(!ade_get_args(L, "o", l_Ship.GetPtr(&objh)))
return ade_set_error(L, "i", 0);
if(!objh->IsValid())
return ade_set_error(L, "i", 0);
int i = 0;
i += ship_fire_primary(objh->objp, 0);
i += ship_fire_primary(objh->objp, 1);
return ade_set_args(L, "i", i);
}
ADE_FUNC(fireSecondary, l_Ship, NULL, "Fires ship secondary bank(s)", "number", "Number of secondary banks fired")
{
object_h *objh;
if(!ade_get_args(L, "o", l_Ship.GetPtr(&objh)))
return ade_set_error(L, "i", 0);
if(!objh->IsValid())
return ade_set_error(L, "i", 0);
return ade_set_args(L, "i", ship_fire_secondary(objh->objp, 0));
}
ADE_FUNC(getAnimationDoneTime, l_Ship, "number Type, number Subtype", "Gets time that animation will be done", "number", "Time (seconds), or 0 if ship handle is invalid")
{
object_h *objh;
const char* s = nullptr;
int subtype=-1;
if(!ade_get_args(L, "o|si", l_Ship.GetPtr(&objh), &s, &subtype))
return ade_set_error(L, "f", 0.0f);
if(!objh->IsValid())
return ade_set_error(L, "f", 0.0f);
int type = model_anim_match_type(s);
if(type < 0)
return ADE_RETURN_FALSE;
int time_ms = model_anim_get_time_type(&Ships[objh->objp->instance], type, subtype);
float time_s = (float)time_ms / 1000.0f;
return ade_set_args(L, "f", time_s);
}
ADE_FUNC(clearOrders, l_Ship, NULL, "Clears a ship's orders list", "boolean", "True if successful, otherwise false or nil")
{
object_h *objh = NULL;
if(!ade_get_args(L, "o", l_Object.GetPtr(&objh)))
return ADE_RETURN_NIL;
if(!objh->IsValid())
return ade_set_error(L, "b", false);
//The actual clearing of the goals
ai_clear_ship_goals( &Ai_info[Ships[objh->objp->instance].ai_index]);
return ADE_RETURN_TRUE;
}
ADE_FUNC(giveOrder, l_Ship, "enumeration Order, [object Target=nil, subsystem TargetSubsystem=nil, number Priority=1.0, shipclass TargetShipclass=nil]", "Uses the goal code to execute orders", "boolean", "True if order was given, otherwise false or nil")
{
object_h *objh = NULL;
enum_h *eh = NULL;
float priority = 1.0f;
int sclass = -1;
object_h *tgh = NULL;
ship_subsys_h *tgsh = NULL;
if(!ade_get_args(L, "oo|oofo", l_Object.GetPtr(&objh), l_Enum.GetPtr(&eh), l_Object.GetPtr(&tgh), l_Subsystem.GetPtr(&tgsh), &priority, l_Shipclass.Get(&sclass)))
return ADE_RETURN_NIL;
if(!objh->IsValid() || !eh->IsValid())
return ade_set_error(L, "b", false);
//wtf...
if(priority < 0.0f)
return ade_set_error(L, "b", false);
if(priority > 1.0f)
priority = 1.0f;
bool tgh_valid = tgh && tgh->IsValid();
bool tgsh_valid = tgsh && tgsh->isSubsystemValid();
int ai_mode = AI_GOAL_NONE;
int ai_submode = -1234567;
char *ai_shipname = NULL;
switch(eh->index)
{
case LE_ORDER_ATTACK:
{
if(tgsh_valid)
{
ai_mode = AI_GOAL_DESTROY_SUBSYSTEM;
ai_shipname = Ships[tgh->objp->instance].ship_name;
ai_submode = ship_get_subsys_index( &Ships[tgsh->objp->instance], tgsh->ss->system_info->subobj_name );
}
else if(tgh_valid && tgh->objp->type == OBJ_WEAPON)
{
ai_mode = AI_GOAL_CHASE_WEAPON;
ai_submode = tgh->objp->instance;
}
else if(tgh_valid && tgh->objp->type == OBJ_SHIP)
{
ai_mode = AI_GOAL_CHASE;
ai_shipname = Ships[tgh->objp->instance].ship_name;
ai_submode = SM_ATTACK;
}
break;
}
case LE_ORDER_DOCK:
{
ai_shipname = Ships[tgh->objp->instance].ship_name;
ai_mode = AI_GOAL_DOCK;
ai_submode = AIS_DOCK_0;
break;
}
case LE_ORDER_WAYPOINTS:
{
if(tgh_valid && tgh->objp->type == OBJ_WAYPOINT)
{
ai_mode = AI_GOAL_WAYPOINTS;
waypoint_list *wp_list = find_waypoint_list_with_instance(tgh->objp->instance);
if(wp_list != NULL)
ai_shipname = wp_list->get_name();
}
break;
}
case LE_ORDER_WAYPOINTS_ONCE:
{
if(tgh_valid && tgh->objp->type == OBJ_WAYPOINT)
{
ai_mode = AI_GOAL_WAYPOINTS_ONCE;
waypoint_list *wp_list = find_waypoint_list_with_instance(tgh->objp->instance);
if(wp_list != NULL)
ai_shipname = wp_list->get_name();
}
break;
}
case LE_ORDER_DEPART:
{
ai_mode = AI_GOAL_WARP;
ai_submode = -1;
break;
}
case LE_ORDER_FORM_ON_WING:
{
if(tgh_valid && tgh->objp->type == OBJ_SHIP)
{
ai_mode = AI_GOAL_FORM_ON_WING;
ai_shipname = Ships[tgh->objp->instance].ship_name;
ai_submode = 0;
}
break;
}
case LE_ORDER_UNDOCK:
{
ai_mode = AI_GOAL_UNDOCK;
ai_submode = AIS_UNDOCK_0;
if(tgh_valid && tgh->objp->type == OBJ_SHIP)
{
ai_shipname = Ships[tgh->objp->instance].ship_name;
}
break;
}
case LE_ORDER_GUARD:
{
if(tgh_valid && tgh->objp->type == OBJ_SHIP)
{
ai_mode = AI_GOAL_GUARD;
ai_submode = AIS_GUARD_PATROL;
ai_shipname = Ships[tgh->objp->instance].ship_name;
}
break;
}
case LE_ORDER_DISABLE:
{
if(tgh_valid && tgh->objp->type == OBJ_SHIP)
{
ai_mode = AI_GOAL_DISABLE_SHIP;
ai_submode = -SUBSYSTEM_ENGINE;
ai_shipname = Ships[tgh->objp->instance].ship_name;
}
break;
}
case LE_ORDER_DISARM:
{
if(tgh_valid && tgh->objp->type == OBJ_SHIP)
{
ai_mode = AI_GOAL_DISARM_SHIP;
ai_submode = -SUBSYSTEM_TURRET;
ai_shipname = Ships[tgh->objp->instance].ship_name;
}
break;
}
case LE_ORDER_ATTACK_ANY:
{
ai_mode = AI_GOAL_CHASE_ANY;
ai_submode = SM_ATTACK;
break;
}
case LE_ORDER_IGNORE:
{
if(tgh_valid && tgh->objp->type == OBJ_SHIP)
{
ai_mode = AI_GOAL_IGNORE_NEW;
ai_submode = 0;
ai_shipname = Ships[tgh->objp->instance].ship_name;
}
break;
}
case LE_ORDER_EVADE:
{
if(tgh_valid && tgh->objp->type == OBJ_SHIP)
{
ai_mode = AI_GOAL_EVADE_SHIP;
ai_shipname = Ships[tgh->objp->instance].ship_name;
}
break;
}
case LE_ORDER_STAY_NEAR:
{
if(tgh_valid && tgh->objp->type == OBJ_SHIP)
{
ai_mode = AI_GOAL_STAY_NEAR_SHIP;
ai_shipname = Ships[tgh->objp->instance].ship_name;
ai_submode = -1;
}
break;
}
case LE_ORDER_KEEP_SAFE_DISTANCE:
{
if(tgh_valid && tgh->objp->type == OBJ_SHIP)
{
ai_mode = AI_GOAL_KEEP_SAFE_DISTANCE;
ai_shipname = Ships[tgh->objp->instance].ship_name;
ai_submode = -1;
}
break;
}
case LE_ORDER_REARM:
{
if(tgh_valid && tgh->objp->type == OBJ_SHIP)
{
ai_mode = AI_GOAL_REARM_REPAIR;
ai_shipname = Ships[tgh->objp->instance].ship_name;
ai_submode = 0;
}
break;
}
case LE_ORDER_STAY_STILL:
{
ai_mode = AI_GOAL_STAY_STILL;
if(tgh_valid && tgh->objp->type == OBJ_SHIP)
{
ai_shipname = Ships[tgh->objp->instance].ship_name;
}
break;
}
case LE_ORDER_PLAY_DEAD:
{
ai_mode = AI_GOAL_PLAY_DEAD;
break;
}
case LE_ORDER_PLAY_DEAD_PERSISTENT:
{
ai_mode = AI_GOAL_PLAY_DEAD_PERSISTENT;
break;
}
case LE_ORDER_FLY_TO:
{
if(tgh_valid && tgh->objp->type == OBJ_SHIP)
{
ai_mode = AI_GOAL_FLY_TO_SHIP;
ai_shipname = Ships[tgh->objp->instance].ship_name;
ai_submode = 0;
}
break;
}
case LE_ORDER_ATTACK_WING:
{
if(tgh_valid && tgh->objp->type == OBJ_SHIP)
{
ship *shipp = &Ships[tgh->objp->instance];
if (shipp->wingnum != -1)
{
ai_mode = AI_GOAL_CHASE_WING;
ai_shipname = Wings[shipp->wingnum].name;
ai_submode = SM_ATTACK;
}
}
break;
}
case LE_ORDER_GUARD_WING:
{
if(tgh_valid && tgh->objp->type == OBJ_SHIP)
{
ship *shipp = &Ships[tgh->objp->instance];
if (shipp->wingnum != -1)
{
ai_mode = AI_GOAL_GUARD_WING;
ai_shipname = Wings[shipp->wingnum].name;
ai_submode = AIS_GUARD_STATIC;
}
}
break;
}
case LE_ORDER_ATTACK_SHIP_CLASS:
{
if(sclass >= 0)
{
ai_mode = AI_GOAL_CHASE_SHIP_CLASS;
ai_shipname = Ship_info[sclass].name;
ai_submode = SM_ATTACK;
}
break;
}
}
//Nothing got set!
if(ai_mode == AI_GOAL_NONE)
return ade_set_error(L, "b", false);
//Fire off the goal
ai_add_ship_goal_scripting(ai_mode, ai_submode, (int)(priority*100.0f), ai_shipname, &Ai_info[Ships[objh->objp->instance].ai_index]);
return ADE_RETURN_TRUE;
}
ADE_FUNC(doManeuver, l_Ship, "number Duration, number Heading, number Pitch, number Bank, boolean Apply-all Rotation, number Vertical, number Sideways, number Forward, boolean Apply-all Movement, number Maneuver Bitfield", "Sets ship maneuver over the defined time period", "boolean", "True if maneuver order was given, otherwise false or nil")
{
object_h *objh;
float heading, pitch, bank, up, sideways, forward;
bool apply_all_rotate = false, apply_all_move = false;
int duration, maneuver_flags = 0;
if(!ade_get_args(L, "oifffbfffb|i", l_Ship.GetPtr(&objh), &duration, &heading, &pitch, &bank, &apply_all_rotate, &up, &sideways, &forward, &apply_all_move, &maneuver_flags))
return ADE_RETURN_NIL;
ship *shipp = &Ships[objh->objp->instance];
ai_info *aip = &Ai_info[shipp->ai_index];
control_info *cip = &aip->ai_override_ci;
aip->ai_override_flags.reset();
// handle infinite timestamps
if (duration >= 2) {
aip->ai_override_timestamp = timestamp(duration);
} else {
aip->ai_override_timestamp = timestamp(10);
aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Never_expire);
}
if (apply_all_rotate) {
aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Full_rot);
cip->heading = heading;
cip->pitch = pitch;
cip->bank = bank;
} else {
if (heading != 0) {
cip->heading = heading;
aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Heading);
}
if (pitch != 0) {
cip->pitch = pitch;
aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Pitch);
}
if (bank != 0) {
cip->bank = bank;
aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Roll);
}
}
if (apply_all_move) {
aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Full_lat);
cip->vertical = up;
cip->sideways = sideways;
cip->forward = forward;
} else {
if (up != 0) {
cip->vertical = up;
aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Up);
}
if (sideways != 0) {
cip->sideways = sideways;
aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Sideways);
}
if (forward != 0) {
cip->forward = forward;
aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Forward);
}
}
if (maneuver_flags & CIF_DONT_BANK_WHEN_TURNING) {
aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Dont_bank_when_turning);
}
if (maneuver_flags & CIF_DONT_CLAMP_MAX_VELOCITY) {
aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Dont_clamp_max_velocity);
}
if (maneuver_flags & CIF_INSTANTANEOUS_ACCELERATION) {
aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Instantaneous_acceleration);
}
return ADE_RETURN_TRUE;
}
ADE_FUNC(triggerAnimation, l_Ship, "string Type, [number Subtype, boolean Forwards, boolean Instant]",
"Triggers an animation. Type is the string name of the animation type, "
"Subtype is the subtype number, such as weapon bank #, Forwards and Instant are boolean, defaulting to true & false respectively."
"<br><strong>IMPORTANT: Function is in testing and should not be used with official mod releases</strong>",
"boolean",
"True if successful, false or nil otherwise")
{
object_h *objh;
const char* s = nullptr;
bool b = true;
bool instant = false;
int subtype=-1;
if(!ade_get_args(L, "o|sibb", l_Ship.GetPtr(&objh), &s, &subtype, &b, &instant))
return ADE_RETURN_NIL;
if(!objh->IsValid())
return ADE_RETURN_NIL;
int type = model_anim_match_type(s);
if(type < 0)
return ADE_RETURN_FALSE;
int dir = 1;
if(!b)
dir = -1;
model_anim_start_type(&Ships[objh->objp->instance], type, subtype, dir, instant);
return ADE_RETURN_TRUE;
}
ADE_FUNC(warpIn, l_Ship, NULL, "Warps ship in", "boolean", "True if successful, or nil if ship handle is invalid")
{
object_h *objh;
if(!ade_get_args(L, "o", l_Ship.GetPtr(&objh)))
return ADE_RETURN_NIL;
if(!objh->IsValid())
return ADE_RETURN_NIL;
shipfx_warpin_start(objh->objp);
return ADE_RETURN_TRUE;
}
ADE_FUNC(warpOut, l_Ship, NULL, "Warps ship out", "boolean", "True if successful, or nil if ship handle is invalid")
{
object_h *objh;
if(!ade_get_args(L, "o", l_Ship.GetPtr(&objh)))
return ADE_RETURN_NIL;
if(!objh->IsValid())
return ADE_RETURN_NIL;
shipfx_warpout_start(objh->objp);
return ADE_RETURN_TRUE;
}
ADE_FUNC(canWarp, l_Ship, nullptr, "Checks whether ship has a working subspace drive, is allowed to use it, and is not disabled or limited by subsystem strength.", "boolean", "True if successful, or nil if ship handle is invalid")
{
object_h *objh;
if(!ade_get_args(L, "o", l_Ship.GetPtr(&objh)))
return ADE_RETURN_NIL;
if(!objh->IsValid())
return ADE_RETURN_NIL;
ship *shipp = &Ships[objh->objp->instance];
if( ship_can_warp_full_check(shipp) ){
return ADE_RETURN_TRUE;
}
return ADE_RETURN_FALSE;
}
ADE_FUNC(canBayDepart, l_Ship, nullptr, "Checks whether ship has a bay departure location and if its mother ship is present.", "boolean", "True if successful, or nil if ship handle is invalid")
{
object_h *objh;
if(!ade_get_args(L, "o", l_Ship.GetPtr(&objh)))
return ADE_RETURN_NIL;
if(!objh->IsValid())
return ADE_RETURN_NIL;
ship *shipp = &Ships[objh->objp->instance];
if( ship_can_bay_depart(shipp) ){
return ADE_RETURN_TRUE;
}
return ADE_RETURN_FALSE;
}
// Aardwolf's function for finding if a ship should be drawn as blue on the radar/minimap
ADE_FUNC(isWarpingIn, l_Ship, NULL, "Checks if ship is warping in", "boolean", "True if the ship is warping in, false or nil otherwise")
{
object_h *objh;
if(!ade_get_args(L, "o", l_Ship.GetPtr(&objh)))
return ADE_RETURN_NIL;
if(!objh->IsValid())
return ADE_RETURN_NIL;
ship *shipp = &Ships[objh->objp->instance];
if(shipp->is_arriving(ship::warpstage::STAGE1, false)){
return ADE_RETURN_TRUE;
}
return ADE_RETURN_FALSE;
}
ADE_FUNC(getEMP, l_Ship, NULL, "Returns the current emp effect strength acting on the object", "number", "Current EMP effect strength or NIL if object is invalid")
{
object_h *objh = NULL;
object *obj = NULL;
if (!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) {
return ADE_RETURN_NIL;
}
if(!objh->IsValid())
return ADE_RETURN_NIL;
obj = objh->objp;
ship *shipp = &Ships[obj->instance];
return ade_set_args(L, "f", shipp->emp_intensity);
}
ADE_FUNC(getTimeUntilExplosion, l_Ship, NULL, "Returns the time in seconds until the ship explodes", "number", "Time until explosion or -1, if invalid handle or ship isn't exploding")
{
object_h *objh = NULL;
if (!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) {
return ade_set_error(L, "f", -1.0f);
}
if(!objh->IsValid())
return ade_set_error(L, "f", -1.0f);
ship *shipp = &Ships[objh->objp->instance];
if (!timestamp_valid(shipp->final_death_time))
{
return ade_set_args(L, "f", -1.0f);
}
int time_until = timestamp_until(shipp->final_death_time);
return ade_set_args(L, "f", (i2fl(time_until) / 1000.0f));
}
ADE_FUNC(getCallsign, l_Ship, NULL, "Gets the callsign of the ship in the current mission", "string", "The callsign or an empty string if the ship doesn't have a callsign or an error occurs")
{
object_h *objh = NULL;
if (!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) {
return ade_set_error(L, "s", "");
}
if(!objh->IsValid())
return ade_set_error(L, "s", "");
ship *shipp = &Ships[objh->objp->instance];
if (shipp->callsign_index < 0)
return ade_set_args(L, "s", "");
char temp_callsign[NAME_LENGTH];
*temp_callsign = 0;
mission_parse_lookup_callsign_index(shipp->callsign_index, temp_callsign);
if (*temp_callsign)
return ade_set_args(L, "s", temp_callsign);
else
return ade_set_args(L, "s", "");
}
ADE_FUNC(getAltClassName, l_Ship, NULL, "Gets the alternate class name of the ship", "string", "The alternate class name or an empty string if the ship doesn't have such a thing or an error occurs")
{
object_h *objh = NULL;
if (!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) {
return ade_set_error(L, "s", "");
}
if(!objh->IsValid())
return ade_set_error(L, "s", "");
ship *shipp = &Ships[objh->objp->instance];
if (shipp->alt_type_index < 0)
return ade_set_args(L, "s", "");
char temp[NAME_LENGTH];
*temp = 0;
mission_parse_lookup_alt_index(shipp->alt_type_index, temp);
if (*temp)
return ade_set_args(L, "s", temp);
else
return ade_set_args(L, "s", "");
}
ADE_FUNC(getMaximumSpeed, l_Ship, "[number energy = 0.333]", "Gets the maximum speed of the ship with the given energy on the engines", "number", "The maximum speed or -1 on error")
{
object_h *objh = NULL;
float energy = 0.333f;
if (!ade_get_args(L, "o|f", l_Ship.GetPtr(&objh), &energy)) {
return ade_set_error(L, "f", -1.0f);
}
if(!objh->IsValid())
return ade_set_error(L, "f", -1.0f);
if (energy < 0.0f || energy > 1.0f)
{
LuaError(L, "Invalid energy level %f! Needs to be in [0, 1].", energy);
return ade_set_args(L, "f", -1.0f);
}
else
{
return ade_set_args(L, "f", ets_get_max_speed(objh->objp, energy));
}
}
ADE_FUNC(EtsSetIndexes, l_Ship, "number Engine Index, number Shield Index, number Weapon Index",
"Sets ships ETS systems to specified values",
"boolean",
"True if successful, false if target ships ETS was missing, or only has one system")
{
object_h *objh=NULL;
int ets_idx[num_retail_ets_gauges] = {0};
if (!ade_get_args(L, "oiii", l_Ship.GetPtr(&objh), &ets_idx[ENGINES], &ets_idx[SHIELDS], &ets_idx[WEAPONS]))
return ADE_RETURN_FALSE;
if (!objh->IsValid())
return ADE_RETURN_FALSE;
sanity_check_ets_inputs(ets_idx);
int sindex = objh->objp->instance;
if (validate_ship_ets_indxes(sindex, ets_idx)) {
Ships[sindex].engine_recharge_index = ets_idx[ENGINES];
Ships[sindex].shield_recharge_index = ets_idx[SHIELDS];
Ships[sindex].weapon_recharge_index = ets_idx[WEAPONS];
return ADE_RETURN_TRUE;
} else {
return ADE_RETURN_FALSE;
}
}
ADE_FUNC(getWing, l_Ship, NULL, "Returns the ship's wing", "wing", "Wing handle, or invalid wing handle if ship is not part of a wing")
{
object_h *objh = NULL;
ship *shipp = NULL;
if (!ade_get_args(L, "o", l_Ship.GetPtr(&objh)))
return ade_set_error(L, "o", l_Wing.Set(-1));
if(!objh->IsValid())
return ade_set_error(L, "o", l_Wing.Set(-1));
shipp = &Ships[objh->objp->instance];
return ade_set_args(L, "o", l_Wing.Set(shipp->wingnum));
}
ADE_FUNC(getDisplayString, l_Ship, nullptr, "Returns the string which should be used when displaying the name of the ship to the player", "string", "The display string or empty if handle is invalid")
{
object_h *objh = nullptr;
ship *shipp = nullptr;
if (!ade_get_args(L, "o", l_Ship.GetPtr(&objh)))
return ade_set_error(L, "s", "");
if(!objh->IsValid())
return ade_set_error(L, "s", "");
shipp = &Ships[objh->objp->instance];
return ade_set_args(L, "s", shipp->get_display_string());
}
}
}