diff --git a/code/model/modelrender.cpp b/code/model/modelrender.cpp index 842c86d135e..2b0b6aec4df 100644 --- a/code/model/modelrender.cpp +++ b/code/model/modelrender.cpp @@ -3106,7 +3106,7 @@ void modelinstance_replace_active_texture(polymodel_instance* pmi, const char* o // renders a model as if in the tech room or briefing UI // model_type 1 for ship class, 2 for weapon class, 3 for pof -bool render_tech_model(tech_render_type model_type, int x1, int y1, int x2, int y2, float zoom, bool lighting, int class_idx, const matrix* orient, const SCP_string &pof_filename, float close_zoom, const vec3d *close_pos, const SCP_string& tcolor) +bool render_tech_model(tech_render_type model_type, int x1, int y1, int x2, int y2, float zoom, bool lighting, int class_idx, const matrix* orient, const SCP_string &pof_filename, float close_zoom, const vec3d *close_pos, const SCP_string& tcolor, const SCP_vector& destroyed_subsystems) { model_render_params render_info; @@ -3204,8 +3204,34 @@ bool render_tech_model(tech_render_type model_type, int x1, int y1, int x2, int // Create an instance for ships that can be used to clear out destroyed subobjects from rendering if (model_type == TECH_SHIP) { + auto sip = &Ship_info[class_idx]; + auto pm = model_get(model_num); model_instance = model_create_instance(model_objnum_special::OBJNUM_NONE, model_num); model_set_up_techroom_instance(&Ship_info[class_idx], model_instance); + model_set_up_techroom_instance(sip, model_instance); + + if (!destroyed_subsystems.empty()) { + auto pmi = model_get_instance(model_instance); + flagset empty; + + for (int idx = 0; idx < sip->n_subsystems; ++idx) { + auto& subsystem = sip->subsystems[idx]; + + if (subsystem.subobj_num < 0 || subsystem.subobj_num >= pm->n_models || + subsystem.model_num != model_num) { + continue; + } + + for (auto& destroyed_name : destroyed_subsystems) { + if (!stricmp(subsystem.subobj_name, destroyed_name.c_str()) || + !stricmp(subsystem.name, destroyed_name.c_str())) { + pmi->submodel[subsystem.subobj_num].blown_off = true; + model_replicate_submodel_instance(pm, pmi, subsystem.subobj_num, empty); + break; + } + } + } + } } render_info.set_detail_level_lock(0); diff --git a/code/model/modelrender.h b/code/model/modelrender.h index 6914074bfe4..be61057feb1 100644 --- a/code/model/modelrender.h +++ b/code/model/modelrender.h @@ -316,7 +316,7 @@ bool model_render_check_detail_box(const vec3d* view_pos, const polymodel* pm, i void model_render_arc(const vec3d* v1, const vec3d* v2, const SCP_vector *persistent_arc_points, const color* primary, const color* secondary, float arc_width, ubyte depth_limit); void model_render_insignias(const insignia_draw_data* insignia); void model_render_set_wireframe_color(const color* clr); -bool render_tech_model(tech_render_type model_type, int x1, int y1, int x2, int y2, float zoom, bool lighting, int class_idx, const matrix* orient, const SCP_string& pof_filename = "", float closeup_zoom = 0, const vec3d* closeup_pos = &vmd_zero_vector, const SCP_string& tcolor = ""); +bool render_tech_model(tech_render_type model_type, int x1, int y1, int x2, int y2, float zoom, bool lighting, int class_idx, const matrix* orient, const SCP_string& pof_filename = "", float closeup_zoom = 0, const vec3d* closeup_pos = &vmd_zero_vector, const SCP_string& tcolor = "", const SCP_vector& destroyed_subsystems = SCP_vector()); float convert_distance_and_diameter_to_pixel_size(float distance, float diameter, float field_of_view, int screen_width); diff --git a/code/scripting/api/objs/shipclass.cpp b/code/scripting/api/objs/shipclass.cpp index 38df49ddd34..79dd940139d 100644 --- a/code/scripting/api/objs/shipclass.cpp +++ b/code/scripting/api/objs/shipclass.cpp @@ -18,6 +18,7 @@ #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" @@ -1114,7 +1115,7 @@ ADE_FUNC(isInTechroom, l_Shipclass, NULL, "Gets whether or not the ship class is 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]", + "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") @@ -1125,7 +1126,8 @@ ADE_FUNC(renderTechModel, float zoom = 1.3f; bool lighting = true; int tc_idx = -1; - if(!ade_get_args(L, "oiiii|ffffbo", l_Shipclass.Get(&idx), &x1, &y1, &x2, &y2, &rot_angles.h, &rot_angles.p, &rot_angles.b, &zoom, &lighting, l_TeamColor.Get(&tc_idx))) + 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()) @@ -1158,18 +1160,35 @@ ADE_FUNC(renderTechModel, } } - return ade_set_args(L, "b", render_tech_model(TECH_SHIP, x1, y1, x2, y2, zoom, lighting, idx, &orient, tcolor)); + SCP_vector 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()); + } 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, &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]", "Draws ship model as if in techroom", "boolean", "Whether ship was rendered") +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; - if(!ade_get_args(L, "oiiiio|fo", l_Shipclass.Get(&idx), &x1, &y1, &x2, &y2, l_Matrix.GetPtr(&mh), &zoom, l_TeamColor.Get(&tc_idx))) + 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()) @@ -1191,7 +1210,23 @@ ADE_FUNC(renderTechModel2, l_Shipclass, "number X1, number Y1, number X2, number } } - return ade_set_args(L, "b", render_tech_model(TECH_SHIP, x1, y1, x2, y2, zoom, true, idx, orient, tcolor)); + SCP_vector 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()); + } 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,