Files
fs2open.github.com/code/scripting/api/objs/subsystem.cpp
T
asarium d54d7d41e6 Output parameter information to JSON
Also fixes the parameter strings which currently could not be parsed by
the argument parser.
2020-06-06 23:45:36 +02:00

768 lines
25 KiB
C++

//
//
#include "subsystem.h"
#include "model_path.h"
#include "object.h"
#include "ship.h"
#include "ship_bank.h"
#include "vecmath.h"
#include "hud/hudtarget.h"
#include "ship/shiphit.h"
bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum, vec3d *turret_pos, vec3d *turret_fvec, vec3d *predicted_pos = NULL, float flak_range_override = 100.0f);
namespace scripting {
namespace api {
ship_subsys_h::ship_subsys_h() : object_h() {
ss = NULL;
}
ship_subsys_h::ship_subsys_h(object* objp_in, ship_subsys* sub) : object_h(objp_in) {
ss = sub;
}
bool ship_subsys_h::isSubsystemValid() const { return object_h::IsValid() && objp->type == OBJ_SHIP && ss != nullptr; }
//**********HANDLE: Subsystem
ADE_OBJ(l_Subsystem, ship_subsys_h, "subsystem", "Ship subsystem handle");
ADE_FUNC(__tostring, l_Subsystem, NULL, "Returns name of subsystem", "string", "Subsystem name, or empty string if handle is invalid")
{
ship_subsys_h *sso;
if(!ade_get_args(L, "o", l_Subsystem.GetPtr(&sso)))
return ade_set_error(L, "s", "");
if (!sso->isSubsystemValid())
return ade_set_error(L, "s", "");
return ade_set_args(L, "s", ship_subsys_get_name(sso->ss));
}
ADE_VIRTVAR(ArmorClass, l_Subsystem, "string", "Current Armor class", "string", "Armor class name, or empty string if none is set")
{
ship_subsys_h *sso;
const char* s = nullptr;
const char *name = nullptr;
if(!ade_get_args(L, "o|s", l_Subsystem.GetPtr(&sso), &s))
return ade_set_error(L, "s", "");
if (!sso->isSubsystemValid())
return ade_set_error(L, "s", "");
ship_subsys *ssys = sso->ss;
int atindex;
if (ADE_SETTING_VAR && s != nullptr) {
atindex = armor_type_get_idx(s);
ssys->armor_type_idx = atindex;
} else {
atindex = ssys->armor_type_idx;
}
if (atindex != -1)
name = Armor_types[atindex].GetNamePtr();
else
name = "";
return ade_set_args(L, "s", name);
}
ADE_VIRTVAR(AWACSIntensity, l_Subsystem, "number", "Subsystem AWACS intensity", "number", "AWACS intensity, or 0 if handle is invalid")
{
ship_subsys_h *sso;
float f = -1.0f;
if(!ade_get_args(L, "o|f", l_Subsystem.GetPtr(&sso), &f))
return ade_set_error(L, "f", 0.0f);
if (!sso->isSubsystemValid())
return ade_set_error(L, "f", 0.0f);
if(ADE_SETTING_VAR && f >= 0.0f)
sso->ss->awacs_intensity = f;
return ade_set_args(L, "f", sso->ss->awacs_intensity);
}
ADE_VIRTVAR(AWACSRadius, l_Subsystem, "number", "Subsystem AWACS radius", "number", "AWACS radius, or 0 if handle is invalid")
{
ship_subsys_h *sso;
float f = -1.0f;
if(!ade_get_args(L, "o|f", l_Subsystem.GetPtr(&sso), &f))
return ade_set_error(L, "f", 0.0f);
if (!sso->isSubsystemValid())
return ade_set_error(L, "f", 0.0f);
if(ADE_SETTING_VAR && f >= 0.0f)
sso->ss->awacs_radius = f;
return ade_set_args(L, "f", sso->ss->awacs_radius);
}
ADE_VIRTVAR(Orientation, l_Subsystem, "orientation", "Orientation of subobject or turret base", "orientation", "Subsystem orientation, or null orientation if handle is invalid")
{
ship_subsys_h *sso;
matrix_h *mh = nullptr;
if(!ade_get_args(L, "o|o", l_Subsystem.GetPtr(&sso), l_Matrix.GetPtr(&mh)))
return ade_set_error(L, "o", l_Matrix.Set(matrix_h()));
if (!sso->isSubsystemValid())
return ade_set_error(L, "o", l_Matrix.Set(matrix_h()));
if(ADE_SETTING_VAR && mh)
{
sso->ss->submodel_info_1.angs = *mh->GetAngles();
}
return ade_set_args(L, "o", l_Matrix.Set(matrix_h(&sso->ss->submodel_info_1.angs)));
}
ADE_VIRTVAR(GunOrientation, l_Subsystem, "orientation", "Orientation of turret gun", "orientation", "Gun orientation, or null orientation if handle is invalid")
{
ship_subsys_h *sso;
matrix_h *mh = nullptr;
if(!ade_get_args(L, "o|o", l_Subsystem.GetPtr(&sso), l_Matrix.GetPtr(&mh)))
return ade_set_error(L, "o", l_Matrix.Set(matrix_h()));
if (!sso->isSubsystemValid())
return ade_set_error(L, "o", l_Matrix.Set(matrix_h()));
if(ADE_SETTING_VAR && mh)
{
sso->ss->submodel_info_2.angs = *mh->GetAngles();
}
return ade_set_args(L, "o", l_Matrix.Set(matrix_h(&sso->ss->submodel_info_2.angs)));
}
ADE_VIRTVAR(HitpointsLeft, l_Subsystem, "number", "Subsystem hitpoints left", "number", "Hitpoints left, or 0 if handle is invalid. Setting a value of 0 will disable it - set a value of -1 or lower to actually blow it up.")
{
ship_subsys_h *sso;
float f = -1.0f;
if(!ade_get_args(L, "o|f", l_Subsystem.GetPtr(&sso), &f))
return ade_set_error(L, "f", 0.0f);
if (!sso->isSubsystemValid())
return ade_set_error(L, "f", 0.0f);
if(ADE_SETTING_VAR)
{
//Only go down to 0 hits
sso->ss->current_hits = MAX(0.0f, f);
ship *shipp = &Ships[sso->objp->instance];
if (f <= -1.0f && sso->ss->current_hits <= 0.0f) {
do_subobj_destroyed_stuff(shipp, sso->ss, NULL);
}
ship_recalc_subsys_strength(shipp);
}
return ade_set_args(L, "f", sso->ss->current_hits);
}
ADE_VIRTVAR(HitpointsMax, l_Subsystem, "number", "Subsystem hitpoints max", "number", "Max hitpoints, or 0 if handle is invalid")
{
ship_subsys_h *sso;
float f = -1.0f;
if(!ade_get_args(L, "o|f", l_Subsystem.GetPtr(&sso), &f))
return ade_set_error(L, "f", 0.0f);
if (!sso->isSubsystemValid())
return ade_set_error(L, "f", 0.0f);
if(ADE_SETTING_VAR)
{
sso->ss->max_hits = MIN(0.0f, f);
ship_recalc_subsys_strength(&Ships[sso->objp->instance]);
}
return ade_set_args(L, "f", sso->ss->max_hits);
}
ADE_VIRTVAR(Position, l_Subsystem, "vector", "Subsystem position with regards to main ship (Local Vector)", "vector", "Subsystem position, or null vector if subsystem handle is invalid")
{
ship_subsys_h *sso;
vec3d *v = NULL;
if(!ade_get_args(L, "o|o", l_Subsystem.GetPtr(&sso), l_Vector.GetPtr(&v)))
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
if (!sso->isSubsystemValid())
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
if(ADE_SETTING_VAR && v != NULL)
{
sso->ss->system_info->pnt = *v;
}
return ade_set_args(L, "o", l_Vector.Set(sso->ss->system_info->pnt));
}
ADE_VIRTVAR(WorldPosition, l_Subsystem, "vector",
"Subsystem position in world space. This handles subsystem attached to a rotating submodel properly.",
"vector", "Subsystem position, or null vector if subsystem handle is invalid")
{
ship_subsys_h* sso;
vec3d* v = nullptr;
if (!ade_get_args(L, "o|o", l_Subsystem.GetPtr(&sso), l_Vector.GetPtr(&v)))
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
if (!sso->isSubsystemValid())
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
vec3d world_pos;
get_subsystem_world_pos(sso->objp, sso->ss, &world_pos);
return ade_set_args(L, "o", l_Vector.Set(world_pos));
}
ADE_VIRTVAR(GunPosition, l_Subsystem, "vector", "Subsystem gun position with regards to main ship (Local vector)", "vector", "Gun position, or null vector if subsystem handle is invalid")
{
ship_subsys_h *sso;
vec3d *v = NULL;
if(!ade_get_args(L, "o|o", l_Subsystem.GetPtr(&sso), l_Vector.GetPtr(&v)))
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
if (!sso->isSubsystemValid())
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
polymodel *pm = model_get(Ship_info[Ships[sso->objp->instance].ship_info_index].model_num);
Assert(pm != NULL);
if(sso->ss->system_info->turret_gun_sobj < 0)
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
bsp_info *sm = &pm->submodel[sso->ss->system_info->turret_gun_sobj];
if(ADE_SETTING_VAR && v != NULL)
sm->offset = *v;
return ade_set_args(L, "o", l_Vector.Set(sm->offset));
}
ADE_VIRTVAR(Name, l_Subsystem, "string", "Subsystem name", "string", "Subsystem name, or an empty string if handle is invalid")
{
ship_subsys_h *sso;
const char* s = nullptr;
if(!ade_get_args(L, "o|s", l_Subsystem.GetPtr(&sso), &s))
return ade_set_error(L, "s", "");
if (!sso->isSubsystemValid())
return ade_set_error(L, "s", "");
if(ADE_SETTING_VAR && s != NULL && strlen(s))
{
ship_subsys_set_name(sso->ss, s);
}
return ade_set_args(L, "s", ship_subsys_get_name(sso->ss));
}
ADE_FUNC(getModelName, l_Subsystem, NULL, "Returns the original name of the subsystem in the model file", "string", "name or empty string on error")
{
ship_subsys_h *sso;
if(!ade_get_args(L, "o", l_Subsystem.GetPtr(&sso)))
return ade_set_error(L, "s", "");
if (!sso->isSubsystemValid())
return ade_set_error(L, "s", "");
return ade_set_args(L, "s", sso->ss->system_info->subobj_name);
}
ADE_VIRTVAR(PrimaryBanks, l_Subsystem, "weaponbanktype", "Array of primary weapon banks", "weaponbanktype", "Primary banks, or invalid weaponbanktype handle if subsystem handle is invalid")
{
ship_subsys_h *sso, *sso2 = nullptr;
if(!ade_get_args(L, "o|o", l_Subsystem.GetPtr(&sso), l_Subsystem.GetPtr(&sso2)))
return ade_set_error(L, "o", l_WeaponBankType.Set(ship_banktype_h()));
if (!sso->isSubsystemValid())
return ade_set_error(L, "o", l_WeaponBankType.Set(ship_banktype_h()));
ship_weapon *dst = &sso->ss->weapons;
if (ADE_SETTING_VAR && sso2 && sso2->isSubsystemValid()) {
ship_weapon *src = &sso2->ss->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(sso->objp, dst, SWH_PRIMARY)));
}
ADE_VIRTVAR(SecondaryBanks, l_Subsystem, "weaponbanktype", "Array of secondary weapon banks", "weaponbanktype", "Secondary banks, or invalid weaponbanktype handle if subsystem handle is invalid")
{
ship_subsys_h *sso, *sso2 = nullptr;
if(!ade_get_args(L, "o|o", l_Subsystem.GetPtr(&sso), l_Subsystem.GetPtr(&sso2)))
return ade_set_error(L, "o", l_WeaponBankType.Set(ship_banktype_h()));
if (!sso->isSubsystemValid())
return ade_set_error(L, "o", l_WeaponBankType.Set(ship_banktype_h()));
ship_weapon *dst = &sso->ss->weapons;
if (ADE_SETTING_VAR && sso2 && sso2->isSubsystemValid()) {
ship_weapon *src = &sso2->ss->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(sso->objp, dst, SWH_SECONDARY)));
}
ADE_VIRTVAR(Target, l_Subsystem, "object", "Object targeted by this subsystem. If used to set a new target, AI targeting will be switched off.", "object", "Targeted object, or invalid object handle if subsystem handle is invalid")
{
ship_subsys_h *sso;
object_h *objh = nullptr;
if(!ade_get_args(L, "o|o", l_Subsystem.GetPtr(&sso), l_Object.GetPtr(&objh)))
return ade_set_error(L, "o", l_Object.Set(object_h()));
if (!sso->isSubsystemValid())
return ade_set_error(L, "o", l_Object.Set(object_h()));
ship_subsys *ss = sso->ss;
if(ADE_SETTING_VAR && objh && objh->IsValid())
{
ss->turret_enemy_objnum = OBJ_INDEX(objh->objp);
ss->turret_enemy_sig = objh->sig;
ss->targeted_subsys = NULL;
ss->scripting_target_override = true;
}
return ade_set_object_with_breed(L, ss->turret_enemy_objnum);
}
ADE_VIRTVAR(TurretResets, l_Subsystem, "boolean", "Specifies wether this turrets resets after a certain time of inactivity", "boolean", "true if turret resets, false otherwise")
{
ship_subsys_h *sso;
bool newVal = false;
if (!ade_get_args(L, "o|b", l_Subsystem.GetPtr(&sso), &newVal))
return ADE_RETURN_FALSE;
if (!sso->isSubsystemValid())
return ADE_RETURN_FALSE;
if(ADE_SETTING_VAR)
{
sso->ss->system_info->flags.set(Model::Subsystem_Flags::Turret_reset_idle, newVal);
}
if (sso->ss->system_info->flags[Model::Subsystem_Flags::Turret_reset_idle])
return ADE_RETURN_TRUE;
else
return ADE_RETURN_FALSE;
}
ADE_VIRTVAR(TurretResetDelay, l_Subsystem, "number", "The time (in milliseconds) after that the turret resets itself", "number", "Reset delay")
{
ship_subsys_h *sso;
int newVal = -1;
if (!ade_get_args(L, "o|i", l_Subsystem.GetPtr(&sso), &newVal))
return ade_set_error(L, "i", -1);
if (!sso->isSubsystemValid())
return ade_set_error(L, "i", -1);
if (!(sso->ss->system_info->flags[Model::Subsystem_Flags::Turret_reset_idle]))
return ade_set_error(L, "i", -1);
if(ADE_SETTING_VAR)
{
if ((sso->ss->system_info->flags[Model::Subsystem_Flags::Turret_reset_idle]))
sso->ss->system_info->turret_reset_delay = newVal;
}
return ade_set_args(L, "i", sso->ss->system_info->turret_reset_delay);
}
ADE_VIRTVAR(TurnRate, l_Subsystem, "number", "The turn rate", "number", "Turnrate or -1 on error")
{
ship_subsys_h *sso;
float newVal = -1.0f;
if (!ade_get_args(L, "o|f", l_Subsystem.GetPtr(&sso), &newVal))
return ade_set_error(L, "f", -1.0f);
if (!sso->isSubsystemValid())
return ade_set_error(L, "f", -1.0f);
if(ADE_SETTING_VAR)
{
sso->ss->system_info->turret_turning_rate = newVal;
}
return ade_set_args(L, "f", sso->ss->system_info->turret_turning_rate);
}
ADE_VIRTVAR(Targetable, l_Subsystem, "boolean", "Targetability of this subsystem", "boolean", "true if targetable, false otherwise or on error")
{
ship_subsys_h *sso;
bool newVal = false;
if (!ade_get_args(L, "o|b", l_Subsystem.GetPtr(&sso), &newVal))
return ade_set_error(L, "b", false);
if (!sso->isSubsystemValid())
return ade_set_error(L, "b", false);
if(ADE_SETTING_VAR)
{
sso->ss->flags.set(Ship::Subsystem_Flags::Untargetable, newVal);
}
return ade_set_args(L, "b", !(sso->ss->flags[Ship::Subsystem_Flags::Untargetable]));
}
ADE_VIRTVAR(Radius, l_Subsystem, "number", "The radius of this subsystem", "number", "The radius or 0 on error")
{
ship_subsys_h *sso;
if (!ade_get_args(L, "o", l_Subsystem.GetPtr(&sso)))
return ade_set_error(L, "f", 0.0f);
if (!sso->isSubsystemValid())
return ade_set_error(L, "f", 0.0f);
if(ADE_SETTING_VAR)
{
LuaError(L, "Setting radius for subsystems is not allowed!");
}
return ade_set_args(L, "f", sso->ss->system_info->radius);
}
ADE_VIRTVAR(TurretLocked, l_Subsystem, "boolean", "Whether the turret is locked. Setting to true locks the turret, setting to false frees it.", "boolean", "True if turret is locked, false otherwise")
{
ship_subsys_h *sso;
bool newVal = false;
if (!ade_get_args(L, "o|b", l_Subsystem.GetPtr(&sso), &newVal))
return ade_set_error(L, "b", false);
if (!sso->isSubsystemValid())
return ade_set_error(L, "b", false);
if(ADE_SETTING_VAR)
{
sso->ss->weapons.flags.set(Ship::Weapon_Flags::Turret_Lock, newVal);
}
return ade_set_args(L, "b", (sso->ss->weapons.flags[Ship::Weapon_Flags::Turret_Lock]));
}
ADE_VIRTVAR(NextFireTimestamp, l_Subsystem, "number", "The next time the turret may attempt to fire", "number", "Mission time (seconds) or -1 on error")
{
ship_subsys_h *sso;
float newVal = -1.0f;
if (!ade_get_args(L, "o|f", l_Subsystem.GetPtr(&sso), &newVal))
return ade_set_error(L, "f", -1.0f);
if (!sso->isSubsystemValid())
return ade_set_error(L, "f", -1.0f);
if(ADE_SETTING_VAR)
{
sso->ss->turret_next_fire_stamp = (int)(newVal * 1000);
}
return ade_set_args(L, "f", sso->ss->turret_next_fire_stamp / 1000.0f);
}
ADE_VIRTVAR(ModelPath, l_Subsystem, "modelpath", "The model path points belonging to this subsystem", "modelpath",
"The model path of this subsystem")
{
ship_subsys_h* sso;
if (!ade_get_args(L, "o", l_Subsystem.GetPtr(&sso)))
return ade_set_error(L, "o", l_ModelPath.Set(model_path_h()));
if (!sso->isSubsystemValid())
return ade_set_error(L, "o", l_ModelPath.Set(model_path_h()));
if (ADE_SETTING_VAR) {
LuaError(L, "Setting ModelPath is not supported yet!");
}
auto model = model_get(sso->ss->system_info->model_num);
auto path_idx = sso->ss->system_info->path_num;
if (path_idx < 0) {
// No model path for this subsystem
return ade_set_args(L, "o", l_ModelPath.Set(model_path_h()));
}
Assertion(path_idx >= 0 && path_idx < model->n_paths, "Path index %d is invalid!", path_idx);
return ade_set_args(L, "o", l_ModelPath.Set(model_path_h(*sso, model->paths[path_idx])));
}
ADE_FUNC(targetingOverride, l_Subsystem, "boolean", "If set to true, AI targeting for this turret is switched off. If set to false, the AI will take over again.", "boolean", "Returns true if successful, false otherwise")
{
bool targetOverride = false;
ship_subsys_h *sso;
if(!ade_get_args(L, "ob", l_Subsystem.GetPtr(&sso), &targetOverride))
return ADE_RETURN_FALSE;
if (!sso->isSubsystemValid())
return ADE_RETURN_FALSE;
ship_subsys *ss = sso->ss;
ss->scripting_target_override = targetOverride;
return ADE_RETURN_TRUE;
}
ADE_FUNC(hasFired, l_Subsystem, NULL, "Determine if a subsystem has fired", "boolean", "true if if fired, false if not fired, or nil if invalid. resets fired flag when called.")
{
ship_subsys_h *sso;
if(!ade_get_args(L, "o", l_Subsystem.GetPtr(&sso)))
return ADE_RETURN_NIL;
if (!sso->isSubsystemValid())
return ADE_RETURN_NIL;
if(sso->ss->flags[Ship::Subsystem_Flags::Has_fired]){
sso->ss->flags.remove(Ship::Subsystem_Flags::Has_fired);
return ADE_RETURN_TRUE;
}
else
return ADE_RETURN_FALSE;
}
ADE_FUNC(isTurret, l_Subsystem, NULL, "Determines if this subsystem is a turret", "boolean", "true if subsystem is turret, false otherwise or nil on error")
{
ship_subsys_h *sso;
if(!ade_get_args(L, "o", l_Subsystem.GetPtr(&sso)))
return ADE_RETURN_NIL;
if (!sso->isSubsystemValid())
return ADE_RETURN_NIL;
return ade_set_args(L, "b", sso->ss->system_info->type == SUBSYSTEM_TURRET);
}
ADE_FUNC(isTargetInFOV, l_Subsystem, "object Target", "Determines if the object is in the turrets FOV", "boolean", "true if in FOV, false if not, nil on error or if subsystem is not a turret ")
{
ship_subsys_h *sso;
object_h *newh = nullptr;
if(!ade_get_args(L, "o|o", l_Subsystem.GetPtr(&sso), l_Object.GetPtr(&newh)))
return ADE_RETURN_NIL;
if (!sso->isSubsystemValid() || !newh || !newh->IsValid() || !(sso->ss->system_info->type == SUBSYSTEM_TURRET))
return ADE_RETURN_NIL;
vec3d tpos,tvec;
ship_get_global_turret_info(sso->objp, sso->ss->system_info, &tpos, &tvec);
int in_fov = object_in_turret_fov(newh->objp,sso->ss,&tvec,&tpos,vm_vec_dist(&newh->objp->pos,&tpos));
if (in_fov)
return ADE_RETURN_TRUE;
else
return ADE_RETURN_FALSE;
}
ADE_FUNC(fireWeapon, l_Subsystem, "[number TurretWeaponIndex = 1, number FlakRange = 100]", "Fires weapon on turret", nullptr, nullptr)
{
ship_subsys_h *sso;
int wnum = 1;
float flak_range = 100.0f;
if(!ade_get_args(L, "o|if", l_Subsystem.GetPtr(&sso), &wnum, &flak_range))
return ADE_RETURN_NIL;
if (!sso->isSubsystemValid())
return ADE_RETURN_NIL;
if (sso->ss->current_hits <= 0)
{
return ADE_RETURN_FALSE;
}
wnum--; //Lua->FS2
//Get default turret info
vec3d gpos, gvec;
ship_get_global_turret_gun_info(sso->objp, sso->ss, &gpos, &gvec, 1, NULL);
bool rtn = turret_fire_weapon(wnum, sso->ss, OBJ_INDEX(sso->objp), &gpos, &gvec, NULL, flak_range);
sso->ss->turret_next_fire_pos++;
return ade_set_args(L, "b", rtn);
}
ADE_FUNC(rotateTurret, l_Subsystem, "vector Pos, boolean reset=false", "Rotates the turret to face Pos or resets the turret to its original state", "boolean", "true on success false otherwise")
{
ship_subsys_h *sso;
vec3d pos = vmd_zero_vector;
bool reset = false;
if (!ade_get_args(L, "oo|b", l_Subsystem.GetPtr(&sso), l_Vector.Get(&pos), &reset))
return ADE_RETURN_NIL;
//Get default turret info
vec3d gpos, gvec;
model_subsystem *tp = sso->ss->system_info;
object *objp = sso->objp;
//Rotate turret position with ship
vm_vec_unrotate(&gpos, &tp->pnt, &sso->objp->orient);
//Add turret position to appropriate world space
vm_vec_add2(&gpos, &sso->objp->pos);
// Find direction of turret
model_instance_find_world_dir(&gvec, &tp->turret_norm, Ships[objp->instance].model_instance_num, tp->turret_gun_sobj, &objp->orient);
int ret_val = model_rotate_gun(Ship_info[(&Ships[sso->objp->instance])->ship_info_index].model_num, tp, &Objects[sso->objp->instance].orient, &sso->ss->submodel_info_1.angs, &sso->ss->submodel_info_2.angs, &Objects[sso->objp->instance].pos, &pos, (&Ships[sso->objp->instance])->objnum, reset);
if (ret_val)
return ADE_RETURN_TRUE;
else
return ADE_RETURN_FALSE;
}
ADE_FUNC(getTurretHeading, l_Subsystem, NULL, "Returns the turrets forward vector", "vector", "Returns a normalized version of the forward vector or null vector on error")
{
ship_subsys_h *sso;
if(!ade_get_args(L, "o", l_Subsystem.GetPtr(&sso)))
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
if (!sso->isSubsystemValid())
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
vec3d gvec;
object *objp = sso->objp;
model_instance_find_world_dir(&gvec, &sso->ss->system_info->turret_norm, Ships[objp->instance].model_instance_num, sso->ss->system_info->turret_gun_sobj, &objp->orient);
vec3d out;
vm_vec_rotate(&out, &gvec, &sso->objp->orient);
return ade_set_args(L, "o", l_Vector.Set(out));
}
ADE_FUNC(getFOVs, l_Subsystem, nullptr, "Returns current turrets FOVs", ade_type_info({"number", "number", "number"}),
"Standard FOV, maximum barrel elevation, turret base fov.")
{
ship_subsys_h *sso;
float fov, fov_e, fov_y;
if(!ade_get_args(L, "o", l_Subsystem.GetPtr(&sso)))
return ADE_RETURN_NIL;
if (!sso->isSubsystemValid())
return ADE_RETURN_NIL;
model_subsystem *tp = sso->ss->system_info;
fov = tp->turret_fov;
fov_e = tp->turret_max_fov;
fov_y = tp->turret_y_fov;
return ade_set_args(L, "fff", fov, fov_e, fov_y);
}
ADE_FUNC(
getNextFiringPosition, l_Subsystem, nullptr,
"Retrieves the next position and firing normal this turret will fire from. This function returns a world position",
ade_type_info({"vector", "vector"}), "vector or null vector on error")
{
ship_subsys_h *sso;
if(!ade_get_args(L, "o", l_Subsystem.GetPtr(&sso)))
return ade_set_error(L, "oo", l_Vector.Set(vmd_zero_vector), l_Vector.Set(vmd_zero_vector));
if (!sso->isSubsystemValid())
return ade_set_error(L, "oo", l_Vector.Set(vmd_zero_vector), l_Vector.Set(vmd_zero_vector));
vec3d gpos, gvec;
ship_get_global_turret_gun_info(sso->objp, sso->ss, &gpos, &gvec, 1, NULL);
return ade_set_args(L, "oo", l_Vector.Set(gpos), l_Vector.Set(gvec));
}
ADE_FUNC(getTurretMatrix, l_Subsystem, nullptr, "Returns current subsystems turret matrix", "orientation", "Turret matrix.")
{
ship_subsys_h *sso;
matrix m;
if(!ade_get_args(L, "o", l_Subsystem.GetPtr(&sso)))
return ADE_RETURN_NIL;
if (!sso->isSubsystemValid())
return ADE_RETURN_NIL;
model_subsystem *tp = sso->ss->system_info;
m = tp->turret_matrix;
return ade_set_args(L, "o", l_Matrix.Set(matrix_h(&m)));
}
ADE_FUNC(getParent, l_Subsystem, NULL, "The object parent of this subsystem, is of type ship", "object", "object handle or invalid handle on error")
{
ship_subsys_h *sso = NULL;
object_h *objhp = NULL;
if(!ade_get_args(L, "o|o", l_Subsystem.GetPtr(&sso), l_Ship.GetPtr(&objhp)))
return ade_set_error(L, "o", l_Object.Set(object_h()));
if (!sso->isSubsystemValid())
return ade_set_error(L, "o", l_Object.Set(object_h()));
return ade_set_args(L, "o", l_Object.Set(object_h(sso->objp)));
}
ADE_FUNC(isInViewFrom, l_Subsystem, "vector from",
"Checks if the subsystem is in view from the specified position. This only checks for occlusion by the parent "
"object, not by other objects in the mission.",
"boolean", "true if in view, false otherwise")
{
ship_subsys_h *sso = nullptr;
vec3d *from = nullptr;
if(!ade_get_args(L, "oo", l_Subsystem.GetPtr(&sso), l_Vector.GetPtr(&from)))
return ADE_RETURN_FALSE;
if (!sso->isSubsystemValid())
return ADE_RETURN_FALSE;
vec3d world_pos;
get_subsystem_world_pos(sso->objp, sso->ss, &world_pos);
// Disable facing check since the HUD code does the same
int in_sight = ship_subsystem_in_sight(sso->objp, sso->ss, from, &world_pos, 0);
return ade_set_args(L, "b", in_sight != 0);
}
ADE_FUNC(isValid, l_Subsystem, NULL, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs")
{
ship_subsys_h *sso;
if(!ade_get_args(L, "o", l_Subsystem.GetPtr(&sso)))
return ADE_RETURN_NIL;
return ade_set_args(L, "b", sso->isSubsystemValid());
}
}
}