Skip to content

Commit 1b75fea

Browse files
committed
subsystem scripting enhancements
Add several API features to improve scripting support for subsystems. 1. A `CanonicalName` virtvar to provide a clear way to get subsystem names for indexing and referencing 2. `Submodel` and `SubmodelInstance` virtvars to get the submodel information associated with the subsystem, if it exists 3. A `getSubsystemList()` function to provide a subsystem iterator
1 parent dbe0af1 commit 1b75fea

5 files changed

Lines changed: 116 additions & 2 deletions

File tree

code/scripting/api/objs/model.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,34 @@ bool submodel_h::isValid() const
6363
}
6464

6565

66+
ADE_FUNC(__eq, l_Model, "model, model", "Checks if two model handles refer to the same model", "boolean", "True if models are equal")
67+
{
68+
model_h* mdl1;
69+
model_h* mdl2;
70+
71+
if (!ade_get_args(L, "oo", l_Model.GetPtr(&mdl1), l_Model.GetPtr(&mdl2)))
72+
return ADE_RETURN_NIL;
73+
74+
if (mdl1->GetID() == mdl2->GetID())
75+
return ADE_RETURN_TRUE;
76+
77+
return ADE_RETURN_FALSE;
78+
}
79+
80+
ADE_FUNC(__eq, l_Submodel, "submodel, submodel", "Checks if two submodel handles refer to the same submodel", "boolean", "True if submodels are equal")
81+
{
82+
submodel_h* smh1;
83+
submodel_h* smh2;
84+
85+
if (!ade_get_args(L, "oo", l_Submodel.GetPtr(&smh1), l_Submodel.GetPtr(&smh2)))
86+
return ADE_RETURN_NIL;
87+
88+
if (smh1->GetModelID() == smh2->GetModelID() && smh1->GetSubmodelIndex() == smh2->GetSubmodelIndex())
89+
return ADE_RETURN_TRUE;
90+
91+
return ADE_RETURN_FALSE;
92+
}
93+
6694
ADE_VIRTVAR(Submodels, l_Model, nullptr, "Model submodels", "submodels", "Model submodels, or an invalid submodels handle if the model handle is invalid")
6795
{
6896
model_h *mdl = nullptr;

code/scripting/api/objs/ship.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,36 @@ ADE_FUNC(__len, l_Ship, NULL, "Number of subsystems on ship", "number", "Subsyst
9494
return ade_set_args(L, "i", ship_get_num_subsys(&Ships[objh->objp()->instance]));
9595
}
9696

97+
ADE_FUNC(getSubsystemList,
98+
l_Ship,
99+
nullptr,
100+
"Get the list of subsystems on this ship",
101+
"iterator<subsystem>",
102+
"An iterator across all subsystems on the ship. Can be used in a for .. in loop. Is not valid for more than one frame.")
103+
{
104+
object_h* objh;
105+
if (!ade_get_args(L, "o", l_Ship.GetPtr(&objh)))
106+
return ADE_RETURN_NIL;
107+
108+
if (!objh->isValid())
109+
return ADE_RETURN_NIL;
110+
111+
ship* shipp = &Ships[objh->objp()->instance];
112+
ship_subsys* ss = &shipp->subsys_list;
113+
114+
return ade_set_args(L, "u", luacpp::LuaFunction::createFromStdFunction(L, [shipp, ss](lua_State* LInner, const luacpp::LuaValueList& /*params*/) mutable -> luacpp::LuaValueList {
115+
//Since the first element of a list is the next element from the head, and we start this function with the captured "ss" object being the head, this GET_NEXT will return the first element on first call of this lambda.
116+
//Similarly, an empty list is defined by the head's next element being itself, hence an empty list will immediately return nil just fine
117+
ss = GET_NEXT(ss);
118+
119+
if (ss == END_OF_LIST(&shipp->subsys_list) || ss == nullptr) {
120+
return luacpp::LuaValueList{ luacpp::LuaValue::createNil(LInner) };
121+
}
122+
123+
return luacpp::LuaValueList{ luacpp::LuaValue::createValue(LInner, l_Subsystem.Set(ship_subsys_h(&Objects[shipp->objnum], ss))) };
124+
}));
125+
}
126+
97127
ADE_FUNC(setFlag, l_Ship, "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")
98128
{
99129
object_h *objh;

code/scripting/api/objs/subsystem.cpp

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
//
33

44
#include "subsystem.h"
5+
#include "model.h"
56
#include "model_path.h"
67
#include "object.h"
78
#include "ship.h"
89
#include "ship_bank.h"
910
#include "vecmath.h"
1011
#include "hud/hudtarget.h"
1112
#include "ship/shiphit.h"
13+
#include "modelinstance.h"
1214

1315
#include "network/multi.h"
1416
#include "network/multimsgs.h"
@@ -121,6 +123,38 @@ ADE_VIRTVAR(AWACSRadius, l_Subsystem, "number", "Subsystem AWACS radius", "numbe
121123
return ade_set_args(L, "f", sso->ss->awacs_radius);
122124
}
123125

126+
ADE_VIRTVAR(Submodel, l_Subsystem, "submodel", "The submodel corresponding to this subsystem, if one exists", "submodel", "Submodel handle, or invalid submodel handle if this subsystem does not have a submodel, or if the subsystem handle is invalid")
127+
{
128+
ship_subsys_h *sso;
129+
if (!ade_get_args(L, "o", l_Subsystem.GetPtr(&sso)))
130+
return ade_set_error(L, "o", l_Submodel.Set(submodel_h()));
131+
132+
if (!sso->isValid())
133+
return ade_set_error(L, "o", l_Submodel.Set(submodel_h()));
134+
135+
if (ADE_SETTING_VAR)
136+
LuaError(L, "Setting the Submodel is not allowed!");
137+
138+
return ade_set_args(L, "o", l_Submodel.Set(submodel_h(sso->ss->system_info->model_num, sso->ss->system_info->subobj_num)));
139+
}
140+
141+
ADE_VIRTVAR(SubmodelInstance, l_Subsystem, "submodel_instance", "The submodel instance corresponding to this subsystem, if one exists", "submodel_instance", "Submodel instance handle, or invalid submodel instance handle if this subsystem does not have a submodel instance, or if the subsystem handle is invalid")
142+
{
143+
ship_subsys_h *sso;
144+
if (!ade_get_args(L, "o", l_Subsystem.GetPtr(&sso)))
145+
return ade_set_error(L, "o", l_SubmodelInstance.Set(submodelinstance_h()));
146+
147+
if (!sso->isValid())
148+
return ade_set_error(L, "o", l_SubmodelInstance.Set(submodelinstance_h()));
149+
150+
if (ADE_SETTING_VAR)
151+
LuaError(L, "Setting the SubmodelInstance is not allowed!");
152+
153+
auto shipp = &Ships[sso->objh.objp()->instance];
154+
auto pmi = model_get_instance(shipp->model_instance_num);
155+
return ade_set_args(L, "o", l_SubmodelInstance.Set(submodelinstance_h(pmi, sso->ss->system_info->subobj_num)));
156+
}
157+
124158
ADE_VIRTVAR(Orientation, l_Subsystem, "orientation", "Orientation of subobject or turret base", "orientation", "Subsystem orientation, or identity orientation if handle is invalid")
125159
{
126160
ship_subsys_h *sso;
@@ -345,6 +379,22 @@ ADE_VIRTVAR(NameOnHUD, l_Subsystem, "string", "Subsystem name as it would be dis
345379
return ade_set_args(L, "s", ship_subsys_get_name_on_hud(sso->ss));
346380
}
347381

382+
ADE_VIRTVAR(CanonicalName, l_Subsystem, "string", "Canonical subsystem name that can be used to reference this subsystem in a SEXP or script", "string", "Canonical subsystem name, or an empty string if handle is invalid")
383+
{
384+
ship_subsys_h *sso;
385+
386+
if (!ade_get_args(L, "o", l_Subsystem.GetPtr(&sso)))
387+
return ade_set_error(L, "s", "");
388+
389+
if (!sso->isValid())
390+
return ade_set_error(L, "s", "");
391+
392+
if (ADE_SETTING_VAR)
393+
LuaError(L, "Setting the CanonicalName is not allowed!");
394+
395+
return ade_set_args(L, "s", ship_subsys_get_canonical_name(sso->ss));
396+
}
397+
348398
ADE_VIRTVAR(NumFirePoints, l_Subsystem, "number", "Number of firepoints", "number", "Number of fire points, or 0 if handle is invalid")
349399
{
350400
ship_subsys_h* sso;
@@ -384,7 +434,7 @@ ADE_VIRTVAR(FireRateMultiplier, l_Subsystem, "number", "Factor by which turret's
384434
return ade_set_args(L, "f", sso->ss->rof_scaler);
385435
}
386436

387-
ADE_FUNC(getModelName, l_Subsystem, NULL, "Returns the original name of the subsystem in the model file", "string", "name or empty string on error")
437+
ADE_FUNC(getModelName, l_Subsystem, nullptr, "Returns the original name of the subsystem as defined in the ship class, which could possibly correspond to a submodel in the model file. This is the same as CanonicalName.", "string", "name or empty string on error")
388438
{
389439
ship_subsys_h *sso;
390440
if(!ade_get_args(L, "o", l_Subsystem.GetPtr(&sso)))
@@ -393,7 +443,7 @@ ADE_FUNC(getModelName, l_Subsystem, NULL, "Returns the original name of the subs
393443
if (!sso->isValid())
394444
return ade_set_error(L, "s", "");
395445

396-
return ade_set_args(L, "s", sso->ss->system_info->subobj_name);
446+
return ade_set_args(L, "s", ship_subsys_get_canonical_name(sso->ss));
397447
}
398448

399449
ADE_VIRTVAR(PrimaryBanks, l_Subsystem, "weaponbanktype", "Array of primary weapon banks", "weaponbanktype", "Primary banks, or invalid weaponbanktype handle if subsystem handle is invalid")

code/ship/ship.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17189,6 +17189,11 @@ const char *ship_subsys_get_name_on_hud(const ship_subsys *ss)
1718917189
return ship_subsys_get_name(ss);
1719017190
}
1719117191

17192+
const char *ship_subsys_get_canonical_name(const ship_subsys *ss)
17193+
{
17194+
return ss->system_info->subobj_name;
17195+
}
17196+
1719217197
/**
1719317198
* Return the shield strength of the specified quadrant on hit_objp
1719417199
*

code/ship/ship.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1803,6 +1803,7 @@ bool ship_subsys_has_instance_name(const ship_subsys *ss);
18031803
void ship_subsys_set_name(ship_subsys* ss, const char* n_name);
18041804

18051805
const char *ship_subsys_get_name_on_hud(const ship_subsys *ss);
1806+
const char *ship_subsys_get_canonical_name(const ship_subsys *ss);
18061807

18071808
// subsys disruption
18081809
extern int ship_subsys_disrupted(const ship_subsys *ss);

0 commit comments

Comments
 (0)