搜尋

惡靈古堡9安魂曲惡靈古堡9安魂曲MOD

返回清單
切換到指定樓層
通知這文章過時或找檔案 發表主題

[電玩遊戲] 《惡靈古堡9:安魂曲》自動格擋MOD 免費下載 REFramework+Fluffy Mod Manager安裝使用教學

[複製連結]
1
a7865412 ( Lv.50 智天使 ) 發表於 6 小時前 | 只看該作者 回覆獎勵 |降序瀏覽 |閱讀模式


《惡靈古堡9:安魂曲》自動格擋MOD 快速閱讀精華


  • 🔽 本篇提供兩個核心工具下載:
    • REFramework(框架): MOD運行的必要底層框架
    • Fluffy Mod Manager(MOD管理器): 方便安裝管理各種MOD
  • 🛠️ MOD核心功能:
    • Auto Parry(自動格擋): 自動觸發格擋動作
    • Auto Just Parry(自動精準格擋): 自動觸發精準完美格擋(預設開啟)
  • 📁 安裝路徑: 將腳本檔放入遊戲根目錄的 \reframework\autorun 資料夾內
  • ⚠️ 重要提醒: 此MOD僅適用單人模式,請務必備份存檔
  • 🎮 設定介面: 遊戲內透過REFramework的imgui選單開關功能





⚠️ 重要提醒:使用MOD前請務必閱讀



在開始之前,有幾件事大家一定要知道👇

  • 僅限單人模式使用: 此自動格擋MOD設計用於單人離線遊玩,絕對不要在任何線上或聯機模式下啟用。
  • 先備份存檔: 安裝任何MOD前,強烈建議先手動備份你的遊戲存檔,以防萬一。
  • 遊戲更新後可能失效: 官方更新遊戲版本後,REFramework或腳本可能暫時失效,需等待作者更新。
  • 玩法影響: 啟用自動格擋後,遊戲戰鬥挑戰性會大幅降低,建議通關後再使用,或在想輕鬆享受劇情時才開啟。



什麼是《惡靈古堡9:安魂曲》自動格擋MOD?



在《惡靈古堡9:安魂曲》裡,里昂的格擋系統是一大戰鬥核心——不只能擋下普通攻擊,精準格擋(Just Parry)更能直接反制敵人。不過,要在正確時機按下格擋鍵,對部分玩家來說還是有點壓力,尤其是面對手速快、出招頻繁的敵人時,一個反應慢就挨了一刀。

這款自動格擋MOD就是為了解決這個煩惱而生的!它會在後台自動監測即將到來的攻擊,並幫你在最佳時機觸發格擋,讓你可以專注在劇情體驗和戰術操作上,不必再為「我擋太早還是太晚?」這種問題分心。

更厲害的是,它還支援自動精準格擋(Auto Just Parry),這相當於系統幫你打出完美時機的格擋反擊,效果比普通格擋還要強!


🔽 檔案下載點



底下是本篇教學所需的兩個核心工具,兩個都要下載才能正常運作:




👉 GM後台版 遊戲 推薦 ⬇️⬇️⬇️ 快速玩各種二次元動漫手遊app




安裝步驟一:REFramework框架安裝



REFramework是一切的基礎,你可以把它想像成是MOD運行的「作業系統」——沒有它,後面的腳本根本沒辦法跑起來。

  • 下載 REFramework 的壓縮檔後,將其解壓縮。
  • 找到解壓縮出來的 dinput8.dll 檔案。
  • 將這個 dinput8.dll 直接複製貼上到你的遊戲根目錄(也就是跟 re9.exe 或遊戲主程式在同一層的資料夾)。
  • 啟動遊戲,如果看到畫面出現REFramework的疊加選單(通常是左上角或可用INSERT鍵呼叫),就代表安裝成功!


【小知識】所謂「遊戲根目錄」,就是你在Steam或其他平台安裝惡靈古堡9的那個資料夾。你可以在Steam的遊戲頁面右鍵 → 管理 → 瀏覽本機檔案,直接跳到該目錄。


安裝步驟二:Fluffy Mod Manager安裝



Fluffy Mod Manager是一個非常方便的MOD管理工具,有了它可以讓你在安裝、啟用、停用各種MOD時更加省力,不必手動搬移檔案。

  • 下載並解壓縮 Fluffy Mod Manager。
  • 執行 FluffyModManager.exe
  • 在首次啟動時,程式會要求你指定遊戲安裝路徑,找到惡靈古堡9安魂曲的根目錄後確認即可。
  • 之後若有其他MOD要安裝,直接把MOD壓縮包拖曳進去或放入對應的MOD資料夾就能輕鬆管理。



安裝步驟三:自動格擋Lua腳本部署(最關鍵!)



這步是整個教學的重頭戲!自動格擋的核心是一個Lua腳本,你需要把它正確放到指定位置,REFramework才會在遊戲啟動時自動載入它。

  • 在遊戲根目錄下,找到(或手動建立)這個路徑的資料夾:
    \reframework\autorun
  • 將自動格擋的Lua腳本檔案(副檔名為 .lua)複製到這個 autorun 資料夾內。
  • 完成!下次啟動遊戲時,REFramework會自動偵測並載入這個腳本。


接下來這步很重要:如果你想要修改腳本裡的設定,用任意文字編輯器(如記事本、Notepad++)打開這個 .lua 檔案就能直接調整。不過一般情況下不需要手動改,直接在遊戲內透過選單操作就好,底下會說明。


遊戲內選單操作說明



安裝完成後,進入遊戲按下INSERT鍵(或依你的REFramework設定),就能叫出REFramework的疊加選單。在選單裡找到 [RE9 Auto Parry] 的選項節點,展開後你會看到兩個開關:

  • Auto Parry(自動格擋):開啟後,遇到可格擋的攻擊時系統會自動幫你執行格擋動作。
  • Auto Just Parry(自動精準格擋):開啟後(預設已開啟),系統會嘗試在最佳時機執行精準格擋,效果更強。


兩個選項可以獨立開關,設定會自動儲存到遊戲目錄下的 re9_auto_parry.json 設定檔,下次啟動遊戲不必重新設定。


完整Lua腳本原始碼



想要自行部署或深入研究這份腳本的朋友,底下是完整的 Lua 原始碼。這是控制自動格擋功能的核心腳本,你可以將其完整內容複製並存為 .lua 副檔名,再放入 autorun 資料夾即可運作。

local MOD_NAME = "[RE9 Auto Parry]"
local CONFIG_PATH = "re9_auto_parry.json"

local FLAG_PARRY = 32
local FLAG_DISABLE_PARRY = 262144
local FLAG_JUST_PARRY = 8192
local AUTO_PARRY_COOLDOWN_FRAMES = 8

local default_cfg = {
    auto_parry = false,
    auto_just_parry = true,
}

local cfg = {
    auto_parry = default_cfg.auto_parry,
    auto_just_parry = default_cfg.auto_just_parry,
}

local state = {
    hooks_installed = false,
    check_parry_hook_installed = false,
    on_check_damage_hit_hook_installed = false,
    on_parry_success_hook_installed = false,
    parry_success_seq = 0,
    frame_count = 0,
    last_auto_parry_frame = -1000000,
    last_auto_parry_damage_info = nil,
}

local cache = {
    character_manager = nil,
}

local function load_config()
    local ok, data = pcall(json.load_file, CONFIG_PATH)
    if not ok or type(data) ~= "table" then
        return
    end

    for key, default_value in pairs(default_cfg) do
        if type(data[key]) == type(default_value) then
            cfg[key] = data[key]
        else
            cfg[key] = default_value
        end
    end
end

local function save_config()
    pcall(json.dump_file, CONFIG_PATH, cfg)
end

local function try_call(obj, method_names, ...)
    if obj == nil then
        return false, nil, nil
    end

    for _, name in ipairs(method_names) do
        local ok, ret = pcall(obj.call, obj, name, ...)
        if ok then
            return true, ret, name
        end
    end

    return false, nil, nil
end

local function try_set_field(obj, field_names, value)
    if obj == nil then
        return false
    end

    for _, name in ipairs(field_names) do
        local ok = pcall(obj.set_field, obj, name, value)
        if ok then
            return true
        end
    end

    return false
end

local function get_singleton(cache_key, type_name)
    local cached = cache[cache_key]
    if cached ~= nil then
        local alive = pcall(cached.get_type_definition, cached)
        if alive then
            return cached
        end
        cache[cache_key] = nil
    end

    local ok, inst = pcall(sdk.get_managed_singleton, type_name)
    if ok and inst ~= nil then
        cache[cache_key] = inst
        return inst
    end

    return nil
end

local function get_hook_storage()
    if thread ~= nil and thread.get_hook_storage ~= nil then
        return thread.get_hook_storage()
    end
    return nil
end

local function get_type_full_name(obj)
    if obj == nil then
        return nil
    end

    local ok_td, td = pcall(obj.get_type_definition, obj)
    if not ok_td or td == nil then
        return nil
    end

    local ok_name, full_name = pcall(td.get_full_name, td)
    if ok_name and type(full_name) == "string" then
        return full_name
    end

    return nil
end

local function is_supported_player_updater(updater)
    local type_name = get_type_full_name(updater)
    if type_name == nil then
        return false
    end

    if type_name == "app.Cp_A000Updater" then
        return true
    end

    return type_name:find("app.Cp_A", 1, true) ~= nil and type_name:find("Updater", 1, true) ~= nil
end

local function is_supported_attack_damage_driver(driver)
    if driver == nil then
        return false
    end

    local type_name = get_type_full_name(driver)
    if type_name == nil or type_name:find("AttackDamageDriver", 1, true) == nil then
        return false
    end

    local ok, updater = try_call(driver, {
        "get_Updater()",
        "get_Updater",
    })
    if ok and updater ~= nil then
        return is_supported_player_updater(updater)
    end

    return false
end

local function is_damage_info_object(obj)
    local type_name = get_type_full_name(obj)
    if type_name == nil then
        return false
    end
    return type_name:find("HitController.DamageInfo", 1, true) ~= nil
end

local function find_method(type_name, signatures)
    local td = sdk.find_type_definition(type_name)
    if td == nil then
        return nil
    end

    for _, sig in ipairs(signatures) do
        local method = td:get_method(sig)
        if method ~= nil then
            return method
        end
    end

    return nil
end

local function get_this_from_args(args)
    if args == nil then
        return nil
    end

    local this_obj = sdk.to_managed_object(args[2])
    if this_obj ~= nil then
        return this_obj
    end

    return sdk.to_managed_object(args[1])
end

local function get_damage_info_from_args(args)
    if args == nil then
        return nil
    end

    local candidates = { args[3], args[4], args[1] }
    for _, ptr in ipairs(candidates) do
        local obj = sdk.to_managed_object(ptr)
        if obj ~= nil and is_damage_info_object(obj) then
            return obj
        end
    end

    return nil
end

local function is_auto_parry_ready(damage_info)
    local frame_delta = state.frame_count - state.last_auto_parry_frame
    if frame_delta <= AUTO_PARRY_COOLDOWN_FRAMES then
        return false
    end

    if damage_info ~= nil
        and state.last_auto_parry_damage_info ~= nil
        and damage_info == state.last_auto_parry_damage_info
        and frame_delta <= (AUTO_PARRY_COOLDOWN_FRAMES + 2) then
        return false
    end

    return true
end

local function get_player_context()
    local mgr = get_singleton("character_manager", "app.CharacterManager")
    if mgr == nil then
        return nil
    end

    local ok, player = try_call(mgr, {
        "getPlayerContextRef()",
        "getPlayerContextRef",
        "getPlayerContextRefFast()",
        "getPlayerContextRefFast",
    })
    if ok and player ~= nil then
        return player
    end

    return nil
end

local function get_player_updater(player)
    local ok, updater = try_call(player, {
        "get_Updater()",
        "get_Updater",
    })
    if ok and updater ~= nil then
        return updater
    end
    return nil
end

local function get_player_parry_driver(player)
    local updater = get_player_updater(player)
    if updater == nil then
        return nil
    end

    local ok, parry_driver = try_call(updater, {
        "get_ParryDriver()",
        "get_ParryDriver",
        "getParryDriver()",
        "getParryDriver",
    })
    if ok and parry_driver ~= nil then
        return parry_driver
    end

    return nil
end

local function apply_parry_damageinfo_flags(damage_info)
    if damage_info == nil then
        return
    end

    try_call(damage_info, {
        "offFlag(app.HitController.DamageInfo.AttackDamageFlagEnum)",
        "offFlag",
    }, FLAG_DISABLE_PARRY)

    try_call(damage_info, {
        "onFlag(app.HitController.DamageInfo.AttackDamageFlagEnum)",
        "onFlag",
    }, FLAG_PARRY)

    if cfg.auto_just_parry then
        try_call(damage_info, {
            "onFlag(app.HitController.DamageInfo.AttackDamageFlagEnum)",
            "onFlag",
        }, FLAG_JUST_PARRY)
    end
end

local function apply_player_just_parry_state(this_obj)
    if not cfg.auto_just_parry or this_obj == nil then
        return
    end

    local ok_unit, parry_unit = try_call(this_obj, {
        "get_ParryUnit()",
        "get_ParryUnit",
    })
    if not ok_unit or parry_unit == nil then
        return
    end

    local set_ok = try_call(parry_unit, {
        "set_IsJustParry(System.Boolean)",
        "set_IsJustParry",
    }, true)

    if not set_ok then
        try_set_field(parry_unit, {
            "IsJustParry",
            "_IsJustParry",
        }, true)
    end
end

local function request_parry_permit()
    local player = get_player_context()
    if player == nil then
        return
    end

    local updater = get_player_updater(player)
    if not is_supported_player_updater(updater) then
        return
    end

    local parry_driver = get_player_parry_driver(player)
    if parry_driver == nil then
        return
    end

    try_call(parry_driver, {
        "requestPermitParryTransitFrame()",
        "requestPermitParryTransitFrame",
    })
end

local function install_check_parry_hook()
    if state.check_parry_hook_installed then
        return
    end

    local method = find_method("app.PlayerAttackDamageDriver", {
        "checkParry(app.HitController.DamageInfo)",
        "checkParry",
    })
    if method == nil then
        return
    end

    sdk.hook(method, function(args)
        local storage = get_hook_storage()
        if storage ~= nil then
            storage.force_auto_parry = false
        end

        local this_obj = get_this_from_args(args)
        if this_obj ~= nil and is_supported_attack_damage_driver(this_obj) then
            local damage_info = get_damage_info_from_args(args)
            if cfg.auto_parry and storage ~= nil and is_auto_parry_ready(damage_info) then
                storage.force_auto_parry = true
            end
        end

        return sdk.PreHookResult.CALL_ORIGINAL
    end, function(retval)
        local storage = get_hook_storage()
        if storage ~= nil and storage.force_auto_parry then
            return true
        end
        return retval
    end)

    state.check_parry_hook_installed = true
end

local function install_on_parry_success_hook()
    if state.on_parry_success_hook_installed then
        return
    end

    local method = find_method("app.PlayerAttackDamageDriver", {
        "onParrySuccess(app.HitController.DamageInfo)",
        "onParrySuccess",
    })
    if method == nil then
        return
    end

    sdk.hook(method, function(args)
        local this_obj = get_this_from_args(args)
        if this_obj ~= nil and is_supported_attack_damage_driver(this_obj) then
            state.parry_success_seq = state.parry_success_seq + 1
            state.last_auto_parry_frame = state.frame_count
            state.last_auto_parry_damage_info = get_damage_info_from_args(args)
        end
        return sdk.PreHookResult.CALL_ORIGINAL
    end, nil)

    state.on_parry_success_hook_installed = true
end

local function install_on_check_damage_hit_hook()
    if state.on_check_damage_hit_hook_installed then
        return
    end

    local method = find_method("app.PlayerAttackDamageDriver", {
        "onCheckDamageHit(app.HitController.DamageInfo)",
        "onCheckDamageHit",
    })
    if method == nil then
        return
    end

    sdk.hook(method, function(args)
        local storage = get_hook_storage()
        if storage ~= nil then
            storage.auto_parry_candidate = false
        end

        local this_obj = get_this_from_args(args)
        if this_obj == nil or not is_supported_attack_damage_driver(this_obj) then
            return sdk.PreHookResult.CALL_ORIGINAL
        end

        if cfg.auto_parry then
            local damage_info = get_damage_info_from_args(args)
            if not is_auto_parry_ready(damage_info) then
                return sdk.PreHookResult.CALL_ORIGINAL
            end

            apply_parry_damageinfo_flags(damage_info)
            apply_player_just_parry_state(this_obj)
            request_parry_permit()

            if storage ~= nil then
                storage.auto_parry_candidate = true
            end
        end

        return sdk.PreHookResult.CALL_ORIGINAL
    end, function(retval)
        return true
    end)

    state.on_check_damage_hit_hook_installed = true
end

local function install_hooks()
    install_check_parry_hook()
    install_on_parry_success_hook()
    install_on_check_damage_hit_hook()

    state.hooks_installed = state.check_parry_hook_installed
        and state.on_parry_success_hook_installed
        and state.on_check_damage_hit_hook_installed
end

pcall(load_config)

re.on_frame(function()
    state.frame_count = state.frame_count + 1

    if not state.hooks_installed then
        pcall(install_hooks)
    end
end)

re.on_draw_ui(function()
    if not imgui then
        return
    end

    if imgui.tree_node(MOD_NAME) then
        local changed = false
        local option_changed = false

        changed, cfg.auto_parry = imgui.checkbox("Auto Parry", cfg.auto_parry)
        option_changed = option_changed or changed

        changed, cfg.auto_just_parry = imgui.checkbox("Auto Just Parry", cfg.auto_just_parry)
        option_changed = option_changed or changed

        if option_changed then
            save_config()
        end

        imgui.tree_pop()
    end
end)

re.on_config_save(function()
    save_config()
end)


以下廣告滑動後還有帖子內容





《惡靈古堡9:安魂曲》自動格擋MOD 常見問題Q&A



Q:我把腳本放進autorun資料夾了,但遊戲內沒有出現任何MOD選單,怎麼辦?
請先確認REFramework的 dinput8.dll 有正確放在遊戲根目錄(和遊戲主程式同一層),而不是放在子資料夾裡。如果路徑錯誤,框架根本不會載入,自然也不會有任何選單出現。

Q:Auto Parry預設是關閉的,Auto Just Parry預設是開啟的,這樣有差嗎?
有差別。Auto Parry是基礎自動格擋,需要你手動在選單開啟才會生效。Auto Just Parry則是在基礎格擋觸發時,額外嘗試輸出「精準格擋」判定,預設開啟代表只要你打開Auto Parry,精準格擋效果也會一起套用。

Q:我啟用這個MOD之後角色完全不會扣血,是正常的嗎?
不完全正常。根據腳本作者的說明,早期版本曾因為邏輯錯誤,誤將角色設成了無敵狀態才導致不扣血。目前已修正,自動格擋應該是真的觸發格擋動作,而非靠無敵跳過傷害。如果你還是遇到不扣血的情況,建議確認你使用的是最新版本的腳本。

Q:這個MOD會不會被卡普空(Capcom)偵測並封鎖帳號?
《惡靈古堡9:安魂曲》是純單人遊戲,官方並無主動掃描玩家電腦的反作弊機制。不過卡普空官方立場是不支持MOD使用,遊戲更新後MOD可能失效,且需要等待相容性更新。只要在離線單人環境下使用,風險相當低,但仍建議自行評估。

Q:Fluffy Mod Manager一定要裝嗎?不裝可以用嗎?
Fluffy Mod Manager並非強制必要,它主要是用來方便管理其他類型的MOD(例如外觀MOD)。自動格擋腳本本身只需要把 .lua 檔放進 \reframework\autorun 就能運作,不一定需要透過Fluffy Mod Manager安裝。

Q:腳本安裝後,重新啟動遊戲還需要重新設定嗎?
不需要。設定會自動存入遊戲目錄下的 re9_auto_parry.json 檔案,下次啟動遊戲時會自動讀取上次的設定,省去每次重新開關的麻煩。







大家正在看啥


收藏收藏 分享文章到FB上分享
回覆 使用道具 檢舉
複製專屬你的推廣連結:發至FB與各論壇宣傳:累積點數換GP商品 & 藍鑽
每五點閱率就可以兌換藍鑽積分或遊戲點卡 夢遊推廣文章換GP商品

你需要登入後才可以回覆 登入 | 加入會員

本版積分規則

Copyright (C) 2010-2020 夢遊電玩論壇

廣告合作:請直接聯繫我們,並附上您預刊登位置的預算。  

快速回覆 返回頂端 返回清單