mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-12 19:06:09 -10:00
* Fix isWeaponAllowedOnShip bank lookup for secondary banks isWeaponAllowedOnShip numbers banks per ship class, with the secondaries right after the primaries, but the bank restriction lists keep secondary bank n at MAX_SHIP_PRIMARY_BANKS + n. On a ship with fewer than three primary banks, the secondary banks were checked against the wrong list. Map the bank before the lookup. The restriction lists are only allocated for ship classes that have $Allowed PBanks/SBanks, so both this function and the loadout weapon setter read past the end of an empty vector for any other class. Skip the bank check when there are no lists. The loadout weapon setter also treated a primary slot the ship does not have (bank 3 on a two-primary ship) as a secondary bank. Fixes #7985 * Cover more bank layouts and the loadout setter in the shipclass tests Add classes with one and three primary banks, a restricted primary bank, the bank-omitted case, and tests for the loadout weapon setter's bank range and restriction checks. * Fall back to the class weapon list in loadout bank checks The weapon loadout's slot and pool moves read a ship class's per-bank restriction lists without checking they exist. Those lists are only allocated for classes with $Allowed PBanks/SBanks, so a move request for any other class (from a script through sendWeaponRequestPacket, or a multiplayer client) read past the end of an empty vector and crashed. When a class has no per-bank lists, check the weapon against the class-wide allowed weapons instead. Classes with lists behave as before. * Simplify the loadout bank checks and tidy the loadout setter wl_bank_allows_weapon already allows a bank with no restriction, so the four loadout checks call it directly. The comment now says what the empty case means: a class without bank lists allows no weapons. The Loadout_Weapon setter rejects a weapon index one past the end, and only resets the amount when it actually stored the weapon. * Check the class weapon list in the loadout bank check A bank without its own list accepted any weapon of the right type, so a move request from a script or a multiplayer client could load a weapon the ship class can't carry. Check the class-wide list first, as the rearm code does. An empty slot coming back from a swap has nothing to check, which also stops it adding a -1 entry to the weapon pool. --------- Co-authored-by: Dustinspace217 <[email protected]>
1623 lines
47 KiB
C++
1623 lines
47 KiB
C++
//
|
|
//
|
|
|
|
#include "freespace.h" //For frametime
|
|
|
|
#include "shipclass.h"
|
|
#include "model.h"
|
|
#include "cockpit_display.h"
|
|
#include "species.h"
|
|
#include "shiptype.h"
|
|
#include "team_colors.h"
|
|
#include "vecmath.h"
|
|
#include "ship/ship.h"
|
|
#include "playerman/player.h"
|
|
#include "weapon/weapon.h"
|
|
#include "mission/missioncampaign.h"
|
|
#include "missionui/missionweaponchoice.h"
|
|
#include "graphics/matrix.h"
|
|
#include "missionui/missionscreencommon.h"
|
|
#include "scripting/api/objs/weaponclass.h"
|
|
#include "scripting/lua/LuaTable.h"
|
|
#include "model/modelrender.h"
|
|
#include "utils/string_utils.h"
|
|
|
|
namespace scripting {
|
|
namespace api {
|
|
|
|
|
|
//**********HANDLE: default primary
|
|
ADE_OBJ(l_Default_Primary, int, "default_primary", "weapon index");
|
|
ADE_OBJ_VALIDATOR_RANGE(l_Default_Primary, ship_info_size());
|
|
|
|
ADE_INDEXER(l_Default_Primary,
|
|
"number idx",
|
|
"Array of ship default primaries for each bank. Returns the Weapon Class or "
|
|
"nil if the bank is invalid for the ship class.",
|
|
"weaponclass",
|
|
"The weapon index")
|
|
{
|
|
int current;
|
|
int idx = -1;
|
|
if (!ade_get_args(L, "oi", l_Default_Primary.Get(¤t), &idx))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "This property is read only.");
|
|
}
|
|
|
|
ship_info* sip = &Ship_info[current];
|
|
|
|
if (idx < 1 || idx > sip->num_primary_banks) {
|
|
return ADE_RETURN_NIL;
|
|
};
|
|
idx--; // Convert to Lua's 1 based index system
|
|
|
|
return ade_set_args(L, "o", l_Weaponclass.Set(sip->primary_bank_weapons[idx]));
|
|
}
|
|
|
|
ADE_FUNC(__len,
|
|
l_Default_Primary,
|
|
nullptr,
|
|
"The number of primary banks with defaults",
|
|
"number",
|
|
"The number of primary banks.")
|
|
{
|
|
int current;
|
|
ade_get_args(L, "o", l_Default_Primary.Get(¤t));
|
|
ship_info* sip = &Ship_info[current];
|
|
return ade_set_args(L, "i", sip->num_primary_banks);
|
|
}
|
|
|
|
//**********HANDLE: default secondary
|
|
ADE_OBJ(l_Default_Secondary, int, "default_secondary", "weapon index");
|
|
ADE_OBJ_VALIDATOR_RANGE(l_Default_Secondary, ship_info_size());
|
|
|
|
ADE_INDEXER(l_Default_Secondary,
|
|
"number idx",
|
|
"Array of ship default secondaries for each bank. Returns the Weapon Class or "
|
|
"nil if the bank is invalid for the ship class.",
|
|
"weaponclass",
|
|
"The weapon index")
|
|
{
|
|
int current;
|
|
int idx = -1;
|
|
if (!ade_get_args(L, "oi", l_Default_Secondary.Get(¤t), &idx))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "This property is read only.");
|
|
}
|
|
|
|
ship_info* sip = &Ship_info[current];
|
|
|
|
if (idx < 1 || idx > sip->num_secondary_banks) {
|
|
return ADE_RETURN_NIL;
|
|
};
|
|
idx--; // Convert to Lua's 1 based index system
|
|
|
|
return ade_set_args(L, "o", l_Weaponclass.Set(sip->secondary_bank_weapons[idx]));
|
|
}
|
|
|
|
ADE_FUNC(__len,
|
|
l_Default_Secondary,
|
|
nullptr,
|
|
"The number of secondary banks with defaults",
|
|
"number",
|
|
"The number of secondary banks.")
|
|
{
|
|
int current;
|
|
ade_get_args(L, "o", l_Default_Secondary.Get(¤t));
|
|
ship_info* sip = &Ship_info[current];
|
|
return ade_set_args(L, "i", sip->num_secondary_banks);
|
|
}
|
|
|
|
//**********HANDLE: Shipclass
|
|
ADE_OBJ(l_Shipclass, int, "shipclass", "Ship class handle");
|
|
ADE_OBJ_VALIDATOR_RANGE(l_Shipclass, ship_info_size());
|
|
|
|
ADE_FUNC(__tostring, l_Shipclass, NULL, "Ship class name", "string", "Ship class name, or an empty string if handle is invalid")
|
|
{
|
|
int idx;
|
|
const char* s = nullptr;
|
|
if(!ade_get_args(L, "o|s", l_Shipclass.Get(&idx), &s))
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "s", "");
|
|
|
|
return ade_set_args(L, "s", Ship_info[idx].name);
|
|
}
|
|
|
|
ADE_FUNC(__eq, l_Shipclass, "shipclass, shipclass", "Checks if the two classes are equal", "boolean", "true if equal, false otherwise")
|
|
{
|
|
int idx1,idx2;
|
|
if(!ade_get_args(L, "oo", l_Shipclass.Get(&idx1), l_Shipclass.Get(&idx2)))
|
|
return ade_set_error(L, "b", false);
|
|
|
|
if(idx1 < 0 || idx1 >= ship_info_size())
|
|
return ade_set_error(L, "b", false);
|
|
|
|
if(idx2 < 0 || idx2 >= ship_info_size())
|
|
return ade_set_error(L, "b", false);
|
|
|
|
return ade_set_args(L, "b", idx1 == idx2);
|
|
}
|
|
|
|
|
|
ADE_VIRTVAR(Name, l_Shipclass, "string", "Ship class name", "string", "Ship class name, or an empty string if handle is invalid")
|
|
{
|
|
int idx;
|
|
const char* s = nullptr;
|
|
if(!ade_get_args(L, "o|s", l_Shipclass.Get(&idx), &s))
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if(ADE_SETTING_VAR && s != NULL) {
|
|
auto len = sizeof(Ship_info[idx].name);
|
|
strncpy(Ship_info[idx].name, s, len);
|
|
Ship_info[idx].name[len - 1] = 0;
|
|
}
|
|
|
|
return ade_set_args(L, "s", Ship_info[idx].name);
|
|
}
|
|
|
|
ADE_VIRTVAR(ShortName, l_Shipclass, "string", "Ship class short name", "string", "Ship short name, or empty string if handle is invalid")
|
|
{
|
|
int idx;
|
|
const char* s = nullptr;
|
|
if(!ade_get_args(L, "o|s", l_Shipclass.Get(&idx), &s))
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if(ADE_SETTING_VAR && s != NULL) {
|
|
auto len = sizeof(Ship_info[idx].short_name);
|
|
strncpy(Ship_info[idx].short_name, s, len);
|
|
Ship_info[idx].short_name[len - 1] = 0;
|
|
}
|
|
|
|
return ade_set_args(L, "s", Ship_info[idx].short_name);
|
|
}
|
|
|
|
static int handle_ship_class_optional_string(lua_State *L, std::unique_ptr<char[]> ship_info::*optional_string_field)
|
|
{
|
|
int idx;
|
|
const char* s = nullptr;
|
|
if (!ade_get_args(L, "o|s", l_Shipclass.Get(&idx), &s))
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if (!SCP_vector_inbounds(Ship_info, idx))
|
|
return ade_set_error(L, "s", "");
|
|
|
|
auto sip = &Ship_info[idx];
|
|
|
|
if(ADE_SETTING_VAR) {
|
|
sip->*optional_string_field = util::unique_copy(s, true);
|
|
}
|
|
|
|
return ade_set_args(L, "s", coalesce((sip->*optional_string_field).get(), ""));
|
|
}
|
|
|
|
ADE_VIRTVAR(TypeString, l_Shipclass, "string", "Ship class type string", "string", "Type string, or empty string if handle is invalid")
|
|
{
|
|
return handle_ship_class_optional_string(L, &ship_info::type_str);
|
|
}
|
|
|
|
ADE_VIRTVAR(ManeuverabilityString, l_Shipclass, "string", "Ship class maneuverability string", "string", "Maneuverability string, or empty string if handle is invalid")
|
|
{
|
|
return handle_ship_class_optional_string(L, &ship_info::maneuverability_str);
|
|
}
|
|
|
|
ADE_VIRTVAR(ArmorString, l_Shipclass, "string", "Ship class armor string", "string", "Armor string, or empty string if handle is invalid")
|
|
{
|
|
return handle_ship_class_optional_string(L, &ship_info::armor_str);
|
|
}
|
|
|
|
ADE_VIRTVAR(ManufacturerString, l_Shipclass, "string", "Ship class manufacturer", "string", "Manufacturer, or empty string if handle is invalid")
|
|
{
|
|
return handle_ship_class_optional_string(L, &ship_info::manufacturer_str);
|
|
}
|
|
|
|
ADE_VIRTVAR(LengthString, l_Shipclass, "string", "Ship class length", "string", "Length, or empty string if handle is invalid")
|
|
{
|
|
return handle_ship_class_optional_string(L, &ship_info::ship_length);
|
|
}
|
|
|
|
ADE_VIRTVAR(GunMountsString, l_Shipclass, "string", "Ship class gun mounts", "string", "Gun mounts, or empty string if handle is invalid")
|
|
{
|
|
return handle_ship_class_optional_string(L, &ship_info::gun_mounts);
|
|
}
|
|
|
|
ADE_VIRTVAR(MissileBanksString, l_Shipclass, "string", "Ship class missile banks", "string", "Missile banks, or empty string if handle is invalid")
|
|
{
|
|
return handle_ship_class_optional_string(L, &ship_info::missile_banks);
|
|
}
|
|
|
|
ADE_VIRTVAR(VelocityString, l_Shipclass, "string", "Ship class velocity", "string", "velocity, or empty string if handle is invalid")
|
|
{
|
|
int idx;
|
|
const char* s = nullptr;
|
|
if(!ade_get_args(L, "o|s", l_Shipclass.Get(&idx), &s))
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "s", "");
|
|
|
|
ship_info *sip = &Ship_info[idx];
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting Velocity is not supported");
|
|
}
|
|
|
|
char str[100];
|
|
sprintf(str, XSTR("%d m/s", 743), fl2i((float)sip->max_vel.xyz.z * Hud_speed_multiplier));
|
|
|
|
return ade_set_args(L, "s", str);
|
|
}
|
|
|
|
ADE_VIRTVAR(Description, l_Shipclass, "string", "Ship class description", "string", "Description, or empty string if handle is invalid")
|
|
{
|
|
return handle_ship_class_optional_string(L, &ship_info::desc);
|
|
}
|
|
|
|
ADE_VIRTVAR(SelectIconFilename, l_Shipclass, "string", "Ship class select icon filename", "string", "Filename, or empty string if handle is invalid")
|
|
{
|
|
int idx;
|
|
const char* s = nullptr;
|
|
if (!ade_get_args(L, "o|s", l_Shipclass.Get(&idx), &s))
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if(ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting Select Icon is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "s", Ship_info[idx].icon_filename);
|
|
}
|
|
|
|
ADE_VIRTVAR(SelectAnimFilename, l_Shipclass, "string", "Ship class select animation filename", "string", "Filename, or empty string if handle is invalid")
|
|
{
|
|
int idx;
|
|
const char* s = nullptr;
|
|
if (!ade_get_args(L, "o|s", l_Shipclass.Get(&idx), &s))
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if(ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting Select Anim is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "s", Ship_info[idx].anim_filename);
|
|
}
|
|
|
|
ADE_VIRTVAR(SelectOverheadFilename, l_Shipclass, "string", "Ship class select overhead filename", "string", "Filename, or empty string if handle is invalid")
|
|
{
|
|
int idx;
|
|
const char* s = nullptr;
|
|
if (!ade_get_args(L, "o|s", l_Shipclass.Get(&idx), &s))
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if(ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting Select Overhead Image is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "s", Ship_info[idx].overhead_filename);
|
|
}
|
|
|
|
ADE_VIRTVAR(TechDescription, l_Shipclass, "string", "Ship class tech description", "string", "Tech description, or empty string if handle is invalid")
|
|
{
|
|
return handle_ship_class_optional_string(L, &ship_info::tech_desc);
|
|
}
|
|
|
|
ADE_VIRTVAR(numPrimaryBanks,
|
|
l_Shipclass,
|
|
nullptr,
|
|
"Number of primary banks on this ship class",
|
|
"number",
|
|
"number of banks or nil is ship handle is invalid")
|
|
{
|
|
int idx;
|
|
if (!ade_get_args(L, "o", l_Shipclass.Get(&idx)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ADE_RETURN_NIL;
|
|
|
|
ship_info* sip = &Ship_info[idx];
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting number of banks is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "i", sip->num_primary_banks);
|
|
}
|
|
|
|
ADE_FUNC(getPrimaryBankCapacity,
|
|
l_Shipclass,
|
|
"number index",
|
|
"Returns the capacity of the specified primary bank",
|
|
"number",
|
|
"The bank capacity or nil if the index is invalid")
|
|
{
|
|
int shipIdx;
|
|
int idx;
|
|
if (!ade_get_args(L, "oi", l_Shipclass.Get(&shipIdx), &idx))
|
|
return ADE_RETURN_NIL;
|
|
|
|
ship_info* sip = &Ship_info[shipIdx];
|
|
|
|
if (idx < 1 || idx > sip->num_primary_banks) {
|
|
return ADE_RETURN_NIL;
|
|
};
|
|
|
|
idx--; // Convert from Lua's 1 based index system
|
|
|
|
return ade_set_args(L, "i", sip->primary_bank_ammo_capacity[idx]);
|
|
}
|
|
|
|
ADE_VIRTVAR(numSecondaryBanks,
|
|
l_Shipclass,
|
|
nullptr,
|
|
"Number of secondary banks on this ship class",
|
|
"number",
|
|
"number of banks or nil is ship handle is invalid")
|
|
{
|
|
int idx;
|
|
if (!ade_get_args(L, "o", l_Shipclass.Get(&idx)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ADE_RETURN_NIL;
|
|
|
|
ship_info* sip = &Ship_info[idx];
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting number of banks is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "i", sip->num_secondary_banks);
|
|
}
|
|
|
|
ADE_FUNC(getSecondaryBankCapacity,
|
|
l_Shipclass,
|
|
"number index",
|
|
"Returns the capacity of the specified secondary bank",
|
|
"number",
|
|
"The bank capacity or nil if the index is invalid")
|
|
{
|
|
int shipIdx;
|
|
int idx;
|
|
if (!ade_get_args(L, "oi", l_Shipclass.Get(&shipIdx), &idx))
|
|
return ADE_RETURN_NIL;
|
|
|
|
ship_info* sip = &Ship_info[shipIdx];
|
|
|
|
if (idx < 1 || idx > sip->num_secondary_banks) {
|
|
return ADE_RETURN_NIL;
|
|
};
|
|
|
|
idx--; // Convert from Lua's 1 based index system
|
|
|
|
return ade_set_args(L, "i", sip->secondary_bank_ammo_capacity[idx]);
|
|
}
|
|
|
|
ADE_VIRTVAR(defaultPrimaries,
|
|
l_Shipclass,
|
|
"number",
|
|
"Array of default primary weapons",
|
|
"default_primary",
|
|
"The weapons array or nil if handle is invalid")
|
|
{
|
|
int idx;
|
|
if (!ade_get_args(L, "o", l_Shipclass.Get(&idx)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "This property is read only.");
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_Default_Primary.Set(idx));
|
|
}
|
|
|
|
ADE_VIRTVAR(defaultSecondaries,
|
|
l_Shipclass,
|
|
"number",
|
|
"Array of default secondary weapons",
|
|
"default_secondary",
|
|
"The weapons array or nil if handle is invalid")
|
|
{
|
|
int idx;
|
|
if (!ade_get_args(L, "o", l_Shipclass.Get(&idx)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "This property is read only.");
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_Default_Secondary.Set(idx));
|
|
}
|
|
|
|
ADE_FUNC(isWeaponAllowedOnShip,
|
|
l_Shipclass,
|
|
"number index, [number bank]",
|
|
"Gets whether or not a weapon is allowed on a ship class. "
|
|
"Optionally check a specific bank. Banks are 1 to a maximum of 7 where the first banks are Primaries and rest are "
|
|
"Secondaries. "
|
|
"Exact numbering depends on the ship class being checked. Note also that this will consider dogfight weapons only "
|
|
"if "
|
|
"a dogfight mission has been loaded. Index is index into Weapon Classes.",
|
|
"boolean",
|
|
"True if allowed, false if not.")
|
|
{
|
|
int idx;
|
|
int wepidx;
|
|
int bank = 0;
|
|
if (!ade_get_args(L, "oi|i", l_Shipclass.Get(&idx), &wepidx, &bank))
|
|
return ade_set_error(L, "b", false);
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "b", false);
|
|
wepidx--; // Convert from Lua
|
|
if (wepidx < 0 || wepidx >= weapon_info_size())
|
|
return ade_set_error(L, "b", false);
|
|
if (bank != 0) {
|
|
if (bank < 0 || bank > (Ship_info[idx].num_primary_banks + Ship_info[idx].num_secondary_banks))
|
|
return ade_set_error(L, "b", false);
|
|
};
|
|
bank--; // Convert from Lua
|
|
// The restriction lists keep secondaries at MAX_SHIP_PRIMARY_BANKS onward, not right after this class's primaries
|
|
if (bank >= Ship_info[idx].num_primary_banks)
|
|
bank += MAX_SHIP_PRIMARY_BANKS - Ship_info[idx].num_primary_banks;
|
|
|
|
bool retv = false;
|
|
if ((bank >= 0) && !Ship_info[idx].restricted_loadout_flag.empty() &&
|
|
(eval_weapon_flag_for_game_type(Ship_info[idx].restricted_loadout_flag[bank]))) {
|
|
if (eval_weapon_flag_for_game_type(Ship_info[idx].allowed_bank_restricted_weapons[bank][wepidx]))
|
|
retv = true;
|
|
} else if (eval_weapon_flag_for_game_type(Ship_info[idx].allowed_weapons[wepidx])) {
|
|
retv = true;
|
|
}
|
|
|
|
return ade_set_args(L, "b", retv);
|
|
}
|
|
|
|
ADE_VIRTVAR(AfterburnerFuelMax, l_Shipclass, "number", "Afterburner fuel capacity", "number", "Afterburner capacity, or 0 if handle is invalid")
|
|
{
|
|
int idx;
|
|
float fuel = -1.0f;
|
|
if(!ade_get_args(L, "o|f", l_Shipclass.Get(&idx), &fuel))
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if(ADE_SETTING_VAR && fuel >= 0.0f)
|
|
Ship_info[idx].afterburner_fuel_capacity = fuel;
|
|
|
|
return ade_set_args(L, "f", Ship_info[idx].afterburner_fuel_capacity);
|
|
}
|
|
|
|
ADE_VIRTVAR(ScanTime, l_Shipclass, nullptr, "Ship scan time", "number", "Time required to scan, or 0 if handle is invalid. This property is read-only")
|
|
{
|
|
int idx;
|
|
if (!ade_get_args(L, "o", l_Shipclass.Get(&idx)))
|
|
return ade_set_error(L, "i", 0);
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "i", 0);
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting ScanTime is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "i", Ship_info[idx].scan_time);
|
|
}
|
|
|
|
ADE_VIRTVAR(CountermeasureClass, l_Shipclass, "weaponclass", "The default countermeasure class assigned to this ship class", "weaponclass", "Countermeasure hardpoint weapon class, or invalid weaponclass handle if no countermeasure class or ship handle is invalid")
|
|
{
|
|
int idx;
|
|
if (!ade_get_args(L, "o", l_Shipclass.Get(&idx)))
|
|
return ade_set_error(L, "o", l_Weaponclass.Set(-1));
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "o", l_Weaponclass.Set(-1));
|
|
|
|
ship_info* sip = &Ship_info[idx];
|
|
|
|
if(ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting CountermeasureClass is not supported");
|
|
}
|
|
|
|
if (sip->cmeasure_type > -1) {
|
|
return ade_set_args(L, "o", l_Weaponclass.Set(sip->cmeasure_type));
|
|
} else {
|
|
return ade_set_error(L, "o", l_Weaponclass.Set(-1));
|
|
}
|
|
}
|
|
|
|
ADE_VIRTVAR(CountermeasuresMax, l_Shipclass, "number", "Maximum number of countermeasures the ship can carry", "number", "Countermeasure capacity, or 0 if handle is invalid")
|
|
{
|
|
int idx;
|
|
int i = -1;
|
|
if(!ade_get_args(L, "o|i", l_Shipclass.Get(&idx), &i))
|
|
return ade_set_error(L, "i", 0);
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "i", 0);
|
|
|
|
if(ADE_SETTING_VAR && i > -1) {
|
|
Ship_info[idx].cmeasure_max = i;
|
|
}
|
|
|
|
return ade_set_args(L, "i", Ship_info[idx].cmeasure_max);
|
|
}
|
|
|
|
ADE_VIRTVAR(Model, l_Shipclass, "model", "Model", "model", "Ship class model, or invalid model handle if shipclass handle is invalid")
|
|
{
|
|
int ship_info_idx=-1;
|
|
model_h *mdl = NULL;
|
|
if(!ade_get_args(L, "o|o", l_Shipclass.Get(&ship_info_idx), l_Model.GetPtr(&mdl)))
|
|
return ade_set_error(L, "o", l_Model.Set(model_h(-1)));
|
|
|
|
if(ship_info_idx < 0 || ship_info_idx >= ship_info_size())
|
|
return ade_set_error(L, "o", l_Model.Set(model_h(-1)));
|
|
|
|
ship_info *sip = &Ship_info[ship_info_idx];
|
|
|
|
int mid = (mdl ? mdl->GetID() : -1);
|
|
|
|
if(ADE_SETTING_VAR && mid > -1) {
|
|
sip->model_num = mid;
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_Model.Set(model_h(sip->model_num)));
|
|
}
|
|
|
|
ADE_VIRTVAR(CloseupPosition, l_Shipclass, nullptr, "Ship class closeup position", "vector", "closeup position, or nil if handle is invalid")
|
|
{
|
|
int idx;
|
|
if (!ade_get_args(L, "o", l_Shipclass.Get(&idx)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (!SCP_vector_inbounds(Ship_info, idx))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting Closeup Position is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_Vector.Set(Ship_info[idx].closeup_pos));
|
|
}
|
|
|
|
ADE_VIRTVAR(CloseupZoom, l_Shipclass, nullptr, "Ship class closeup zoom", "number", "closeup zoom, or nil if handle is invalid")
|
|
{
|
|
int idx;
|
|
if (!ade_get_args(L, "o", l_Shipclass.Get(&idx)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (!SCP_vector_inbounds(Ship_info, idx))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting Closeup Zoom is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "f", Ship_info[idx].closeup_zoom);
|
|
}
|
|
|
|
ADE_VIRTVAR(CockpitModel, l_Shipclass, "model", "Model used for first-person cockpit", "model", "Cockpit model")
|
|
{
|
|
int ship_info_idx=-1;
|
|
model_h *mdl = NULL;
|
|
if(!ade_get_args(L, "o|o", l_Shipclass.Get(&ship_info_idx), l_Model.GetPtr(&mdl)))
|
|
return ade_set_error(L, "o", l_Model.Set(model_h()));
|
|
|
|
if(ship_info_idx < 0 || ship_info_idx >= ship_info_size())
|
|
return ade_set_error(L, "o", l_Model.Set(model_h()));
|
|
|
|
ship_info *sip = &Ship_info[ship_info_idx];
|
|
|
|
int mid = (mdl ? mdl->GetID() : -1);
|
|
|
|
if(ADE_SETTING_VAR) {
|
|
sip->cockpit_model_num = mid;
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_Model.Set(model_h(sip->cockpit_model_num)));
|
|
}
|
|
|
|
ADE_VIRTVAR(CockpitDisplays, l_Shipclass, "cockpitdisplays", "Gets the cockpit display information array of this ship class", "cockpitdisplays", "Array handle containing the information or invalid handle on error")
|
|
{
|
|
int ship_info_idx=-1;
|
|
cockpit_displays_info_h *cdih = NULL;
|
|
if(!ade_get_args(L, "o|o", l_Shipclass.Get(&ship_info_idx), l_CockpitDisplayInfos.GetPtr(&cdih)))
|
|
return ade_set_error(L, "o", l_CockpitDisplayInfos.Set(cockpit_displays_info_h()));
|
|
|
|
if(ship_info_idx < 0 || ship_info_idx >= ship_info_size())
|
|
return ade_set_error(L, "o", l_CockpitDisplayInfos.Set(cockpit_displays_info_h()));
|
|
|
|
if(ADE_SETTING_VAR) {
|
|
LuaError(L, "Attempted to use incomplete feature: Cockpit display information copy");
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_CockpitDisplayInfos.Set(cockpit_displays_info_h(ship_info_idx)));
|
|
}
|
|
|
|
ADE_VIRTVAR(HitpointsMax, l_Shipclass, "number", "Ship class hitpoints", "number", "Hitpoints, or 0 if handle is invalid")
|
|
{
|
|
int idx;
|
|
float f = -1.0f;
|
|
if(!ade_get_args(L, "o|f", l_Shipclass.Get(&idx), &f))
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if(ADE_SETTING_VAR && f >= 0.0f) {
|
|
Ship_info[idx].max_hull_strength = f;
|
|
}
|
|
|
|
return ade_set_args(L, "f", Ship_info[idx].max_hull_strength);
|
|
}
|
|
|
|
ADE_VIRTVAR(ShieldHitpointsMax, l_Shipclass, nullptr, "Ship class shield hitpoints", "number", "Shield hitpoints, or 0 if handle is invalid")
|
|
{
|
|
int idx;
|
|
if(!ade_get_args(L, "o", l_Shipclass.Get(&idx)))
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if(ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting Shield Max Hitpoints is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "f", Ship_info[idx].max_shield_strength);
|
|
}
|
|
|
|
ADE_VIRTVAR(Species, l_Shipclass, "species", "Ship class species", "species", "Ship class species, or invalid species handle if shipclass handle is invalid")
|
|
{
|
|
int idx;
|
|
int sidx = -1;
|
|
if(!ade_get_args(L, "o|o", l_Shipclass.Get(&idx), l_Species.Get(&sidx)))
|
|
return ade_set_error(L, "o", l_Species.Set(-1));
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "o", l_Species.Set(-1));
|
|
|
|
if(ADE_SETTING_VAR && sidx > -1 && sidx < (int)Species_info.size()) {
|
|
Ship_info[idx].species = sidx;
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_Species.Set(Ship_info[idx].species));
|
|
}
|
|
|
|
ADE_VIRTVAR(Type, l_Shipclass, "shiptype", "Ship class type", "shiptype", "Ship type, or invalid handle if shipclass handle is invalid")
|
|
{
|
|
int idx;
|
|
int sidx = -1;
|
|
if(!ade_get_args(L, "o|o", l_Shipclass.Get(&idx), l_Shiptype.Get(&sidx)))
|
|
return ade_set_error(L, "o", l_Shiptype.Set(-1));
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "o", l_Shiptype.Set(-1));
|
|
|
|
if(ADE_SETTING_VAR && sidx > -1 && sidx < (int)Ship_types.size()) {
|
|
Ship_info[idx].class_type = sidx;
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_Shiptype.Set(Ship_info[idx].class_type));
|
|
}
|
|
|
|
ADE_VIRTVAR(AltName, l_Shipclass, "string", "Alternate name for ship class", "string", "Alternate string or empty string if handle is invalid")
|
|
{
|
|
const char* newName = nullptr;
|
|
int idx;
|
|
if(!ade_get_args(L, "o|s", l_Shipclass.Get(&idx), &newName))
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if(ADE_SETTING_VAR && newName != nullptr) {
|
|
if (newName == Ship_info[idx].name) {
|
|
Ship_info[idx].display_name = "";
|
|
Ship_info[idx].flags.remove(Ship::Info_Flags::Has_display_name);
|
|
} else {
|
|
Ship_info[idx].display_name = newName;
|
|
Ship_info[idx].flags.set(Ship::Info_Flags::Has_display_name);
|
|
}
|
|
}
|
|
|
|
return ade_set_args(L, "s", Ship_info[idx].display_name.c_str());
|
|
}
|
|
|
|
ADE_VIRTVAR(VelocityMax, l_Shipclass, "vector", "Ship's lateral and forward speeds", "vector", "Maximum velocity, or null vector if handle is invalid")
|
|
{
|
|
int idx;
|
|
vec3d* vec = NULL;
|
|
if (!ade_get_args(L, "o|o", l_Shipclass.Get(&idx), l_Vector.GetPtr(&vec)))
|
|
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting VelocityMax is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_Vector.Set(Ship_info[idx].max_vel));
|
|
}
|
|
|
|
ADE_VIRTVAR(VelocityDamping, l_Shipclass, "number", "Damping, the natural period (1 / omega) of the dampening effects on top of the acceleration model. ", "number", "Damping, or 0 if handle is invalid")
|
|
{
|
|
int idx;
|
|
float f = 0.0f;
|
|
if (!ade_get_args(L, "o|f", l_Shipclass.Get(&idx), &f))
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting VelocityDamping is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "f", Ship_info[idx].damp);
|
|
}
|
|
|
|
ADE_VIRTVAR(RearVelocityMax, l_Shipclass, "number", "The maximum rear velocity of the ship", "number", "Speed, or 0 if handle is invalid")
|
|
{
|
|
int idx;
|
|
float f = 0.0f;
|
|
if (!ade_get_args(L, "o|f", l_Shipclass.Get(&idx), &f))
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting RearVelocityMax is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "f", Ship_info[idx].max_rear_vel);
|
|
}
|
|
|
|
ADE_VIRTVAR(ForwardAccelerationTime, l_Shipclass, "number", "Forward acceleration time", "number", "Forward acceleration time, or 0 if handle is invalid")
|
|
{
|
|
int idx;
|
|
float f = 0.0f;
|
|
if (!ade_get_args(L, "o|f", l_Shipclass.Get(&idx), &f))
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting ForwardAccelerationTime is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "f", Ship_info[idx].forward_accel);
|
|
}
|
|
|
|
ADE_VIRTVAR(ForwardDecelerationTime, l_Shipclass, "number", "Forward deceleration time", "number", "Forward deceleration time, or 0 if handle is invalid")
|
|
{
|
|
int idx;
|
|
float f = 0.0f;
|
|
if (!ade_get_args(L, "o|f", l_Shipclass.Get(&idx), &f))
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting ForwardDecelerationTime is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "f", Ship_info[idx].forward_decel);
|
|
}
|
|
|
|
ADE_VIRTVAR(RotationTime, l_Shipclass, "vector", "Maximum rotation time on each axis", "vector", "Full rotation time for each axis, or null vector if handle is invalid")
|
|
{
|
|
int idx;
|
|
vec3d* vec = NULL;
|
|
if (!ade_get_args(L, "o|o", l_Shipclass.Get(&idx), l_Vector.GetPtr(&vec)))
|
|
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting RotationTime is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_Vector.Set(Ship_info[idx].rotation_time));
|
|
}
|
|
|
|
ADE_VIRTVAR(RotationalVelocityDamping, l_Shipclass, "number", "Rotational damping, ie derivative of rotational speed", "number", "Rotational damping, or 0 if handle is invalid")
|
|
{
|
|
int idx;
|
|
float f = 0.0f;
|
|
if (!ade_get_args(L, "o|f", l_Shipclass.Get(&idx), &f))
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting RotationalVelocityDamping is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "f", Ship_info[idx].rotdamp);
|
|
}
|
|
|
|
ADE_VIRTVAR(AfterburnerAccelerationTime, l_Shipclass, "number", "Afterburner acceleration time", "number", "Afterburner acceleration time, or 0 if handle is invalid")
|
|
{
|
|
int idx;
|
|
float f = 0.0f;
|
|
if (!ade_get_args(L, "o|f", l_Shipclass.Get(&idx), &f))
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting AfterburnerAccelerationTime is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "f", Ship_info[idx].afterburner_forward_accel);
|
|
}
|
|
|
|
ADE_VIRTVAR(AfterburnerVelocityMax, l_Shipclass, "vector", "Afterburner max velocity", "vector", "Afterburner max velocity, or null vector if handle is invalid")
|
|
{
|
|
int idx;
|
|
vec3d* vec = NULL;
|
|
if (!ade_get_args(L, "o|o", l_Shipclass.Get(&idx), l_Vector.GetPtr(&vec)))
|
|
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting AfterburnerVelocityMax is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_Vector.Set(Ship_info[idx].afterburner_max_vel));
|
|
}
|
|
|
|
ADE_VIRTVAR(AfterburnerRearVelocityMax, l_Shipclass, "number", "Afterburner maximum rear velocity", "number", "Rear velocity, or 0 if handle is invalid")
|
|
{
|
|
int idx;
|
|
float f = 0.0f;
|
|
if (!ade_get_args(L, "o|f", l_Shipclass.Get(&idx), &f))
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting AfterburnerRearVelocityMax is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "f", Ship_info[idx].afterburner_max_reverse_vel);
|
|
}
|
|
|
|
ADE_VIRTVAR(Score, l_Shipclass, "string", "The score of this ship class", "number", "The score or -1 on invalid ship class")
|
|
{
|
|
int idx;
|
|
int new_score;
|
|
if(!ade_get_args(L, "o|i", l_Shipclass.Get(&idx), &new_score))
|
|
return ade_set_error(L, "i", -1);
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "i", -1);
|
|
|
|
if(ADE_SETTING_VAR) {
|
|
Ship_info[idx].score = new_score;
|
|
}
|
|
|
|
return ade_set_args(L, "i", Ship_info[idx].score);
|
|
}
|
|
|
|
ADE_VIRTVAR(InTechDatabase, l_Shipclass, "boolean", "Gets or sets whether this ship class is visible in the tech room", "boolean", "True or false")
|
|
{
|
|
int idx;
|
|
bool new_value;
|
|
if (!ade_get_args(L, "o|b", l_Shipclass.Get(&idx), &new_value))
|
|
return ade_set_error(L, "b", false);
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "b", false);
|
|
|
|
auto flag = (Player && (Player->flags & PLAYER_FLAGS_IS_MULTI))
|
|
? Ship::Info_Flags::In_tech_database_m
|
|
: Ship::Info_Flags::In_tech_database;
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
Ship_info[idx].flags.set(flag, new_value);
|
|
}
|
|
|
|
return ade_set_args(L, "b", Ship_info[idx].flags[flag]);
|
|
}
|
|
|
|
ADE_VIRTVAR(AllowedInCampaign, l_Shipclass, "boolean", "Gets or sets whether this ship class is allowed in loadouts in campaign mode", "boolean", "True or false")
|
|
{
|
|
int idx;
|
|
bool new_value;
|
|
if (!ade_get_args(L, "o|b", l_Shipclass.Get(&idx), &new_value))
|
|
return ade_set_error(L, "b", false);
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "b", false);
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
if (new_value) {
|
|
Campaign.ships_allowed.insert(idx);
|
|
} else {
|
|
Campaign.ships_allowed.erase(idx);
|
|
}
|
|
}
|
|
|
|
return Campaign.ships_allowed.contains(idx) ? ADE_RETURN_TRUE : ADE_RETURN_FALSE;
|
|
}
|
|
|
|
ADE_VIRTVAR(PowerOutput, l_Shipclass, "number", "Gets or sets a ship class' power output", "number", "The ship class' current power output")
|
|
{
|
|
int idx;
|
|
float new_power;
|
|
if (!ade_get_args(L, "o|f", l_Shipclass.Get(&idx), &new_power))
|
|
return ade_set_error(L, "f", -1.0f);
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "f", -1.0f);
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
Ship_info[idx].power_output = new_power;
|
|
}
|
|
|
|
return ade_set_args(L, "f", Ship_info[idx].power_output);
|
|
}
|
|
|
|
ADE_VIRTVAR(ScanningTimeMultiplier, l_Shipclass, nullptr, "Time multiplier for scans performed by this ship class", "number", "Scanning time multiplier, or 0 if handle is invalid")
|
|
{
|
|
int idx;
|
|
if(!ade_get_args(L, "o", l_Shipclass.Get(&idx)))
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if(ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting ScanningTimeMultiplier is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "f", Ship_info[idx].scanning_time_multiplier);
|
|
}
|
|
|
|
ADE_VIRTVAR(ScanningRangeMultiplier, l_Shipclass, nullptr, "Range multiplier for scans performed by this ship class", "number", "Scanning range multiplier, or 0 if handle is invalid")
|
|
{
|
|
int idx;
|
|
if(!ade_get_args(L, "o", l_Shipclass.Get(&idx)))
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
if(ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting ScanningRangeMultiplier is not supported");
|
|
}
|
|
|
|
return ade_set_args(L, "f", Ship_info[idx].scanning_range_multiplier);
|
|
}
|
|
|
|
ADE_VIRTVAR(CustomData, l_Shipclass, nullptr, "Gets the custom data table for this ship class", "table", "The ship class's custom data table")
|
|
{
|
|
int idx;
|
|
if(!ade_get_args(L, "o", l_Shipclass.Get(&idx)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ADE_RETURN_NIL;
|
|
|
|
auto table = luacpp::LuaTable::create(L);
|
|
|
|
ship_info *sip = &Ship_info[idx];
|
|
|
|
for (const auto& pair : sip->custom_data)
|
|
{
|
|
table.addValue(pair.first, pair.second);
|
|
}
|
|
|
|
return ade_set_args(L, "t", &table);
|
|
}
|
|
|
|
ADE_FUNC(hasCustomData, l_Shipclass, nullptr, "Detects whether the ship class has any custom data", "boolean", "true if the shipclass's custom_data is not empty, false otherwise")
|
|
{
|
|
int idx;
|
|
if(!ade_get_args(L, "o", l_Shipclass.Get(&idx)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ADE_RETURN_NIL;
|
|
|
|
ship_info *sip = &Ship_info[idx];
|
|
|
|
bool result = !sip->custom_data.empty();
|
|
return ade_set_args(L, "b", result);
|
|
}
|
|
|
|
ADE_VIRTVAR(CustomStrings,
|
|
l_Shipclass,
|
|
nullptr,
|
|
"Gets the indexed custom string table for this ship. Each item in the table is a table with the following values: "
|
|
"Name - the name of the custom string, Value - the value associated with the custom string, String - the custom "
|
|
"string itself.",
|
|
"table",
|
|
"The ship's custom data table")
|
|
{
|
|
int idx;
|
|
if (!ade_get_args(L, "o", l_Shipclass.Get(&idx)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ADE_RETURN_NIL;
|
|
|
|
ship_info* sip = &Ship_info[idx];
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "Setting Custom Data is not supported");
|
|
}
|
|
|
|
auto table = luacpp::LuaTable::create(L);
|
|
|
|
int cnt = 0;
|
|
|
|
for (const auto& cs : sip->custom_strings) {
|
|
cnt++;
|
|
auto item = luacpp::LuaTable::create(L);
|
|
|
|
item.addValue("Name", luacpp::LuaValue::createValue(Script_system.GetLuaSession(), cs.name));
|
|
item.addValue("Value", luacpp::LuaValue::createValue(Script_system.GetLuaSession(), cs.value));
|
|
item.addValue("String", luacpp::LuaValue::createValue(Script_system.GetLuaSession(), cs.text));
|
|
|
|
table.addValue(cnt, item);
|
|
}
|
|
|
|
return ade_set_args(L, "t", &table);
|
|
}
|
|
|
|
ADE_FUNC(hasCustomStrings,
|
|
l_Shipclass,
|
|
nullptr,
|
|
"Detects whether the ship has any custom strings",
|
|
"boolean",
|
|
"true if the ship's custom_strings is not empty, false otherwise")
|
|
{
|
|
int idx;
|
|
if (!ade_get_args(L, "o", l_Shipclass.Get(&idx)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ADE_RETURN_NIL;
|
|
|
|
ship_info* sip = &Ship_info[idx];
|
|
|
|
bool result = !sip->custom_strings.empty();
|
|
return ade_set_args(L, "b", result);
|
|
}
|
|
|
|
ADE_FUNC(isInTechroom, l_Shipclass, NULL, "Gets whether or not the ship class is available in the techroom", "boolean", "Whether ship has been revealed in the techroom, false if handle is invalid")
|
|
{
|
|
int idx;
|
|
if(!ade_get_args(L, "o", l_Shipclass.Get(&idx)))
|
|
return ade_set_error(L, "b", false);
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ade_set_error(L, "b", false);
|
|
|
|
bool b = false;
|
|
if(Player != NULL && (Player->flags & PLAYER_FLAGS_IS_MULTI) && (Ship_info[idx].flags[Ship::Info_Flags::In_tech_database_m])) {
|
|
b = true;
|
|
} else if(Ship_info[idx].flags[Ship::Info_Flags::In_tech_database]) {
|
|
b = true;
|
|
}
|
|
|
|
return ade_set_args(L, "b", b);
|
|
}
|
|
|
|
ADE_FUNC(renderTechModel,
|
|
l_Shipclass,
|
|
"number X1, number Y1, number X2, number Y2, [number RotationPercent =0, number PitchPercent =0, number "
|
|
"BankPercent=40, number Zoom=1.3, boolean Lighting=true, teamcolor TeamColor=nil, string[] DestroyedSubsystems=nil]",
|
|
"Draws ship model as if in techroom. True for regular lighting, false for flat lighting.",
|
|
"boolean",
|
|
"Whether ship was rendered")
|
|
{
|
|
int x1,y1,x2,y2;
|
|
angles rot_angles = {0.0f, 0.0f, 40.0f};
|
|
int idx;
|
|
float zoom = 1.3f;
|
|
bool lighting = true;
|
|
int tc_idx = -1;
|
|
auto destroyed_subsystems_table = luacpp::LuaTable::create(L);
|
|
if(!ade_get_args(L, "oiiii|ffffbot", l_Shipclass.Get(&idx), &x1, &y1, &x2, &y2, &rot_angles.h, &rot_angles.p, &rot_angles.b, &zoom, &lighting, l_TeamColor.Get(&tc_idx), &destroyed_subsystems_table))
|
|
return ade_set_error(L, "b", false);
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ade_set_args(L, "b", false);
|
|
|
|
if(x2 < x1 || y2 < y1)
|
|
return ade_set_args(L, "b", false);
|
|
|
|
ship_info* sip = &Ship_info[idx];
|
|
|
|
CLAMP(rot_angles.p, 0.0f, 100.0f);
|
|
CLAMP(rot_angles.b, 0.0f, 100.0f);
|
|
CLAMP(rot_angles.h, 0.0f, 100.0f);
|
|
|
|
//Handle angles
|
|
matrix orient = vmd_identity_matrix;
|
|
angles view_angles = {-0.6f, 0.0f, 0.0f};
|
|
vm_angles_2_matrix(&orient, &view_angles);
|
|
|
|
rot_angles.p = (rot_angles.p*0.01f) * PI2;
|
|
rot_angles.b = (rot_angles.b*0.01f) * PI2;
|
|
rot_angles.h = (rot_angles.h*0.01f) * PI2;
|
|
vm_rotate_matrix_by_angles(&orient, &rot_angles);
|
|
|
|
SCP_string tcolor = sip->default_team_name;
|
|
if (SCP_vector_inbounds(Team_Names, tc_idx)) {
|
|
const auto& it = Team_Colors.find(Team_Names[tc_idx]);
|
|
if (it != Team_Colors.end()) {
|
|
tcolor = Team_Names[tc_idx];
|
|
}
|
|
}
|
|
|
|
SCP_vector<SCP_string> destroyed_subsystems;
|
|
if (destroyed_subsystems_table.isValid()) {
|
|
for (const auto& item : destroyed_subsystems_table) {
|
|
if (!item.second.is(luacpp::ValueType::STRING)) {
|
|
LuaError(L, "DestroyedSubsystems must be a table of strings.");
|
|
return ade_set_args(L, "b", false);
|
|
}
|
|
|
|
try {
|
|
destroyed_subsystems.emplace_back(item.second.getValue<SCP_string>());
|
|
} catch (const luacpp::LuaException& /*e*/) {
|
|
return ade_set_args(L, "b", false);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ade_set_args(L, "b", render_tech_model(TECH_SHIP, x1, y1, x2, y2, zoom, lighting, idx, &orient, "", 0.0f, &vmd_zero_vector, tcolor, destroyed_subsystems));
|
|
}
|
|
|
|
// Nuke's alternate tech model rendering function
|
|
ADE_FUNC(renderTechModel2, l_Shipclass, "number X1, number Y1, number X2, number Y2, [orientation Orientation=nil, number Zoom=1.3, teamcolor TeamColor=nil, string[] DestroyedSubsystems=nil]", "Draws ship model as if in techroom", "boolean", "Whether ship was rendered")
|
|
{
|
|
int x1,y1,x2,y2;
|
|
int idx;
|
|
float zoom = 1.3f;
|
|
matrix_h *mh = nullptr;
|
|
int tc_idx = -1;
|
|
auto destroyed_subsystems_table = luacpp::LuaTable::create(L);
|
|
if(!ade_get_args(L, "oiiiio|fot", l_Shipclass.Get(&idx), &x1, &y1, &x2, &y2, l_Matrix.GetPtr(&mh), &zoom, l_TeamColor.Get(&tc_idx), &destroyed_subsystems_table))
|
|
return ade_set_error(L, "b", false);
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ade_set_args(L, "b", false);
|
|
|
|
if(x2 < x1 || y2 < y1)
|
|
return ade_set_args(L, "b", false);
|
|
|
|
ship_info* sip = &Ship_info[idx];
|
|
|
|
//Handle angles
|
|
matrix *orient = mh->GetMatrix();
|
|
|
|
SCP_string tcolor = sip->default_team_name;
|
|
if (SCP_vector_inbounds(Team_Names, tc_idx)) {
|
|
const auto& it = Team_Colors.find(Team_Names[tc_idx]);
|
|
if (it != Team_Colors.end()) {
|
|
tcolor = Team_Names[tc_idx];
|
|
}
|
|
}
|
|
|
|
SCP_vector<SCP_string> destroyed_subsystems;
|
|
if (destroyed_subsystems_table.isValid()) {
|
|
for (const auto& item : destroyed_subsystems_table) {
|
|
if (!item.second.is(luacpp::ValueType::STRING)) {
|
|
LuaError(L, "DestroyedSubsystems must be a table of strings.");
|
|
return ade_set_args(L, "b", false);
|
|
}
|
|
|
|
try {
|
|
destroyed_subsystems.emplace_back(item.second.getValue<SCP_string>());
|
|
} catch (const luacpp::LuaException& /*e*/) {
|
|
return ade_set_args(L, "b", false);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ade_set_args(L, "b", render_tech_model(TECH_SHIP, x1, y1, x2, y2, zoom, true, idx, orient, "", 0, &vmd_zero_vector, tcolor, destroyed_subsystems));
|
|
}
|
|
|
|
ADE_FUNC(renderSelectModel,
|
|
l_Shipclass,
|
|
"boolean restart, number x, number y, [number width = 629, number height = 355, number currentEffectSetting = default, number zoom = 1.3, teamcolor TeamColor=nil]",
|
|
"Draws the 3D select ship model with the chosen effect at the specified coordinates. Restart should "
|
|
"be true on the first frame this is called and false on subsequent frames. Valid selection effects are 1 (fs1) or 2 (fs2), "
|
|
"defaults to the mod setting or the model's setting. Zoom is a multiplier to the model's closeup_zoom value.",
|
|
"boolean",
|
|
"true if rendered, false if error")
|
|
{
|
|
int idx;
|
|
bool restart;
|
|
int x1;
|
|
int y1;
|
|
int x2 = 629;
|
|
int y2 = 355;
|
|
int effect = -1;
|
|
float zoom = 1.3f;
|
|
int tc_idx = -1;
|
|
if (!ade_get_args(L, "obii|iiifo", l_Shipclass.Get(&idx), &restart, &x1, &y1, &x2, &y2, &effect, &zoom, l_TeamColor.Get(&tc_idx)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_args(L, "b", false);
|
|
|
|
if (effect == 0 || effect > 2) {
|
|
LuaError(L, "Valid effect values are 1 or 2, got %i", effect);
|
|
return ade_set_args(L, "b", false);
|
|
}
|
|
|
|
if (restart) {
|
|
anim_timer_start = timer_get_milliseconds();
|
|
}
|
|
|
|
ship_info* sip = &Ship_info[idx];
|
|
|
|
if (effect == -1) {
|
|
effect = sip->selection_effect;
|
|
}
|
|
|
|
float rev_rate = REVOLUTION_RATE;
|
|
if (sip->is_big_ship()) {
|
|
rev_rate *= 1.7f;
|
|
}
|
|
if (sip->is_huge_ship()) {
|
|
rev_rate *= 3.0f;
|
|
}
|
|
|
|
int modelNum = model_load(sip->pof_file, sip);
|
|
static float ShipRot = 0.0f;
|
|
|
|
model_render_params render_info;
|
|
|
|
if (sip->uses_team_colors) {
|
|
SCP_string tcolor = sip->default_team_name;
|
|
|
|
if (SCP_vector_inbounds(Team_Names, tc_idx)) {
|
|
const auto& it = Team_Colors.find(Team_Names[tc_idx]);
|
|
if (it != Team_Colors.end()) {
|
|
tcolor = Team_Names[tc_idx];
|
|
}
|
|
}
|
|
render_info.set_team_color(tcolor, "none", 0, 0);
|
|
}
|
|
|
|
if (sip->replacement_textures.size() > 0) {
|
|
render_info.set_replacement_textures(modelNum, sip->replacement_textures);
|
|
}
|
|
|
|
select_effect_params params;
|
|
params.effect = effect;
|
|
params.fs2_grid_color = sip->fs2_effect_grid_color;
|
|
params.fs2_scanline_color = sip->fs2_effect_scanline_color;
|
|
params.fs2_grid_density = sip->fs2_effect_grid_density;
|
|
params.fs2_wireframe_color = sip->fs2_effect_wireframe_color;
|
|
|
|
draw_model_rotating(&render_info,
|
|
idx,
|
|
modelNum,
|
|
x1,
|
|
y1,
|
|
x2,
|
|
y2,
|
|
&ShipRot,
|
|
&sip->closeup_pos,
|
|
sip->closeup_zoom * zoom,
|
|
rev_rate,
|
|
MR_AUTOCENTER | MR_NO_FOGGING,
|
|
GR_RESIZE_NONE,
|
|
params);
|
|
|
|
return ade_set_args(L, "b", true);
|
|
}
|
|
|
|
ADE_FUNC(renderOverheadModel,
|
|
l_Shipclass,
|
|
"number x, number y, [number width = 467, number height = 362, number|table /* selectedSlot = -1 or empty table */, number selectedWeapon = -1, number hoverSlot = -1, "
|
|
"number bank1_x = 170, number bank1_y = 203, number bank2_x = 170, number bank2_y = 246, number bank3_x = 170, number bank3_y = 290, "
|
|
"number bank4_x = 552, number bank4_y = 203, number bank5_x = 552, number bank5_y = 246, number bank6_x = 552, number bank6_y = 290, "
|
|
"number bank7_x = 552, number bank7_y = 333, number style = 0, teamcolor TeamColor=nil]",
|
|
"Draws the 3D overhead ship model with the lines pointing from bank weapon selections to bank firepoints. SelectedSlot refers to loadout "
|
|
"ship slots 1-12 where wing 1 is 1-4, wing 2 is 5-8, and wing 3 is 9-12. SelectedWeapon is the index into weapon classes. HoverSlot refers "
|
|
"to the bank slots 1-7 where 1-3 are primaries and 4-6 are secondaries. Lines will be drawn from any bank containing the SelectedWeapon to "
|
|
"the firepoints on the model of that bank. Similarly, lines will be drawn from the bank defined by HoverSlot to the firepoints on the model "
|
|
"of that slot. Line drawing for HoverSlot takes precedence over line drawing for SelectedWeapon. Set either or both to -1 to stop line drawing. "
|
|
"The bank coordinates are the coordinates from which the lines for that bank will be drawn. It is expected that primary slots will be on the "
|
|
"left of the ship model and secondaries will be on the right. The lines have a hard-coded curve expecing to be drawn from those directions. "
|
|
"Style can be 0 or 1. 0 for the ship to be drawn stationary from top down, 1 for the ship to be rotating.",
|
|
"boolean",
|
|
"true if rendered, false if error")
|
|
{
|
|
int idx;
|
|
int x1;
|
|
int y1;
|
|
int x2 = 467;
|
|
int y2 = 362;
|
|
int selectedSlot = -1;
|
|
auto weapon_table = luacpp::LuaTable::create(L);
|
|
int selectedWeapon = -1;
|
|
int hoverSlot = -1;
|
|
|
|
//Bank coords
|
|
int bank1_x = 170;
|
|
int bank1_y = 203;
|
|
int bank2_x = 170;
|
|
int bank2_y = 246;
|
|
int bank3_x = 170;
|
|
int bank3_y = 290;
|
|
int bank4_x = 552;
|
|
int bank4_y = 203;
|
|
int bank5_x = 552;
|
|
int bank5_y = 246;
|
|
int bank6_x = 552;
|
|
int bank6_y = 290;
|
|
int bank7_x = 552;
|
|
int bank7_y = 333;
|
|
int style = 0;
|
|
|
|
int weapon_list[MAX_SHIP_WEAPONS] = {-1, -1, -1, -1, -1, -1, -1};
|
|
|
|
int tc_idx = -1;
|
|
|
|
if (lua_isnumber(L, 6)) {
|
|
|
|
if (!ade_get_args(L,
|
|
"oii|iiiiiiiiiiiiiiiiiiiio",
|
|
l_Shipclass.Get(&idx),
|
|
&x1,
|
|
&y1,
|
|
&x2,
|
|
&y2,
|
|
&selectedSlot,
|
|
&selectedWeapon,
|
|
&hoverSlot,
|
|
&bank1_x,
|
|
&bank1_y,
|
|
&bank2_x,
|
|
&bank2_y,
|
|
&bank3_x,
|
|
&bank3_y,
|
|
&bank4_x,
|
|
&bank4_y,
|
|
&bank5_x,
|
|
&bank5_y,
|
|
&bank6_x,
|
|
&bank6_y,
|
|
&bank7_x,
|
|
&bank7_y,
|
|
&style,
|
|
l_TeamColor.Get(&tc_idx)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
// Convert this from the Lua index
|
|
selectedSlot--;
|
|
|
|
if (selectedSlot < 0)
|
|
return ADE_RETURN_FALSE;
|
|
|
|
for (int i = 0; i < (MAX_SHIP_WEAPONS); i++) {
|
|
weapon_list[i] = Wss_slots[selectedSlot].wep[i];
|
|
}
|
|
} else {
|
|
if (!ade_get_args(L,
|
|
"oii|iitiiiiiiiiiiiiiiiiio",
|
|
l_Shipclass.Get(&idx),
|
|
&x1,
|
|
&y1,
|
|
&x2,
|
|
&y2,
|
|
&weapon_table,
|
|
&selectedWeapon,
|
|
&hoverSlot,
|
|
&bank1_x,
|
|
&bank1_y,
|
|
&bank2_x,
|
|
&bank2_y,
|
|
&bank3_x,
|
|
&bank3_y,
|
|
&bank4_x,
|
|
&bank4_y,
|
|
&bank5_x,
|
|
&bank5_y,
|
|
&bank6_x,
|
|
&bank6_y,
|
|
&bank7_x,
|
|
&bank7_y,
|
|
&style,
|
|
l_TeamColor.Get(&tc_idx)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
int count = 0;
|
|
if (weapon_table.isValid()) {
|
|
for (const auto& item : weapon_table) {
|
|
if (item.second.is(luacpp::ValueType::NUMBER)) {
|
|
// This'll lua-error internally if it's not fed only numbers. Additionally, catch the lua exception
|
|
// and then carry on
|
|
try {
|
|
int wep = item.second.getValue<int>();
|
|
wep--; // convert from the lua index
|
|
weapon_list[count++] = wep;
|
|
} catch (const luacpp::LuaException& /*e*/) {
|
|
// We were likely fed a userdata that was not a number.
|
|
// Since we can't actually tell whether that's the case before we try to get the value, and the
|
|
// attempt to get the value is printing a LuaError itself, just eat the exception here and
|
|
// return
|
|
return ADE_RETURN_FALSE;
|
|
}
|
|
} else {
|
|
// This happens on a non-userdata value, i.e. a string
|
|
LuaError(L, "Weapon index table contained non-number values! Aborting...");
|
|
return ADE_RETURN_FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ade_set_args(L, "b", false);
|
|
|
|
//Convert these from Lua indecies
|
|
selectedWeapon--;
|
|
hoverSlot--;
|
|
|
|
if ((style < 0) || (style > 1))
|
|
LuaError(L, "Overhead style can only be 0 or 1!");
|
|
|
|
if (selectedWeapon < 0 || selectedWeapon >= weapon_info_size())
|
|
selectedWeapon = -1;
|
|
|
|
if (hoverSlot < 0 || hoverSlot >= (MAX_SHIP_PRIMARY_BANKS + MAX_SHIP_SECONDARY_BANKS))
|
|
hoverSlot = -1;
|
|
|
|
ship_info* sip = &Ship_info[idx];
|
|
|
|
SCP_string tcolor = sip->default_team_name;
|
|
if (SCP_vector_inbounds(Team_Names, tc_idx)) {
|
|
const auto& it = Team_Colors.find(Team_Names[tc_idx]);
|
|
if (it != Team_Colors.end()) {
|
|
tcolor = Team_Names[tc_idx];
|
|
}
|
|
}
|
|
|
|
int modelNum = model_load(sip->pof_file, sip);
|
|
model_page_in_textures(modelNum, idx);
|
|
static float ShipRot = 0.0f;
|
|
|
|
draw_3d_overhead_view(modelNum,
|
|
idx,
|
|
&ShipRot,
|
|
flFrametime,
|
|
weapon_list,
|
|
selectedWeapon,
|
|
hoverSlot,
|
|
x1,
|
|
y1,
|
|
x2,
|
|
y2,
|
|
GR_RESIZE_NONE,
|
|
bank1_x,
|
|
bank1_y,
|
|
bank2_x,
|
|
bank2_y,
|
|
bank3_x,
|
|
bank3_y,
|
|
bank4_x,
|
|
bank4_y,
|
|
bank5_x,
|
|
bank5_y,
|
|
bank6_x,
|
|
bank6_y,
|
|
bank7_x,
|
|
bank7_y,
|
|
0,
|
|
0,
|
|
0,
|
|
(overhead_style)style,
|
|
tcolor);
|
|
|
|
return ade_set_args(L, "b", true);
|
|
}
|
|
|
|
ADE_FUNC(isModelLoaded, l_Shipclass, "[boolean Load = false]", "Checks if the model used for this shipclass is loaded or not and optionally loads the model, which might be a slow operation.", "boolean", "If the model is loaded or not")
|
|
{
|
|
int idx;
|
|
bool load_check = false;
|
|
if(!ade_get_args(L, "o|b", l_Shipclass.Get(&idx), &load_check))
|
|
return ADE_RETURN_FALSE;
|
|
|
|
ship_info *sip = &Ship_info[idx];
|
|
|
|
if (sip == NULL)
|
|
return ADE_RETURN_FALSE;
|
|
|
|
if(load_check){
|
|
sip->model_num = model_load(sip->pof_file, sip);
|
|
}
|
|
|
|
if (sip->model_num > -1)
|
|
return ADE_RETURN_TRUE;
|
|
else
|
|
return ADE_RETURN_FALSE;
|
|
}
|
|
|
|
ADE_FUNC(isPlayerAllowed,
|
|
l_Shipclass,
|
|
nullptr,
|
|
"Detects whether the ship has the player allowed flag",
|
|
"boolean",
|
|
"true if player allowed, false otherwise, nil if a syntax/type error occurs")
|
|
{
|
|
int idx;
|
|
if (!ade_get_args(L, "o", l_Shipclass.Get(&idx)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (idx < 0 || idx >= ship_info_size())
|
|
return ADE_RETURN_FALSE;
|
|
|
|
ship_info* sip = &Ship_info[idx];
|
|
|
|
if (sip->flags[Ship::Info_Flags::Player_ship]) {
|
|
return ADE_RETURN_TRUE;
|
|
}
|
|
|
|
return ADE_RETURN_FALSE;
|
|
}
|
|
|
|
ADE_FUNC(getShipClassIndex, l_Shipclass, nullptr, "Gets the index value of the ship class", "number", "index value of the ship class")
|
|
{
|
|
int idx;
|
|
if(!ade_get_args(L, "o", l_Shipclass.Get(&idx)))
|
|
return ade_set_args(L, "i", -1);
|
|
|
|
if(idx < 0 || idx >= ship_info_size())
|
|
return ade_set_args(L, "i", -1);
|
|
|
|
return ade_set_args(L, "i", idx + 1); // Lua is 1-based
|
|
}
|
|
|
|
|
|
}
|
|
}
|