mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-15 07:53:23 -05:00
970 lines
34 KiB
Lua
970 lines
34 KiB
Lua
local menu = {}
|
|
|
|
--;===========================================================
|
|
--; PAUSE MENU
|
|
--;===========================================================
|
|
|
|
-- Associative elements table storing arrays with training menu option names.
|
|
-- Can be appended via external module.
|
|
menu.t_valuename = {
|
|
dummycontrol = {
|
|
{itemname = 'cooperative', displayname = motif.pause_menu.training_pause_menu.menu.valuename.dummycontrol_cooperative},
|
|
{itemname = 'ai', displayname = motif.pause_menu.training_pause_menu.menu.valuename.dummycontrol_ai},
|
|
{itemname = 'manual', displayname = motif.pause_menu.training_pause_menu.menu.valuename.dummycontrol_manual},
|
|
},
|
|
ailevel = {
|
|
{itemname = '1', displayname = motif.pause_menu.training_pause_menu.menu.valuename.ailevel_1},
|
|
{itemname = '2', displayname = motif.pause_menu.training_pause_menu.menu.valuename.ailevel_2},
|
|
{itemname = '3', displayname = motif.pause_menu.training_pause_menu.menu.valuename.ailevel_3},
|
|
{itemname = '4', displayname = motif.pause_menu.training_pause_menu.menu.valuename.ailevel_4},
|
|
{itemname = '5', displayname = motif.pause_menu.training_pause_menu.menu.valuename.ailevel_5},
|
|
{itemname = '6', displayname = motif.pause_menu.training_pause_menu.menu.valuename.ailevel_6},
|
|
{itemname = '7', displayname = motif.pause_menu.training_pause_menu.menu.valuename.ailevel_7},
|
|
{itemname = '8', displayname = motif.pause_menu.training_pause_menu.menu.valuename.ailevel_8},
|
|
},
|
|
dummymode = {
|
|
{itemname = 'stand', displayname = motif.pause_menu.training_pause_menu.menu.valuename.dummymode_stand},
|
|
{itemname = 'crouch', displayname = motif.pause_menu.training_pause_menu.menu.valuename.dummymode_crouch},
|
|
{itemname = 'jump', displayname = motif.pause_menu.training_pause_menu.menu.valuename.dummymode_jump},
|
|
{itemname = 'wjump', displayname = motif.pause_menu.training_pause_menu.menu.valuename.dummymode_wjump},
|
|
},
|
|
guardmode = {
|
|
{itemname = 'none', displayname = motif.pause_menu.training_pause_menu.menu.valuename.guardmode_none},
|
|
{itemname = 'auto', displayname = motif.pause_menu.training_pause_menu.menu.valuename.guardmode_auto},
|
|
{itemname = 'all', displayname = motif.pause_menu.training_pause_menu.menu.valuename.guardmode_all},
|
|
{itemname = 'random', displayname = motif.pause_menu.training_pause_menu.menu.valuename.guardmode_random},
|
|
},
|
|
fallrecovery = {
|
|
{itemname = 'none', displayname = motif.pause_menu.training_pause_menu.menu.valuename.fallrecovery_none},
|
|
{itemname = 'ground', displayname = motif.pause_menu.training_pause_menu.menu.valuename.fallrecovery_ground},
|
|
{itemname = 'air', displayname = motif.pause_menu.training_pause_menu.menu.valuename.fallrecovery_air},
|
|
{itemname = 'random', displayname = motif.pause_menu.training_pause_menu.menu.valuename.fallrecovery_random},
|
|
},
|
|
distance = {
|
|
{itemname = 'any', displayname = motif.pause_menu.training_pause_menu.menu.valuename.distance_any},
|
|
{itemname = 'close', displayname = motif.pause_menu.training_pause_menu.menu.valuename.distance_close},
|
|
{itemname = 'medium', displayname = motif.pause_menu.training_pause_menu.menu.valuename.distance_medium},
|
|
{itemname = 'far', displayname = motif.pause_menu.training_pause_menu.menu.valuename.distance_far},
|
|
},
|
|
buttonjam = {
|
|
{itemname = 'none', displayname = motif.pause_menu.training_pause_menu.menu.valuename.buttonjam_none},
|
|
{itemname = 'a', displayname = motif.pause_menu.training_pause_menu.menu.valuename.buttonjam_a},
|
|
{itemname = 'b', displayname = motif.pause_menu.training_pause_menu.menu.valuename.buttonjam_b},
|
|
{itemname = 'c', displayname = motif.pause_menu.training_pause_menu.menu.valuename.buttonjam_c},
|
|
{itemname = 'x', displayname = motif.pause_menu.training_pause_menu.menu.valuename.buttonjam_x},
|
|
{itemname = 'y', displayname = motif.pause_menu.training_pause_menu.menu.valuename.buttonjam_y},
|
|
{itemname = 'z', displayname = motif.pause_menu.training_pause_menu.menu.valuename.buttonjam_z},
|
|
{itemname = 's', displayname = motif.pause_menu.training_pause_menu.menu.valuename.buttonjam_s},
|
|
{itemname = 'd', displayname = motif.pause_menu.training_pause_menu.menu.valuename.buttonjam_d},
|
|
{itemname = 'w', displayname = motif.pause_menu.training_pause_menu.menu.valuename.buttonjam_w},
|
|
},
|
|
}
|
|
|
|
-- Shared logic for pause menu option change, returns 2 values:
|
|
-- * boolean depending if option has changed (via right/left button press)
|
|
-- * itemname read from t_valuename table based on currently active option
|
|
-- (or nil, if there was no option change in this frame)
|
|
function menu.f_valueChanged(t, sec)
|
|
local valueitem = menu[t.itemname] or 1
|
|
local chk = valueitem
|
|
if getInput(-1, sec.menu.add.key) then
|
|
valueitem = valueitem + 1
|
|
elseif getInput(-1, sec.menu.subtract.key) then
|
|
valueitem = valueitem - 1
|
|
end
|
|
if valueitem > #menu.t_valuename[t.itemname] then
|
|
valueitem = 1
|
|
elseif valueitem < 1 then
|
|
valueitem = #menu.t_valuename[t.itemname]
|
|
end
|
|
-- true upon option change
|
|
if chk ~= valueitem then
|
|
sndPlay(motif.Snd, sec.cursor.move.snd[1], sec.cursor.move.snd[2])
|
|
t.vardisplay = menu.t_valuename[t.itemname][valueitem].displayname
|
|
menu[t.itemname] = valueitem
|
|
menu.itemname = t.itemname
|
|
return true, menu.t_valuename[t.itemname][valueitem].itemname
|
|
end
|
|
return false, nil
|
|
end
|
|
|
|
-- Current pause menu itemname for internal use (key from menu.t_itemname table)
|
|
menu.itemname = ''
|
|
|
|
-- Associative elements table storing functions controlling behaviour of each
|
|
-- pause menu item. Can be appended via external module.
|
|
menu.t_itemname = {
|
|
--Back
|
|
['back'] = function(t, item, cursorPosY, moveTxt, sec)
|
|
if getInput(-1, sec.menu.done.key) then
|
|
if menu.currentMenu[1] == menu.currentMenu[2] then
|
|
sndPlay(motif.Snd, sec.exit.snd[1], sec.exit.snd[2])
|
|
menu.pauseExitDelay = gameOption('Input.PauseExitDelay')
|
|
else
|
|
sndPlay(motif.Snd, sec.cancel.snd[1], sec.cancel.snd[2])
|
|
end
|
|
if menu.currentMenu[1] ~= menu.currentMenu[2] then
|
|
main.f_menuSnap(sec)
|
|
end
|
|
menu.currentMenu[1] = menu.currentMenu[2]
|
|
return false
|
|
end
|
|
return true
|
|
end,
|
|
--Dummy Control
|
|
['dummycontrol'] = function(t, item, cursorPosY, moveTxt, sec)
|
|
local ok, name = menu.f_valueChanged(t.items[item], sec)
|
|
if ok then
|
|
if name == 'cooperative' or name == 'manual' then
|
|
player(2)
|
|
setAILevel(0)
|
|
elseif name == 'ai' then
|
|
player(2)
|
|
setAILevel(menu.ailevel)
|
|
end
|
|
player(2)
|
|
mapSet('_iksys_trainingDummyControl', menu.dummycontrol - 1)
|
|
end
|
|
return true
|
|
end,
|
|
--AI Level
|
|
['ailevel'] = function(t, item, cursorPosY, moveTxt, sec)
|
|
if menu.f_valueChanged(t.items[item], sec) then
|
|
if menu.t_valuename.dummycontrol[menu.dummycontrol or 1].itemname == 'ai' then
|
|
player(2)
|
|
setAILevel(menu.ailevel)
|
|
end
|
|
end
|
|
return true
|
|
end,
|
|
--Dummy Mode
|
|
['dummymode'] = function(t, item, cursorPosY, moveTxt, sec)
|
|
if menu.f_valueChanged(t.items[item], sec) then
|
|
player(2)
|
|
mapSet('_iksys_trainingDummyMode', menu.dummymode - 1)
|
|
end
|
|
return true
|
|
end,
|
|
--Guard Mode
|
|
['guardmode'] = function(t, item, cursorPosY, moveTxt, sec)
|
|
if menu.f_valueChanged(t.items[item], sec) then
|
|
player(2)
|
|
mapSet('_iksys_trainingGuardMode', menu.guardmode - 1)
|
|
end
|
|
return true
|
|
end,
|
|
--Fall Recovery
|
|
['fallrecovery'] = function(t, item, cursorPosY, moveTxt, sec)
|
|
if menu.f_valueChanged(t.items[item], sec) then
|
|
player(2)
|
|
mapSet('_iksys_trainingFallRecovery', menu.fallrecovery - 1)
|
|
end
|
|
return true
|
|
end,
|
|
--Distance
|
|
['distance'] = function(t, item, cursorPosY, moveTxt, sec)
|
|
if menu.f_valueChanged(t.items[item], sec) then
|
|
player(2)
|
|
mapSet('_iksys_trainingDistance', menu.distance - 1)
|
|
end
|
|
return true
|
|
end,
|
|
--Button Jam
|
|
['buttonjam'] = function(t, item, cursorPosY, moveTxt, sec)
|
|
if menu.f_valueChanged(t.items[item], sec) then
|
|
player(2)
|
|
mapSet('_iksys_trainingButtonJam', menu.buttonjam - 1)
|
|
end
|
|
return true
|
|
end,
|
|
--Key Config
|
|
['keyboard'] = function(t, item, cursorPosY, moveTxt, sec)
|
|
if getInput(-1, sec.menu.done.key) then
|
|
sndPlay(motif.Snd, sec.cursor.done.snd[1], sec.cursor.done.snd[2])
|
|
options.f_keyCfgInit('Keys', t.submenu[t.items[item].itemname].title)
|
|
menu.itemname = t.items[item].itemname
|
|
end
|
|
return true
|
|
end,
|
|
--Joystick Config
|
|
['gamepad'] = function(t, item, cursorPosY, moveTxt, sec)
|
|
if getInput(-1, sec.menu.done.key) then
|
|
sndPlay(motif.Snd, sec.cursor.done.snd[1], sec.cursor.done.snd[2])
|
|
options.f_keyCfgInit('Joystick', t.submenu[t.items[item].itemname].title)
|
|
menu.itemname = t.items[item].itemname
|
|
end
|
|
return true
|
|
end,
|
|
--Default
|
|
['inputdefault'] = function(t, item, cursorPosY, moveTxt, sec)
|
|
if getInput(-1, sec.menu.done.key) then
|
|
sndPlay(motif.Snd, sec.cursor.done.snd[1], sec.cursor.done.snd[2])
|
|
options.f_keyDefault()
|
|
options.f_setKeyConfig('Keys')
|
|
if getCommandLineValue("-nojoy") == nil then
|
|
options.f_setKeyConfig('Joystick')
|
|
end
|
|
options.f_saveCfg(false)
|
|
end
|
|
return true
|
|
end,
|
|
--Round Reset
|
|
['reset'] = function(t, item, cursorPosY, moveTxt, sec)
|
|
if getInput(-1, sec.menu.done.key) then
|
|
sndPlay(motif.Snd, sec.cursor.done.snd[1], sec.cursor.done.snd[2])
|
|
--togglePause(false)
|
|
resetRound()
|
|
main.pauseMenuActive = false
|
|
return false
|
|
end
|
|
return true
|
|
end,
|
|
--Reload (Rematch)
|
|
['reload'] = function(t, item, cursorPosY, moveTxt, sec)
|
|
if getInput(-1, sec.menu.done.key) then
|
|
sndPlay(motif.Snd, sec.cursor.done.snd[1], sec.cursor.done.snd[2])
|
|
--togglePause(false)
|
|
reload()
|
|
main.pauseMenuActive = false
|
|
return false
|
|
end
|
|
return true
|
|
end,
|
|
--Command List
|
|
['commandlist'] = function(t, item, cursorPosY, moveTxt, sec)
|
|
if getInput(-1, sec.menu.done.key) then
|
|
sndPlay(motif.Snd, sec.cursor.done.snd[1], sec.cursor.done.snd[2])
|
|
menu.f_commandlistParse()
|
|
menu.itemname = t.items[item].itemname
|
|
end
|
|
return true
|
|
end,
|
|
--Character Change
|
|
['characterchange'] = function(t, item, cursorPosY, moveTxt, sec)
|
|
if getInput(-1, sec.menu.done.key) then
|
|
sndPlay(motif.Snd, sec.cursor.done.snd[1], sec.cursor.done.snd[2], 100, 0, 0, 0, 0, true)
|
|
--togglePause(false)
|
|
endMatch()
|
|
start.characterchange = true
|
|
main.pauseMenuActive = false
|
|
return false
|
|
end
|
|
return true
|
|
end,
|
|
--Exit
|
|
['exit'] = function(t, item, cursorPosY, moveTxt, sec)
|
|
if getInput(-1, sec.menu.done.key) then
|
|
sndPlay(motif.Snd, sec.cursor.done.snd[1], sec.cursor.done.snd[2], 100, 0, 0, 0, 0, true)
|
|
--togglePause(false)
|
|
endMatch()
|
|
start.exit = true
|
|
main.pauseMenuActive = false
|
|
return false
|
|
end
|
|
return true
|
|
end,
|
|
}
|
|
-- options.t_itemname table functions are also appended to this table, to make
|
|
-- option screen settings logic accessible from within pause menu.
|
|
for k, v in pairs(options.t_itemname) do
|
|
if menu.t_itemname[k] == nil then
|
|
menu.t_itemname[k] = v
|
|
end
|
|
end
|
|
|
|
-- Shared menu loop logic
|
|
function menu.f_createMenu(tbl, sec, bg, bool_main)
|
|
return function()
|
|
hook.run("menu.menu.loop")
|
|
if menu._lastMenuTbl ~= tbl then
|
|
menu._lastMenuTbl = tbl
|
|
main.f_menuItemBgAnimReset(sec)
|
|
end
|
|
local t = tbl.items
|
|
if tbl.reset then
|
|
tbl.reset = false
|
|
else
|
|
main.f_menuCommonDraw(t, tbl.item, tbl.cursorPosY, tbl.moveTxt, sec, bg, true)
|
|
end
|
|
-- Draw during fades, but don't accept menu input until they finish.
|
|
if not main.pauseMenuActive or fadeActive() or menu.pauseExitDelay >= 0 then
|
|
return
|
|
end
|
|
tbl.cursorPosY, tbl.moveTxt, tbl.item = main.f_menuCommonCalc(t, tbl.item, tbl.cursorPosY, tbl.moveTxt, sec, sec.cursor)
|
|
textImgReset(sec.title.TextSpriteData)
|
|
textImgSetText(sec.title.TextSpriteData, tbl.title)
|
|
if esc() or getInput(-1, sec.menu.cancel.key) then
|
|
if bool_main then
|
|
sndPlay(motif.Snd, sec.exit.snd[1], sec.exit.snd[2])
|
|
menu.pauseExitDelay = gameOption('Input.PauseExitDelay')
|
|
else
|
|
sndPlay(motif.Snd, sec.cancel.snd[1], sec.cancel.snd[2])
|
|
end
|
|
if menu.currentMenu[1] ~= menu.currentMenu[2] then
|
|
main.f_menuSnap(sec)
|
|
end
|
|
menu.currentMenu[1] = menu.currentMenu[2]
|
|
return
|
|
elseif menu.t_itemname[t[tbl.item].itemname] ~= nil then
|
|
if not menu.t_itemname[t[tbl.item].itemname](tbl, tbl.item, tbl.cursorPosY, tbl.moveTxt, sec) then
|
|
return
|
|
end
|
|
elseif getInput(-1, sec.menu.done.key) then
|
|
local f = t[tbl.item].itemname
|
|
if tbl.submenu[f].loop ~= nil then
|
|
sndPlay(motif.Snd, sec.cursor.done.snd[1], sec.cursor.done.snd[2])
|
|
menu.currentMenu[1] = tbl.submenu[f].loop
|
|
main.f_menuSnap(sec)
|
|
elseif not menu.t_itemname[f](tbl, tbl.item, tbl.cursorPosY, tbl.moveTxt, sec) then
|
|
return
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
menu.t_vardisplayPointers = {}
|
|
|
|
-- Associative elements table storing functions returning current setting values
|
|
-- rendered alongside menu item name. Can be appended via external module.
|
|
menu.t_vardisplay = {
|
|
['dummycontrol'] = function()
|
|
return menu.t_valuename.dummycontrol[menu.dummycontrol or 1].displayname
|
|
end,
|
|
['ailevel'] = function()
|
|
return menu.t_valuename.ailevel[menu.ailevel or gameOption('Options.Difficulty')].displayname
|
|
end,
|
|
['dummymode'] = function()
|
|
return menu.t_valuename.dummymode[menu.dummymode or 1].displayname
|
|
end,
|
|
['guardmode'] = function()
|
|
return menu.t_valuename.guardmode[menu.guardmode or 1].displayname
|
|
end,
|
|
['fallrecovery'] = function()
|
|
return menu.t_valuename.fallrecovery[menu.fallrecovery or 1].displayname
|
|
end,
|
|
['distance'] = function()
|
|
return menu.t_valuename.distance[menu.distance or 1].displayname
|
|
end,
|
|
['buttonjam'] = function()
|
|
return menu.t_valuename.buttonjam[menu.buttonjam or 1].displayname
|
|
end,
|
|
}
|
|
|
|
-- Returns setting value rendered alongside menu item name (calls appropriate
|
|
-- function from menu or options t_vardisplay table)
|
|
function menu.f_vardisplay(itemname)
|
|
if menu.t_vardisplay[itemname] ~= nil then
|
|
return menu.t_vardisplay[itemname]()
|
|
end
|
|
if options.t_vardisplay[itemname] ~= nil then
|
|
return options.t_vardisplay[itemname]()
|
|
end
|
|
return ''
|
|
end
|
|
|
|
-- Table storing arrays with data used for different pause menu types generation.
|
|
-- Can be appended via external module but not necessary - can specify gamemode-specific [<gamemode> Pause Menu] sections in `system.def` instead.
|
|
menu.t_menus = {
|
|
{id = 'menu', sec = motif.pause_menu.pause_menu, bg = motif.pausebgdef.pausebgdef, movelist = true},
|
|
{id = 'training', sec = motif.pause_menu.training_pause_menu, bg = motif.pausebgdef.trainingpausebgdef, movelist = true},
|
|
}
|
|
menu.t_menuIndex = {}
|
|
|
|
local function f_pauseMenuKey(gamemodeName)
|
|
gamemodeName = tostring(gamemodeName or ''):lower()
|
|
gamemodeName = gamemodeName:gsub('%s+', '_')
|
|
if gamemodeName == '' then
|
|
return ''
|
|
end
|
|
return gamemodeName .. '_pause_menu'
|
|
end
|
|
|
|
local function f_pauseMenuIdFromKey(key)
|
|
key = tostring(key or ''):lower()
|
|
if key:sub(-11) == '_pause_menu' then
|
|
key = key:sub(1, -12)
|
|
end
|
|
return key
|
|
end
|
|
|
|
local function f_pauseMenuBgKey(gamemodeName)
|
|
gamemodeName = tostring(gamemodeName or ''):lower()
|
|
gamemodeName = gamemodeName:gsub('%s+', '_')
|
|
if gamemodeName == '' then
|
|
return ''
|
|
end
|
|
return gamemodeName .. 'pausebgdef'
|
|
end
|
|
|
|
local function f_registerPauseMenu(id, sec, bg, movelist)
|
|
if id == '' or sec == nil then
|
|
return
|
|
end
|
|
for i = 1, #menu.t_menus do
|
|
if menu.t_menus[i].id == id then
|
|
return
|
|
end
|
|
end
|
|
table.insert(menu.t_menus, {id = id, sec = sec, bg = bg, movelist = movelist})
|
|
end
|
|
|
|
local function f_indexPauseMenus()
|
|
menu.t_menuIndex = {}
|
|
for i = 1, #menu.t_menus do
|
|
menu.t_menuIndex[menu.t_menus[i].id] = menu.t_menus[i]
|
|
end
|
|
end
|
|
|
|
-- Dynamically generates all menus and submenus
|
|
function menu.f_start()
|
|
if motif.pause_menu ~= nil then
|
|
for k, sec in pairs(motif.pause_menu) do
|
|
local id = f_pauseMenuIdFromKey(k)
|
|
if id ~= '' and id ~= 'pause_menu' then
|
|
local bg = motif.pausebgdef.pausebgdef
|
|
local bgKey = f_pauseMenuBgKey(id)
|
|
if bgKey ~= '' and motif.pausebgdef ~= nil and motif.pausebgdef[bgKey] ~= nil then
|
|
bg = motif.pausebgdef[bgKey]
|
|
end
|
|
f_registerPauseMenu(id, sec, bg, true)
|
|
end
|
|
end
|
|
end
|
|
f_indexPauseMenus()
|
|
for k, v in ipairs(menu.t_menus) do
|
|
menu[v.id] = {
|
|
title = main.f_itemnameUpper(v.sec.title.text, v.sec.menu.title.uppercase),
|
|
cursorPosY = 1,
|
|
moveTxt = 0,
|
|
item = 1,
|
|
submenu = {},
|
|
items = {}
|
|
}
|
|
menu[v.id].loop = menu.f_createMenu(menu[v.id], v.sec, v.bg, true)
|
|
local w = main.f_menuWindow(v.sec.menu)
|
|
local t_pos = {} --for storing current table position
|
|
local lastNum = 0
|
|
for i, suffix in ipairs(v.sec.menu.itemname_order) do
|
|
for j, c in ipairs(main.f_strsplit('_', suffix)) do --split using "_" delimiter
|
|
--appending the menu table
|
|
if j == 1 then --first string after menu.itemname (either reserved one or custom submenu assignment)
|
|
if menu[v.id].submenu[c] == nil or c:match("^spacer%d*$") then
|
|
menu[v.id].submenu[c] = {}
|
|
menu[v.id].submenu[c].title = main.f_itemnameUpper(v.sec.menu.itemname[suffix], v.sec.menu.title.uppercase)
|
|
if menu.t_itemname[c] == nil and not c:match("^spacer%d*$") then
|
|
menu[v.id].submenu[c].cursorPosY = 1
|
|
menu[v.id].submenu[c].moveTxt = 0
|
|
menu[v.id].submenu[c].item = 1
|
|
menu[v.id].submenu[c].submenu = {}
|
|
menu[v.id].submenu[c].items = {}
|
|
menu[v.id].submenu[c].loop = menu.f_createMenu(menu[v.id].submenu[c], v.sec, v.bg, false)
|
|
end
|
|
if not suffix:match(c .. '_') then
|
|
table.insert(menu[v.id].items, {
|
|
itemname = c,
|
|
displayname = v.sec.menu.itemname[suffix],
|
|
paramname = suffix,
|
|
vardisplay = menu.f_vardisplay(c),
|
|
selected = false,
|
|
})
|
|
table.insert(menu.t_vardisplayPointers, menu[v.id].items[#menu[v.id].items])
|
|
end
|
|
end
|
|
t_pos = menu[v.id].submenu[c]
|
|
t_pos.name = c
|
|
else --following strings
|
|
if t_pos.submenu[c] == nil or c:match("^spacer%d*$") then
|
|
t_pos.submenu[c] = {}
|
|
t_pos.submenu[c].title = main.f_itemnameUpper(v.sec.menu.itemname[suffix], v.sec.menu.title.uppercase)
|
|
if menu.t_itemname[c] == nil and not c:match("^spacer%d*$") then
|
|
t_pos.submenu[c].cursorPosY = 1
|
|
t_pos.submenu[c].moveTxt = 0
|
|
t_pos.submenu[c].item = 1
|
|
t_pos.submenu[c].submenu = {}
|
|
t_pos.submenu[c].items = {}
|
|
t_pos.submenu[c].loop = menu.f_createMenu(t_pos.submenu[c], v.sec, v.bg, false)
|
|
end
|
|
table.insert(t_pos.items, {
|
|
itemname = c,
|
|
displayname = v.sec.menu.itemname[suffix],
|
|
paramname = suffix,
|
|
vardisplay = menu.f_vardisplay(c),
|
|
selected = false,
|
|
})
|
|
table.insert(menu.t_vardisplayPointers, t_pos.items[#t_pos.items])
|
|
end
|
|
if j > lastNum then
|
|
t_pos = t_pos.submenu[c]
|
|
t_pos.name = c
|
|
end
|
|
end
|
|
lastNum = j
|
|
end
|
|
end
|
|
-- Runtime platform filtering
|
|
if getRuntimeOS() == 'android' then
|
|
local excluded = {keyboard = true}
|
|
main.f_pruneMenu(menu[v.id], excluded)
|
|
main.f_prunePointers(menu.t_vardisplayPointers, excluded)
|
|
end
|
|
-- Menu windows
|
|
textImgSetWindow(v.sec.menu.item.selected.active.TextSpriteData, w[1], w[2], w[3], w[4])
|
|
textImgSetWindow(v.sec.menu.item.active.TextSpriteData, w[1], w[2], w[3], w[4])
|
|
textImgSetWindow(v.sec.menu.item.value.active.TextSpriteData, w[1], w[2], w[3], w[4])
|
|
textImgSetWindow(v.sec.menu.item.selected.TextSpriteData, w[1], w[2], w[3], w[4])
|
|
textImgSetWindow(v.sec.menu.item.TextSpriteData, w[1], w[2], w[3], w[4])
|
|
textImgSetWindow(v.sec.menu.item.value.TextSpriteData, w[1], w[2], w[3], w[4])
|
|
--for _, v2 in pairs(v.sec.menu.item.bg) do
|
|
-- animSetWindow(v2.AnimData, w[1], w[2], w[3], w[4])
|
|
--end
|
|
--for _, v2 in pairs(v.sec.menu.item.active.bg) do
|
|
-- animSetWindow(v2.AnimData, w[1], w[2], w[3], w[4])
|
|
--end
|
|
if gameOption('Debug.DumpLuaTables') then main.f_printTable(menu[v.id], 'debug/t_' .. v.id .. 'Menu.txt') end
|
|
-- Move list
|
|
if v.movelist then
|
|
local t = v.sec.movelist
|
|
if t.window.margins.y[1] ~= 0 or t.window.margins.y[2] ~= 0 then
|
|
local fontProps = motif.files.font['font' .. v.sec.movelist.text.font[1]]
|
|
if fontProps ~= nil then
|
|
menu.movelistW = {
|
|
0,
|
|
math.max(0, t.pos[2] + t.text.offset[2] - t.window.margins.y[1]),
|
|
t.pos[1] + t.text.offset[1] + t.window.width,
|
|
t.pos[2] + t.text.offset[2] + (t.window.visibleitems - 1) * main.f_round((fontProps.size[2] + fontProps.spacing[2]) * t.text.scale[2] + t.text.spacing[2]) + t.window.margins.y[2] + math.max(0, t.glyphs.offset[2])
|
|
}
|
|
textImgSetWindow(t.text.TextSpriteData, menu.movelistW[1], menu.movelistW[2], menu.movelistW[3], menu.movelistW[4])
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Called from start.lua right before game() function to reset training menu values and p2 settings for a new match
|
|
function menu.f_trainingReset()
|
|
for k, _ in pairs(menu.t_valuename) do
|
|
menu[k] = 1
|
|
end
|
|
menu.ailevel = gameOption('Options.Difficulty')
|
|
for _, v in ipairs(menu.t_vardisplayPointers) do
|
|
v.vardisplay = menu.f_vardisplay(v.itemname)
|
|
end
|
|
player(2)
|
|
setAILevel(0)
|
|
end
|
|
|
|
hook.add('loop#training', 'trainingSettings', function()
|
|
if not roundStart() then return end
|
|
player(2)
|
|
setAILevel(menu.dummycontrol == 2 and menu.ailevel or 0)
|
|
mapSet('_iksys_trainingDummyControl', menu.dummycontrol - 1)
|
|
mapSet('_iksys_trainingDummyMode', menu.dummymode - 1)
|
|
mapSet('_iksys_trainingGuardMode', menu.guardmode - 1)
|
|
mapSet('_iksys_trainingFallRecovery', menu.fallrecovery - 1)
|
|
mapSet('_iksys_trainingDistance', menu.distance - 1)
|
|
mapSet('_iksys_trainingButtonJam', menu.buttonjam - 1)
|
|
end)
|
|
|
|
menu.movelistChar = 1
|
|
function menu.f_init()
|
|
esc(false)
|
|
main.pauseMenuActive = true
|
|
bgReset(motif.optionbgdef.BGDef)
|
|
local id = f_pauseMenuIdFromKey(f_pauseMenuKey(gameMode()))
|
|
if id == '' or menu.t_menuIndex == nil or menu.t_menuIndex[id] == nil then
|
|
id = 'menu'
|
|
end
|
|
if menu.t_menuIndex ~= nil and menu.t_menuIndex[id] ~= nil then
|
|
local entry = menu.t_menuIndex[id]
|
|
sndPlay(motif.Snd, entry.sec.enter.snd[1], entry.sec.enter.snd[2])
|
|
bgReset(entry.bg.BGDef)
|
|
if menu[id] ~= nil and menu[id].loop ~= nil then
|
|
menu.currentMenu = {menu[id].loop, menu[id].loop}
|
|
menu.currentMenuId = id
|
|
else
|
|
menu.currentMenu = {menu.menu.loop, menu.menu.loop}
|
|
menu.currentMenuId = 'menu'
|
|
end
|
|
else
|
|
sndPlay(motif.Snd, motif.pause_menu.pause_menu.enter.snd[1], motif.pause_menu.pause_menu.enter.snd[2])
|
|
bgReset(motif.pausebgdef.pausebgdef.BGDef)
|
|
menu.currentMenu = {menu.menu.loop, menu.menu.loop}
|
|
menu.currentMenuId = 'menu'
|
|
end
|
|
end
|
|
|
|
menu.pauseExitDelay = -1
|
|
|
|
function menu.f_run()
|
|
local entry = nil
|
|
if menu.t_menuIndex ~= nil then
|
|
if menu.currentMenuId ~= nil and menu.t_menuIndex[menu.currentMenuId] ~= nil then
|
|
entry = menu.t_menuIndex[menu.currentMenuId]
|
|
else
|
|
local id = f_pauseMenuIdFromKey(f_pauseMenuKey(gameMode()))
|
|
if id ~= '' and menu.t_menuIndex[id] ~= nil then
|
|
entry = menu.t_menuIndex[id]
|
|
elseif menu.t_menuIndex['menu'] ~= nil then
|
|
entry = menu.t_menuIndex['menu']
|
|
end
|
|
end
|
|
end
|
|
local sec = motif.pause_menu.pause_menu
|
|
local bg = motif.pausebgdef.pausebgdef
|
|
if entry ~= nil and entry.sec ~= nil and entry.bg ~= nil then
|
|
sec = entry.sec
|
|
bg = entry.bg
|
|
end
|
|
--draw overlay
|
|
rectDraw(sec.overlay.RectData)
|
|
--pause exit delay
|
|
if menu.pauseExitDelay >= 0 then
|
|
if menu.pauseExitDelay > 0 then
|
|
menu.pauseExitDelay = menu.pauseExitDelay - 1
|
|
else
|
|
-- Keep the game paused. Go owns the fade-out/fade-in handoff and unpauses afterwards.
|
|
main.pauseMenuActive = false
|
|
end
|
|
end
|
|
--Button Config
|
|
if menu.itemname == 'keyboard' or menu.itemname == 'gamepad' then
|
|
if menu.itemname == 'keyboard' then
|
|
options.f_keyCfg('Keys', menu.itemname, bg, true)
|
|
else
|
|
options.f_keyCfg('Joystick', menu.itemname, bg, true)
|
|
end
|
|
--Command List
|
|
elseif menu.itemname == 'commandlist' then
|
|
menu.f_commandlistRender(sec, menu.t_movelists[menu.movelistChar])
|
|
--Menu
|
|
else
|
|
menu.currentMenu[1]()
|
|
end
|
|
local active = main.pauseMenuActive
|
|
if not active then
|
|
menu.pauseExitDelay = -1
|
|
end
|
|
return active
|
|
end
|
|
|
|
-- Reset selection/scroll state recursively for a menu table (root + submenus)
|
|
local function f_resetMenuState(tbl)
|
|
if type(tbl) ~= "table" then return end
|
|
-- Reset cursor/scroll
|
|
tbl.cursorPosY = 1
|
|
tbl.moveTxt = 0
|
|
tbl.item = 1
|
|
-- Clear any "selected" flags on items (if used by custom menus)
|
|
if type(tbl.items) == "table" then
|
|
for i = 1, #tbl.items do
|
|
if type(tbl.items[i]) == "table" then
|
|
tbl.items[i].selected = false
|
|
end
|
|
end
|
|
end
|
|
-- Recurse into submenus
|
|
if type(tbl.submenu) == "table" then
|
|
for _, sub in pairs(tbl.submenu) do
|
|
f_resetMenuState(sub)
|
|
end
|
|
end
|
|
end
|
|
|
|
function menu.f_reset()
|
|
-- exit any special screens rendered by menu.f_run()
|
|
menu.itemname = ''
|
|
-- Reset movelist selector (command list screen)
|
|
menu.movelistChar = 1
|
|
-- Reset tween caches
|
|
if menu.t_menus ~= nil then
|
|
for i = 1, #menu.t_menus do
|
|
local sec = menu.t_menus[i].sec
|
|
if sec ~= nil then
|
|
sec.menuTweenData = nil
|
|
sec.boxCursorData = nil
|
|
end
|
|
end
|
|
end
|
|
-- Determine which root menu is active and reset its cursor/item/scroll (and all submenus)
|
|
if menu.currentMenu ~= nil and menu.currentMenu[2] ~= nil then
|
|
if menu.currentMenuId ~= nil and menu[menu.currentMenuId] ~= nil then
|
|
f_resetMenuState(menu[menu.currentMenuId])
|
|
elseif menu.training ~= nil and menu.training.loop ~= nil and menu.currentMenu[2] == menu.training.loop then
|
|
f_resetMenuState(menu.training)
|
|
else
|
|
f_resetMenuState(menu.menu)
|
|
end
|
|
end
|
|
-- Force snap on next calc so we don't keep old scroll offsets.
|
|
main.menuSnap = true
|
|
-- restore root menu loop
|
|
if menu.currentMenu ~= nil and menu.currentMenu[2] ~= nil then
|
|
menu.currentMenu[1] = menu.currentMenu[2]
|
|
end
|
|
end
|
|
|
|
function menuInit()
|
|
return menu.f_init()
|
|
end
|
|
|
|
function menuRun()
|
|
return menu.f_run()
|
|
end
|
|
|
|
function menuReset()
|
|
return menu.f_reset()
|
|
end
|
|
|
|
--;===========================================================
|
|
--; COMMAND LIST
|
|
--;===========================================================
|
|
function colorFromHex(h)
|
|
h = tostring(h)
|
|
if h:sub(0, 1) =="#" then h = h:sub(2, -1) end
|
|
if h:sub(0, 2) =="0x" then h = h:sub(3, -1) end
|
|
local r = tonumber(h:sub(1, 2), 16) or 255
|
|
local g = tonumber(h:sub(3, 4), 16) or 255
|
|
local b = tonumber(h:sub(5, 6), 16) or 255
|
|
local src = tonumber(h:sub(7, 8), 16) or 255
|
|
local dst = tonumber(h:sub(9, 10), 16) or 0
|
|
return {r = r, g = g, b = b, src = src, dst = dst}
|
|
end
|
|
|
|
local function f_commandlistData(t, str, align, col)
|
|
local t_insert = {}
|
|
str = str .. '<#>'
|
|
for m1, m2 in str:gmatch('(.-)<([^<>%s]+)>') do
|
|
if m1 ~= '' then
|
|
table.insert(t_insert, {glyph = false, text = m1, align = align, col = col})
|
|
end
|
|
m2 = m2:gsub('<', '<'):gsub('>', '>'):gsub('&', '&')
|
|
if not m2:match('^#[A-Za-z0-9]+$') and not m2:match('^/$') and not m2:match('^#$') then
|
|
table.insert(t_insert, {glyph = true, text = m2, align = align, col = col})
|
|
elseif m2:match('^#[A-Za-z0-9]+$') then
|
|
col = colorFromHex(m2)
|
|
elseif m2:match('^/$') then
|
|
col = {}
|
|
end
|
|
end
|
|
if align == -1 then
|
|
for i = #t_insert, 1, -1 do
|
|
table.insert(t, t_insert[i])
|
|
end
|
|
else
|
|
for i = 1, #t_insert do
|
|
table.insert(t, t_insert[i])
|
|
end
|
|
end
|
|
return t, col
|
|
end
|
|
|
|
function menu.f_commandlistParse()
|
|
menu.t_movelists = {}
|
|
for side, tbl in ipairs({start.p[1].t_selected, start.p[2].t_selected}) do
|
|
for member, sel in ipairs(tbl) do
|
|
if sel.movelistLine == nil then
|
|
sel.movelistLine = 1
|
|
end
|
|
local pn = side
|
|
if member > 1 then
|
|
pn = pn + (member - 1) * 2
|
|
end
|
|
if player(pn) and aiLevel() == 0 then
|
|
local movelist = getMovelist()
|
|
if sel.movelistText ~= movelist then
|
|
sel.movelistText = movelist
|
|
sel.commandlist = nil
|
|
sel.movelistLine = 1
|
|
if movelist ~= '' then
|
|
-- Replace glyph tokens with <token> for later lookup in motif.glyphs.
|
|
for k, v in main.f_sortKeys(motif.glyphs, function(t, a, b) return string.len(a) > string.len(b) end) do
|
|
local s = movelist
|
|
movelist = s:gsub('()' .. main.f_escapePattern(k), function(pos)
|
|
-- If the match starts immediately after a '<', it's already inside a tag.
|
|
-- Leave it unchanged to prevent nested replacements.
|
|
if pos > 1 and s:sub(pos - 1, pos - 1) == '<' then
|
|
return k
|
|
end
|
|
local escaped = k:gsub('&', '&'):gsub('<', '<'):gsub('>', '>')
|
|
return '<' .. escaped .. '>'
|
|
end)
|
|
end
|
|
local t = {}
|
|
local col = {}
|
|
for line in movelist:gmatch('([^\n]*)\n?') do
|
|
line = line:gsub('%s+$', '')
|
|
local subt = {}
|
|
for m in line:gmatch('( *[^ ]+)') do
|
|
local tabs = 0
|
|
m = m:gsub('^( *)', function(m1)
|
|
tabs = string.len(m1)
|
|
return ''
|
|
end)
|
|
local align = 1 --left align
|
|
if tabs == 1 then
|
|
align = 0 --center align
|
|
elseif tabs > 1 then
|
|
align = -1 --right align
|
|
end
|
|
subt, col = f_commandlistData(subt, m, align, col)
|
|
end
|
|
table.insert(t, subt)
|
|
end
|
|
t[#t] = nil --blank line produced by regexp matching
|
|
sel.commandlist = t
|
|
end
|
|
end
|
|
table.insert(menu.t_movelists, {
|
|
pn = pn,
|
|
name = displayName(),
|
|
tbl = sel,
|
|
commandlist = sel.commandlist,
|
|
})
|
|
end
|
|
end
|
|
end
|
|
if #menu.t_movelists == 0 then
|
|
table.insert(menu.t_movelists, {
|
|
pn = 1,
|
|
name = "",
|
|
tbl = {movelistLine = 1},
|
|
commandlist = nil,
|
|
})
|
|
end
|
|
if menu.movelistChar > #menu.t_movelists then
|
|
menu.movelistChar = 1
|
|
end
|
|
if gameOption('Debug.DumpLuaTables') then main.f_printTable(menu.t_movelists, "debug/t_movelists.txt") end
|
|
end
|
|
|
|
function menu.f_commandlistRender(sec, t)
|
|
local cmdList = {}
|
|
if t.commandlist ~= nil then
|
|
cmdList = t.commandlist
|
|
else
|
|
table.insert(cmdList, {{glyph = false, text = sec.movelist.text.text, align = 1, col = {}}})
|
|
end
|
|
if esc() or getInput(-1, sec.menu.cancel.key, sec.menu.done.key) then
|
|
sndPlay(motif.Snd, sec.cancel.snd[1], sec.cancel.snd[2])
|
|
menu.itemname = ''
|
|
return
|
|
elseif getInput(-1, sec.menu.subtract.key) and #menu.t_movelists > 1 then
|
|
sndPlay(motif.Snd, sec.cursor.move.snd[1], sec.cursor.move.snd[2])
|
|
menu.movelistChar = menu.movelistChar - 1
|
|
if menu.movelistChar < 1 then
|
|
menu.movelistChar = #menu.t_movelists
|
|
end
|
|
elseif getInput(-1, sec.menu.add.key) and #menu.t_movelists > 1 then
|
|
sndPlay(motif.Snd, sec.cursor.move.snd[1], sec.cursor.move.snd[2])
|
|
menu.movelistChar = menu.movelistChar + 1
|
|
if menu.movelistChar > #menu.t_movelists then
|
|
menu.movelistChar = 1
|
|
end
|
|
elseif getInput(-1, sec.menu.previous.key) and t.tbl.movelistLine > 1 then
|
|
sndPlay(motif.Snd, sec.cursor.move.snd[1], sec.cursor.move.snd[2])
|
|
t.tbl.movelistLine = t.tbl.movelistLine - 1
|
|
elseif getInput(-1, sec.menu.next.key) and t.tbl.movelistLine <= #cmdList - sec.movelist.window.visibleitems then
|
|
sndPlay(motif.Snd, sec.cursor.move.snd[1], sec.cursor.move.snd[2])
|
|
t.tbl.movelistLine = t.tbl.movelistLine + 1
|
|
end
|
|
--draw overlay
|
|
rectDraw(sec.movelist.overlay.RectData)
|
|
--draw title
|
|
textImgReset(sec.movelist.title.TextSpriteData)
|
|
textImgSetText(sec.movelist.title.TextSpriteData, main.f_itemnameUpper(string.format(sec.movelist.title.text, t.name), sec.movelist.title.uppercase))
|
|
textImgDraw(sec.movelist.title.TextSpriteData)
|
|
--draw commands
|
|
local i = 0
|
|
for n = t.tbl.movelistLine, math.min(t.tbl.movelistLine + sec.movelist.window.visibleitems + 1, #cmdList) do
|
|
i = i + 1
|
|
local alignOffset = 0
|
|
local lengthOffset = 0
|
|
local align = 1
|
|
local width = 0
|
|
for k, v in ipairs(cmdList[n]) do
|
|
if v.text ~= '' then
|
|
alignOffset = 0
|
|
if v.align == 0 then --center align
|
|
alignOffset = sec.movelist.window.width * 0.5
|
|
elseif v.align == -1 then --right align
|
|
alignOffset = sec.movelist.window.width
|
|
end
|
|
if v.align ~= align then
|
|
lengthOffset = 0
|
|
align = v.align
|
|
end
|
|
local fontProps = motif.files.font['font' .. sec.movelist.text.font[1]]
|
|
--render glyph
|
|
if v.glyph and motif.glyphs[v.text] ~= nil then
|
|
local g = motif.glyphs[v.text]
|
|
if g.Size ~= nil and g.AnimData ~= nil then
|
|
local scaleX = fontProps.size[2] * sec.movelist.text.scale[2] / g.Size[2] * sec.movelist.glyphs.scale[1]
|
|
local scaleY = fontProps.size[2] * sec.movelist.text.scale[2] / g.Size[2] * sec.movelist.glyphs.scale[2]
|
|
if v.align == -1 then
|
|
alignOffset = alignOffset - g.Size[1] * scaleX
|
|
end
|
|
animSetScale(g.AnimData, scaleX, scaleY)
|
|
--animSetFacing(g.AnimData, facing)
|
|
animSetPos(
|
|
g.AnimData,
|
|
math.floor(sec.movelist.pos[1] + sec.movelist.text.offset[1] + sec.movelist.glyphs.offset[1] + alignOffset + lengthOffset),
|
|
sec.movelist.pos[2] + sec.movelist.text.offset[2] + sec.movelist.glyphs.offset[2] + main.f_round((fontProps.size[2] + fontProps.spacing[2]) * sec.movelist.text.scale[2] + sec.movelist.text.spacing[2]) * (i - 1)
|
|
)
|
|
animSetWindow(g.AnimData, menu.movelistW[1], menu.movelistW[2], menu.movelistW[3], menu.movelistW[4])
|
|
--animUpdate(g.AnimData)
|
|
animDraw(g.AnimData)
|
|
if k < #cmdList[n] then
|
|
width = g.Size[1] * scaleX + sec.movelist.glyphs.spacing[1]
|
|
end
|
|
end
|
|
--render text
|
|
else
|
|
textImgReset(sec.movelist.text.TextSpriteData)
|
|
local align = v.align
|
|
if align == 0 and lengthOffset ~= 0 then
|
|
align = 1
|
|
end
|
|
textImgSetAlign(sec.movelist.text.TextSpriteData, align)
|
|
textImgSetColor(
|
|
sec.movelist.text.TextSpriteData,
|
|
v.col.r or sec.movelist.text.font[4],
|
|
v.col.g or sec.movelist.text.font[5],
|
|
v.col.b or sec.movelist.text.font[6],
|
|
v.col.a or sec.movelist.text.font[7]
|
|
)
|
|
textImgAddPos(
|
|
sec.movelist.text.TextSpriteData,
|
|
alignOffset + lengthOffset,
|
|
main.f_round((fontProps.size[2] + fontProps.spacing[2]) * sec.movelist.text.scale[2] + sec.movelist.text.spacing[2]) * (i - 1)
|
|
)
|
|
textImgSetText(sec.movelist.text.TextSpriteData, v.text)
|
|
textImgDraw(sec.movelist.text.TextSpriteData)
|
|
if k < #cmdList[n] then
|
|
width = textImgGetTextWidth(sec.movelist.text.TextSpriteData, v.text) * sec.movelist.text.scale[1] + sec.movelist.text.spacing[1]
|
|
end
|
|
end
|
|
if v.align == 0 and not v.glyph and lengthOffset == 0 then
|
|
lengthOffset = lengthOffset + width / 2
|
|
elseif v.align == -1 then
|
|
lengthOffset = lengthOffset - width
|
|
else
|
|
lengthOffset = lengthOffset + width
|
|
end
|
|
end
|
|
end
|
|
end
|
|
--draw scroll arrows
|
|
if #cmdList > sec.movelist.window.visibleitems then
|
|
if t.tbl.movelistLine > 1 then
|
|
animUpdate(sec.movelist.arrow.up.AnimData)
|
|
animDraw(sec.movelist.arrow.up.AnimData)
|
|
end
|
|
if t.tbl.movelistLine <= #cmdList - sec.movelist.window.visibleitems then
|
|
animUpdate(sec.movelist.arrow.down.AnimData)
|
|
animDraw(sec.movelist.arrow.down.AnimData)
|
|
end
|
|
end
|
|
end
|
|
|
|
return menu
|