mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 08:15:59 -10:00
* Automatically generate the isValid() Lua API function for handle types If an ADE object's stored type has an isValid() member, ade_obj now registers an isValid function for it automatically. An explicit ADE_FUNC(isValid, ...) declared after the ADE_OBJ replaces the generated one, so types with special semantics (e.g. sound) keep their own. The 67 hand-written functions that merely delegated to the member are removed, and 26 types that previously exposed no isValid() gain one. Co-Authored-By: Claude Fable 5.1 <[email protected]> * Add ADE_OBJ_VALIDATOR for index-based Lua handles Int-index handles (shipclass, weaponclass, team, etc.) can now declare their validity predicate with a single ADE_OBJ_VALIDATOR or ADE_OBJ_VALIDATOR_RANGE line after the ADE_OBJ. The registered validator drives the generated isValid() function and is also honored by ade_set_args when the mod table asks for nil instead of invalid objects, which previously never applied to these handles. The 19 hand-written range-check functions are replaced, and loadout_ship, default_primary, default_secondary, and support_rearm_pool_team gain isValid(). Add a validator to HudGauge while we're at it. Also fully qualify the scripting namespace in LuaConvert.h so its templates can be instantiated from the unit tests. Co-Authored-By: Claude Fable 5.1 <[email protected]> --------- Co-authored-by: Claude Fable 5.1 <[email protected]>
892 lines
28 KiB
C++
892 lines
28 KiB
C++
|
|
#include "parse_object.h"
|
|
|
|
#include "ship.h"
|
|
#include "shipclass.h"
|
|
#include "team.h"
|
|
#include "vecmath.h"
|
|
#include "weaponclass.h"
|
|
#include "wing.h"
|
|
#include "team_colors.h"
|
|
#include "globalincs/alphacolors.h" //Needed for team colors
|
|
|
|
#include "network/multi.h"
|
|
#include "network/multimsgs.h"
|
|
#include "network/multiutil.h"
|
|
#include "ship/ship.h"
|
|
|
|
extern bool sexp_check_flag_arrays(const char *flag_name, Object::Object_Flags &object_flag, Ship::Ship_Flags &ship_flags, Mission::Parse_Object_Flags &parse_obj_flag, AI::AI_Flags &ai_flag);
|
|
extern void sexp_alter_ship_flag_helper(object_ship_wing_point_team &oswpt, bool future_ships, Object::Object_Flags object_flag, Ship::Ship_Flags ship_flag, Mission::Parse_Object_Flags parse_obj_flag, AI::AI_Flags ai_flag, bool set_flag);
|
|
|
|
namespace scripting {
|
|
namespace api {
|
|
|
|
parse_object_h::parse_object_h(p_object* obj) : _obj(obj) {}
|
|
p_object* parse_object_h::getObject() const { return _obj; }
|
|
bool parse_object_h::isValid() const { return _obj != nullptr; }
|
|
|
|
void parse_object_h::serialize(lua_State* /*L*/, const scripting::ade_table_entry& /*tableEntry*/, const luacpp::LuaValue& value, ubyte* data, int& packet_size) {
|
|
parse_object_h pobj(nullptr);
|
|
value.getValue(l_ParseObject.Get(&pobj));
|
|
const ushort& netsig = pobj.isValid() ? pobj._obj->net_signature : 0;
|
|
ADD_USHORT(netsig);
|
|
}
|
|
|
|
void parse_object_h::deserialize(lua_State* /*L*/, const scripting::ade_table_entry& /*tableEntry*/, char* data_ptr, ubyte* data, int& offset) {
|
|
ushort net_signature;
|
|
GET_USHORT(net_signature);
|
|
new(data_ptr) parse_object_h(mission_parse_get_arrival_ship(net_signature));
|
|
}
|
|
|
|
|
|
//**********HANDLE: parse_object
|
|
ADE_OBJ(l_ParseObject, parse_object_h, "parse_object", "Handle to a parsed ship");
|
|
|
|
ADE_VIRTVAR(Name, l_ParseObject, "string",
|
|
"The name of the parsed ship. If possible, don't set the name but set the display name instead.", "string",
|
|
"The name or empty string on error")
|
|
{
|
|
parse_object_h* poh = nullptr;
|
|
const char* newName = nullptr;
|
|
if (!ade_get_args(L, "o|s", l_ParseObject.GetPtr(&poh), &newName))
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if (poh == nullptr)
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if (!poh->isValid())
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
strcpy_s(poh->getObject()->name, newName);
|
|
}
|
|
|
|
return ade_set_args(L, "s", poh->getObject()->name);
|
|
}
|
|
|
|
ADE_VIRTVAR(
|
|
DisplayName, l_ParseObject, "string",
|
|
"The display name of the parsed ship. If the name should be shown to the user, use this since it can be translated.",
|
|
"string", "The display name or empty string on error")
|
|
{
|
|
parse_object_h* poh = nullptr;
|
|
const char* newName = nullptr;
|
|
if (!ade_get_args(L, "o|s", l_ParseObject.GetPtr(&poh), &newName))
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if (poh == nullptr)
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if (!poh->isValid())
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
poh->getObject()->display_name = newName;
|
|
|
|
// for compatibility reasons, if we are setting this to the empty string, clear the flag
|
|
poh->getObject()->flags.set(Mission::Parse_Object_Flags::SF_Has_display_name, newName[0] != 0);
|
|
}
|
|
|
|
return ade_set_args(L, "s", poh->getObject()->get_display_name());
|
|
}
|
|
|
|
ADE_FUNC(getBreedName, l_ParseObject, nullptr, "Gets the FreeSpace type name", "string", "'Parse Object', or empty string if handle is invalid")
|
|
{
|
|
parse_object_h* poh = nullptr;
|
|
if (!ade_get_args(L, "o", l_ParseObject.GetPtr(&poh)))
|
|
return ade_set_error(L, "s", "");
|
|
|
|
if (!poh->isValid())
|
|
return ade_set_error(L, "s", "");
|
|
|
|
return ade_set_args(L, "s", "Parse Object");
|
|
}
|
|
|
|
ADE_FUNC(isPlayer, l_ParseObject, nullptr, "Checks whether the parsed ship is a player ship", "boolean", "Whether the parsed ship is a player ship")
|
|
{
|
|
parse_object_h *poh = nullptr;
|
|
if (!ade_get_args(L, "o", l_ParseObject.GetPtr(&poh)))
|
|
return ade_set_error(L, "b", false);
|
|
|
|
if (!poh->isValid())
|
|
return ade_set_error(L, "b", false);
|
|
|
|
// singleplayer
|
|
if (!(Game_mode & GM_MULTIPLAYER))
|
|
{
|
|
if (poh->getObject()->flags[Mission::Parse_Object_Flags::OF_Player_start])
|
|
return ADE_RETURN_TRUE;
|
|
else
|
|
return ADE_RETURN_FALSE;
|
|
}
|
|
// multiplayer
|
|
else
|
|
{
|
|
// try and find the player
|
|
int np_index = multi_find_player_by_parse_object(poh->getObject());
|
|
if ((np_index >= 0) && (np_index < MAX_PLAYERS))
|
|
return ADE_RETURN_TRUE;
|
|
else
|
|
return ADE_RETURN_FALSE;
|
|
}
|
|
}
|
|
|
|
ADE_FUNC(setFlag, l_ParseObject, "boolean set_it, string flag_name", "Sets or clears one or more flags - this function can accept an arbitrary number of flag arguments. The flag names can be any string that the alter-ship-flag SEXP operator supports.", nullptr, "Returns nothing")
|
|
{
|
|
parse_object_h *poh = nullptr;
|
|
bool set_it;
|
|
const char *flag_name;
|
|
|
|
if (!ade_get_args(L, "obs", l_ParseObject.GetPtr(&poh), &set_it, &flag_name))
|
|
return ADE_RETURN_NIL;
|
|
int skip_args = 2; // not 3 because there will be one more below
|
|
|
|
if (!poh->isValid())
|
|
return ADE_RETURN_NIL;
|
|
|
|
auto pobjp = poh->getObject();
|
|
object_ship_wing_point_team oswpt(pobjp);
|
|
|
|
do {
|
|
auto object_flag = Object::Object_Flags::NUM_VALUES;
|
|
auto ship_flag = Ship::Ship_Flags::NUM_VALUES;
|
|
auto parse_obj_flag = Mission::Parse_Object_Flags::NUM_VALUES;
|
|
auto ai_flag = AI::AI_Flags::NUM_VALUES;
|
|
|
|
sexp_check_flag_arrays(flag_name, object_flag, ship_flag, parse_obj_flag, ai_flag);
|
|
|
|
if (parse_obj_flag == Mission::Parse_Object_Flags::NUM_VALUES)
|
|
{
|
|
Warning(LOCATION, "Parsed ship flag '%s' not found!", flag_name);
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
sexp_alter_ship_flag_helper(oswpt, true, object_flag, ship_flag, parse_obj_flag, ai_flag, set_it);
|
|
|
|
// read the next flag
|
|
internal::Ade_get_args_skip = ++skip_args;
|
|
} while (ade_get_args(L, "|s", &flag_name) > 0);
|
|
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
ADE_FUNC(getFlag, l_ParseObject, "string flag_name", "Checks whether one or more flags are set - this function can accept an arbitrary number of flag arguments. The flag names can be any string that the alter-ship-flag SEXP operator supports.", "boolean", "Returns whether all flags are set, or nil if the parsed ship is not valid")
|
|
{
|
|
parse_object_h *poh = nullptr;
|
|
const char *flag_name;
|
|
|
|
if (!ade_get_args(L, "os", l_ParseObject.GetPtr(&poh), &flag_name))
|
|
return ADE_RETURN_NIL;
|
|
int skip_args = 1; // not 2 because there will be one more below
|
|
|
|
if (!poh->isValid())
|
|
return ADE_RETURN_NIL;
|
|
|
|
auto pobjp = poh->getObject();
|
|
|
|
do {
|
|
auto object_flag = Object::Object_Flags::NUM_VALUES;
|
|
auto ship_flag = Ship::Ship_Flags::NUM_VALUES;
|
|
auto parse_obj_flag = Mission::Parse_Object_Flags::NUM_VALUES;
|
|
auto ai_flag = AI::AI_Flags::NUM_VALUES;
|
|
|
|
sexp_check_flag_arrays(flag_name, object_flag, ship_flag, parse_obj_flag, ai_flag);
|
|
|
|
if (parse_obj_flag == Mission::Parse_Object_Flags::NUM_VALUES)
|
|
{
|
|
Warning(LOCATION, "Parsed ship flag '%s' not found!", flag_name);
|
|
return ADE_RETURN_FALSE;
|
|
}
|
|
|
|
// we only check parse flags, unless this is the one object flag that is the same thing in reverse
|
|
if (object_flag == Object::Object_Flags::Collides)
|
|
{
|
|
if (pobjp->flags[Mission::Parse_Object_Flags::OF_No_collide])
|
|
return ADE_RETURN_FALSE;
|
|
}
|
|
|
|
if (parse_obj_flag != Mission::Parse_Object_Flags::NUM_VALUES)
|
|
{
|
|
if (!pobjp->flags[parse_obj_flag])
|
|
return ADE_RETURN_FALSE;
|
|
}
|
|
|
|
// read the next flag
|
|
internal::Ade_get_args_skip = ++skip_args;
|
|
} while (ade_get_args(L, "|s", &flag_name) > 0);
|
|
|
|
// if we're still here, all the flags we were looking for were present
|
|
return ADE_RETURN_TRUE;
|
|
}
|
|
|
|
static int parse_object_getset_helper(lua_State* L, int p_object::* field, bool canSet = false, bool canBeNegative = false)
|
|
{
|
|
parse_object_h* poh;
|
|
int value;
|
|
if (!ade_get_args(L, "o|i", l_ParseObject.GetPtr(&poh), &value))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (!poh || !poh->isValid())
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (ADE_SETTING_VAR)
|
|
{
|
|
if (canSet)
|
|
{
|
|
if (canBeNegative || value >= 0)
|
|
poh->getObject()->*field = value;
|
|
}
|
|
else
|
|
LuaError(L, "This property is read only.");
|
|
}
|
|
|
|
return ade_set_args(L, "i", poh->getObject()->*field);
|
|
}
|
|
|
|
ADE_VIRTVAR(Position, l_ParseObject, "vector", "The position at which the parsed ship will arrive.", "vector",
|
|
"The position of the parsed ship.")
|
|
{
|
|
parse_object_h* poh = nullptr;
|
|
vec3d* newPos = nullptr;
|
|
if (!ade_get_args(L, "o|o", l_ParseObject.GetPtr(&poh), l_Vector.GetPtr(&newPos)))
|
|
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
|
|
|
|
if (poh == nullptr)
|
|
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
|
|
|
|
if (!poh->isValid())
|
|
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
poh->getObject()->pos = *newPos;
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_Vector.Set(poh->getObject()->pos));
|
|
}
|
|
|
|
ADE_VIRTVAR(Orientation, l_ParseObject, "orientation", "The orientation of the parsed ship.", "orientation", "The orientation")
|
|
{
|
|
parse_object_h* poh = nullptr;
|
|
matrix_h* newMat = nullptr;
|
|
if (!ade_get_args(L, "o|o", l_ParseObject.GetPtr(&poh), l_Matrix.GetPtr(&newMat)))
|
|
return ade_set_error(L, "o", l_Matrix.Set(matrix_h()));
|
|
|
|
if (poh == nullptr)
|
|
return ade_set_error(L, "o", l_Matrix.Set(matrix_h()));
|
|
|
|
if (!poh->isValid())
|
|
return ade_set_error(L, "o", l_Matrix.Set(matrix_h()));
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
poh->getObject()->orient = *newMat->GetMatrix();
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_Matrix.Set(matrix_h(&poh->getObject()->orient)));
|
|
}
|
|
|
|
ADE_VIRTVAR(ShipClass, l_ParseObject, "shipclass", "The ship class of the parsed ship.", "shipclass", "The ship class")
|
|
{
|
|
parse_object_h* poh = nullptr;
|
|
int newClass = -1;
|
|
if (!ade_get_args(L, "o|o", l_ParseObject.GetPtr(&poh), l_Shipclass.Get(&newClass)))
|
|
return ade_set_error(L, "o", l_Shipclass.Set(-1));
|
|
|
|
if (poh == nullptr)
|
|
return ade_set_error(L, "o", l_Shipclass.Set(-1));
|
|
|
|
if (!poh->isValid())
|
|
return ade_set_error(L, "o", l_Shipclass.Set(-1));
|
|
|
|
if (ADE_SETTING_VAR && newClass >= 0) {
|
|
poh->getObject()->ship_class = newClass;
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_Shipclass.Set(poh->getObject()->ship_class));
|
|
}
|
|
|
|
ADE_VIRTVAR(Team, l_ParseObject, "team", "The team of the parsed ship.", "team", "The team")
|
|
{
|
|
parse_object_h* poh = nullptr;
|
|
int newTeam = -1;
|
|
if (!ade_get_args(L, "o|o", l_ParseObject.GetPtr(&poh), l_Team.Get(&newTeam)))
|
|
return ade_set_error(L, "o", l_Team.Set(-1));
|
|
|
|
if (poh == nullptr)
|
|
return ade_set_error(L, "o", l_Team.Set(-1));
|
|
|
|
if (!poh->isValid())
|
|
return ade_set_error(L, "o", l_Team.Set(-1));
|
|
|
|
if (ADE_SETTING_VAR && newTeam >= 0) {
|
|
poh->getObject()->team = newTeam;
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_Team.Set(poh->getObject()->team));
|
|
}
|
|
|
|
ADE_VIRTVAR(TeamColor, l_ParseObject, "teamcolor", "The team color. Setting the team color here will not be reflected in the mission if the ship is already created. You must do that on the Ship object instead.", "teamcolor", "The team color handle or nil if not set or invalid.")
|
|
{
|
|
parse_object_h* poh = nullptr;
|
|
int idx = -1;
|
|
if (!ade_get_args(L, "o|o", l_ParseObject.GetPtr(&poh), l_TeamColor.Get(&idx)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (!poh->isValid())
|
|
return ADE_RETURN_NIL;
|
|
|
|
// Set team color
|
|
if (ADE_SETTING_VAR && SCP_vector_inbounds(Team_Names, idx)) {
|
|
// Verify
|
|
const auto& it = Team_Colors.find(Team_Names[idx]);
|
|
if (it == Team_Colors.end()) {
|
|
mprintf(("Invalid team color specified in mission file for ship %s. Not setting!\n", poh->getObject()->name));
|
|
} else {
|
|
poh->getObject()->team_color_setting = Team_Names[idx];
|
|
}
|
|
}
|
|
|
|
// look up by name
|
|
for (int i = 0; i < static_cast<int>(Team_Names.size()); ++i) {
|
|
if (lcase_equal(Team_Names[i], poh->getObject()->team_color_setting)) {
|
|
return ade_set_args(L, "o", l_TeamColor.Set(i));
|
|
}
|
|
}
|
|
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
ADE_VIRTVAR(InitialHull, l_ParseObject, "number", "The initial hull percentage of this parsed ship.", "number",
|
|
"The initial hull")
|
|
{
|
|
parse_object_h* poh = nullptr;
|
|
int newInitialHull = -1;
|
|
if (!ade_get_args(L, "o|i", l_ParseObject.GetPtr(&poh), &newInitialHull))
|
|
return ade_set_error(L, "i", -1);
|
|
|
|
if (poh == nullptr)
|
|
return ade_set_error(L, "i", -1);
|
|
|
|
if (!poh->isValid())
|
|
return ade_set_error(L, "i", -1);
|
|
|
|
if (ADE_SETTING_VAR && newInitialHull >= 0 && newInitialHull <= 100) {
|
|
poh->getObject()->initial_hull = newInitialHull;
|
|
}
|
|
|
|
return ade_set_args(L, "i", poh->getObject()->initial_hull);
|
|
}
|
|
|
|
ADE_VIRTVAR(InitialShields, l_ParseObject, "number", "The initial shields percentage of this parsed ship.", "number",
|
|
"The initial shields")
|
|
{
|
|
parse_object_h* poh = nullptr;
|
|
int newInitialShields = -1;
|
|
if (!ade_get_args(L, "o|i", l_ParseObject.GetPtr(&poh), &newInitialShields))
|
|
return ade_set_error(L, "i", -1);
|
|
|
|
if (poh == nullptr)
|
|
return ade_set_error(L, "i", -1);
|
|
|
|
if (!poh->isValid())
|
|
return ade_set_error(L, "i", -1);
|
|
|
|
if (ADE_SETTING_VAR && newInitialShields >= 0 && newInitialShields <= 100) {
|
|
poh->getObject()->initial_shields = newInitialShields;
|
|
}
|
|
|
|
return ade_set_args(L, "i", poh->getObject()->initial_shields);
|
|
}
|
|
|
|
ADE_VIRTVAR(MainStatus, l_ParseObject, nullptr,
|
|
"Gets the \"subsystem\" status of the ship itself. This is a special subsystem that represents the primary "
|
|
"and secondary weapons and the AI class.",
|
|
"parse_subsystem", "The subsystem handle or invalid handle if there were no changes to the main status")
|
|
{
|
|
parse_object_h* poh = nullptr;
|
|
if (!ade_get_args(L, "o", l_ParseObject.GetPtr(&poh)))
|
|
return ade_set_error(L, "o", l_ParseSubsystem.Set(parse_subsys_h()));
|
|
|
|
if (poh == nullptr)
|
|
return ade_set_error(L, "o", l_ParseSubsystem.Set(parse_subsys_h()));
|
|
|
|
if (!poh->isValid())
|
|
return ade_set_error(L, "o", l_ParseSubsystem.Set(parse_subsys_h()));
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "This property is read only.");
|
|
}
|
|
|
|
auto po = poh->getObject();
|
|
for (int i = 0; i < po->subsys_count; ++i) {
|
|
if (!stricmp(Subsys_status[po->subsys_index + i].name, "Pilot")) {
|
|
return ade_set_args(L, "o", l_ParseSubsystem.Set(parse_subsys_h(po, i)));
|
|
}
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_ParseSubsystem.Set(parse_subsys_h()));
|
|
}
|
|
|
|
ADE_VIRTVAR(Subsystems, l_ParseObject, nullptr, "Get the list of subsystems of this parsed ship",
|
|
"parse_subsystem[]", "An array of the parse subsystems of this parsed ship")
|
|
{
|
|
parse_object_h* poh = nullptr;
|
|
if (!ade_get_args(L, "o", l_ParseObject.GetPtr(&poh)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (poh == nullptr)
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (!poh->isValid())
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "This property is read only.");
|
|
}
|
|
|
|
luacpp::LuaTable tbl = luacpp::LuaTable::create(L);
|
|
auto po = poh->getObject();
|
|
int luaIdx = 1;
|
|
for (int i = 0; i < po->subsys_count; ++i) {
|
|
// Only include the "non-main" subsystems
|
|
if (stricmp(Subsys_status[po->subsys_index + i].name, "Pilot")) {
|
|
tbl.addValue(luaIdx, l_ParseSubsystem.Set(parse_subsys_h(poh->getObject(), i)));
|
|
++luaIdx;
|
|
}
|
|
}
|
|
|
|
return ade_set_args(L, "t", tbl);
|
|
}
|
|
|
|
template <typename LOC>
|
|
static int parse_object_getset_location_helper(lua_State* L, LOC p_object::* field, const char* location_type, const char** location_names, size_t location_names_size)
|
|
{
|
|
parse_object_h* poh;
|
|
const char* s = nullptr;
|
|
if (!ade_get_args(L, "o|s", l_ParseObject.GetPtr(&poh), &s))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (!poh || !poh->isValid())
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (ADE_SETTING_VAR && s != nullptr)
|
|
{
|
|
int location = string_lookup(s, location_names, location_names_size);
|
|
if (location < 0)
|
|
{
|
|
Warning(LOCATION, "%s location '%s' not found.", location_type, s);
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
poh->getObject()->*field = static_cast<LOC>(location);
|
|
}
|
|
|
|
return ade_set_args(L, "s", location_names[static_cast<int>(poh->getObject()->*field)]);
|
|
}
|
|
|
|
ADE_VIRTVAR(ArrivalLocation, l_ParseObject, "string", "The ship's arrival location", "string", "Arrival location, or nil if handle is invalid")
|
|
{
|
|
return parse_object_getset_location_helper(L, &p_object::arrival_location, "Arrival", Arrival_location_names, MAX_ARRIVAL_NAMES);
|
|
}
|
|
|
|
ADE_VIRTVAR(DepartureLocation, l_ParseObject, "string", "The ship's departure location", "string", "Departure location, or nil if handle is invalid")
|
|
{
|
|
return parse_object_getset_location_helper(L, &p_object::departure_location, "Departure", Departure_location_names, MAX_DEPARTURE_NAMES);
|
|
}
|
|
|
|
static int parse_object_getset_anchor_helper(lua_State* L, anchor_t p_object::* field)
|
|
{
|
|
parse_object_h* poh;
|
|
const char* s = nullptr;
|
|
if (!ade_get_args(L, "o|s", l_ParseObject.GetPtr(&poh), &s))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (!poh || !poh->isValid())
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (ADE_SETTING_VAR && s != nullptr)
|
|
{
|
|
poh->getObject()->*field = (stricmp(s, "<no anchor>") == 0) ? anchor_t::invalid() : anchor_t(ship_registry_get_index(s));
|
|
}
|
|
|
|
auto anchor_entry = ship_registry_get(poh->getObject()->*field);
|
|
return ade_set_args(L, "s", anchor_entry ? anchor_entry->name : "<no anchor>");
|
|
}
|
|
|
|
ADE_VIRTVAR(ArrivalAnchor, l_ParseObject, "string", "The ship's arrival anchor", "string", "Arrival anchor, or nil if handle is invalid")
|
|
{
|
|
return parse_object_getset_anchor_helper(L, &p_object::arrival_anchor);
|
|
}
|
|
|
|
ADE_VIRTVAR(DepartureAnchor, l_ParseObject, "string", "The ship's departure anchor", "string", "Departure anchor, or nil if handle is invalid")
|
|
{
|
|
return parse_object_getset_anchor_helper(L, &p_object::departure_anchor);
|
|
}
|
|
|
|
ADE_VIRTVAR(ArrivalPathMask, l_ParseObject, "number", "The ship's arrival path mask", "number", "Arrival path mask, or nil if handle is invalid")
|
|
{
|
|
return parse_object_getset_helper(L, &p_object::arrival_path_mask, true);
|
|
}
|
|
|
|
ADE_VIRTVAR(DeparturePathMask, l_ParseObject, "number", "The ship's departure path mask", "number", "Departure path mask, or nil if handle is invalid")
|
|
{
|
|
return parse_object_getset_helper(L, &p_object::departure_path_mask, true);
|
|
}
|
|
|
|
ADE_VIRTVAR(ArrivalDelay, l_ParseObject, "number", "The ship's arrival delay", "number", "Arrival delay, or nil if handle is invalid")
|
|
{
|
|
return parse_object_getset_helper(L, &p_object::arrival_delay, true);
|
|
}
|
|
|
|
ADE_VIRTVAR(DepartureDelay, l_ParseObject, "number", "The ship's departure delay", "number", "Departure delay, or nil if handle is invalid")
|
|
{
|
|
return parse_object_getset_helper(L, &p_object::departure_delay, true);
|
|
}
|
|
|
|
ADE_VIRTVAR(ArrivalDistance, l_ParseObject, "number", "The ship's arrival distance", "number", "Arrival distance, or nil if handle is invalid")
|
|
{
|
|
return parse_object_getset_helper(L, &p_object::arrival_distance, true);
|
|
}
|
|
|
|
ADE_FUNC(isPlayerStart, l_ParseObject, nullptr, "Determines if this parsed ship is a player start.", "boolean",
|
|
"true if player start, false if not or if invalid")
|
|
{
|
|
parse_object_h* poh = nullptr;
|
|
if (!ade_get_args(L, "o", l_ParseObject.GetPtr(&poh)))
|
|
return ade_set_error(L, "b", false);
|
|
|
|
if (poh == nullptr)
|
|
return ade_set_error(L, "b", false);
|
|
|
|
if (!poh->isValid())
|
|
return ade_set_error(L, "b", false);
|
|
|
|
return ade_set_args(L, "b", poh->getObject()->flags[Mission::Parse_Object_Flags::OF_Player_start]);
|
|
}
|
|
|
|
ADE_FUNC(getShip, l_ParseObject, nullptr, "Returns the ship that was created from this parsed ship, if it is present in the mission. Note that parse objects are reused when a wing has multiple waves, so this will always return a ship from the most recently created wave.", "ship", "The created ship, an invalid handle if no ship exists, or nil if the current handle is invalid")
|
|
{
|
|
parse_object_h* poh = nullptr;
|
|
if (!ade_get_args(L, "o", l_ParseObject.GetPtr(&poh)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (!poh || !poh->isValid())
|
|
return ADE_RETURN_NIL;
|
|
|
|
auto objp = poh->getObject()->created_object;
|
|
if (!objp)
|
|
return ade_set_args(L, "o", l_Ship.Set(-1));
|
|
|
|
return ade_set_object_with_breed(L, OBJ_INDEX(objp));
|
|
}
|
|
|
|
ADE_FUNC(getWing, l_ParseObject, nullptr, "Returns the wing that this parsed ship belongs to, if any", "wing", "The parsed ship's wing, an invalid wing handle if no wing exists, or nil if the handle is invalid")
|
|
{
|
|
parse_object_h* poh = nullptr;
|
|
if (!ade_get_args(L, "o", l_ParseObject.GetPtr(&poh)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (poh == nullptr)
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (!poh->isValid())
|
|
return ADE_RETURN_NIL;
|
|
|
|
return ade_set_args(L, "o", l_Wing.Set(poh->getObject()->wingnum));
|
|
}
|
|
|
|
ADE_FUNC(makeShipArrive, l_ParseObject, nullptr, "Causes this parsed ship to arrive as if its arrival cue had become true. Note that reinforcements are only marked as available, not actually created.", "boolean", "true if created, false otherwise")
|
|
{
|
|
parse_object_h* poh = nullptr;
|
|
if (!ade_get_args(L, "o", l_ParseObject.GetPtr(&poh)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (poh == nullptr)
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (!poh->isValid())
|
|
return ADE_RETURN_NIL;
|
|
|
|
poh->getObject()->arrival_delay = 0;
|
|
return mission_maybe_make_ship_arrive(poh->getObject(), true) ? ADE_RETURN_TRUE : ADE_RETURN_FALSE;
|
|
}
|
|
|
|
ADE_VIRTVAR(CollisionGroups, l_ParseObject, "number", "Collision group data", "number", "Current set of collision groups. NOTE: This is a bitfield, NOT a normal number.")
|
|
{
|
|
parse_object_h* poh = nullptr;
|
|
int id = 0;
|
|
if (!ade_get_args(L, "o|i", l_ParseObject.GetPtr(&poh), &id))
|
|
return ade_set_error(L, "i", 0);
|
|
|
|
if (!poh->isValid())
|
|
return ade_set_error(L, "i", 0);
|
|
|
|
//Set collision group data
|
|
if (ADE_SETTING_VAR)
|
|
poh->getObject()->collision_group_id = id;
|
|
|
|
return ade_set_args(L, "i", poh->getObject()->collision_group_id);
|
|
}
|
|
|
|
ADE_FUNC(addToCollisionGroup, l_ParseObject, "number group", "Adds this parsed ship to the specified collision group. The group must be between 0 and 31, inclusive.", nullptr, "Returns nothing")
|
|
{
|
|
parse_object_h* poh = nullptr;
|
|
int group;
|
|
|
|
if (!ade_get_args(L, "oi", l_ParseObject.GetPtr(&poh), &group))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (!poh->isValid())
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (group >= 0 && group <= 31)
|
|
poh->getObject()->collision_group_id |= (1 << group);
|
|
else
|
|
Warning(LOCATION, "In addToCollisionGroup, group %d must be between 0 and 31, inclusive", group);
|
|
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
ADE_FUNC(removeFromCollisionGroup, l_ParseObject, "number group", "Removes this parsed ship from the specified collision group. The group must be between 0 and 31, inclusive.", nullptr, "Returns nothing")
|
|
{
|
|
parse_object_h* poh = nullptr;
|
|
int group;
|
|
|
|
if (!ade_get_args(L, "oi", l_ParseObject.GetPtr(&poh), &group))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (!poh->isValid())
|
|
return ADE_RETURN_NIL;
|
|
|
|
if (group >= 0 && group <= 31)
|
|
poh->getObject()->collision_group_id &= ~(1 << group);
|
|
else
|
|
Warning(LOCATION, "In removeFromCollisionGroup, group %d must be between 0 and 31, inclusive", group);
|
|
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
parse_subsys_h::parse_subsys_h() = default;
|
|
parse_subsys_h::parse_subsys_h(p_object* obj, int subsys_offset) : _obj(obj), _subsys_offset(subsys_offset) {}
|
|
subsys_status* parse_subsys_h::getSubsys() const { return &Subsys_status[_obj->subsys_index + _subsys_offset]; }
|
|
bool parse_subsys_h::isValid() const { return _obj != nullptr && _subsys_offset < _obj->subsys_count; }
|
|
|
|
void parse_subsys_h::serialize(lua_State* /*L*/, const scripting::ade_table_entry& /*tableEntry*/, const luacpp::LuaValue& value, ubyte* data, int& packet_size) {
|
|
parse_subsys_h pobj;
|
|
value.getValue(l_ParseSubsystem.Get(&pobj));
|
|
const ushort& netsig = pobj.isValid() ? pobj._obj->net_signature : 0;
|
|
ADD_USHORT(netsig);
|
|
ADD_INT(pobj._subsys_offset);
|
|
}
|
|
|
|
void parse_subsys_h::deserialize(lua_State* /*L*/, const scripting::ade_table_entry& /*tableEntry*/, char* data_ptr, ubyte* data, int& offset) {
|
|
ushort net_signature;
|
|
int ss;
|
|
GET_USHORT(net_signature);
|
|
GET_INT(ss);
|
|
new(data_ptr) parse_subsys_h(mission_parse_get_arrival_ship(net_signature), ss);
|
|
}
|
|
|
|
//**********HANDLE: parse_object
|
|
ADE_OBJ(l_ParseSubsystem, parse_subsys_h, "parse_subsystem", "Handle to a parse subsystem");
|
|
|
|
ADE_VIRTVAR(Name, l_ParseSubsystem, "string",
|
|
"The name of the subsystem. If possible, don't set the name but set the display name instead.", "string",
|
|
"The name or empty string on error")
|
|
{
|
|
parse_subsys_h* poh = nullptr;
|
|
const char* newName = nullptr;
|
|
if (!ade_get_args(L, "o|s", l_ParseSubsystem.GetPtr(&poh), &newName)) {
|
|
return ade_set_error(L, "s", "");
|
|
}
|
|
|
|
if (poh == nullptr) {
|
|
return ade_set_error(L, "s", "");
|
|
}
|
|
|
|
if (!poh->isValid()) {
|
|
return ade_set_error(L, "s", "");
|
|
}
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
strcpy_s(poh->getSubsys()->name, newName);
|
|
}
|
|
|
|
return ade_set_args(L, "s", poh->getSubsys()->name);
|
|
}
|
|
|
|
ADE_VIRTVAR(Damage, l_ParseSubsystem, "number", "The percentage to what the subsystem is damage", "number",
|
|
"The percentage or negative on error")
|
|
{
|
|
parse_subsys_h* poh = nullptr;
|
|
float newPercentage = -1.0f;
|
|
if (!ade_get_args(L, "o|f", l_ParseSubsystem.GetPtr(&poh), &newPercentage)) {
|
|
return ade_set_error(L, "f", -1.0f);
|
|
}
|
|
|
|
if (poh == nullptr) {
|
|
return ade_set_error(L, "f", -1.0f);
|
|
}
|
|
|
|
if (!poh->isValid()) {
|
|
return ade_set_error(L, "f", -1.0f);
|
|
}
|
|
|
|
if (ADE_SETTING_VAR && newPercentage >= 0.0f && newPercentage <= 100.0f) {
|
|
poh->getSubsys()->percent = newPercentage;
|
|
}
|
|
|
|
return ade_set_args(L, "f", poh->getSubsys()->percent);
|
|
}
|
|
|
|
ADE_VIRTVAR(PrimaryBanks, l_ParseSubsystem, nullptr, "The overridden primary banks", "weaponclass[]",
|
|
"The primary bank weapons or nil if not changed from default")
|
|
{
|
|
parse_subsys_h* poh = nullptr;
|
|
float newPercentage = -1.0f;
|
|
if (!ade_get_args(L, "o|f", l_ParseSubsystem.GetPtr(&poh), &newPercentage)) {
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
if (poh == nullptr) {
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
if (!poh->isValid()) {
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "This property is read only.");
|
|
}
|
|
|
|
if (poh->getSubsys()->primary_banks[0] == SUBSYS_STATUS_NO_CHANGE) {
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
luacpp::LuaTable tbl = luacpp::LuaTable::create(L);
|
|
auto po = poh->getSubsys();
|
|
for (int i = 0; i < MAX_SHIP_PRIMARY_BANKS; ++i) {
|
|
if (po->primary_banks[i] == -1) {
|
|
break;
|
|
}
|
|
tbl.addValue(i + 1, l_Weaponclass.Set(po->primary_banks[i]));
|
|
}
|
|
|
|
return ade_set_args(L, "t", tbl);
|
|
}
|
|
|
|
ADE_VIRTVAR(PrimaryAmmo, l_ParseSubsystem, nullptr, "The overridden primary ammunition, as a percentage of the default",
|
|
"weaponclass[]", "The primary bank ammunition percantage or nil if not changed from default")
|
|
{
|
|
parse_subsys_h* poh = nullptr;
|
|
float newPercentage = -1.0f;
|
|
if (!ade_get_args(L, "o|f", l_ParseSubsystem.GetPtr(&poh), &newPercentage)) {
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
if (poh == nullptr) {
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
if (!poh->isValid()) {
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "This property is read only.");
|
|
}
|
|
|
|
// Check the primary banks to see if changes were applied
|
|
if (poh->getSubsys()->primary_banks[0] == SUBSYS_STATUS_NO_CHANGE) {
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
luacpp::LuaTable tbl = luacpp::LuaTable::create(L);
|
|
auto po = poh->getSubsys();
|
|
for (int i = 0; i < MAX_SHIP_PRIMARY_BANKS; ++i) {
|
|
if (po->primary_banks[i] == -1) {
|
|
break;
|
|
}
|
|
tbl.addValue(i + 1, po->primary_ammo[i]);
|
|
}
|
|
|
|
return ade_set_args(L, "t", tbl);
|
|
}
|
|
|
|
ADE_VIRTVAR(SecondaryBanks, l_ParseSubsystem, nullptr, "The overridden secondary banks", "weaponclass[]",
|
|
"The secondary bank weapons or nil if not changed from default")
|
|
{
|
|
parse_subsys_h* poh = nullptr;
|
|
float newPercentage = -1.0f;
|
|
if (!ade_get_args(L, "o|f", l_ParseSubsystem.GetPtr(&poh), &newPercentage)) {
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
if (poh == nullptr) {
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
if (!poh->isValid()) {
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "This property is read only.");
|
|
}
|
|
|
|
if (poh->getSubsys()->secondary_banks[0] == SUBSYS_STATUS_NO_CHANGE) {
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
luacpp::LuaTable tbl = luacpp::LuaTable::create(L);
|
|
auto po = poh->getSubsys();
|
|
for (int i = 0; i < MAX_SHIP_SECONDARY_BANKS; ++i) {
|
|
if (po->secondary_banks[i] == -1) {
|
|
break;
|
|
}
|
|
tbl.addValue(i + 1, l_Weaponclass.Set(po->secondary_banks[i]));
|
|
}
|
|
|
|
return ade_set_args(L, "t", tbl);
|
|
}
|
|
|
|
ADE_VIRTVAR(SecondaryAmmo, l_ParseSubsystem, nullptr, "The overridden secondary ammunition, as a percentage of the default",
|
|
"weaponclass[]", "The secondary bank ammunition percantage or nil if not changed from default")
|
|
{
|
|
parse_subsys_h* poh = nullptr;
|
|
float newPercentage = -1.0f;
|
|
if (!ade_get_args(L, "o|f", l_ParseSubsystem.GetPtr(&poh), &newPercentage)) {
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
if (poh == nullptr) {
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
if (!poh->isValid()) {
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
if (ADE_SETTING_VAR) {
|
|
LuaError(L, "This property is read only.");
|
|
}
|
|
|
|
// Check the secondary banks to see if changes were applied
|
|
if (poh->getSubsys()->secondary_banks[0] == SUBSYS_STATUS_NO_CHANGE) {
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
luacpp::LuaTable tbl = luacpp::LuaTable::create(L);
|
|
auto po = poh->getSubsys();
|
|
for (int i = 0; i < MAX_SHIP_SECONDARY_BANKS; ++i) {
|
|
if (po->secondary_banks[i] == -1) {
|
|
break;
|
|
}
|
|
tbl.addValue(i + 1, po->secondary_ammo[i]);
|
|
}
|
|
|
|
return ade_set_args(L, "t", tbl);
|
|
}
|
|
|
|
} // namespace api
|
|
} // namespace scripting
|