External weapon model cleanup: consolidate duplicated logic, fix several longstanding bugs#7588
Open
Goober5000 wants to merge 6 commits into
Open
External weapon model cleanup: consolidate duplicated logic, fix several longstanding bugs#7588Goober5000 wants to merge 6 commits into
Goober5000 wants to merge 6 commits into
Conversation
Goober5000
force-pushed
the
cleanup/external_weapons
branch
3 times, most recently
from
July 9, 2026 02:16
7cdf52b to
24df058
Compare
weapons_page_in(), weapons_page_in_cheats(), and weapon_page_in() each duplicated the same ~60-line block for loading a weapon's models and graphics. Extract it into a weapon_page_in_one() helper; the cheats variant passes load_graphics = false to preserve its behavior of loading only model geometry. Also fix the tautological Assertion in the default render_type case: the old condition was always true inside that branch, so it could never fire. It now asserts render_type == WRT_NONE, which is the only other legitimate value (invisible weapons). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The logic for offsetting a shot by the external weapon model's firing points was duplicated in ship_fire_primary(), ship_fire_secondary(), and the AI's line-of-sight check. Extract it into ship_get_external_model_fp_offset(). This fixes two bugs that were present in all three copies: 1. The chain counter for "chain external model fps" weapons was reset when it reached weapon_model->n_guns (the number of gun banks) rather than the number of firing points in the bank being indexed. For the typical model with one gun bank the counter reset after every shot, so chaining never advanced past the first firing point; for a model with several gun banks the counter could index past the end of the first bank's point array. 2. The AI line-of-sight check advanced the chain counter even though it is only a query, desyncing the counter from the shots actually fired. It now reads the current firing point without advancing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…sition The per-slot placement math for rendered external weapon models (the angle-offset yaw plus the reload slide-back for missiles) was duplicated four times across ship_render_weapon_models() and HudGaugeHardpoints::render(). Extract it into ship_get_weapon_model_slot_transform() so that future changes (such as submodel-attached weapon banks) only need to touch one place. This fixes a bug in the hardpoints gauge: the launcher-style secondary branch computed the view-rotated world position but then rendered the model at the untransformed local point, misplacing launcher models in the rotated top/front views. Also: hoist per-bank invariants out of the slot loops, drop the redundant render_flags parameter of ship_render_weapon_models() (it always equaled the flags already set on the render params), remove long-dead commented-out code, and read the reload percentage once per slot. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The model instance used to spin Gun_rotation submodels (gatling barrels) was created lazily on first render, guarded by a once-per-bank bool that nothing ever reset. If a primary bank's weapon changed mid-mission (set-primary-weapon SEXP, scripting, rearm precedence swap, multiplayer sync), the old weapon's instance leaked until the ship was deleted and was silently discarded at render time by the model/instance mismatch guard, while the new weapon never got an instance, so its barrels never spun. Replace the bool with a record of which weapon the instance was created for, and move the logic into ship_get_external_weapon_model_instance(), which recreates the instance whenever the bank's weapon differs. This self-heals after every swap path without needing hooks in each of them. The HUD hardpoints gauge now goes through the same function instead of reading the possibly-stale instance array directly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The draw-distance cull for attached external weapon models checked MR_ATTACHED_MODEL, but nothing has set that flag since commit 1ef7688, so $Weapon Model Draw Distance: has been dead for years. The check also needed the ship resolved from the render params' object number, which is deliberately not set while weapon models render (setting it would make model_render_queue clobber the explicitly passed gatling model instance), and it compared against a depth computed as if the weapon model's ship-local position were in world space. Carry the distance in model_render_params instead (set_attached_model_draw_distance, negative = not an attached model), set by ship_render_weapon_models from the ship's tabled value. When set, model_render_queue measures depth from the eye position expressed in the parent's frame (model_draw_list::get_view_position), which is correct under the pushed parent transform, culls against the tabled distance, and uses that same corrected depth for detail level selection -- previously attached weapon models picked their LOD from a garbage depth (roughly the eye's distance from the world origin). MR_ATTACHED_MODEL is removed; nothing else referenced it. The unused flags are also removed and the remaining flags are consolidated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ship_render_weapon_models(), HudGaugeHardpoints::render(), and ship_stop_fire_primary_bank() indexed Weapon_info[] with the bank's weapon index without checking for an empty bank (-1). Banks within num_*_banks are normally populated, but other code that iterates banks treats them as possibly empty and guards accordingly (e.g. ship_do_cargo_hidden, ship_page_in), so these paths now do too. In the hardpoints gauge an empty primary bank still draws its firing point circles. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Goober5000
force-pushed
the
cleanup/external_weapons
branch
from
July 13, 2026 17:19
24df058 to
009529b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is a cleanup pass over the external weapon model code (
$Show Primary/Secondary Models:), consolidating duplicated logic and fixing the bugs that were hiding in the copies.Consolidations
weapons_page_in(),weapons_page_in_cheats(), andweapon_page_in()each duplicated the same ~60-line per-weapon block (model load, thruster flag, external model load, shockwaves, graphics paging). Extracted intoweapon_page_in_one(); the cheats variant passesload_graphics = falseto preserve its model-only behavior.ship_fire_primary(),ship_fire_secondary(), and the AI line-of-sight check. Now shared asship_get_external_model_fp_offset().ship_render_weapon_models()andHudGaugeHardpoints::render(). Now shared asship_get_weapon_model_slot_transform().Bug fixes
n_guns(the number of gun banks) instead of the number of firing points in bank 0. For the typical one-bank model the counter reset after every shot, so chaining never advanced; models with several banks could read past the end of the point array.set-primary-weapon, a script swap, or a rearm-precedence swap, the old weapon's instance leaked and the new weapon's barrels never spun. The instance is now keyed to the weapon it was created for and recreated on change (ship_get_external_weapon_model_instance()), which self-heals after every swap path.$Weapon Model Draw Distance:has been dead for years — nothing setMR_ATTACHED_MODELsince 1ef7688. The distance is now carried inmodel_render_paramsand enforced again. The old check also computed depth as if the weapon model's ship-local position were in world space; depth is now measured from the eye position in the parent's frame, which additionally fixes attached weapon models choosing their LOD from a garbage distance.MR_ATTACHED_MODELis removed (nothing else referenced it).external model launcherbranch computed the view-rotated position but rendered at the untransformed local point.defaultcase; it now assertsrender_type == WRT_NONE.ship_stop_fire_primary_bank()indexedWeapon_info[]without checking for an empty bank (-1), unlike other bank-iterating code.Notes for modders
$Weapon Model Draw Distance:(default 200) is enforced again, and attached weapon models now LOD correctly with distance — missions far from the world origin previously got worst-case LODs regardless of camera distance.🤖 Generated with Claude Code