88
99MONITOR (NumPropsRend)
1010
11+ bool Props_inited = false;
12+
1113SCP_vector<prop_info> Prop_info;
1214
1315SCP_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\n mismatch. Table has %d,\n POF 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+
330511void prop_render (object* obj, model_draw_list* scene)
331512{
332513 int num = obj->instance ;
0 commit comments