main.t_commands = { {name = "~U", input = "/U"}, {name = "~D", input = "/D"}, {name = "~B", input = "/B"}, {name = "~F", input = "/F"}, {name = "$U", input = "$U"}, {name = "$D", input = "$D"}, {name = "$B", input = "$B"}, {name = "$F", input = "$F"}, {name = "a", input = "a"}, {name = "b", input = "b"}, {name = "c", input = "c"}, {name = "x", input = "x"}, {name = "y", input = "y"}, {name = "z", input = "z"}, {name = "s", input = "s"}, {name = "d", input = "d"}, {name = "w", input = "w"}, {name = "m", input = "m"}, {name = "/s", input = "/s"}, {name = "/d", input = "/d"}, {name = "/w", input = "/w"}, } function main.f_commandNew(controllerNo) local c = commandNew(controllerNo) for k, v in pairs(main.t_commands) do commandAdd(c, v.name, v.input) -- commandAdd(c, k, v[1], v[2], v[3]) end return c end --修改部分1 local ANALOG_DEAD_TIME = 20 -- dead time to limit scrolling behavior main.playerInput = 1 main.lastAxis = nil main.analogDeadTime = ANALOG_DEAD_TIME function main.f_input(p, b) for _, pn in ipairs(p) do for _, btn in ipairs(b) do if btn == 'pal' then if main.f_btnPalNo(pn) > 0 then main.playerInput = pn main.lastAxis = nil return true end elseif btn == 'LS_X-' or btn == 'LS_X+' or btn == 'LS_Y-' or btn == 'LS_Y+' or btn == 'RS_X-' or btn == 'RS_X+' or btn == 'RS_Y-' or btn == 'RS_Y+' or btn == 'LT' or btn == 'RT' then local key = getJoystickKey(pn-1) -- fix off-by-one local stickIsNeutral = (key == nil or key == '') and pn == main.playerInput -- Handle analog axes if stickIsNeutral then main.lastAxis = nil return false else if main.analogDeadTime > 0 then main.analogDeadTime = main.analogDeadTime - 1 end if key == btn and main.analogDeadTime == 0 and key ~= main.lastAxis then main.playerInput = pn main.analogDeadTime = ANALOG_DEAD_TIME main.lastAxis = key return true end end elseif commandGetState(main.t_cmd[pn], btn) then main.playerInput = pn return true end end end return false end --prepare players/command tables main.t_cmd = {} function main.f_setPlayers() local n = gameOption('Config.Players') setPlayers(n) for i = 3, n do if gameOption('Keys_P' .. i .. '.Joystick') == 0 then local c = {Joystick = -1, GUID = ""} for k, v in pairs(main.t_defaultKeysMapping) do c[k] = v end setKeyConfig(i, c.Joystick, {c.up, c.down, c.left, c.right, c.a, c.b, c.c, c.x, c.y, c.z, c.start, c.d, c.w, c.menu}) for k, v in pairs(c) do modifyGameOption('Keys_P' .. i .. '.' .. k, v) end end if getCommandLineValue("-nojoy") == nil then if gameOption('Joystick_P' .. i .. '.Joystick') == 0 then local c = {Joystick = i - 1, GUID = ""} for k, v in pairs(main.t_defaultJoystickMapping) do c[k] = v end setKeyConfig(i, c.Joystick, {c.up, c.down, c.left, c.right, c.a, c.b, c.c, c.x, c.y, c.z, c.start, c.d, c.w, c.menu}) for k, v in pairs(c) do modifyGameOption('Joystick_P' .. i .. '.' .. k, v) end end end end main.t_players = {} for i = #main.t_cmd + 1, n do table.insert(main.t_cmd, main.f_commandNew(i)) table.insert(main.t_players, i) end end main.f_setPlayers() -- 模式定义 main.t_itemname = { --ARCADE / TEAM ARCADE ['arcade'] = function(t, item) Global_replay = 0 main.aiRamp = true main.charparam.ai = true main.charparam.arcadepath = true main.charparam.music = true main.charparam.rounds = true main.charparam.single = true main.charparam.stage = true main.charparam.time = true main.exitSelect = true --main.lifebar.p1score = true --main.lifebar.p2ailevel = true main.makeRoster = true main.motif.challenger = true main.motif.continuescreen = true main.motif.hiscore = false main.motif.versusscreen = true main.motif.versusmatchno = true main.motif.victoryscreen = true main.motif.winscreen = true main.orderSelect[1] = true main.orderSelect[2] = true main.resetScore = true main.stageOrder = true main.storyboard.credits = true main.storyboard.ending = true main.storyboard.gameover = true main.storyboard.intro = true if (t ~= nil and t[item].itemname == 'arcade') or (t == nil and not main.teamarcade) then main.teamMenu[1].single = true main.teamMenu[2].single = true textImgSetText(motif.select_info.title.TextSpriteData, motif.select_info.title.text.arcade) main.teamarcade = false else --teamarcade main.teamMenu[1].ratio = true main.teamMenu[1].simul = true main.teamMenu[1].single = true main.teamMenu[1].tag = true main.teamMenu[1].turns = true main.teamMenu[2].ratio = true main.teamMenu[2].simul = true main.teamMenu[2].single = true main.teamMenu[2].tag = true main.teamMenu[2].turns = true textImgSetText(motif.select_info.title.TextSpriteData, motif.select_info.title.text.teamarcade) main.teamarcade = true end main.f_setCredits() remapInput(1, getLastInputController()) setCommandInputSource(2, 1) setGameMode('arcade') hook.run("main.t_itemname") if start.challenger == 0 then return start.f_selectMode end return nil end, --BONUS CHAR ['bonus'] = function(t, item) Global_replay = 0 main.charparam.ai = true main.charparam.music = true main.charparam.rounds = true main.charparam.single = true main.charparam.stage = true main.charparam.time = true main.forceChar[2] = {main.t_bonusChars[item]} main.selectMenu[2] = true main.teamMenu[1].single = true main.teamMenu[2].single = true textImgSetText(motif.select_info.title.TextSpriteData, motif.select_info.title.text.bonus) remapInput(1, getLastInputController()) setGameMode('bonus') hook.run("main.t_itemname") return start.f_selectMode end, --DEMO ['demo'] = function() Global_replay = 0 return main.f_demoStart end, --FREE BATTLE (QUICK VS) ['freebattle'] = function() Global_replay = 0 --main.lifebar.p1score = true --main.lifebar.p2ailevel = true main.motif.versusscreen = true main.motif.victoryscreen = true main.orderSelect[1] = true main.orderSelect[2] = true main.selectMenu[2] = true main.stageMenu = true main.teamMenu[1].ratio = true main.teamMenu[1].simul = true main.teamMenu[1].single = true main.teamMenu[1].tag = true main.teamMenu[1].turns = true main.teamMenu[2].ratio = true main.teamMenu[2].simul = true main.teamMenu[2].single = true main.teamMenu[2].tag = true main.teamMenu[2].turns = true textImgSetText(motif.select_info.title.TextSpriteData, motif.select_info.title.text.freebattle) remapInput(1, getLastInputController()) setCommandInputSource(2, 1) setGameMode('freebattle') hook.run("main.t_itemname") return start.f_selectMode end, --JOIN (NEW ADDRESS) ['joinadd'] = function(t, item) Global_replay = 0 sndPlay(motif.Snd, motif[main.group].cursor.move.snd[1], motif[main.group].cursor.move.snd[2]) local name = main.f_drawInput( motif[main.group].textinput.TextSpriteData, motif[main.group].textinput.text.name, motif[main.group], motif[main.background], motif[main.group].textinput.overlay.RectData ) if name ~= '' then sndPlay(motif.Snd, motif[main.group].cursor.move.snd[1], motif[main.group].cursor.move.snd[2]) local address = main.f_drawInput( motif[main.group].textinput.TextSpriteData, motif[main.group].textinput.text.address, motif[main.group], motif[main.background], motif[main.group].textinput.overlay.RectData ) if address:match('^[0-9%.]+$') then sndPlay(motif.Snd, motif[main.group].cursor.done.snd.default[1], motif[main.group].cursor.done.snd.default[2]) modifyGameOption('Netplay.IP.' .. name, address) table.insert(t, #t, {itemname = 'ip_' .. name, displayname = name}) saveGameOption(getCommandLineValue("-config")) else sndPlay(motif.Snd, motif[main.group].cancel.snd[1], motif[main.group].cancel.snd[2]) end else sndPlay(motif.Snd, motif[main.group].cancel.snd[1], motif[main.group].cancel.snd[2]) end main.f_cmdBufReset() return t end, --NETPLAY SURVIVAL ['netplaysurvivalcoop'] = function() main.aiRamp = true main.charparam.ai = true main.charparam.music = true main.charparam.single = true main.charparam.stage = true main.charparam.time = true main.coop = true main.elimination = true main.exitSelect = true --main.lifebar.match = true --main.lifebar.p2ailevel = true main.makeRoster = true main.motif.losescreen = true main.motif.winscreen = true main.matchWins.draw = {0, 0} main.matchWins.simul = {1, 1} main.matchWins.single = {1, 1} main.matchWins.tag = {1, 1} main.numSimul = {2, 2} main.numTag = {2, 2} main.persistLife = true main.persistMusic = true main.persistRounds = true main.stageMenu = true main.storyboard.credits = true main.storyboard.gameover = true main.teamMenu[1].simul = true main.teamMenu[1].tag = true main.teamMenu[2].ratio = true main.teamMenu[2].simul = true main.teamMenu[2].single = true main.teamMenu[2].tag = true main.teamMenu[2].turns = true textImgSetText(motif.select_info.title.TextSpriteData, motif.select_info.title.text.netplaysurvivalcoop) setGameMode('netplaysurvivalcoop') hook.run("main.t_itemname") return start.f_selectMode end, --NETPLAY CO-OP ['netplayteamcoop'] = function() main.aiRamp = true main.charparam.ai = true main.charparam.arcadepath = true main.charparam.music = true main.charparam.rounds = true main.charparam.single = true main.charparam.stage = true main.charparam.time = true main.coop = true main.exitSelect = true --main.lifebar.p1score = true --main.lifebar.p2ailevel = true main.makeRoster = true main.motif.continuescreen = true main.motif.versusscreen = true main.motif.versusmatchno = true main.motif.victoryscreen = true main.motif.winscreen = true main.numSimul = {2, 2} main.numTag = {2, 2} main.resetScore = true main.stageOrder = true main.storyboard.credits = true main.storyboard.ending = true main.storyboard.gameover = true main.storyboard.intro = true main.teamMenu[1].simul = true main.teamMenu[1].tag = true main.teamMenu[2].ratio = true main.teamMenu[2].simul = true main.teamMenu[2].single = true main.teamMenu[2].tag = true main.teamMenu[2].turns = true main.f_setCredits() textImgSetText(motif.select_info.title.TextSpriteData, motif.select_info.title.text.netplayteamcoop) setGameMode('netplayteamcoop') hook.run("main.t_itemname") return start.f_selectMode end, --NETPLAY VERSUS ['netplayversus'] = function() setHomeTeam(1) main.cpuSide[2] = false --main.lifebar.p1wincount = true --main.lifebar.p2wincount = true main.motif.versusscreen = true main.motif.victoryscreen = true main.orderSelect[1] = true main.orderSelect[2] = true main.selectMenu[2] = true main.stageMenu = true main.teamMenu[1].ratio = false main.teamMenu[1].simul = false main.teamMenu[1].single = true main.teamMenu[1].tag = false main.teamMenu[1].turns = false main.teamMenu[2].ratio = false main.teamMenu[2].simul = false main.teamMenu[2].single = true main.teamMenu[2].tag = false main.teamMenu[2].turns = false textImgSetText(motif.select_info.title.TextSpriteData, motif.select_info.title.text.netplayversus) setGameMode('netplayversus') hook.run("main.t_itemname") return start.f_selectMode end, --OPTIONS ['options'] = function() Global_replay = 0 hook.run("main.t_itemname") return options.menu.loop end, --RANDOMTEST ['randomtest'] = function() Global_replay = 0 setGameMode('randomtest') hook.run("main.t_itemname") return main.f_randomtest end, --REPLAY ['replay'] = function() Global_replay = 1 return main.f_replay end, --SERVER CONNECT ['serverconnect'] = function(t, item) Global_replay = 0 local doneSnd = motif[main.group].cursor.done.snd.serverconnect or motif[main.group].cursor.done.snd.default sndPlay(motif.Snd, doneSnd[1], doneSnd[2]) if main.f_connect(gameOption('Netplay.IP.' .. t[item].displayname), t[item].displayname) then synchronize() main.f_clearShuffleTables() math.randomseed(sszRandom()) main.f_cmdBufReset() main.menu.submenu.server.loop() replayStop() exitNetPlay() exitReplay() end return nil end, --SERVER HOST ['serverhost'] = function(t, item) Global_replay = 0 local doneSnd = motif[main.group].cursor.done.snd.serverhost or motif[main.group].cursor.done.snd.default sndPlay(motif.Snd, doneSnd[1], doneSnd[2]) if main.f_connect("", gameOption('Netplay.ListenPort')) then synchronize() main.f_clearShuffleTables() math.randomseed(sszRandom()) main.f_cmdBufReset() main.menu.submenu.server.loop() replayStop() exitNetPlay() exitReplay() end return nil end, --STORY MODE ARC ['storyarc'] = function(t, item) Global_replay = 0 main.motif.continuescreen = true main.selectMenu[1] = false for _, v in ipairs(main.t_selStoryMode) do if v.name == t[item].itemname then main.luaPath = v.path break end end remapInput(1, getLastInputController()) setGameMode(t[item].itemname) hook.run("main.t_itemname") return start.f_selectMode end, --SURVIVAL ['survival'] = function() Global_replay = 0 main.aiRamp = true main.charparam.ai = true main.charparam.music = true main.charparam.single = true main.charparam.stage = true main.charparam.time = true main.dropDefeated = true main.elimination = true main.exitSelect = true --main.lifebar.match = true --main.lifebar.p2ailevel = true main.makeRoster = true main.motif.hiscore = true main.motif.losescreen = true main.motif.winscreen = true main.matchWins.draw = {0, 0} main.matchWins.simul = {1, 1} main.matchWins.single = {1, 1} main.matchWins.tag = {1, 1} main.orderSelect[1] = true main.orderSelect[2] = true main.persistLife = true main.persistMusic = true main.persistRounds = true main.rotationChars = true main.stageMenu = true main.storyboard.credits = true main.storyboard.gameover = true main.teamMenu[1].ratio = true main.teamMenu[1].simul = true main.teamMenu[1].single = true main.teamMenu[1].tag = true main.teamMenu[1].turns = true main.teamMenu[2].ratio = true main.teamMenu[2].simul = true main.teamMenu[2].single = true main.teamMenu[2].tag = true main.teamMenu[2].turns = true textImgSetText(motif.select_info.title.TextSpriteData, motif.select_info.title.text.survival) remapInput(1, getLastInputController()) setCommandInputSource(2, 1) setGameMode('survival') hook.run("main.t_itemname") return start.f_selectMode end, --SURVIVAL CO-OP ['survivalcoop'] = function() Global_replay = 0 main.aiRamp = true main.charparam.ai = true main.charparam.music = true main.charparam.single = true main.charparam.stage = true main.charparam.time = true main.coop = true main.elimination = true main.exitSelect = true --main.lifebar.match = true --main.lifebar.p2ailevel = true main.makeRoster = true main.motif.hiscore = true main.motif.winscreen = true main.matchWins.draw = {0, 0} main.matchWins.simul = {1, 1} main.matchWins.single = {1, 1} main.matchWins.tag = {1, 1} main.numSimul = {2, math.min(4, gameOption('Config.Players'))} main.numTag = {2, math.min(4, gameOption('Config.Players'))} main.persistLife = true main.persistMusic = true main.persistRounds = true main.rotationChars = true main.stageMenu = true main.storyboard.credits = true main.storyboard.gameover = true main.teamMenu[1].simul = true main.teamMenu[1].tag = true main.teamMenu[2].ratio = true main.teamMenu[2].simul = true main.teamMenu[2].single = true main.teamMenu[2].tag = true main.teamMenu[2].turns = true textImgSetText(motif.select_info.title.TextSpriteData, motif.select_info.title.text.survivalcoop) setGameMode('survivalcoop') hook.run("main.t_itemname") return start.f_selectMode end, --TEAM CO-OP ['teamcoop'] = function() Global_replay = 0 main.aiRamp = true main.charparam.ai = true main.charparam.arcadepath = true main.charparam.music = true main.charparam.rounds = true main.charparam.single = true main.charparam.stage = true main.charparam.time = true main.coop = true main.exitSelect = true --main.lifebar.p1score = true --main.lifebar.p2ailevel = true main.makeRoster = true main.motif.continuescreen = true main.motif.hiscore = true main.motif.versusscreen = true main.motif.versusmatchno = true main.motif.victoryscreen = true main.motif.winscreen = true main.numSimul = {2, math.min(4, gameOption('Config.Players'))} main.numTag = {2, math.min(4, gameOption('Config.Players'))} main.resetScore = true main.stageOrder = true main.storyboard.credits = true main.storyboard.ending = true main.storyboard.gameover = true main.storyboard.intro = true main.teamMenu[1].simul = true main.teamMenu[1].tag = true main.teamMenu[2].ratio = true main.teamMenu[2].simul = true main.teamMenu[2].single = true main.teamMenu[2].tag = true main.teamMenu[2].turns = true main.f_setCredits() textImgSetText(motif.select_info.title.TextSpriteData, motif.select_info.title.text.teamcoop) setGameMode('teamcoop') hook.run("main.t_itemname") return start.f_selectMode end, --TIME ATTACK ['timeattack'] = function() Global_replay = 0 main.aiRamp = true main.charparam.ai = true main.charparam.music = true main.charparam.rounds = true main.charparam.single = true main.charparam.stage = true main.charparam.time = true main.exitSelect = true --main.lifebar.p2ailevel = true --main.lifebar.timer = true main.makeRoster = true main.motif.continuescreen = true main.motif.hiscore = true main.motif.versusscreen = true main.motif.versusmatchno = true main.motif.winscreen = true main.quickContinue = true main.orderSelect[1] = true main.orderSelect[2] = true main.resetScore = true main.stageOrder = true main.storyboard.credits = true main.storyboard.gameover = true main.teamMenu[1].ratio = true main.teamMenu[1].simul = true main.teamMenu[1].single = true main.teamMenu[1].tag = true main.teamMenu[1].turns = true main.teamMenu[2].ratio = true main.teamMenu[2].simul = true main.teamMenu[2].single = true main.teamMenu[2].tag = true main.teamMenu[2].turns = true main.f_setCredits() textImgSetText(motif.select_info.title.TextSpriteData, motif.select_info.title.text.timeattack) remapInput(1, getLastInputController()) setCommandInputSource(2, 1) setGameMode('timeattack') hook.run("main.t_itemname") return start.f_selectMode end, --TRAINING ['training'] = function() Global_replay = 0 setHomeTeam(1) setCommandInputSource(2, 1) if main.t_charDef[gameOption('Config.TrainingChar'):lower()] ~= nil then main.forceChar[2] = {main.t_charDef[gameOption('Config.TrainingChar'):lower()]} end --main.lifebar.p1score = true --main.lifebar.p2ailevel = true main.roundTime = -1 main.selectMenu[2] = true if gameOption('Config.TrainingStage') == '' then main.stageMenu = true end main.teamMenu[1].ratio = false main.teamMenu[1].simul = false main.teamMenu[1].single = true main.teamMenu[1].tag = false main.teamMenu[1].turns = false main.teamMenu[2].single = true main.matchWins.draw = {0, 0} main.matchWins.simul = {0, 0} main.matchWins.single = {0, 0} main.matchWins.tag = {0, 0} textImgSetText(motif.select_info.title.TextSpriteData, motif.select_info.title.text.training) remapInput(1, getLastInputController()) setGameMode('training') hook.run("main.t_itemname") return start.f_selectMode end, --TRIALS ['trials'] = function() Global_replay = 0 end, --VS MODE / TEAM VERSUS ['versus'] = function(t, item) Global_replay = 0 setHomeTeam(1) main.cpuSide[2] = false --main.lifebar.p1wincount = true --main.lifebar.p2wincount = true main.motif.versusscreen = true main.motif.victoryscreen = true main.orderSelect[1] = true main.orderSelect[2] = true main.selectMenu[2] = true main.stageMenu = true if (start.challenger == 0 and t[item].itemname == 'versus') or (start.challenger ~= 0 and not main.teamarcade) then main.teamMenu[1].single = true main.teamMenu[2].single = true textImgSetText(motif.select_info.title.TextSpriteData, motif.select_info.title.text.versus) else --teamversus main.teamMenu[1].ratio = true main.teamMenu[1].simul = true main.teamMenu[1].single = true main.teamMenu[1].tag = true main.teamMenu[1].turns = true main.teamMenu[2].ratio = true main.teamMenu[2].simul = true main.teamMenu[2].single = true main.teamMenu[2].tag = true main.teamMenu[2].turns = true textImgSetText(motif.select_info.title.TextSpriteData, motif.select_info.title.text.teamversus) end if start.challenger > 0 then setCommandInputSource(2, start.challenger) setGameMode('challenger') else setCommandInputSource(2, 2) setGameMode('versus') end hook.run("main.t_itemname") if start.challenger == 0 then return start.f_selectMode end return nil end, --VERSUS CO-OP ['versuscoop'] = function() Global_replay = 0 setHomeTeam(1) main.coop = true main.cpuSide[2] = false --main.lifebar.p1wincount = true --main.lifebar.p2wincount = true main.motif.versusscreen = true main.motif.victoryscreen = true main.numSimul = {2, math.min(4, math.max(2, math.ceil(gameOption('Config.Players') / 2)))} main.numTag = {2, math.min(4, math.max(2, math.ceil(gameOption('Config.Players') / 2)))} main.selectMenu[2] = true main.stageMenu = true main.teamMenu[1].simul = true main.teamMenu[1].tag = true main.teamMenu[2].simul = true main.teamMenu[2].tag = true textImgSetText(motif.select_info.title.TextSpriteData, motif.select_info.title.text.versuscoop) setGameMode('versuscoop') hook.run("main.t_itemname") return start.f_selectMode end, --WATCH ['watch'] = function() Global_replay = 0 setHomeTeam(1) main.cpuSide[1] = true --main.lifebar.p1ailevel = true --main.lifebar.p2ailevel = true main.motif.versusscreen = true main.motif.victoryscreen = true main.selectMenu[2] = true main.stageMenu = true main.teamMenu[1].ratio = false main.teamMenu[1].simul = false main.teamMenu[1].single = true main.teamMenu[1].tag = false main.teamMenu[1].turns = false main.teamMenu[2].ratio = false main.teamMenu[2].simul = false main.teamMenu[2].single = true main.teamMenu[2].tag = false main.teamMenu[2].turns = false textImgSetText(motif.select_info.title.TextSpriteData, motif.select_info.title.text.watch) remapInput(1, getLastInputController()) setCommandInputSource(2, 1) setGameMode('watch') hook.run("main.t_itemname") return start.f_selectMode end, --SAKI ['saki'] = function() main.cpuSide = {false, false} main.roundTime = -1 main.selectMenu[1] = false main.luaPath = 'training/saki.lua' setGameMode('saki') hook.run("main.t_itemname") return start.f_selectMode end, --M3 ['m3'] = function() main.cpuSide = {false, false} main.roundTime = -1 main.selectMenu[1] = false main.luaPath = 'training/m3.lua' setGameMode('m3') hook.run("main.t_itemname") return start.f_selectMode end } -- 新版菜单循环逻辑 Shared menu loop logic (Mod Optimized Version) function main.f_createMenu(tbl, bool_bgreset, bool_main, bool_f1, bool_del) return function() hook.run("main.menu.loop") -- --- 安全初始化变量 --- local groupMotif = motif[main.group] or {} local bg = motif[main.background] or {BGDef = {}} local snd = motif.Snd local menu = groupMotif.menu or { window = {visibleitems = 10}, item = {spacing = {0, 0}}, cancel = {key = {}}, done = {key = {}}, hiscore = {key = {}} } local cursor = groupMotif.cursor or { done = {snd = {default = {0, 0}}} } local cursorPosY = 1 local moveTxt = 0 local item = 1 local lastItem = item local t = main.f_hiddenItems(tbl.items) local call_t_override = nil local call_item_override = nil -- 硬编码的 BGM 映射表 local bgmMap = { saki = "motif.saki", m3 = "motif.m3", } -- 菜单默认 BGM 映射(根据 main.group 确定) local defaultBgmSource = nil local menuBgmMap = { title_info = "motif.title", -- 可以添加其他菜单,例如 select_info = "motif.select" 等 } if menuBgmMap[main.group] then local src = menuBgmMap[main.group] -- 确保 src 是有效非空字符串 if src and src ~= "" then defaultBgmSource = src end end -- 播放 BGM 函数,使用全局 main.currentBgm 进行状态共享 local function playMenuBgm(itemData) if not itemData then return end -- 计算新 BGM 的 source 标识 local newBgm = bgmMap[itemData.itemname] -- 专用 BGM 路径 if not newBgm then newBgm = defaultBgmSource -- 默认 BGM 的 source 字符串 end -- 如果源为空或空字符串,则不播放,保持当前音乐 if not newBgm or newBgm == "" then return end -- 如果与全局当前播放的相同,则跳过 if newBgm == main.currentBgm then return end -- 播放新 BGM,并更新全局记录 playBgm({source = newBgm, interrupt = true}) main.currentBgm = newBgm end local initialPlayed = false local prevMenuF = nil -- --- 预执行逻辑 --- main.f_menuSnap(groupMotif) main.f_menuItemBgAnimReset(groupMotif) local single_f, single_t = main.f_getSingleMenuAction(tbl) if single_f ~= nil and bool_bgreset then main.f_default() if main.t_itemname[single_f] then main.menu.f = main.t_itemname[single_f](single_t, item) main.f_unlock(false) if main.menu.f ~= nil then main.menu.f() end end main.f_default() main.f_unlock(false) local itemNum = #t t = main.f_hiddenItems(tbl.items) main.menu.f = nil if itemNum == #t then return end end -- Storyboard 处理 if bool_main and motif.files then if (motif.files.logo or {}).storyboard ~= '' then main.f_storyboard(motif.files.logo.storyboard) end if (motif.files.intro or {}).storyboard ~= '' then main.f_storyboard(motif.files.intro.storyboard) end end if bool_bgreset then if not (motif.attract_mode or {}).enabled then bgReset(bg.BGDef) playMenuBgm(t[item]) end main.f_fadeReset('fadein', groupMotif) end main.menu.f = nil if not initialPlayed then playMenuBgm(t[item]) initialPlayed = true end -- --- 主循环 --- while true do local justReturned = (prevMenuF ~= nil and main.menu.f == nil) if justReturned then playMenuBgm(t[item]) end prevMenuF = main.menu.f if tbl.reset then tbl.reset = false else main.f_menuCommonDraw(t, item, cursorPosY, moveTxt, groupMotif, bg, false) end if main.menu.f ~= nil and not main.fadeActive then main.f_unlock(false) main.menu.f() main.f_default() main.f_unlock(false) t = main.f_hiddenItems(tbl.items) main.menu.f = nil else if bool_main then main.f_demo() end local item_sav = item cursorPosY, moveTxt, item = main.f_menuCommonCalc(t, item, cursorPosY, moveTxt, groupMotif, cursor) if groupMotif.title and groupMotif.title.TextSpriteData then textImgSetText(groupMotif.title.TextSpriteData, tbl.title or "") end -- 光标移动时切换 BGM if item ~= lastItem then playMenuBgm(t[item]) lastItem = item end -- --- 输入处理 --- if esc() or (menu.cancel and getInput(-1, menu.cancel.key)) then if not bool_main then if groupMotif.cancel then sndPlay(snd, groupMotif.cancel.snd[1], groupMotif.cancel.snd[2]) end break elseif not esc() and t[item] and t[item].itemname ~= 'exit' then for i = 1, #t do if t[i].itemname == 'exit' then if groupMotif.cancel then sndPlay(snd, groupMotif.cancel.snd[1], groupMotif.cancel.snd[2]) end item = i cursorPosY = math.min(item, menu.window.visibleitems) if cursorPosY >= menu.window.visibleitems then moveTxt = (item - menu.window.visibleitems) * menu.item.spacing[2] end break end end end if not bool_main or esc() then break end elseif bool_f1 and (getKey('F1') or gameOption('Config.FirstRun')) then if motif.infobox then main.f_warning( motif.infobox.text.text, groupMotif, bg, motif.infobox.overlay.RectData, motif.infobox.title.TextSpriteData, motif.infobox.text.TextSpriteData ) end main.f_cmdBufReset() elseif getInput(-1, menu.done.key) then demoFrameCounter = 0 if t[item] then local f = t[item].itemname if f == 'back' or f == 'exit' then if f == 'back' and groupMotif.cancel then sndPlay(snd, groupMotif.cancel.snd[1], groupMotif.cancel.snd[2]) end break elseif main.t_itemname[f] == nil then if _G.t_storyModeList and _G.t_storyModeList[f] then f = 'storyarc' elseif f:match('^bonus_') then f = 'bonus' elseif f:match('^ip_') then f = 'serverconnect' elseif tbl.submenu and tbl.submenu[f] and tbl.submenu[f].loop ~= nil and #(tbl.submenu[f].items or {}) > 0 then local single_f2, single_t2 = main.f_getSingleMenuAction(tbl.submenu[f]) if single_f2 ~= nil then f = single_f2 call_t_override = single_t2 call_item_override = 1 else local doneSnd = (groupMotif.cursor.done.snd or {})[f] or groupMotif.cursor.done.snd.default sndPlay(snd, doneSnd[1], doneSnd[2]) tbl.submenu[f].loop() playMenuBgm(t[item]) f = '' main.f_menuSnap(groupMotif) main.f_menuItemBgAnimReset(groupMotif) end else break end end if f ~= '' then main.f_default() if f == 'joinadd' then tbl.items = main.t_itemname[f](t, item) elseif main.t_itemname[f] ~= nil then local call_t = call_t_override or t local call_item = call_item_override or item main.menu.f = main.t_itemname[f](call_t, call_item) end call_t_override, call_item_override = nil, nil if main.menu.f ~= nil then local doneSnd = (groupMotif.cursor.done.snd or {})[f] or groupMotif.cursor.done.snd.default sndPlay(snd, doneSnd[1], doneSnd[2]) main.f_fadeReset('fadeout', groupMotif) end end end end end end end end