diff --git a/gamedata/configs/2_guide_on_adding_to_new_anim_sets.ltx b/gamedata/configs/2_guide_on_adding_to_new_anim_sets.ltx index bf5e11a..5838048 100644 --- a/gamedata/configs/2_guide_on_adding_to_new_anim_sets.ltx +++ b/gamedata/configs/2_guide_on_adding_to_new_anim_sets.ltx @@ -22,4 +22,28 @@ And thats it! it should be working once you relaunch the game ADDING NEW MAGAZINE MODELs: preferably, you should try to align the mag models and their bones so they all line up Then add the sections and models associated to the "scripted_magazines.script"'s "mag_models" table -Thats it ! But remember to actually make them appear you need to do the above \ No newline at end of file +Thats it ! But remember to actually make them appear you need to do the above +PER-MAG COORDINATES (optional, backward compatible): +By default every mag on a gun uses the same shared offset (s_magazine_positions_[BONE], etc). +If a particular mag model has a different pivot / size and needs its own offset, add a key +suffixed with that magazine's SECTION name: + s_magazine_positions_[BONE]_[MAG_SECTION] = x,y,z + s_magazine_rotations_[BONE]_[MAG_SECTION] = x,y,z + s_magazine_scale_[BONE]_[MAG_SECTION] = float + s_magazine_parent_bone_[BONE]_[MAG_SECTION] = [bone] +[MAG_SECTION] is the loaded magazine item section, e.g. mag_ak_5.45x39_extended. +Resolution per field: if the suffixed key exists it is used, otherwise the script falls back +to the shared s_magazine_..._[BONE] key. So guns that only define the shared keys keep working +exactly as before - the shared coords are applied to every mag on that gun. + +Example (bone "magazin", standard mag uses shared coords, the longer 45-round mag overrides): + ![wpn_ak74] + s_magazine_hide_bones = magazin + s_magazine_parent_bone_magazin = magazin + ; shared / fallback (used by the standard mag and any unlisted mag): + s_magazine_positions_magazin = 0,0,0 + s_magazine_rotations_magazin = 0,0,0 + s_magazine_scale_magazin = 1 + ; per-mag override for the extended mag only: + s_magazine_positions_magazin_mag_ak_5.45x39_extended = 0,-0.01,0 + s_magazine_scale_magazin_mag_ak_5.45x39_extended = 1 diff --git a/gamedata/scripts/scripted_magazines.script b/gamedata/scripts/scripted_magazines.script index 8825b9d..12eea28 100644 --- a/gamedata/scripts/scripted_magazines.script +++ b/gamedata/scripts/scripted_magazines.script @@ -209,7 +209,11 @@ function change_specific_mag_model(configs) -- this function returns an id local parent_bone = string.sub(name, 10) if parent_bone == bone_to_switch then - attachment:set_model(model_path, false) + -- only swap the model when it actually changed (see update_scripted_magazines): + -- re-setting a live attachment's model resets its transform for a frame + if attachment:get_model() ~= model_path then + attachment:set_model(model_path, false) + end -- bullet swapping behaviour local configs2 = {} @@ -219,7 +223,29 @@ function change_specific_mag_model(configs) add_bullets_to_magazines(obj, configs2) -- bullet swapping behaviour - local scale = ini_sys:r_float_ex(obj_sec, "s_magazine_scale_" .. parent_bone) or 1 + -- per-mag offsets (mirrors update_scripted_magazines): prefer the mag-suffixed + -- key so the swapped model lands on its FINAL position/rotation/scale immediately. + -- Without setting position/rotation here the model swaps but keeps the previous + -- mag's pose until the next idle refresh - visibly wrong mid-reload. + local swap_sec = configs2.section + local function swap_key(prefix) + local base = prefix .. parent_bone + if swap_sec and ini_sys:r_string_ex(obj_sec, base .. "_" .. swap_sec) then + return base .. "_" .. swap_sec + end + return base + end + + local positions = str_explode(ini_sys:r_string_ex(obj_sec, swap_key("s_magazine_positions_")) or "", ",") + for i,v in pairs(positions) do positions[i] = tonumber(v) end + + local rotations = str_explode(ini_sys:r_string_ex(obj_sec, swap_key("s_magazine_rotations_")) or "", ",") + for i,v in pairs(rotations) do rotations[i] = tonumber(v) end + + local scale = ini_sys:r_float_ex(obj_sec, swap_key("s_magazine_scale_")) or 1 + + attachment:set_position(positions[1], positions[2], positions[3]) + attachment:set_rotation(rotations[1], rotations[2], rotations[3]) attachment:set_scale(scale) end dbg("obj %s, bone_to_switch %s, model_path %s, name %s parent_bone %s", obj:name(), bone_to_switch, model_path, name, parent_bone) @@ -268,8 +294,12 @@ function update_scripted_magazines(obj, configs) attachment:set_scale(0) end end - if configs.hide_override then - -- basically hide_override is true if the gun is doing an animation that ISNT reload. So if the gun is reloading we wont hide the magazine bone + -- basically hide_override is true if the gun is doing an animation that ISNT reload. So if the gun is reloading we wont hide the magazine bone + -- ...and not while a Mags Reloaded reload is still in progress: at reload end the + -- idle anim can trigger this refresh BEFORE the new mag data commits (same frame), + -- and scaling the attachment to 0 in that window hides the freshly inserted mag + -- until the next anim change (movement) + if configs.hide_override and not (magazines.action_in_progress and magazines.action_in_progress()) then obj:iterate_attachments(iterator) end @@ -299,6 +329,23 @@ function update_scripted_magazines(obj, configs) -- iterates through each mag bone, not really necessary i just thought it would be useful when i first made it configs.skip_bone_name = configs.skip_bone_name or {} + + -- PER-MAG OFFSETS (backward compatible): for each offset field, prefer a key suffixed + -- with the magazine's section ("s_magazine___") and fall back + -- to the shared per-bone key ("s_magazine__"). Guns that only define the + -- shared keys are unaffected. The loaded mag is authoritative; during the mid-reload + -- swap it is still nil/old, so we fall back to the incoming/pending section dev already + -- captures, so the model lands on its final coords immediately instead of jumping. + local loaded_mag = get_mag_loaded(obj:id()) + local mag_section = (loaded_mag and loaded_mag.section) or incoming_mag_section or pending_swap_mag_section + local function mag_key(prefix, name) + local base = prefix .. name + if mag_section and ini_sys:r_string_ex(obj_section, base .. "_" .. mag_section) then + return base .. "_" .. mag_section + end + return base + end + for i,name in pairs(mag_bone_names) do if configs.skip_bone_name[name] then goto continue end @@ -314,28 +361,33 @@ function update_scripted_magazines(obj, configs) -- add_attachment can fail if not s_magazine then goto continue end - - s_magazine:set_model(magazine_model_path, false) + + -- only swap the model when it actually changed: set_model on a live attachment + -- resets its transform until the setters below re-apply, rendering one frame at + -- the default pose + if s_magazine:get_model() ~= magazine_model_path then + s_magazine:set_model(magazine_model_path, false) + end -- finds positions - local positions = ini_sys:r_string_ex(obj_section, "s_magazine_positions_" .. name) or "" + local positions = ini_sys:r_string_ex(obj_section, mag_key("s_magazine_positions_", name)) or "" positions = str_explode(positions, ",") for i,v in pairs(positions) do positions[i] = tonumber(v) end - + -- finds rotations - local rotations = ini_sys:r_string_ex(obj_section, "s_magazine_rotations_" .. name) or "" + local rotations = ini_sys:r_string_ex(obj_section, mag_key("s_magazine_rotations_", name)) or "" rotations = str_explode(rotations, ",") for i,v in pairs(rotations) do rotations[i] = tonumber(v) end - + -- finds scale - local scale = ini_sys:r_float_ex(obj_section, "s_magazine_scale_" .. name) or 1 - + local scale = ini_sys:r_float_ex(obj_section, mag_key("s_magazine_scale_", name)) or 1 + -- finds parent bone - local parent_bone = ini_sys:r_string_ex(obj_section, "s_magazine_parent_bone_" .. name) or "wpn_body" + local parent_bone = ini_sys:r_string_ex(obj_section, mag_key("s_magazine_parent_bone_", name)) or "wpn_body" -- sets everything necessary s_magazine:set_type(script_attachment_type.Hud)