------------------------------- mcm stuff -------------------------------------- local weapon_sway_enable = weapon_sway_mcm.get_config("weapon_sway_feature") local aim_anm = weapon_sway_mcm.get_config("animation_type") local max_effect_power = weapon_sway_mcm.get_config("max_effect_power") local sway_keybind = weapon_sway_mcm.get_config("sway_keybind") local power_stand = weapon_sway_mcm.get_config("power_stand") local power_crouch = weapon_sway_mcm.get_config("power_crouch") local power_low_crouch = weapon_sway_mcm.get_config("power_low_crouch") local power_stand_scoped = weapon_sway_mcm.get_config("power_stand_scoped") local power_crouch_scoped = weapon_sway_mcm.get_config("power_crouch_scoped") local power_low_crouch_scoped = weapon_sway_mcm.get_config("power_low_crouch_scoped") local weapon_mount_feature = weapon_sway_mcm.get_config("weapon_mount_feature") local weapon_mounted_power = weapon_sway_mcm.get_config("weapon_mounted_power") local y_axis_mounted_distance = weapon_sway_mcm.get_config("y_axis_mounted_distance") local weapon_handling_mult = weapon_sway_mcm.get_config("handling_mult") local weight_factor = weapon_sway_mcm.get_config("weight_factor") local max_power_weight = weapon_sway_mcm.get_config("max_power_weight") local hold_breath_feature = weapon_sway_mcm.get_config("hold_breath_feature") local enable_breath_sound = weapon_sway_mcm.get_config("enable_breath_sound") local breath_restore_mult = weapon_sway_mcm.get_config("breath_restore_mult") local max_hold_breath_time = weapon_sway_mcm.get_config("max_hold_breath_time") local hold_breath_mult = weapon_sway_mcm.get_config("hold_breath_mult") local release_breath_mult = weapon_sway_mcm.get_config("release_breath_mult") local weapon_sway_debug = weapon_sway_mcm.get_config("debugx") ------------------------------- mcm patch -------------------------------------- local bhs_patch = 1 local effects_mult = zzz_player_injuries.effects_mult -- If you changed this in BHS script - you need to change it here too -- demonized's and Raven's magic, i dont even know how it works if zzz_player_injuries then zzz_player_injuries.RegisterScriptCallback = function(k, func) if not (k == "actor_on_weapon_zoom_in") then _G.RegisterScriptCallback(k, func) end end end ------------------------------- main ---------------------------------- local zoom_flag = false local holding_breath = false local breath_held_for = 0 function weapon_sway() local wpn = db.actor:active_item() if not (wpn and IsWeapon(wpn)) then return end if (IsMelee(wpn)) then return end local wpn_sec = wpn:section() if not wpn_sec then return end local wpn_scoped = wpn:weapon_is_scope() local handling = utils_ui.prop_handling(wpn, wpn_sec) -- anm power mults local body_mult = get_body_state_power(wpn, wpn_scoped) or 1 -- power based on body state local extra_mult = wpn_scoped and 0.02 or 0.1 -- reduce scoped anm power local mount_mult = wpn_mounted() and weapon_mounted_power or 1 -- weapon mounted local handling_mult = handling and ((2.5 - 0.02 * handling * 100)^weapon_handling_mult) or 1 -- handling local weight = get_weight_power(wpn_sec) and clamp(get_weight_power(wpn_sec) * weight_factor, 0.01, max_power_weight) or 1 -- weight factor local breath_mult = holding_breath and hold_breath_mult or 1 + breath_held_for * release_breath_mult -- breath mult -- Summary power local cam_power = body_mult * weight * extra_mult * mount_mult * breath_mult * handling_mult cam_power = clamp(cam_power, 0, max_effect_power) -- Play anim or Change its power if level.check_cam_effector(99215) then level.set_cam_effector_factor(99215, cam_power) else level.add_cam_effector("weapon_sway\\sway_" .. aim_anm .. ".anm", 99215, true, "", 0, true, cam_power) end -- dbg if not weapon_sway_debug then return end actor_menu.set_msg(1, strformat("weight_mult: %s | handling_mult: %s | Total Power: %s", r(weight), r(handling_mult), r(cam_power))) end function weapon_sway_remove() level.remove_cam_effector(99215) end ----------------------- manage breath ------------------------ -- start holding breath local press_tg = 0 function on_key_press(key) if not weapon_sway_enable then return end if not hold_breath_feature then return end -- when we aiming and press "hold breath" button if not (zoom_flag and key == sway_keybind) then return end -- set "holding_breath" to TRUE holding_breath = true local tg = time_global() if tg < press_tg then return end press_tg = tg + 2000 -- against people who trying their best to break it ;] -- and play hold sound breath_snd_hold() end -- increase/decrease breath hold local breath_tmr = 0 function breath_update() local tg = time_global() if tg < breath_tmr then return end breath_tmr = tg + 250 -- increase "breath_held_for" if hold, decrease "breath_held_for" otherwise breath_held_for = holding_breath and breath_held_for + 0.25 or breath_held_for - 0.25 * breath_restore_mult breath_held_for = clamp(breath_held_for, 0, max_hold_breath_time) -- end holding breath if reached max time if breath_held_for < max_hold_breath_time then return end -- to give at least 1 sec if someone tries to spam it xd breath_held_for = breath_held_for - 1 -- set "holding_breath" to FALSE holding_breath = false -- and play release sound breath_snd_release() end -- end holding breath on key function on_key_release(key) if not (zoom_flag and holding_breath and key == sway_keybind) then return end -- set "holding_breath" to FALSE holding_breath = false -- if breath was held for more than 3 seconds - play release sound if breath_held_for > 3 then breath_snd_release() end end function breath_snd_hold() if not enable_breath_sound then return end local snd_hold = sound_object("weapon_sway\\hold_1") snd_hold:play_no_feedback(db.actor, sound_object.s2d, 0, VEC_ZERO, 1.0, 1.0) end function breath_snd_release() if not enable_breath_sound then return end local snd_release = sound_object("weapon_sway\\release_1") snd_release:play_no_feedback(db.actor, sound_object.s2d, 0, VEC_ZERO, 1.0, 1.0) end ----------------------- power mults ------------------------ function get_body_state_power(wpn, scope) local body_state = get_body_state() if not body_state then return end local body_mult = 1 body_mult = scope and power_stand_scoped or power_stand if body_state == "crouch" then body_mult = scope and power_crouch_scoped or power_crouch elseif body_state == "low_crouch" then body_mult = scope and power_low_crouch_scoped or power_low_crouch end return body_mult end function wpn_mounted() if not weapon_mount_feature then return end local rp_diff = get_rp_diff() return rp_diff > 0.1 end function get_weight_power(wpn_sec) if not ini_sys:section_exist(wpn_sec, "inv_weight") then return end return ini_sys:r_float_ex(wpn_sec, "inv_weight") end ----------------------- utils ------------------------ function get_body_state() local crouch = IsMoveState('mcCrouch') local accel = IsMoveState('mcAccel') local body_st = "stand" if crouch then if accel then body_st = "low_crouch" else body_st = "crouch" end end return body_st end function ray_pick_dir(add_x, add_y, add_z, range) local pos = device().cam_pos local dir = device().cam_dir local vec_x = dir.x + add_x local vec_y = dir.y + add_y local vec_z = dir.z + add_z vec_x = clamp( r(vec_x), -1, 1) vec_y = clamp( r(vec_y), -1, 1) vec_z = clamp( r(vec_z), -1, 1) -- dbg if weapon_sway_debug then printf("--------------------") printf("dir: %s", dir) printf("edited dir: x: %s, y: %s, z: %s", vec_x, vec_y, vec_z) end local pick = ray_pick() pick:set_position(pos) pick:set_direction(vector():set(vec_x, vec_y, vec_z)) pick:set_flags(2) pick:set_range(range) pick:query() local distance = pick:get_distance() return distance end function normal_ray_pick() local pos = device().cam_pos local dir = device().cam_dir local pick = ray_pick() pick:set_position(pos) pick:set_direction(dir) pick:set_flags(2) pick:set_range(0.85) pick:query() local distance = pick:get_distance() return distance end function get_rp_diff() local default_raycast = normal_ray_pick() local x = 0 local y = y_axis_mounted_distance local z = 0 local range = 0.85 local custom_raycast = r(ray_pick_dir(x, y, z, range)) local diff = custom_raycast - default_raycast return diff end function r(val) return round_idp(val, 2) end ----------------------- BHS compatibility ------------------------ if bhs_patch and zzz_player_injuries then function bhs_sway_func() local wpn = db.actor:active_item() if not (wpn and IsWeapon(wpn)) then return end if (IsMelee(wpn)) then return end local wpn_sec = wpn:section() if not wpn_sec then return end local wpn_scoped = wpn:weapon_is_scope() local handling = utils_ui.prop_handling(wpn, wpn_sec) local body_state = get_body_state() local left_arm = (zzz_player_injuries.health.rightarm + zzz_player_injuries.timedhp.rightarm) * effects_mult left_arm = left_arm >=1 and left_arm or 0.75 local right_arm = (zzz_player_injuries.health.leftarm + zzz_player_injuries.timedhp.leftarm) * effects_mult right_arm = right_arm >=1 and right_arm or 0.75 local arms_sum = left_arm + right_arm local max_arms_sum = (zzz_player_injuries.maxhp.rightarm + zzz_player_injuries.maxhp.leftarm) * effects_mult -- anm power mults local bhs_cam_power = 1 local body_mult = get_body_state_power(wpn, wpn_scoped) or 1 -- power based on body state local extra_mult = wpn_scoped and 0.02 or 0.1 -- reduce scoped anm power local mount_mult = wpn_mounted() and weapon_mounted_power or 1 -- weapon mounted local handling_mult = handling and ((2.5 - 0.02 * handling * 100)^weapon_handling_mult) or 1 -- handling local weight = get_weight_power(wpn_sec) and clamp(get_weight_power(wpn_sec) * weight_factor, 0.01, max_power_weight) or 1 -- weight factor local breath_mult = holding_breath and hold_breath_mult or 1 + breath_held_for * release_breath_mult -- breath mult -- Summary Weapon Sway power local cam_power = body_mult * weight * extra_mult * mount_mult * breath_mult * handling_mult cam_power = clamp(cam_power, 0, max_effect_power) -- BHS if arms_sum < (max_arms_sum * (zzz_player_injuries_mcm.get_config("arm_penalty_minimum_hp") * 0.05)) then if (left_arm < right_arm / 1.5) or (right_arm < left_arm / 1.5) then bhs_cam_power = 1.15 * weight / arms_sum bhs_cam_power = (body_state == "crouch") and (0.8 * weight / arms_sum) or bhs_cam_power bhs_cam_power = (body_state == "low_crouch") and (0.4 * weight / arms_sum) or bhs_cam_power else bhs_cam_power = 0.8 * weight / arms_sum bhs_cam_power = (body_state == "crouch") and (0.55 * weight / arms_sum) or bhs_cam_power bhs_cam_power = (body_state == "low_crouch") and (0.3 * weight / arms_sum) or bhs_cam_power end -- Summary BHS power bhs_cam_power = clamp((bhs_cam_power * mount_mult * breath_mult * handling_mult), 0, 3) bhs_cam_power = bhs_cam_power * (zzz_player_injuries_mcm.get_config("arm_animation_power")) local cam_power_scope = bhs_cam_power * 0.2 if wpn:weapon_is_scope() then bhs_cam_power = cam_power_scope end -- Play anim or Change its power if level.check_cam_effector(99215) then level.set_cam_effector_factor(99215, bhs_cam_power) else level.add_cam_effector("weapon_sway\\sway_" .. aim_anm .. ".anm", 99215, true, "", 0, true, bhs_cam_power) end -- Weapon Sway elseif weapon_sway_enable then -- Play anim or Change its power if level.check_cam_effector(99215) then level.set_cam_effector_factor(99215, cam_power) else level.add_cam_effector("weapon_sway\\sway_" .. aim_anm .. ".anm", 99215, true, "", 0, true, cam_power) end end -- dbg if not weapon_sway_debug then return end news_manager.send_tip(db.actor, string.format("y-axis diff: %s", ( get_rp_diff() )), 0, nil, 1500) if not hold_breath_feature then return end news_manager.send_tip(db.actor, string.format("Breath being held for: %s", breath_held_for), 0, nil, 1500) end end ----------------------- cb ------------------------ function actor_on_weapon_zoom_in(wpn) zoom_flag = true end function actor_on_weapon_zoom_out(wpn) weapon_sway_remove() zoom_flag = false if not (holding_breath) then return end holding_breath = false -- if breath was held for more than 3 seconds - play release sound if breath_held_for > 3 then breath_snd_release() end end local tg_act = 0 function main_update() local tg = time_global() if tg < tg_act then return end tg_act = tg + 250 if weapon_sway_enable and zoom_flag then if bhs_patch and zzz_player_injuries and bhs_sway_func then bhs_sway_func() else weapon_sway() end end -- dbg if not weapon_sway_debug then return end news_manager.send_tip(db.actor, string.format("y-axis diff: %s", ( get_rp_diff() )), 0, nil, 1500) if not hold_breath_feature then return end news_manager.send_tip(db.actor, string.format("Breath being held for: %s", breath_held_for), 0, nil, 1500) end function on_option_change() weapon_sway_enable = weapon_sway_mcm.get_config("weapon_sway_feature") aim_anm = weapon_sway_mcm.get_config("animation_type") max_effect_power = weapon_sway_mcm.get_config("max_effect_power") sway_keybind = weapon_sway_mcm.get_config("sway_keybind") power_stand = weapon_sway_mcm.get_config("power_stand") power_crouch = weapon_sway_mcm.get_config("power_crouch") power_low_crouch = weapon_sway_mcm.get_config("power_low_crouch") power_stand_scoped = weapon_sway_mcm.get_config("power_stand_scoped") power_crouch_scoped = weapon_sway_mcm.get_config("power_crouch_scoped") power_low_crouch_scoped = weapon_sway_mcm.get_config("power_low_crouch_scoped") weapon_mount_feature = weapon_sway_mcm.get_config("weapon_mount_feature") weapon_mounted_power = weapon_sway_mcm.get_config("weapon_mounted_power") y_axis_mounted_distance = weapon_sway_mcm.get_config("y_axis_mounted_distance") weapon_handling_mult = weapon_sway_mcm.get_config("handling_mult") weight_factor = weapon_sway_mcm.get_config("weight_factor") max_power_weight = weapon_sway_mcm.get_config("max_power_weight") hold_breath_feature = weapon_sway_mcm.get_config("hold_breath_feature") enable_breath_sound = weapon_sway_mcm.get_config("enable_breath_sound") breath_restore_mult = weapon_sway_mcm.get_config("breath_restore_mult") max_hold_breath_time = weapon_sway_mcm.get_config("max_hold_breath_time") hold_breath_mult = weapon_sway_mcm.get_config("hold_breath_mult") release_breath_mult = weapon_sway_mcm.get_config("release_breath_mult") weapon_sway_debug = weapon_sway_mcm.get_config("debugx") end function on_game_start() RegisterScriptCallback("on_key_press", on_key_press) RegisterScriptCallback("actor_on_update", breath_update) RegisterScriptCallback("on_key_release", on_key_release) RegisterScriptCallback("actor_on_weapon_zoom_in", actor_on_weapon_zoom_in) RegisterScriptCallback("actor_on_weapon_zoom_out", actor_on_weapon_zoom_out) RegisterScriptCallback("actor_on_update", main_update) RegisterScriptCallback("on_option_change", on_option_change) end