Skip to content

Commit a76efe9

Browse files
committed
lua table prop support
1 parent 9622cda commit a76efe9

File tree

12 files changed

+793
-9
lines changed

12 files changed

+793
-9
lines changed

code/model/modelrender.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "mod_table/mod_table.h"
2626
#include "nebula/neb.h"
2727
#include "particle/particle.h"
28+
#include "prop/prop.h"
2829
#include "render/3dinternal.h"
2930
#include "render/batching.h"
3031
#include "ship/ship.h"
@@ -3135,6 +3136,22 @@ bool render_tech_model(tech_render_type model_type, int x1, int y1, int x2, int
31353136

31363137
break;
31373138

3139+
case TECH_PROP:
3140+
prop_info* pip;
3141+
pip = &Prop_info[class_idx];
3142+
3143+
closeup_pos = &pip->closeup_pos;
3144+
closeup_zoom = pip->closeup_zoom;
3145+
3146+
if (pip->flags[Prop::Info_Flags::No_lighting]) {
3147+
model_lighting = false;
3148+
}
3149+
3150+
// Make sure model is loaded
3151+
model_num = model_load(pip->pof_file);
3152+
3153+
break;
3154+
31383155
case TECH_WEAPON:
31393156
weapon_info* wip;
31403157
wip = &Weapon_info[class_idx];

code/model/modelrender.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ typedef enum {
3131
TECH_SHIP,
3232
TECH_WEAPON,
3333
TECH_POF,
34-
TECH_JUMP_NODE
34+
TECH_JUMP_NODE,
35+
TECH_PROP,
3536
} tech_render_type;
3637

3738
inline int in_box(const vec3d *min, const vec3d *max, const vec3d *pos, const vec3d *view_position)

code/parse/sexp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
class ship_subsys;
2121
class ship;
22+
class prop;
2223
class waypoint_list;
2324
class object;
2425
class waypoint;
@@ -1484,6 +1485,7 @@ struct wing;
14841485
// Goober5000 - stuff with caching
14851486
// (included in the header file because Lua uses the first three)
14861487
extern const ship_registry_entry *eval_ship(int node);
1488+
extern const prop* eval_prop(int node);
14871489
extern wing *eval_wing(int node);
14881490
extern int sexp_get_variable_index(int node);
14891491
extern int sexp_atoi(int node);

code/parse/sexp/LuaSEXP.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include "scripting/api/objs/message.h"
1818
#include "scripting/api/objs/model.h"
1919
#include "scripting/api/objs/oswpt.h"
20+
#include "scripting/api/objs/prop.h"
21+
#include "scripting/api/objs/propclass.h"
2022
#include "scripting/api/objs/sexpvar.h"
2123
#include "scripting/api/objs/ship.h"
2224
#include "scripting/api/objs/shipclass.h"
@@ -28,6 +30,7 @@
2830
#include "scripting/api/objs/wing.h"
2931
#include "scripting/scripting.h"
3032
#include "ship/ship.h"
33+
#include "prop/prop.h"
3134
#include "utils/string_utils.h"
3235
#include "weapon/weapon.h"
3336

@@ -41,13 +44,16 @@ static SCP_unordered_map<SCP_string, int> parameter_type_mapping {
4144
{ "string", OPF_STRING },
4245
{ "ship", OPF_SHIP },
4346
{ "shipname", OPF_SHIP },
47+
{ "prop", OPF_PROP },
48+
{ "propname", OPF_PROP },
4449
{ "team", OPF_IFF },
4550
{ "waypointpath", OPF_WAYPOINT_PATH },
4651
{ "waypoint", OPF_POINT },
4752
{ "variable", OPF_VARIABLE_NAME },
4853
{ "message", OPF_MESSAGE },
4954
{ "wing", OPF_WING },
5055
{ "shipclass", OPF_SHIP_CLASS_NAME },
56+
{ "propclass", OPF_PROP_CLASS_NAME },
5157
{ "weaponclass", OPF_WEAPON_NAME },
5258
{ "soundentry", OPF_GAME_SND },
5359
{ "ship+waypoint",OPF_SHIP_POINT },
@@ -199,6 +205,29 @@ luacpp::LuaValue LuaSEXP::sexpToLua(int node, int argnum, int parent_node) const
199205

200206
return LuaValue::createValue(_action.getLuaState(), l_Ship.Set(object_h(objp)));
201207
}
208+
case OPF_PROP: {
209+
auto ship_entry = eval_prop(node);
210+
211+
// if this is a shipname type, we want the name of a valid ship but not the ship itself
212+
// (if the ship is not valid, return an empty string)
213+
if (argtype.first == "propname") {
214+
return LuaValue::createValue(_action.getLuaState(), ship_entry ? ship_entry->prop_name : "");
215+
}
216+
217+
if (!ship_entry || (ship_entry->objnum >= 0)) {
218+
// Name is invalid
219+
return LuaValue::createValue(_action.getLuaState(), l_Prop.Set(object_h()));
220+
}
221+
222+
auto objp = &Objects[ship_entry->objnum];
223+
224+
// The other SEXP code does not validate the object type so this should be safe
225+
Assertion(objp->type == OBJ_PROP,
226+
"Prop '%s' was found in the Props array but has a different object type in the Objects array. Get a coder!",
227+
CTEXT(node));
228+
229+
return LuaValue::createValue(_action.getLuaState(), l_Prop.Set(object_h(objp)));
230+
}
202231
case OPF_MESSAGE: {
203232
auto name = CTEXT(node);
204233

@@ -224,6 +253,10 @@ luacpp::LuaValue LuaSEXP::sexpToLua(int node, int argnum, int parent_node) const
224253
auto name = CTEXT(node);
225254
return LuaValue::createValue(_action.getLuaState(), l_Shipclass.Set(ship_info_lookup(name)));
226255
}
256+
case OPF_PROP_CLASS_NAME: {
257+
auto name = CTEXT(node);
258+
return LuaValue::createValue(_action.getLuaState(), l_Propclass.Set(prop_info_lookup(name)));
259+
}
227260
case OPF_WEAPON_NAME: {
228261
auto name = CTEXT(node);
229262
return LuaValue::createValue(_action.getLuaState(), l_Weaponclass.Set(weapon_info_lookup(name)));

code/prop/prop.cpp

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
MONITOR(NumPropsRend)
1010

11+
bool Props_inited = false;
12+
1113
SCP_vector<prop_info> Prop_info;
1214

1315
SCP_vector<prop> Props;
@@ -142,9 +144,67 @@ void parse_prop_table(const char* filename)
142144
required_string("+POF file:");
143145
stuff_string(pip->pof_file, F_NAME, MAX_FILENAME_LEN);
144146

147+
if (optional_string("$Closeup_pos:")) {
148+
stuff_vec3d(&pip->closeup_pos);
149+
} else if (first_time && VALID_FNAME(pip->pof_file)) {
150+
// Calculate from the model file. This is inefficient, but whatever
151+
int model_idx = model_load(pip->pof_file);
152+
polymodel* pm = model_get(model_idx);
153+
154+
// Go through, find best
155+
pip->closeup_pos.xyz.z = fabsf(pm->maxs.xyz.z);
156+
157+
float temp = fabsf(pm->mins.xyz.z);
158+
if (temp > pip->closeup_pos.xyz.z)
159+
pip->closeup_pos.xyz.z = temp;
160+
161+
// Now multiply by 2
162+
pip->closeup_pos.xyz.z *= -2.0f;
163+
164+
// We're done with the model.
165+
model_unload(model_idx);
166+
}
167+
168+
if (optional_string("$Closeup_zoom:")) {
169+
stuff_float(&pip->closeup_zoom);
170+
171+
if (pip->closeup_zoom <= 0.0f) {
172+
mprintf(("Warning! Prop '%s' has a $Closeup_zoom value that is less than or equal to 0 (%f). Setting "
173+
"to default value.\n",
174+
pip->name,
175+
pip->closeup_zoom));
176+
pip->closeup_zoom = 0.5f;
177+
}
178+
}
179+
145180
if(optional_string("$Detail distance:")) {
146181
pip->num_detail_levels = (int)stuff_int_list(pip->detail_distance, MAX_PROP_DETAIL_LEVELS, RAW_INTEGER_TYPE);
147182
}
183+
184+
if (optional_string("$Custom data:")) {
185+
parse_string_map(pip->custom_data, "$end_custom_data", "+Val:");
186+
}
187+
188+
if (optional_string("$Custom Strings")) {
189+
while (optional_string("$Name:")) {
190+
custom_string cs;
191+
192+
// The name of the string
193+
stuff_string(cs.name, F_NAME);
194+
195+
// Arbitrary string value used for grouping strings together
196+
required_string("+Value:");
197+
stuff_string(cs.value, F_NAME);
198+
199+
// The string text itself
200+
required_string("+String:");
201+
stuff_string(cs.text, F_MULTITEXT);
202+
203+
pip->custom_strings.push_back(cs);
204+
}
205+
206+
required_string("$end_custom_strings");
207+
}
148208
}
149209

150210
required_string("#END");
@@ -160,6 +220,8 @@ void prop_init()
160220

161221
// parse any modular tables
162222
parse_modular_table("*-prp.tbm", parse_prop_table);
223+
224+
Props_inited = true;
163225
}
164226

165227
/**
@@ -327,6 +389,125 @@ void prop_delete(object* obj)
327389
Props.erase(Props.begin() + num);
328390
}
329391

392+
/**
393+
* Change the prop model for a prop to that for prop class 'prop_type'
394+
*
395+
* @param n index of prop in ::Props[] array
396+
* @param prop_type prop class (index into ::Prop_info vector)
397+
*/
398+
static void prop_model_change(int n, int prop_type)
399+
{
400+
Assert( n >= 0 && n < MAX_PROPS );
401+
prop* sp = &Props[n];
402+
prop_info* sip = &(Prop_info[prop_type]);
403+
object* objp = &Objects[sp->objnum];
404+
polymodel_instance* pmi = model_get_instance(sp->model_instance_num);
405+
406+
// get new model
407+
if (sip->model_num == -1) {
408+
sip->model_num = model_load(sip->pof_file);
409+
}
410+
411+
polymodel* pm = model_get(sip->model_num);
412+
Objects[sp->objnum].radius = model_get_radius(pm->id);
413+
414+
// page in nondims in game
415+
if ( !Fred_running )
416+
model_page_in_textures(sip->model_num, prop_type);
417+
418+
// allocate memory for keeping glow point bank status (enabled/disabled)
419+
{
420+
bool val = true; // default value, enabled
421+
422+
// clear out any old gpb's first, then add new ones if needed
423+
sp->glow_point_bank_active.clear();
424+
425+
if (pm->n_glow_point_banks)
426+
sp->glow_point_bank_active.resize( pm->n_glow_point_banks, val );
427+
428+
// set any default off banks to off
429+
for (int bank = 0; bank < pm->n_glow_point_banks; bank++) {
430+
glow_point_bank_override* gpo = nullptr;
431+
432+
SCP_unordered_map<int, void*>::iterator gpoi = sip->glowpoint_bank_override_map.find(bank);
433+
if (gpoi != sip->glowpoint_bank_override_map.end()) {
434+
gpo = (glow_point_bank_override*)sip->glowpoint_bank_override_map[bank];
435+
}
436+
437+
if (gpo) {
438+
if (gpo->default_off) {
439+
sp->glow_point_bank_active[bank] = false;
440+
}
441+
}
442+
}
443+
}
444+
445+
if ( sip->num_detail_levels != pm->n_detail_levels )
446+
{
447+
if ( !Is_standalone )
448+
{
449+
// just log to file for standalone servers
450+
Warning(LOCATION, "For prop '%s', detail level\nmismatch. Table has %d,\nPOF has %d.", sip->name, sip->num_detail_levels, pm->n_detail_levels );
451+
}
452+
else
453+
{
454+
nprintf(("Warning", "For prop '%s', detail level mismatch. Table has %d, POF has %d.", sip->name, sip->num_detail_levels, pm->n_detail_levels ));
455+
}
456+
}
457+
for (int i=0; i<pm->n_detail_levels; i++ )
458+
pm->detail_depth[i] = (i < sip->num_detail_levels) ? i2fl(sip->detail_distance[i]) : 0.0f;
459+
460+
// reset texture animations
461+
//sp->base_texture_anim_timestamp = _timestamp();
462+
463+
model_delete_instance(sp->model_instance_num);
464+
465+
// create new model instance data
466+
// note: this is needed for both subsystem stuff and submodel animation stuff
467+
sp->model_instance_num = model_create_instance(OBJ_INDEX(objp), sip->model_num);
468+
pmi = model_get_instance(sp->model_instance_num);
469+
}
470+
471+
/**
472+
* Change the prop class on a prop, and changing all required information
473+
* for consistency
474+
*
475+
* @param n index of prop in ::Props[] array
476+
* @param prop_type prop class (index into ::Prop_info vector)
477+
* @param by_sexp SEXP reference
478+
*/
479+
void change_prop_type(int n, int prop_type)
480+
{
481+
Assert( n >= 0 && n < MAX_PROPS );
482+
prop* sp = &Props[n];
483+
484+
// do a quick out if we're already using the new ship class
485+
if (sp->prop_info_index == prop_type)
486+
return;
487+
488+
int objnum = sp->objnum;
489+
//auto prop_entry = ship_registry_get(sp->prop_name);
490+
491+
prop_info* sip = &(Prop_info[prop_type]);
492+
prop_info* sip_orig = &Prop_info[sp->prop_info_index];
493+
object* objp = &Objects[objnum];
494+
495+
// point to new ship data
496+
prop_model_change(n, prop_type);
497+
sp->prop_info_index = prop_type;
498+
499+
// get the before and after models (the new model may have only been loaded in ship_model_change)
500+
auto pm = model_get(sip->model_num);
501+
auto pm_orig = model_get(sip_orig->model_num);
502+
503+
// check class-specific flags
504+
505+
if (sip->flags[Prop::Info_Flags::No_collide]) // changing TO a no-collision ship class
506+
obj_set_flags(objp, objp->flags - Object::Object_Flags::Collides);
507+
else if (sip_orig->flags[Prop::Info_Flags::No_collide]) // changing FROM a no-collision ship class
508+
obj_set_flags(objp, objp->flags + Object::Object_Flags::Collides);
509+
}
510+
330511
void prop_render(object* obj, model_draw_list* scene)
331512
{
332513
int num = obj->instance;

code/prop/prop.h

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,17 @@
1010
#define MAX_PROP_DETAIL_LEVELS MAX_SHIP_DETAIL_LEVELS
1111

1212
typedef struct prop_info {
13-
char name[NAME_LENGTH]; // Prop name
14-
char pof_file[MAX_FILENAME_LEN]; // Pof filename
15-
int model_num; // The model number of the loaded POF
16-
//int model_instance; // The model instance
17-
int num_detail_levels; // Detail levels of the model
18-
int detail_distance[MAX_PROP_DETAIL_LEVELS]; // distance to change detail levels at
19-
SCP_unordered_map<int, void*> glowpoint_bank_override_map;
20-
flagset<Prop::Info_Flags> flags; // Info flags
13+
char name[NAME_LENGTH]; // Prop name
14+
char pof_file[MAX_FILENAME_LEN]; // Pof filename
15+
vec3d closeup_pos; // position for camera when using ship in closeup view (eg briefing and techroom)
16+
float closeup_zoom; // zoom when using ship in closeup view (eg briefing and techroom)
17+
int model_num; // The model number of the loaded POF
18+
int num_detail_levels; // Detail levels of the model
19+
int detail_distance[MAX_PROP_DETAIL_LEVELS]; // distance to change detail levels at
20+
SCP_unordered_map<int, void*> glowpoint_bank_override_map; // Glow point bank overrides currently unused
21+
flagset<Prop::Info_Flags> flags; // Info flags
22+
SCP_map<SCP_string, SCP_string> custom_data; // Custom data for this prop
23+
SCP_vector<custom_string> custom_strings; // Custom strings for this prop
2124
} prop_info;
2225

2326
typedef struct prop {
@@ -41,11 +44,18 @@ typedef struct parsed_prop {
4144
flagset<Mission::Parse_Object_Flags> flags;
4245
} parsed_prop;
4346

47+
extern bool Props_inited;
48+
4449
// Global prop info array
4550
extern SCP_vector<prop_info> Prop_info;
4651

4752
extern SCP_vector<prop> Props;
4853

54+
inline int prop_info_size()
55+
{
56+
return static_cast<int>(Prop_info.size());
57+
}
58+
4959
// Load all props from table
5060
void prop_init();
5161

@@ -59,4 +69,6 @@ void props_level_close();
5969
int prop_info_lookup(const char* token);
6070
int prop_name_lookup(const char* name);
6171

72+
void change_prop_type(int n, int prop_type);
73+
6274
void spawn_test_prop();

0 commit comments

Comments
 (0)