Merge pull request #1368 from cracyc/lua_dats

Move UI dats to lua plugin
This commit is contained in:
Miodrag Milanović 2016-09-07 14:27:35 +02:00 committed by GitHub
commit fa4b5bdee6
31 changed files with 1742 additions and 1268 deletions

View File

@ -0,0 +1,245 @@
local default_text =
{
-- Alphabetic Buttons (NeoGeo): A~D,H,Z
["A"] = 1, -- BTN_A
["B"] = 2, -- BTN_B
["C"] = 3, -- BTN_C
["D"] = 4, -- BTN_D
["H"] = 8, -- BTN_H
["Z"] = 26, -- BTN_Z
-- Numerical Buttons (Capcom): 1~10
["a"] = 27, -- BTN_1
["b"] = 28, -- BTN_2
["c"] = 29, -- BTN_3
["d"] = 30, -- BTN_4
["e"] = 31, -- BTN_5
["f"] = 32, -- BTN_6
["g"] = 33, -- BTN_7
["h"] = 34, -- BTN_8
["i"] = 35, -- BTN_9
["j"] = 36, -- BTN_10
-- Directions of Arrow, Joystick Ball
["+"] = 39, -- BTN_+
["."] = 40, -- DIR_...
["1"] = 41, -- DIR_1
["2"] = 42, -- DIR_2
["3"] = 43, -- DIR_3
["4"] = 44, -- DIR_4
["5"] = 45, -- Joystick Ball
["6"] = 46, -- DIR_6
["7"] = 47, -- DIR_7
["8"] = 48, -- DIR_8
["9"] = 49, -- DIR_9
["N"] = 50, -- DIR_N
-- Special Buttons
["S"] = 51, -- BTN_START
["P"] = 53, -- BTN_PUNCH
["K"] = 54, -- BTN_KICK
["G"] = 55, -- BTN_GUARD
-- Composition of Arrow Directions
["!"] = 90, -- Arrow
["k"] = 100, -- Half Circle Back
["l"] = 101, -- Half Circle Front Up
["m"] = 102, -- Half Circle Front
["n"] = 103, -- Half Circle Back Up
["o"] = 104, -- 1/4 Cir For 2 Down
["p"] = 105, -- 1/4 Cir Down 2 Back
["q"] = 106, -- 1/4 Cir Back 2 Up
["r"] = 107, -- 1/4 Cir Up 2 For
["s"] = 108, -- 1/4 Cir Back 2 Down
["t"] = 109, -- 1/4 Cir Down 2 For
["u"] = 110, -- 1/4 Cir For 2 Up
["v"] = 111, -- 1/4 Cir Up 2 Back
["w"] = 112, -- Full Clock Forward
["x"] = 113, -- Full Clock Back
["y"] = 114, -- Full Count Forward
["z"] = 115, -- Full Count Back
["L"] = 116, -- 2x Forward
["M"] = 117, -- 2x Back
["Q"] = 118, -- Dragon Screw Forward
["R"] = 119, -- Dragon Screw Back
-- Big letter Text
["^"] = 121, -- AIR
["?"] = 122, -- DIR
["X"] = 124, -- TAP
-- Condition of Positions
["|"] = 125, -- Jump
["O"] = 126, -- Hold
["-"] = 127, -- Air
["="] = 128, -- Squatting
["~"] = 131, -- Charge
-- Special Character Text
["`"] = 135, -- Small Dot
["@"] = 136, -- Double Ball
[")"] = 137, -- Single Ball
["("] = 138, -- Solid Ball
["*"] = 139, -- Star
["&"] = 140, -- Solid star
["%"] = 141, -- Triangle
["$"] = 142, -- Solid Triangle
["#"] = 143, -- Double Square
["]"] = 144, -- Single Square
["["] = 145, -- Solid Square
["{"] = 146, -- Down Triangle
["}"] = 147, -- Solid Down Triangle
["<"] = 148, -- Diamond
[">"] = 149, -- Solid Diamond
}
local expand_text =
{
-- Alphabetic Buttons (NeoGeo): S (Slash Button)
["s"] = 19, -- BTN_S
-- Special Buttons
["S"] = 52, -- BTN_SELECT
-- Multiple Punches & Kicks
["E"] = 57, -- Light Punch
["F"] = 58, -- Middle Punch
["G"] = 59, -- Strong Punch
["H"] = 60, -- Light Kick
["I"] = 61, -- Middle Kick
["J"] = 62, -- Strong Kick
["T"] = 63, -- 3 Kick
["U"] = 64, -- 3 Punch
["V"] = 65, -- 2 Kick
["W"] = 66, -- 2 Pick
-- Composition of Arrow Directions
["!"] = 91, -- Continue Arrow
-- Charge of Arrow Directions
["1"] = 92, -- Charge DIR_1
["2"] = 93, -- Charge DIR_2
["3"] = 94, -- Charge DIR_3
["4"] = 95, -- Charge DIR_4
["6"] = 96, -- Charge DIR_6
["7"] = 97, -- Charge DIR_7
["8"] = 98, -- Charge DIR_8
["9"] = 99, -- Charge DIR_9
-- Big letter Text
["M"] = 123, -- MAX
-- Condition of Positions
["-"] = 129, -- Close
["="] = 130, -- Away
["*"] = 132, -- Serious Tap
["?"] = 133, -- Any Button
}
local convert_text =
{
-- Alphabetic Buttons: A~Z
["A-button"] = 1, -- BTN_A
["B-button"] = 2, -- BTN_B
["C-button"] = 3, -- BTN_C
["D-button"] = 4, -- BTN_D
["E-button"] = 5, -- BTN_E
["F-button"] = 6, -- BTN_F
["G-button"] = 7, -- BTN_G
["H-button"] = 8, -- BTN_H
["I-button"] = 9, -- BTN_I
["J-button"] = 10, -- BTN_J
["K-button"] = 11, -- BTN_K
["L-button"] = 12, -- BTN_L
["M-button"] = 13, -- BTN_M
["N-button"] = 14, -- BTN_N
["O-button"] = 15, -- BTN_O
["P-button"] = 16, -- BTN_P
["Q-button"] = 17, -- BTN_Q
["R-button"] = 18, -- BTN_R
["S-button"] = 19, -- BTN_S
["T-button"] = 20, -- BTN_T
["U-button"] = 21, -- BTN_U
["V-button"] = 22, -- BTN_V
["W-button"] = 23, -- BTN_W
["X-button"] = 24, -- BTN_X
["Y-button"] = 25, -- BTN_Y
["Z-button"] = 26, -- BTN_Z
-- Special Moves and Buttons
["decrease"] = 37, -- BTN_DEC
["increase"] = 38, -- BTN_INC
["BALL"] = 45, -- Joystick Ball
["start"] = 51, -- BTN_START
["select"] = 52, -- BTN_SELECT
["punch"] = 53, -- BTN_PUNCH
["kick"] = 54, -- BTN_KICK
["guard"] = 55, -- BTN_GUARD
["L-punch"] = 57, -- Light Punch
["M-punch"] = 58, -- Middle Punch
["S-punch"] = 59, -- Strong Punch
["L-kick"] = 60, -- Light Kick
["M-kick"] = 61, -- Middle Kick
["S-kick"] = 62, -- Strong Kick
["3-kick"] = 63, -- 3 Kick
["3-punch"] = 64, -- 3 Punch
["2-kick"] = 65, -- 2 Kick
["2-punch"] = 66, -- 2 Pick
-- Custom Buttons and Cursor Buttons
["custom1"] = 67, -- CUSTOM_1
["custom2"] = 68, -- CUSTOM_2
["custom3"] = 69, -- CUSTOM_3
["custom4"] = 70, -- CUSTOM_4
["custom5"] = 71, -- CUSTOM_5
["custom6"] = 72, -- CUSTOM_6
["custom7"] = 73, -- CUSTOM_7
["custom8"] = 74, -- CUSTOM_8
["up"] = 75, -- (Cursor Up)
["down"] = 76, -- (Cursor Down)
["left"] = 77, -- (Cursor Left)
["right"] = 78, -- (Cursor Right)
-- Player Lever
["lever"] = 79, -- Non Player Lever
["nplayer"] = 80, -- Gray Color Lever
["1player"] = 81, -- 1 Player Lever
["2player"] = 82, -- 2 Player Lever
["3player"] = 83, -- 3 Player Lever
["4player"] = 84, -- 4 Player Lever
["5player"] = 85, -- 5 Player Lever
["6player"] = 86, -- 6 Player Lever
["7player"] = 87, -- 7 Player Lever
["8player"] = 88, -- 8 Player Lever
-- Composition of Arrow Directions
["-->"] = 90, -- Arrow
["==>"] = 91, -- Continue Arrow
["hcb"] = 100, -- Half Circle Back
["huf"] = 101, -- Half Circle Front Up
["hcf"] = 102, -- Half Circle Front
["hub"] = 103, -- Half Circle Back Up
["qfd"] = 104, -- 1/4 Cir For 2 Down
["qdb"] = 105, -- 1/4 Cir Down 2 Back
["qbu"] = 106, -- 1/4 Cir Back 2 Up
["quf"] = 107, -- 1/4 Cir Up 2 For
["qbd"] = 108, -- 1/4 Cir Back 2 Down
["qdf"] = 109, -- 1/4 Cir Down 2 For
["qfu"] = 110, -- 1/4 Cir For 2 Up
["qub"] = 111, -- 1/4 Cir Up 2 Back
["fdf"] = 112, -- Full Clock Forward
["fub"] = 113, -- Full Clock Back
["fuf"] = 114, -- Full Count Forward
["fdb"] = 115, -- Full Count Back
["xff"] = 116, -- 2x Forward
["xbb"] = 117, -- 2x Back
["dsf"] = 118, -- Dragon Screw Forward
["dsb"] = 119, -- Dragon Screw Back
-- Big letter Text
["AIR"] = 121, -- AIR
["DIR"] = 122, -- DIR
["MAX"] = 123, -- MAX
["TAP"] = 124, -- TAP
-- Condition of Positions
["jump"] = 125, -- Jump
["hold"] = 126, -- Hold
["air"] = 127, -- Air
["sit"] = 128, -- Squatting
["close"] = 129, -- Close
["away"] = 130, -- Away
["charge"] = 131, -- Charge
["tap"] = 132, -- Serious Tap
["button"] = 133, -- Any Button
}
local function convert_char(str)
str = str:gsub("@([a-zA-Z%-]+)", function(s) if convert_text[s] then return utf8.char(convert_text[s] + 0xe000) end return s end)
str = str:gsub("_(.)", function(s) if default_text[s] then return utf8.char(default_text[s] + 0xe000) end return s end)
str = str:gsub("%^(.)", function(s) if expand_text[s] then return utf8.char(expand_text[s] + 0xe000) end return s end)
return str
end
return convert_char

View File

@ -0,0 +1,25 @@
local dat = {}
local info, ver
local datread = require("data/load_dat")
datread, ver = datread.open("command.dat", nil)
function dat.check(set, softlist)
if softlist or not datread then
return nil
end
local status
status, info = pcall(datread, "cmd", "info", set)
if not status or not info then
return nil
end
local convert = require("data/button_char")
info = "#jf\n" .. convert(info)
return "Command"
end
function dat.get()
return info
end
return dat

View File

@ -0,0 +1,27 @@
local dat = {}
local ver, info
local datread = require("data/load_dat")
datread, ver = datread.open("gameinit.dat", "# GAMEINIT.DAT")
function dat.check(set, softlist)
if softlist or not datread then
return nil
end
local status
status, info = pcall(datread, "mame", "info", set)
if not status or not info then
return nil
end
return "Gameinit"
end
function dat.get()
return info
end
function dat.ver()
return ver
end
return dat

View File

@ -0,0 +1,803 @@
-- to use this get the package from http://greatstone.free.fr/hi2txt/
-- extract the hi2txt.zip and place it in your history path
local dat = {}
local env = {}
local output
local curset
function dat.check(set, softlist)
if softlist then
return nil
end
local datpath
local function xml_parse()
local file = emu.file(lfs.env_replace(mame_manager:ui():options().entries.historypath:value():gsub("([^;]+)", "%1/hi2txt")), 1)
local ret = file:open(set .. ".xml")
local table
if ret then
return nil
end
datpath = file:fullpath():gsub(".zip", "/")
local data = file:read(file:size())
data = data:match("<hi2txt>(.*)</ *hi2txt>")
local function get_tags(str, parent)
local arr = {}
while str ~= "" do
local tag, attr, stop
tag, attr, stop, str = str:match("<([%w!_%-]+) ?(.-)(/?)[ %-]->(.*)")
if not tag then
return arr
end
if tag:sub(0, 3) ~= "!--" then
local block = {}
if stop ~= "/" then
local nest
nest, str = str:match("(.-)</ *" .. tag .. " *>(.*)")
local children = get_tags(nest, tag)
if not next(children) then
nest = nest:gsub("<!--.-%-%->", "")
nest = nest:gsub("^%s*(.-)%s*$", "%1")
block["text"] = nest
else
block = children
end
end
if attr then
for name, value in attr:gmatch("([-%w]-)=\"(.-)\"") do
block[name] = value:gsub("^(.-)$", "%1")
end
end
if not arr[tag] then
arr[tag] = {}
end
if parent == "structure" or parent == "output" or parent == "format" or parent == "loop" or parent == "concat" then
block["tag"] = tag
arr[#arr + 1] = block
elseif tag == "charset" or tag == "bitmask" then
arr[tag][block["id"]] = block
elseif tag == "case" or tag == "char" then
arr[tag][block["src"]] = block
else
arr[tag][#arr[tag] + 1] = block
end
end
end
return arr
end
return get_tags(data, "")
end
local function parse_table(xml)
local total_size = 0
local s = { "data = open('" .. xml.structure[1].file .. "', size)\noffset = 1\narr = {}" }
local fparam = {}
if xml.bitmask then
local bitmask = "bitmask = {"
for id, masks in pairs(xml.bitmask) do
bitmask = bitmask .. "['" .. id .. "'] = {"
for num, mask in ipairs(masks.character) do
mask = mask:gsub("( )", "")
local newmask = tonumber(mask, 2)
local shift = 0
local count = 8
while (newmask & 1) == 0 do
newmask = newmask >> 1
shift = shift + 1
end
if masks.byte-completion and masks.byte-completion == "no" then
count = 0
while (newmask >> count) & 1 == 1 do
count = count + 1
end
end
bitmask = bitmask .. "{ mask = " .. newmask .. ", ishift = " .. shift .. ", oshift = " .. count .. "},"
end
bitmask = bitmask .. "},"
end
s[#s + 1] = bitmask .. "}"
end
if xml.charset then
local charset = "charset = {"
for id, set in pairs(xml.charset) do
local default
charset = charset .. "['" .. id .. "'] = {"
for src, char in pairs(set.char) do
if char.default and char.default == "yes" then
default = char.dst
end
charset = charset .. "[" .. src .. "]" .. " = '" .. char.dst .. "',"
end
if default then
charset = charset .. "default = " .. default
end
charset = charset .. "},"
end
s[#s + 1] = charset .. "}"
end
local function check_format(formstr)
local formats = {}
local ret = " function tempform(val)"
formstr = formstr:gsub("&gt;", ">")
formstr:gsub("([^;]+)", function(s) formats[#formats + 1] = s end)
for num, form in ipairs(formats) do
local oper
local first, rest = form:match("^(.)(.*)$")
if first == "*" and tonumber(rest) then
oper = " val = val * " .. rest
elseif first == "/" and tonumber(rest) then
oper = " val = val / " .. rest
elseif first == "d" and tonumber(rest) then
oper = " val = math.floor(val / " .. rest .. ")"
elseif first == "D" and tonumber(rest) then
oper = " val = math.floor((val / " .. rest .. ") + 0.5)"
elseif first == "-" and tonumber(rest) then
oper = " val = val - " .. rest
elseif first == "+" and tonumber(rest) then
oper = " val = val + " .. rest
elseif first == "%" and tonumber(rest) then
oper = " val = val % " .. rest
elseif first == ">" and tonumber(rest) then
oper = " val = val << " .. rest
elseif first == "L" and (rest == "C" or rest == "owercase") then
oper = " val = val:lower()"
elseif first == "U" and (rest == "C" or rest == "ppercase") then
oper = " val = val:upper()"
elseif first == "C" and rest == "apitalize" then
oper = " val = val:gsub('^(.)', function(s) return s:upper() end)"
elseif first == "R" and (rest == "" or rest == "ound") then
oper = " val = math.floor(" .. var .. " + 0.5)"
elseif first == "T" then
local trim, char = rest:match("rim(L?R?)(.)$")
if trim == "L" or trim == "" then
oper = " val = val:gsub('^(" .. char .. "*)', '')"
end
if trim == "R" or trim == "" then
oper = " val = val:gsub('(" .. char .. "*)$', '')"
end
elseif first == "P" then
local pad, count, char = rest:match("ad(L?R?)(%d-)(.)$")
if pad == "L" then
oper = " val = string.rep('" .. char .. "', " .. count .. " - #val) .. val"
elseif pad == "R" then
oper = "val = val .. string.rep('" .. char .. "', " .. count .. " - #val)"
elseif pad == nil then
local prefix = rest:match("refix(.*)")
if prefix then
oper = " val = '" .. rest .. "' .. val"
end
end
elseif first == "S" then
local suffix = rest:match("uffix(.*)")
if suffix then
oper = " val = val .. '" .. rest .. "'"
end
elseif (first == "h" and rest == "exadecimal_string") or (first == "0" and rest == "x") then
oper = " val = string.format('0x%x', val)"
elseif (first == "L" and rest == "oopIndex") then
oper = " val = index"
end
if not oper then
oper = " val = format['" .. form .. "'](val, {"
for num1, colpar in ipairs(fparam[form]) do
oper = oper .. "arr['" .. colpar .. "'][i].val or arr['" .. colpar .. "'][1].val,"
end
oper = oper .. "})"
end
ret = ret .. oper
end
return ret .. " return val\nend"
end
if xml.format then
local format = { "format = {" }
for num, form in ipairs(xml.format) do
local param = {}
format[#format + 1] = "['" .. form["id"] .. "'] = "
--[[if form["input-as-subcolumns-input"] then
format[#format + 1] = "input_as_subcolumns_input = '" .. form["input-as-subcolumns-input"] .. "',"
end]]--
format[#format + 1] = "function(val, param) "
if form["formatter"] then
format[#format + 1] = "function tempform(val) "
end
if form["apply-to"] == "char" then
format[#format + 1] = "val = val:gsub('(.)', function(val) "
end
format[#format + 1] = "local temp = val"
for num1, op in ipairs(form) do
if op.tag == "add" then
format[#format + 1] = "val = val + " .. op.text
elseif op.tag == "prefix" then
format[#format + 1] = "val = '" .. op.text .. "' .. val "
elseif op.tag == "suffix" then
format[#format + 1] = "val = val .. '" .. op.text .. "'"
elseif op.tag == "multiply" then
format[#format + 1] = "val = val * " .. op.text
elseif op.tag == "divide" then
format[#format + 1] = "val = val / " .. op.text
elseif op.tag == "sum" then
format[#format + 1] = "val = 0"
for num2, col in ipairs(op) do
param[#param + 1] = col["id"]
if col["format"] then
local colform = check_format(col["format"])
format[#format + 1] = colform .. " val = val + tempform(val)"
else
format[#format + 1] = "val = val + param[" .. #param .. "]"
end
end
elseif op.tag == "concat" then
format[#format + 1] = "val = ''"
for num2, col in ipairs(op) do
if col["tag"] == "txt" then
format[#format + 1] = "val = val .. '" .. col["text"] .. "'"
elseif col["format"] then
param[#param + 1] = col["id"]
local n = #param
format[#format + 1] = function() return " " .. check_format(col["format"]) .. " val = val .. tempform(param[" .. n .. "])" end
else
param[#param + 1] = col["id"]
format[#format + 1] = "val = val .. param[" .. #param .. "]"
end
end
elseif op.tag == "min" then
format[#format + 1] = "val = 0x7fffffffffffffff"
for num2, col in ipairs(op) do
param[#param + 1] = col["id"]
format[#format + 1] = "val = math.min(val, param[" .. #param .. "])"
end
elseif op.tag == "max" then
format[#format + 1] = "val = 0"
for num2, col in ipairs(op) do
param[#param + 1] = col["id"]
format[#format + 1] = "val = math.max(val, param[" .. #param .. "])"
end
elseif op.tag == "pad" then
format[#format + 1] = "if type(val) == 'number' then val = tostring(val) end"
format[#format + 1] = "if #val < " .. op.max .. " then"
if op.direction == "left" then
format[#format + 1] = "val = string.rep('" .. op.text .. "', " .. op.max .. " - #val) .. val"
elseif op.direction == "right" then
format[#format + 1] = "val = val .. string.rep('" .. op.text .. "', " .. op.max .. " - #val)"
end
format[#format + 1] = "end"
elseif op.tag == "trim" then
if op.direction == "left" or op.direction == "both" then
format[#format + 1] = "val = val:gsub('^(" .. op.text .. "*)', '')"
end
if op.direction == "right" or op.direction == "both" then
format[#format + 1] = "val = val:gsub('(" .. op.text .. "*)$', '')"
end
elseif op.tag == "substract" then
format[#format + 1] = "val = val - " .. op.text
elseif op.tag == "remainder" then
format[#format + 1] = "val = val % " .. op.text
elseif op.tag == "trunc" then
format[#format + 1] = "val = math.floor(val)"
elseif op.tag == "round" then
format[#format + 1] = "val = math.floor(val + 0.5)"
elseif op.tag == "divide_trunc" then
format[#format + 1] = "val = math.floor(val / " .. op.text .. ")"
elseif op.tag == "divide_round" then
format[#format + 1] = "val = math.floor((val / " .. op.text .. ") + 0.5)"
elseif op.tag == "replace" then
format[#format + 1] = "val = val:gsub('" .. op.src .. "', '" .. op.dst .. "')"
elseif op.tag == "shift" then
format[#format + 1] = "val = val << " .. op.text
elseif op.tag == "lowercase" then
format[#format + 1] = "val = val:lower()"
elseif op.tag == "uppercase" then
format[#format + 1] = "val = val:upper()"
elseif op.tag == "capitalize" then
format[#format + 1] = "val = val:gsub('^(.)', function(s) return s:upper() end)"
elseif op.tag == "loopindex" then
param[#param + 1] = "loopindex"
format[#format + 1] = "val = param[" .. #param .. "]"
elseif op.tag == "case" then
format[#format + 1] = "val = temp"
if not tonumber(op["src"]) then
op["src"] = "'" .. op["src"] .. "'"
end
if not tonumber(op["dst"]) then
op["dst"] = "'" .. op["dst"] .. "'"
end
if op["default"] == "yes" then
format[#format + 1] = "local default = " .. op["dst"]
end
if op["operator-format"] then
format[#format + 1] = function() return " val = ".. check_format(col["operator-format"]) end
end
if not op["operator"] then
op["operator"] = "=="
else
op["operator"] = op["operator"]:gsub("&lt;", "<")
op["operator"] = op["operator"]:gsub("&gt;", ">")
end
format[#format + 1] = "if val " .. op["operator"] .. " " .. op["src"] .. " then"
format[#format + 1] = "val = " .. op["dst"]
if op["format"] then
format[#format + 1] = function() return " val = ".. check_format(col["operator-format"]) end
end
format[#format + 1] = "return val\n end"
end
end
fparam[form["id"]] = param
if form["apply-to"] == "char" then
format[#format + 1] = "if default then\nreturn default\nend\nreturn val\nend)\nreturn val\nend"
else
format[#format + 1] = "if default then\nreturn default\nend\nreturn val\nend"
end
if form["formatter"] then
format[#format + 1] = "return string.format('" .. form["formatter"] .. "', tempform(val))\nend"
end
format[#format + 1] = ","
end
for num, line in ipairs(format) do
if type(line) == "string" then
s[#s + 1] = line
elseif type(line) == "function" then
s[#s + 1] = line()
end
end
s[#s + 1] = "}"
end
local function parse_elem(elem, loopelem)
local ret = 0
if elem["tag"] == "loop" then
if elem["skip-first-bytes"] then
s[#s + 1] = "offset = offset + " .. elem["skip-first-bytes"]
end
s[#s + 1] = "for i = 1, " .. elem["count"] .. " do"
for num, elt in ipairs(elem) do
index = parse_elem(elt, elem)
end
s[#s + 1] = "end"
if elem["skip-last-bytes"] then
s[#s + 1] = "offset = offset + " .. elem["skip-last-bytes"]
end
elseif elem["tag"] == "elt" then
s[#s + 1] = "if not arr['" .. elem["id"] .. "'] then arr['" .. elem["id"] .. "'] = {} end\nelem = {}"
s[#s + 1] = "bytes = table.pack(string.unpack('" .. string.rep("c1", elem["size"]) .. "', data, offset))"
if loopelem then
total_size = total_size + elem["size"] * loopelem["count"]
else
total_size = total_size + elem["size"]
end
s[#s + 1] = "offset = table.remove(bytes)"
if elem["decoding-profile"] then
if elem["decoding-profile"] == "base-40" then
elem["src-unit-size"] = 16
elem["base"] = "40"
elem["dst-unit-size"] = 3
elem["ascii-offset"] = 64
elseif elem["decoding-profile"] == "base-32" then
elem["src-unit-size"] = 16
elem["base"] = "32"
elem["dst-unit-size"] = 3
elem["ascii-offset"] = 64
elseif elem["decoding-profile"] == "bcd" then
elem["endianness"] = "big-endian"
elem["nibble-skip"] = "odd"
elem["base"] = "16"
elseif elem["decoding-profile"] == "bcd-le" then
elem["endianness"] = "big-endian"
elem["nibble-skip"] = "odd"
elem["base"] = "16"
end
end
local bytedec = elem["swap-skip-order"] or "byte-swap;bit-swap;byte-skip;endianness;byte-trim;nibble-skip;bitmask"
local bytedecl = {}
bytedec:gsub("([^;]*)", function(c) bytedecl[#bytedecl + 1] = c end)
for num, func in ipairs(bytedecl) do
if elem[func] then
fixfunc = func:gsub("-", "_")
if func == "bitmask" then
s[#s + 1] = "bytes = " .. fixfunc .. "(bytes, bitmask['" .. elem[func] .. "'])"
else
s[#s + 1] = "bytes = " .. fixfunc .. "(bytes, '" .. elem[func] .. "')"
end
end
end
if elem["type"] == "int" then
s[#s + 1] = "value = string.unpack('>I' .. #bytes, table.concat(bytes))"
elem["base"] = elem["base"] or "10"
if elem["base"] == "16" then
s[#s + 1] = "value = frombcd(value)"
end
s[#s + 1] = "elem.val = value"
elseif elem["type"] == "text" then
if elem["ascii-step"] then
s[#s + 1] = "bytes = ascii_step(bytes, " .. elem["ascii-step"] .. ")"
end
if elem["ascii-offset"] then
s[#s + 1] = "bytes = ascii_offset(bytes, " .. elem["ascii-offset"] .. ")"
end
if elem["base"] then
s[#s + 1] = "bytes = basechar(bytes, " .. elem["base"] .. ")"
end
if elem["charset"] then
local charsets = {}
elem["charset"]:gsub("([^;]*)", function(s) charsets[#charsets + 1] = s return "" end)
for num, charset in pairs(charsets) do
if charset:match("^CS_") then
s[#s + 1] = "bytes = charset_conv(bytes, " .. charset .. ")"
elseif charset ~= "" then
s[#s + 1] = "bytes = charset_conv(bytes, charset['" .. charset .. "'])"
end
end
end
s[#s + 1] = "elem.val = table.concat(bytes)"
end
local index
if elem["table-index"] then
index = tonumber(elem["table-index"])
end
if not index and loopelem then
local total = loopelem["count"]
local start = loopelem["start"] or 0
local step = loopelem["step"] or 1
local ref, reftype
if elem["table-index"] then
elem["table-index"]:match("([%w ]*):([%a_]*)")
end
if not elem["table-index"] or elem["table-index"] == "loop_index" then
index = "(i - 1) * " .. step .. " + " .. start
elseif elem["table-index"] == "loop_reverse_index" then
index = "(" .. total .. "- i) * " .. step .. " + " .. start
elseif elem["table-index"] == "itself" then
index = "value"
elseif elem["table-index"] == "last" then
index = "lastindex"
elseif reftype then
index = reftype .. "(arr, '" .. ref .. "')"
end
end
if index then
s[#s + 1] = "elem.index = " .. index
s[#s + 1] = "lastindex = elem.index"
end
s[#s + 1] = "arr['" .. elem["id"] .. "'][#arr['" .. elem["id"] .. "'] + 1] = elem"
end
return index
end
for num, elem in ipairs(xml.structure[1]) do
if elem["tag"] == "loop" or elem["tag"] == "elt" then
parse_elem(elem)
end
end
table.insert(s, 1, "size = " .. total_size)
s[#s + 1] = "output = ''"
for num1, fld in ipairs(xml.output[1]) do
if not fld["display"] or fld["display"] == "always" then
if fld["tag"] == "field" then
if not fld["src"] then
fld["src"] = fld["id"]
end
s[#s + 1] = "output = output .. '" .. fld["id"] .. " '"
s[#s + 1] = "val = arr['" .. fld["src"] .. "'][1]"
if fld["format"] then
s[#s + 1] = check_format(fld["format"])
s[#s + 1] = "val = tempform(val)"
end
s[#s + 1] = "output = output .. val .. '\\n'"
elseif fld["tag"] == "table" then
local head = {}
local dat = {}
local loopcnt
local igncol, ignval
if fld["line-ignore"] then
igncol, ignval = fld["line-ignore"]:match("([^:]*):(.*)")
end
for num2, col in ipairs(fld["column"]) do
if not col["display"] or col["display"] == "always" then
if not col["src"] then
col["src"] = col["id"]
end
if not loopcnt and col["src"] ~= "index" then
table.insert(dat, 1, "for i = 1, #arr['" .. col["src"] .. "'] do")
table.insert(dat, 2, "index = arr['" .. col["src"] .. "'][i].index")
table.insert(dat, 3, "line = ''")
loopcnt = true
end
head[#head + 1] = "output = output .. '" .. col["id"] .. "\\t'"
if col["src"] == "index" then
dat[#dat + 1] = "val = index"
else
dat[#dat + 1] = "if arr['" .. col["src"] .. "'] then val = arr['" .. col["src"] .. "'][i].val end"
end
if col["format"] then
dat[#dat + 1] = check_format(col["format"])
dat[#dat + 1] = "val = tempform(val)"
end
if igncol == col["id"] then
dat[#dat + 1] = "checkval = val"
end
dat[#dat + 1] = "line = line .. val .. '\\t'"
end
end
if igncol then
dat[#dat + 1] = "if checkval ~= " .. ignval .. " then output = output .. line .. '\\n' end\nend"
else
dat[#dat + 1] = "output = output .. line .. '\\n'\nend"
end
s[#s + 1] = table.concat(head, "\n") .. "\noutput = output .. '\\n'"
s[#s + 1] = table.concat(dat, "\n")
end
end
end
s[#s + 1] = "return output"
-- cache script
local script = table.concat(s, "\n")
local scrpath = datpath .. "/"
local scrfile = io.open(scrpath .. set .. ".lua", "w+")
if not scrfile then
lfs.mkdir(scrpath)
scrfile = io.open(scrpath .. set .. ".lua", "w+")
end
if scrfile then
scrfile:write(script)
end
return script
end
if #env == 0 then
function env.open(file, size)
if file == ".hi" then
local path = "hi"
local ini = emu.file(lfs.env_replace(manager:options().entries.inipath:value()), 1)
local ret = ini:open("hiscore.ini")
if not ret then
local inifile = ini:read(ini:size())
for line in inifile:gmatch("[^\n\r]") do
token, value = string.match(line, '([^ ]+) ([^ ]+)');
if token == "hi_path" then
path = value
break
end
end
end
file = path .. "/" .. set .. ".hi"
else
file = lfs.env_replace(manager:options().entries.nvram_directory:value()) .. "/" .. set .. "/" .. file
end
local f = io.open(file, "rb")
local content = f:read("*all")
f:close()
if #content < size then
content = content .. string.rep("\0", size - #content)
end
return content
end
function env.endianness(bytes, endian)
local newbytes = {}
if endian == "little_endian" then
for i = 1, #bytes do
newbytes[i] = bytes[#bytes - i + 1]
end
else
newbytes = bytes
end
return newbytes
end
function env.byte_skip(bytes, skip)
local newbytes = {}
if skip == "odd" then
-- lua lists are 1 based so use even indexes
for i = 2, #bytes, 2 do
newbytes[i/2] = bytes[i]
end
elseif skip == "even" then
for i = 1, #bytes, 2 do
newbytes[(i+1)/2] = bytes[i]
end
elseif skip == "1000" then
for i = 1, #bytes, 4 do
newbytes[(i+3)/4] = bytes[i]
end
elseif skip == "0100" then
for i = 2, #bytes, 4 do
newbytes[(i+2)/4] = bytes[i]
end
elseif skip == "0010" then
for i = 3, #bytes, 4 do
newbytes[(i+1)/4] = bytes[i]
end
elseif skip == "0001" then
for i = 4, #bytes, 4 do
newbytes[i/4] = bytes[i]
end
else
skip = tonumber(skip)
for i = 1, #bytes do
if bytes[i] ~= skip then
newbytes[#newbytes + 1] = bytes[i]
end
end
end
return newbytes
end
function env.byte_trim(bytes, val)
val = tonumber(val)
for i = 1, #bytes do
if bytes[i] ~= val then
return bytes
end
table.remove(bytes, 1)
end
return bytes
end
function env.byte_swap(bytes, val)
local newbytes = {}
val = tonumber(val)
for i = 1, #bytes do
local off = i + val - 1 - 2 * ((i - 1) % val)
if off > #bytes then -- ??
break
end
newbytes[i] = bytes[off]
end
return newbytes
end
function env.nibble_skip(bytes, skip)
local newbytes = {}
if skip == "odd" then
for i = 1, #bytes, 2 do
val = bytes[i]:byte(1)
newbytes[(i+1)/2] = string.char(((val & 0x0f) << 4) | (val & 0x0f))
end
elseif skip == "even" then
for i = 1, #bytes, 2 do
val = bytes[i]:byte(1)
newbytes[(i+1)/2] = string.char((val & 0xf0) | ((val & 0xf0) >> 4))
end
end
return newbytes
end
function env.bit_swap(bytes, swap)
if swap == "yes" then
for i = 1, #bytes do
val = bytes[i]:byte(1)
bytes[i] = string.char(((val & 1) << 7) | ((val & 2) << 5) | ((val & 4) << 3) | ((val & 8) << 1) | ((val & 0x10) >> 1) | ((val & 0x20) >> 3) | ((val & 0x40) >> 5) | ((val & 0x80) >> 7))
end
end
return bytes
end
function env.bitmask(bytes, mask)
local newbytes = 0
bytes = string.unpack(">I" .. #bytes, table.concat(bytes))
for i = 1, #mask do
newbytes = newbytes | (((bytes >> mask.ishift) & mask.mask) << mask.oshift)
end
bytes = {}
while newbytes ~= 0 do
bytes[#bytes + 1] = newbytes & 0xff
newbytes = newbytes >> 8
end
newbytes = {}
for i = 1, #bytes do
newbytes[i] = string.char(bytes[#bytes + 1 - i])
end
return newbytes
end
function env.frombcd(val)
local result = 0
local mul = 1
while val ~= 0 do
result = result + ((val % 16) * mul)
val = val >> 4
mul = mul * 10
end
return result
end
function env.basechar(bytes, base)
if base == "32" then
elseif base == "40" then
end
return bytes
end
function env.charset_conv(bytes, charset)
if type(charset) == "string" then
local chartype, offset, delta = charset:match("CS_(%w*)%[?(%-?%d?%d?),?(%d?%d?)%]?")
if chartype == "NUMBER" then
end
return
end
for num, char in ipairs(bytes) do
char = string.byte(char)
if charset[char] then
bytes[num] = charset[char]
elseif charset.default then
bytes[num] = charset.default
end
end
return bytes
end
function env.ascii_step(bytes, step)
for num, char in ipairs(bytes) do
bytes[num] = string.char(char:byte() / step)
end
return bytes
end
function env.ascii_offset(bytes, offset)
for num, char in ipairs(bytes) do
bytes[num] = string.char(char:byte() + offset)
end
return bytes
end
env.tostring = tostring
env.type = type
env.table = { pack = table.pack, concat = table.concat, insert = table.insert, remove = table.remove }
env.string = { unpack = string.unpack, format = string.format, rep = string.rep, gsub = string.gsub, lower = string.lower, upper = string.upper }
env.math = { min = math.min, max = math.max, floor = math.floor }
end
if curset == set then
if output then
return "High Scores"
else
return nil
end
end
output = nil
curset = set
local scrfile = emu.file(lfs.env_replace(mame_manager:ui():options().entries.historypath:value():gsub("([^;]+)", "%1/hi2txt")), 1)
local ret = scrfile:open(set .. ".lua")
local script
if ret then
local xml = xml_parse()
if not xml then
return nil
end
local status
status, script = pcall(parse_table, xml)
if not status then
emu.print_verbose("error creating hi score parse script: " .. script)
return nil
end
else
script = scrfile:read(scrfile:size())
end
local scr, err = load(script, script, "t", env)
if err then
emu.print_verbose("error loading hi score script file: " .. err)
else
status, output = pcall(scr, xml_table)
if not status then
emu.print_verbose("error in hi score parse script: " .. output)
output = nil
end
end
if output then
return "High Scores"
else
return nil
end
end
function dat.get()
return output
end
return dat

View File

@ -0,0 +1,26 @@
local dat = {}
local ver, info
local datread = require("data/load_dat")
datread, ver = datread.open("history.dat", "## REVISION:")
function dat.check(set, softlist)
if not datread then
return nil
end
local status
status, info = pcall(datread, "bio", softlist or "info", set)
if not status or not info then
return nil
end
return "History"
end
function dat.get()
return info
end
function dat.ver()
return ver
end
return dat

View File

@ -0,0 +1,26 @@
local dat = {}
local ver, info
local datread = require("data/load_dat")
datread, ver = datread.open("mameinfo.dat", "# MAMEINFO.DAT")
function dat.check(set, softlist)
if softlist or not datread then
return nil
end
local status
status, info = pcall(datread, "mame", "info", set)
if not status or not info then
return nil
end
return "Mameinfo"
end
function dat.get()
return info
end
function dat.ver()
return ver
end
return dat

View File

@ -0,0 +1,27 @@
local dat = {}
local ver, info
local datread = require("data/load_dat")
datread, ver = datread.open("messinfo.dat", "# MESSINFO.DAT")
function dat.check(set, softlist)
if softlist or not datread then
return nil
end
local status
status, info = pcall(datread, "mame", "info", set)
if not status or not info then
return nil
end
return "Messinfo"
end
function dat.get()
return info
end
function dat.ver()
return ver
end
return dat

View File

@ -0,0 +1,32 @@
local dat = {}
local ver, info
local datread = require("data/load_dat")
local space_wid = mame_manager:ui():get_char_width(0x200a)
datread, ver = datread.open("story.dat", "# version")
function dat.check(set, softlist)
if softlist or not datread then
return nil
end
local status
status, info = pcall(datread, "story", "info", set)
if not status or not info then
return nil
end
info = "#jf\n" .. info:gsub("([^%s]-)(%f[_]_+%f[0-9])([0-9.]+)",
function(name, sep, score)
local wid = mame_manager:ui():get_string_width(name .. score, 1.0)
return name .. string.rep(utf8.char(0x200a), math.floor((.4 - wid) / space_wid)) .. score
end)
return "Mamescore"
end
function dat.get()
return info
end
function dat.ver()
return ver
end
return dat

View File

@ -0,0 +1,26 @@
local dat = {}
local ver, info
local datread = require("data/load_dat")
datread, ver = datread.open("sysinfo.dat", "# This file was generated on")
function dat.check(set, softlist)
if softlist or not datread then
return nil
end
local status
status, info = pcall(datread, "bio", "info", set)
if not status or not info then
return nil
end
return "Sysinfo"
end
function dat.get()
return info
end
function dat.ver()
return ver
end
return dat

85
plugins/data/init.lua Normal file
View File

@ -0,0 +1,85 @@
-- license:BSD-3-Clause
-- copyright-holders:Carl
-- A data script should contain two functions check which takes a set name and returns the data
-- heading if it supports the set otherwise nil and get which returns the data
-- the script should be named data_<name>.lua
-- this is set default on in the plugin.json
local exports = {}
exports.name = "data"
exports.version = "0.0.1"
exports.description = "Data plugin"
exports.license = "The BSD 3-Clause License"
exports.author = { name = "Carl" }
local data = exports
function data.set_folder(path)
data.path = path
end
function data.startplugin()
local data_scr = {}
local valid_lst = {}
local cur_set
local cur_list
emu.register_start(function()
data_scr = {}
for file in lfs.dir(data.path) do
local name = string.match(file, "^(data_.*).lua$")
if name then
local script = require("data/" .. name)
if script then
data_scr[#data_scr + 1] = script
end
end
end
end)
emu.register_callback(function(set)
local ret
if set == cur_set then
return cur_list
elseif set == "" then
set = cur_set
else
cur_set = set
end
if not set then
return nil
end
valid_lst = {}
for num, scr in ipairs(data_scr) do
local setname, softname = set:match("^([^,]+),?(.*)$")
if softname == "" then
softname = nil
end
local name = scr.check(setname, softname)
if name then
if not ret then
ret = name
else
ret = ret .. "," .. name
end
valid_lst[#valid_lst + 1] = scr
end
end
cur_list = ret
return ret
end, "data_list")
emu.register_callback(function(num)
return valid_lst[num + 1].get()
end, "data")
emu.register_callback(function(num)
local ver
if valid_lst[num + 1].ver then
ver = valid_lst[num + 1].ver()
end
if ver then
return ver
end
return ""
end, "data_version")
end
return exports

97
plugins/data/load_dat.lua Normal file
View File

@ -0,0 +1,97 @@
local datfile = {}
function datfile.open(file, vertag)
local data = {}
local ver
local filepath
local fh
for path in mame_manager:ui():options().entries.historypath:value():gmatch("([^;]+)") do
filepath = lfs.env_replace(path) .. "/" .. file
fh = io.open(filepath, "rb")
if fh then
break
end
end
if not fh then
return nil
end
do
local inblock = false
local buffer = fh:read("a")
if vertag then
local match = buffer:match(vertag .. "%s*([^%s]+)")
if match then
ver = match
end
end
local function gmatchpos()
local pos = 1
local function iter()
local spos, epos = buffer:find("\n$", pos, true)
if not spos then
return nil
end
spos = spos + 1
local spos, epos, match = buffer:find("([^\n]+)", spos)
pos = epos + 1
return match, pos, iter
end
return iter
end
for line, epos, iter in gmatchpos() do
local flag = line:sub(1, 1)
if flag ~= "#" then
if flag == "$" then
if line:sub(1, 4) == "$end" then
inblock = false
elseif not inblock then
local tag, set = line:match("^%$([^%s=]+)=?([^%s]*)")
if set and set ~= "" then
local tags = {}
local sets = {}
local tag1 = ""
tag:gsub("([^,]+)", function(s) tags[#tags + 1] = s end)
set:gsub("([^,]+)", function(s) sets[#sets + 1] = s end)
repeat
tag1, epos = iter()
until tag1:sub(1, 1) == "$"
tag1 = tag1:match("^$([^%s]*)")
if not data[tag1] then
data[tag1] = {}
end
for num1, tag2 in pairs(tags) do
if not data[tag1][tag2] then
data[tag1][tag2] = {}
end
for num2, set in pairs(sets) do
data[tag1][tag2][set] = epos
end
end
end
inblock = true
end
end
end
end
end
fh:close()
fh = io.open(filepath, "r")
local function read(tag1, tag2, set)
local output = {}
if not data[tag1][tag2][set] then
return nil
end
fh:seek("set", data[tag1][tag2][set])
for line in fh:lines() do
if line == "$end" then
return table.concat(output, "\n")
end
output[#output + 1] = line
end
end
return read, ver
end
return datfile

10
plugins/data/plugin.json Normal file
View File

@ -0,0 +1,10 @@
{
"plugin": {
"name": "data",
"description": "Data plugin",
"version": "0.0.1",
"author": "Carl",
"type": "plugin",
"start": "true"
}
}

View File

@ -130,8 +130,6 @@ files {
MAME_DIR .. "src/frontend/mame/ui/custmenu.h",
MAME_DIR .. "src/frontend/mame/ui/custui.cpp",
MAME_DIR .. "src/frontend/mame/ui/custui.h",
MAME_DIR .. "src/frontend/mame/ui/datfile.cpp",
MAME_DIR .. "src/frontend/mame/ui/datfile.h",
MAME_DIR .. "src/frontend/mame/ui/datmenu.cpp",
MAME_DIR .. "src/frontend/mame/ui/datmenu.h",
MAME_DIR .. "src/frontend/mame/ui/defimg.ipp",

View File

@ -2280,6 +2280,17 @@ int lua_engine::l_osd_printf_debug(lua_State *L)
return 0;
}
int lua_engine::l_driver_find(lua_State *L)
{
luaL_argcheck(L, lua_isstring(L, 1), 1, "message (string) expected");
int index = driver_list::find(lua_tostring(L, 1));
if(index == -1)
lua_pushnil(L);
else
luabridge::Stack<const game_driver &>::push(L, driver_list::driver(index));
return 1;
}
//-------------------------------------------------
// initialize - initialize lua hookup to emu engine
//-------------------------------------------------
@ -2316,6 +2327,7 @@ void lua_engine::initialize()
.addCFunction ("print_error", l_osd_printf_error )
.addCFunction ("print_info", l_osd_printf_info )
.addCFunction ("print_debug", l_osd_printf_debug )
.addCFunction ("driver_find", l_driver_find )
.beginClass <machine_manager>("manager")
.addFunction("machine", &machine_manager::machine)
.addFunction("options", &machine_manager::options)
@ -2577,6 +2589,8 @@ void lua_engine::initialize()
.addProperty <bool, bool> ("show_profiler", &mame_ui_manager::show_profiler, &mame_ui_manager::set_show_profiler)
.addProperty <bool, bool> ("single_step", &mame_ui_manager::single_step, &mame_ui_manager::set_single_step)
.addFunction ("get_line_height", &mame_ui_manager::get_line_height)
.addFunction ("get_string_width", &mame_ui_manager::get_string_width)
.addFunction ("get_char_width", &mame_ui_manager::get_char_width)
.endClass()
.beginClass <lua_screen> ("lua_screen_dev")
.addCFunction ("draw_box", &lua_screen::l_draw_box)

View File

@ -143,6 +143,7 @@ private:
static int l_osd_printf_error(lua_State *L);
static int l_osd_printf_info(lua_State *L);
static int l_osd_printf_debug(lua_State *L);
static int l_driver_find(lua_State *L);
static int register_function(lua_State *L, const char *id);
// "emu.machine" namespace

View File

@ -16,14 +16,12 @@
#include "osdepend.h"
#include "validity.h"
#include "clifront.h"
#include "drivenum.h"
#include "luaengine.h"
#include <time.h>
#include "ui/ui.h"
#include "ui/selgame.h"
#include "ui/simpleselgame.h"
#include "cheat.h"
#include "ui/datfile.h"
#include "ui/inifile.h"
#include "xmlfile.h"
@ -297,9 +295,6 @@ void mame_machine_manager::create_custom(running_machine& machine)
// allocate autoboot timer
m_autoboot_timer = machine.scheduler().timer_alloc(timer_expired_delegate(FUNC(mame_machine_manager::autoboot_callback), this));
// start datfile manager
m_datfile = std::make_unique<ui::datfile_manager>(machine, m_ui->options());
// start favorite manager
m_favorite = std::make_unique<favorite_manager>(machine, m_ui->options());

View File

@ -25,7 +25,6 @@ class favorite_manager;
class mame_ui_manager;
namespace ui {
class datfile_manager;
} // namespace ui
// ======================> machine_manager
@ -61,7 +60,6 @@ public:
void schedule_new_driver(const game_driver &driver);
mame_ui_manager& ui() const { assert(m_ui != nullptr); return *m_ui; }
cheat_manager &cheat() const { assert(m_cheat != nullptr); return *m_cheat; }
ui::datfile_manager &datfile() const { assert(m_datfile != nullptr); return *m_datfile; }
inifile_manager &inifile() const { assert(m_inifile != nullptr); return *m_inifile; }
favorite_manager &favorite() const { assert(m_favorite != nullptr); return *m_favorite; }
private:
@ -75,7 +73,6 @@ private:
emu_timer *m_autoboot_timer; // autoboot timer
std::unique_ptr<mame_ui_manager> m_ui; // internal data from ui.cpp
std::unique_ptr<cheat_manager> m_cheat; // internal data from cheat.cpp
std::unique_ptr<ui::datfile_manager> m_datfile; // internal data from datfile.c
std::unique_ptr<inifile_manager> m_inifile; // internal data from inifile.c for INIs
std::unique_ptr<favorite_manager> m_favorite; // internal data from inifile.c for favorites

View File

@ -1,581 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Maurizio Petrarota
/***************************************************************************
ui/datfile.cpp
UI DATs manager.
***************************************************************************/
#include "emu.h"
#include "ui/datfile.h"
#include "drivenum.h"
#include "ui/moptions.h"
#include "ui/utils.h"
#include <utility>
namespace ui {
namespace {
//-------------------------------------------------
// TAGS
//-------------------------------------------------
std::string const DATAFILE_TAG("$");
std::string const TAG_BIO("$bio");
std::string const TAG_INFO("$info");
std::string const TAG_MAME("$mame");
std::string const TAG_COMMAND("$cmd");
std::string const TAG_END("$end");
std::string const TAG_DRIVER("$drv");
std::string const TAG_STORY("$story");
std::string const TAG_HISTORY_R("## REVISION:");
std::string const TAG_MAMEINFO_R("# MAMEINFO.DAT");
std::string const TAG_MESSINFO_R("# MESSINFO.DAT");
std::string const TAG_SYSINFO_R("# This file was generated on");
std::string const TAG_STORY_R("# version");
std::string const TAG_COMMAND_SEPARATOR("-----------------------------------------------");
std::string const TAG_GAMEINIT_R("# GAMEINIT.DAT");
} // anonymous namespace
//-------------------------------------------------
// Statics
//-------------------------------------------------
datfile_manager::dataindex datfile_manager::m_histidx;
datfile_manager::dataindex datfile_manager::m_mameidx;
datfile_manager::dataindex datfile_manager::m_messidx;
datfile_manager::dataindex datfile_manager::m_cmdidx;
datfile_manager::dataindex datfile_manager::m_sysidx;
datfile_manager::dataindex datfile_manager::m_storyidx;
datfile_manager::dataindex datfile_manager::m_ginitidx;
datfile_manager::drvindex datfile_manager::m_drvidx;
datfile_manager::drvindex datfile_manager::m_messdrvidx;
datfile_manager::drvindex datfile_manager::m_menuidx;
datfile_manager::swindex datfile_manager::m_swindex;
std::string datfile_manager::m_history_rev;
std::string datfile_manager::m_mame_rev;
std::string datfile_manager::m_mess_rev;
std::string datfile_manager::m_sysinfo_rev;
std::string datfile_manager::m_story_rev;
std::string datfile_manager::m_ginit_rev;
bool datfile_manager::first_run = true;
#define opendatsfile(f) do { fileptr datfile = parseopen(#f".dat"); if (datfile) init_##f(std::move(datfile)); } while (false)
//-------------------------------------------------
// ctor
//-------------------------------------------------
datfile_manager::datfile_manager(running_machine &machine, ui_options &moptions)
: m_machine(machine)
, m_options(moptions)
{
if (m_options.enabled_dats() && first_run)
{
first_run = false;
opendatsfile(mameinfo);
opendatsfile(command);
opendatsfile(story);
opendatsfile(messinfo);
opendatsfile(sysinfo);
opendatsfile(history);
opendatsfile(gameinit);
}
}
//-------------------------------------------------
// initialize sysinfo.dat index
//-------------------------------------------------
void datfile_manager::init_sysinfo(fileptr &&fp)
{
int swcount = 0;
auto count = index_datafile(std::move(fp), m_sysidx, swcount, m_sysinfo_rev, TAG_SYSINFO_R, '.');
osd_printf_verbose("Sysinfo.dat games found = %i\n", count);
osd_printf_verbose("Rev = %s\n", m_sysinfo_rev.c_str());
}
//-------------------------------------------------
// initialize story.dat index
//-------------------------------------------------
void datfile_manager::init_story(fileptr &&fp)
{
int swcount = 0;
auto count = index_datafile(std::move(fp), m_storyidx, swcount, m_story_rev, TAG_STORY_R, 's');
osd_printf_verbose("Story.dat games found = %i\n", count);
}
//-------------------------------------------------
// initialize history.dat index
//-------------------------------------------------
void datfile_manager::init_history(fileptr &&fp)
{
int swcount = 0;
auto count = index_datafile(std::move(fp), m_histidx, swcount, m_history_rev, TAG_HISTORY_R, ' ');
osd_printf_verbose("History.dat systems found = %i\n", count);
osd_printf_verbose("History.dat software packages found = %i\n", swcount);
osd_printf_verbose("Rev = %s\n", m_history_rev.c_str());
}
//-------------------------------------------------
// initialize gameinit.dat index
//-------------------------------------------------
void datfile_manager::init_gameinit(fileptr &&fp)
{
int swcount = 0;
drvindex tmp;
auto count = index_mame_mess_info(std::move(fp), m_ginitidx, tmp, swcount);
osd_printf_verbose("Gameinit.dat games found = %i\n", count);
osd_printf_verbose("Rev = %s\n", m_ginit_rev.c_str());
}
//-------------------------------------------------
// initialize mameinfo.dat index
//-------------------------------------------------
void datfile_manager::init_mameinfo(fileptr &&fp)
{
int drvcount = 0;
auto count = index_mame_mess_info(std::move(fp), m_mameidx, m_drvidx, drvcount);
osd_printf_verbose("Mameinfo.dat games found = %i\n", count);
osd_printf_verbose("Mameinfo.dat drivers found = %d\n", drvcount);
osd_printf_verbose("Rev = %s\n", m_mame_rev.c_str());
}
//-------------------------------------------------
// initialize messinfo.dat index
//-------------------------------------------------
void datfile_manager::init_messinfo(fileptr &&fp)
{
int drvcount = 0;
auto count = index_mame_mess_info(std::move(fp), m_messidx, m_messdrvidx, drvcount);
osd_printf_verbose("Messinfo.dat games found = %i\n", count);
osd_printf_verbose("Messinfo.dat drivers found = %d\n", drvcount);
osd_printf_verbose("Rev = %s\n", m_mess_rev.c_str());
}
//-------------------------------------------------
// initialize command.dat index
//-------------------------------------------------
void datfile_manager::init_command(fileptr &&fp)
{
int swcount = 0;
std::string tmp;
auto count = index_datafile(std::move(fp), m_cmdidx, swcount, tmp, std::string(), 'c');
osd_printf_verbose("Command.dat games found = %i\n", count);
}
bool datfile_manager::has_software(std::string const &softlist, std::string const &softname, std::string const &parentname) const
{
return bool(find_software(softlist, softname, parentname));
}
long const *datfile_manager::find_software(std::string const &softlist, std::string const &softname, std::string const &parentname) const
{
// Find software in software list index
auto const software(m_swindex.find(softlist));
if (software == m_swindex.end())
return nullptr;
auto itemsiter = software->second.find(softname);
if ((itemsiter == software->second.end()) && !parentname.empty())
itemsiter = software->second.find(parentname);
return (itemsiter != software->second.end()) ? &itemsiter->second : nullptr;
}
//-------------------------------------------------
// load software info
//-------------------------------------------------
void datfile_manager::load_software_info(std::string const &softlist, std::string &buffer, std::string const &softname, std::string const &parentname)
{
if (m_swindex.empty())
return;
// Load history text
fileptr const datfile = parseopen("history.dat");
if (datfile)
{
// Find software in software list index
long const *const s_offset = find_software(softlist, softname, parentname);
if (!s_offset)
return;
char rbuf[64 * 1024];
std::fseek(datfile.get(), *s_offset, SEEK_SET);
std::string readbuf;
while (std::fgets(rbuf, 64 * 1024, datfile.get()) != nullptr)
{
readbuf = chartrimcarriage(rbuf);
// end entry when a end tag is encountered
if (readbuf == TAG_END)
break;
// add this string to the buffer
buffer.append(readbuf).append("\n");
}
}
}
//-------------------------------------------------
// load_data_info
//-------------------------------------------------
void datfile_manager::load_data_info(const game_driver *drv, std::string &buffer, int type)
{
dataindex const *index_idx = nullptr;
drvindex const *driver_idx = nullptr;
std::string const *tag;
std::string filename;
switch (type)
{
case UI_HISTORY_LOAD:
filename = "history.dat";
tag = &TAG_BIO;
index_idx = &m_histidx;
break;
case UI_MAMEINFO_LOAD:
filename = "mameinfo.dat";
tag = &TAG_MAME;
index_idx = &m_mameidx;
driver_idx = &m_drvidx;
break;
case UI_SYSINFO_LOAD:
filename = "sysinfo.dat";
tag = &TAG_BIO;
index_idx = &m_sysidx;
break;
case UI_MESSINFO_LOAD:
filename = "messinfo.dat";
tag = &TAG_MAME;
index_idx = &m_messidx;
driver_idx = &m_messdrvidx;
break;
case UI_STORY_LOAD:
filename = "story.dat";
tag = &TAG_STORY;
index_idx = &m_storyidx;
break;
case UI_GINIT_LOAD:
filename = "gameinit.dat";
tag = &TAG_MAME;
index_idx = &m_ginitidx;
break;
default:
assert(false);
return;
}
fileptr const datfile = parseopen(filename.c_str());
if (datfile)
{
load_data_text(datfile.get(), drv, buffer, *index_idx, *tag);
// load driver info
if (driver_idx && !driver_idx->empty())
load_driver_text(datfile.get(), drv, buffer, *driver_idx, TAG_DRIVER);
// cleanup mameinfo and sysinfo double line spacing
if (((*tag == TAG_MAME) && (type != UI_GINIT_LOAD)) || (type == UI_SYSINFO_LOAD))
strreplace(buffer, "\n\n", "\n");
}
}
//-------------------------------------------------
// load a game text into the buffer
//-------------------------------------------------
void datfile_manager::load_data_text(FILE *fp, game_driver const *drv, std::string &buffer, dataindex const &idx, std::string const &tag)
{
auto itemsiter = idx.find(drv);
if (itemsiter == idx.end())
{
auto cloneof = driver_list::non_bios_clone(*drv);
if (cloneof == -1)
return;
else
{
auto c_drv = &driver_list::driver(cloneof);
itemsiter = idx.find(c_drv);
if (itemsiter == idx.end())
return;
}
}
auto s_offset = itemsiter->second;
std::fseek(fp, s_offset, SEEK_SET);
char rbuf[64 * 1024];
std::string readbuf;
while (std::fgets(rbuf, 64 * 1024, fp) != nullptr)
{
readbuf = chartrimcarriage(rbuf);
// end entry when a end tag is encountered
if (readbuf == TAG_END)
break;
// continue if a specific tag is encountered
if (readbuf == tag)
continue;
// add this string to the buffer
buffer.append(readbuf).append("\n");
}
}
//-------------------------------------------------
// load a driver name and offset into an
// indexed array
//-------------------------------------------------
void datfile_manager::load_driver_text(FILE *fp, game_driver const *drv, std::string &buffer, drvindex const &idx, std::string const &tag)
{
std::string s(core_filename_extract_base(drv->source_file));
auto index = idx.find(s);
// if driver not found, return
if (index == idx.end())
return;
buffer.append("\n--- DRIVER INFO ---\n").append("Driver: ").append(s).append("\n\n");
auto s_offset = index->second;
std::fseek(fp, s_offset, SEEK_SET);
char rbuf[64 * 1024];
std::string readbuf;
while (std::fgets(rbuf, 64 * 1024, fp) != nullptr)
{
readbuf = chartrimcarriage(rbuf);
// end entry when a end tag is encountered
if (readbuf == TAG_END)
break;
// continue if a specific tag is encountered
if (readbuf == tag)
continue;
// add this string to the buffer
buffer.append(readbuf).append("\n");
}
}
//-------------------------------------------------
// load a game name and offset into an
// indexed array (mameinfo)
//-------------------------------------------------
int datfile_manager::index_mame_mess_info(fileptr &&fp, dataindex &index, drvindex &index_drv, int &drvcount)
{
size_t foundtag;
auto t_mame = TAG_MAMEINFO_R.size();
auto t_mess = TAG_MESSINFO_R.size();
auto t_ginit = TAG_GAMEINIT_R.size();
auto t_info = TAG_INFO.size();
char rbuf[64 * 1024];
std::string readbuf, xid, name;
while (std::fgets(rbuf, 64 * 1024, fp.get()) != nullptr)
{
readbuf = chartrimcarriage(rbuf);
if (m_mame_rev.empty() && readbuf.compare(0, t_mame, TAG_MAMEINFO_R) == 0)
{
auto found = readbuf.find(" ", t_mame + 1);
m_mame_rev = readbuf.substr(t_mame + 1, found - t_mame);
}
else if (m_mess_rev.empty() && (foundtag = readbuf.find(TAG_MESSINFO_R)) != std::string::npos)
{
auto found = readbuf.find(" ", foundtag + t_mess + 1);
m_mess_rev = readbuf.substr(foundtag + t_mess + 1, found - t_mess - foundtag);
}
else if (m_ginit_rev.empty() && readbuf.compare(0, t_ginit, TAG_GAMEINIT_R) == 0)
{
auto found = readbuf.find(" ", t_ginit + 1);
m_ginit_rev = readbuf.substr(t_ginit + 1, found - t_ginit);
}
else if (readbuf.compare(0, t_info, TAG_INFO) == 0)
{
// TAG_INFO
std::fgets(rbuf, 64 * 1024, fp.get());
xid = chartrimcarriage(rbuf);
name = readbuf.substr(t_info + 1);
if (xid == TAG_MAME)
{
// validate driver
auto game_index = driver_list::find(name.c_str());
if (game_index != -1)
index.emplace(&driver_list::driver(game_index), std::ftell(fp.get()));
}
else if (xid == TAG_DRIVER)
{
index_drv.emplace(name, std::ftell(fp.get()));
drvcount++;
}
}
}
return index.size();
}
//-------------------------------------------------
// load a game name and offset into an
// indexed array
//-------------------------------------------------
int datfile_manager::index_datafile(fileptr &&fp, dataindex &index, int &swcount, std::string &rev, std::string const &tag, char sep)
{
std::string readbuf;
auto const tag_size = tag.size();
auto const t_info = TAG_INFO.size();
auto const t_bio = TAG_BIO.size();
char rbuf[64 * 1024];
while (std::fgets(rbuf, 64 * 1024, fp.get()) != nullptr)
{
readbuf = chartrimcarriage(rbuf);
if (!tag.empty())
{
if (rev.empty() && readbuf.compare(0, tag_size, tag) == 0)
{
if (sep != 's')
rev = readbuf.substr(tag_size + 1, readbuf.find(sep, tag_size + 1) - tag_size);
else
rev = readbuf.substr(tag_size + 1);
}
}
if (readbuf.compare(0, t_info, TAG_INFO) == 0)
{
// search for game info
auto rd = readbuf.substr(t_info + 1);
std::vector<std::string> gamelist = tokenize(rd, ',');
for (auto & e : gamelist)
{
auto game_index = driver_list::find(e.c_str());
if (game_index != -1)
index.emplace(&driver_list::driver(game_index), std::ftell(fp.get()));
}
}
else if (!readbuf.empty() && readbuf[0] == DATAFILE_TAG[0])
{
// search for software info
std::fgets(rbuf, 64 * 1024, fp.get());
std::string readbuf_2(chartrimcarriage(rbuf));
if (readbuf_2.compare(0, t_bio, TAG_BIO) == 0)
{
auto eq_sign = readbuf.find('=');
std::string s_list(readbuf.substr(1, eq_sign - 1));
std::string s_roms(readbuf.substr(eq_sign + 1));
std::vector<std::string> token_list = tokenize(s_list, ',');
std::vector<std::string> token_roms = tokenize(s_roms, ',');
for (auto & li : token_list)
for (auto & ro : token_roms)
m_swindex[li].emplace(ro, std::ftell(fp.get()));
swcount++;
}
}
}
return index.size();
}
//---------------------------------------------------------
// parseopen - Open up file for reading
//---------------------------------------------------------
datfile_manager::fileptr datfile_manager::parseopen(const char *filename)
{
emu_file file(m_options.history_path(), OPEN_FLAG_READ);
if (file.open(filename) != osd_file::error::NONE)
return fileptr(nullptr, &std::fclose);
std::string const fullpath = file.fullpath();
file.close();
fileptr result(std::fopen(fullpath.c_str(), "rb"), &std::fclose);
fgetc(result.get());
fseek(result.get(), 0, SEEK_SET);
return result;
}
//-------------------------------------------------
// create the menu index
//-------------------------------------------------
void datfile_manager::index_menuidx(fileptr &&fp, const game_driver *drv, dataindex const &idx, drvindex &index)
{
auto itemsiter = idx.find(drv);
if (itemsiter == idx.end())
{
auto const cloneof = driver_list::non_bios_clone(*drv);
if (cloneof == -1)
return;
auto const c_drv = &driver_list::driver(cloneof);
if ((itemsiter = idx.find(c_drv)) == idx.end())
return;
}
// seek to correct point in datafile
auto const s_offset = itemsiter->second;
std::fseek(fp.get(), s_offset, SEEK_SET);
auto const tinfo = TAG_INFO.size();
char rbuf[64 * 1024];
std::string readbuf;
while (std::fgets(rbuf, 64 * 1024, fp.get()) != nullptr)
{
readbuf = chartrimcarriage(rbuf);
if (!core_strnicmp(TAG_INFO.c_str(), readbuf.c_str(), tinfo))
break;
// TAG_COMMAND identifies the driver
if (readbuf == TAG_COMMAND)
{
std::fgets(rbuf, 64 * 1024, fp.get());
chartrimcarriage(rbuf);
index.emplace(rbuf, std::ftell(fp.get()));
}
}
}
//-------------------------------------------------
// load command text into the buffer
//-------------------------------------------------
void datfile_manager::load_command_info(std::string &buffer, std::string const &sel)
{
fileptr const datfile = parseopen("command.dat");
if (datfile)
{
// open and seek to correct point in datafile
auto const offset = m_menuidx.at(sel);
std::fseek(datfile.get(), offset, SEEK_SET);
char rbuf[64 * 1024];
std::string readbuf;
while (std::fgets(rbuf, 64 * 1024, datfile.get()) != nullptr)
{
readbuf = chartrimcarriage(rbuf);
// skip separator lines
if (readbuf == TAG_COMMAND_SEPARATOR)
continue;
// end entry when a tag is encountered
if (readbuf == TAG_END)
break;
// add this string to the buffer
buffer.append(readbuf).append("\n");;
}
}
}
//-------------------------------------------------
// load submenu item for command.dat
//-------------------------------------------------
void datfile_manager::command_sub_menu(const game_driver *drv, std::vector<std::string> &menuitems)
{
fileptr datfile = parseopen("command.dat");
if (datfile)
{
m_menuidx.clear();
index_menuidx(std::move(datfile), drv, m_cmdidx, m_menuidx);
menuitems.reserve(m_menuidx.size());
for (auto const &elem : m_menuidx)
menuitems.push_back(elem.first);
}
}
} // namespace ui

View File

@ -1,106 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Maurizio Petrarota
/***************************************************************************
ui/datfile.h
UI DATs manager.
***************************************************************************/
#ifndef MAME_FRONTEND_UI_DATFILE_H
#define MAME_FRONTEND_UI_DATFILE_H
#pragma once
#include <cstdio>
#include <memory>
#include <string>
#include <unordered_map>
class ui_options;
namespace ui {
//-------------------------------------------------
// Datafile Manager
//-------------------------------------------------
class datfile_manager
{
public:
// construction/destruction
datfile_manager(running_machine &machine, ui_options &moptions);
// getters
running_machine &machine() const { return m_machine; }
// actions
void load_data_info(const game_driver *drv, std::string &buffer, int type);
void load_command_info(std::string &buffer, std::string const &sel);
void load_software_info(std::string const &softlist, std::string &buffer, std::string const &softname, std::string const &parentname);
void command_sub_menu(const game_driver *drv, std::vector<std::string> &menuitems);
void reset_run() { first_run = true; }
std::string const &rev_history() const { return m_history_rev; }
std::string const &rev_mameinfo() const { return m_mame_rev; }
std::string const &rev_messinfo() const { return m_mess_rev; }
std::string const &rev_sysinfo() const { return m_sysinfo_rev; }
std::string const &rev_storyinfo() const { return m_story_rev; }
std::string const &rev_ginitinfo() const { return m_ginit_rev; }
bool has_history(game_driver const *driver) const { return m_histidx.find(driver) != m_histidx.end(); }
bool has_mameinfo(game_driver const *driver) const { return m_mameidx.find(driver) != m_mameidx.end(); }
bool has_messinfo(game_driver const *driver) const { return m_messidx.find(driver) != m_messidx.end(); }
bool has_command(game_driver const *driver) const { return m_cmdidx.find(driver) != m_cmdidx.end(); }
bool has_sysinfo(game_driver const *driver) const { return m_sysidx.find(driver) != m_sysidx.end(); }
bool has_story(game_driver const *driver) const { return m_storyidx.find(driver) != m_storyidx.end(); }
bool has_gameinit(game_driver const *driver) const { return m_ginitidx.find(driver) != m_ginitidx.end(); }
bool has_software(std::string const &softlist, std::string const &softname, std::string const &parentname) const;
bool has_data(game_driver const *a = nullptr) const
{
game_driver const *const d(a ? a : &machine().system());
return has_history(d) || has_mameinfo(d) || has_messinfo(d) || has_command(d) || has_sysinfo(d) || has_story(d) || has_gameinit(d);
}
private:
using drvindex = std::unordered_map<std::string, long>;
using dataindex = std::unordered_map<const game_driver *, long>;
using swindex = std::unordered_map<std::string, drvindex>;
using fileptr = std::unique_ptr<FILE, int (*)(FILE *)>;
// global index
static dataindex m_histidx, m_mameidx, m_messidx, m_cmdidx, m_sysidx, m_storyidx, m_ginitidx;
static drvindex m_drvidx, m_messdrvidx, m_menuidx;
static swindex m_swindex;
// internal helpers
void init_history(fileptr &&fp);
void init_mameinfo(fileptr &&fp);
void init_messinfo(fileptr &&fp);
void init_command(fileptr &&fp);
void init_sysinfo(fileptr &&fp);
void init_story(fileptr &&fp);
void init_gameinit(fileptr &&fp);
fileptr parseopen(char const *filename);
int index_mame_mess_info(fileptr &&fp, dataindex &index, drvindex &index_drv, int &drvcount);
int index_datafile(fileptr &&fp, dataindex &index, int &swcount, std::string &rev, std::string const &tag, char sep);
void index_menuidx(fileptr &&fp, game_driver const *drv, dataindex const &idx, drvindex &index);
long const *find_software(std::string const &softlist, std::string const &softname, std::string const &parentname) const;
void load_data_text(FILE *fp, game_driver const *drv, std::string &buffer, dataindex const &idx, std::string const &tag);
void load_driver_text(FILE *fp, game_driver const *drv, std::string &buffer, drvindex const &idx, std::string const &tag);
// internal state
running_machine &m_machine; // reference to our machine
ui_options &m_options;
static std::string m_history_rev, m_mame_rev, m_mess_rev, m_sysinfo_rev, m_story_rev, m_ginit_rev;
static bool first_run;
};
} // namespace ui
#endif // MAME_FRONTEND_UI_DATFILE_H

View File

@ -11,7 +11,6 @@
#include "emu.h"
#include "ui/ui.h"
#include "ui/datfile.h"
#include "ui/datmenu.h"
#include "ui/utils.h"
@ -19,6 +18,7 @@
#include "rendfont.h"
#include "softlist.h"
#include "uiinput.h"
#include "luaengine.h"
#include <cmath>
@ -45,8 +45,19 @@ menu_dats_view::menu_dats_view(mame_ui_manager &mui, render_container &container
m_parent = image.software_entry()->parentname();
}
}
init_items();
const char *lua_list = mame_machine_manager::instance()->lua()->call_plugin(driver->name, "data_list");
if(lua_list)
{
std::string list(lua_list);
char *token = strtok((char *)list.c_str(), ",");
int count = 0;
while(token)
{
m_items_list.emplace_back(_(token), count, mame_machine_manager::instance()->lua()->call_plugin(util::string_format("%d", count).c_str(), "data_version"));
count++;
token = strtok(nullptr, ",");
}
}
}
//-------------------------------------------------
@ -65,10 +76,21 @@ menu_dats_view::menu_dats_view(mame_ui_manager &mui, render_container &container
, m_issoft(true)
{
if (mame_machine_manager::instance()->datfile().has_software(m_list, m_short, m_parent))
m_items_list.emplace_back(_("Software History"), UI_HISTORY_LOAD, mame_machine_manager::instance()->datfile().rev_history());
if (swinfo != nullptr && !swinfo->usage.empty())
m_items_list.emplace_back(_("Software Usage"), 0, "");
const char *lua_list = mame_machine_manager::instance()->lua()->call_plugin(std::string(m_short).append(1, ',').append(m_list).c_str(), "data_list");
if(lua_list)
{
std::string list(lua_list);
char *token = strtok((char *)list.c_str(), ",");
int count = 1;
while(token)
{
m_items_list.emplace_back(_(token), count, mame_machine_manager::instance()->lua()->call_plugin(util::string_format("%d", count - 1).c_str(), "data_version"));
count++;
token = strtok(nullptr, ",");
}
}
}
//-------------------------------------------------
@ -368,25 +390,8 @@ void menu_dats_view::custom_render(void *selectedref, float top, float bottom, f
void menu_dats_view::get_data()
{
std::vector<int> xstart, xend;
std::string buffer;
if (m_items_list[m_actual].option == UI_COMMAND_LOAD)
{
std::vector<std::string> m_item;
mame_machine_manager::instance()->datfile().command_sub_menu(m_driver, m_item);
if (!m_item.empty())
{
for (auto & e : m_item)
{
std::string t_buffer;
buffer.append(e).append("\n");
mame_machine_manager::instance()->datfile().load_command_info(t_buffer, e);
if (!t_buffer.empty()) buffer.append(t_buffer).append("\n");
}
convert_command_glyph(buffer);
}
}
else
mame_machine_manager::instance()->datfile().load_data_info(m_driver, buffer, m_items_list[m_actual].option);
std::string buffer(mame_machine_manager::instance()->lua()->call_plugin(util::string_format("%d", m_items_list[m_actual].option).c_str(), "data"));
auto lines = ui().wrap_text(container(), buffer.c_str(), 0.0f, 0.0f, 1.0f - (4.0f * UI_BOX_LR_BORDER), xstart, xend);
for (int x = 0; x < lines; ++x)
@ -404,12 +409,7 @@ void menu_dats_view::get_data_sw()
if (m_items_list[m_actual].option == 0)
buffer = m_swinfo->usage;
else
{
if (m_swinfo->startempty == 1)
mame_machine_manager::instance()->datfile().load_data_info(m_swinfo->driver, buffer, UI_HISTORY_LOAD);
else
mame_machine_manager::instance()->datfile().load_software_info(m_swinfo->listname, buffer, m_swinfo->shortname, m_swinfo->parentname);
}
buffer = mame_machine_manager::instance()->lua()->call_plugin(util::string_format("%d", m_items_list[m_actual].option - 1).c_str(), "data");
auto lines = ui().wrap_text(container(), buffer.c_str(), 0.0f, 0.0f, 1.0f - (4.0f * UI_BOX_LR_BORDER), xstart, xend);
for (int x = 0; x < lines; ++x)
@ -419,23 +419,4 @@ void menu_dats_view::get_data_sw()
}
}
void menu_dats_view::init_items()
{
datfile_manager &datfile = mame_machine_manager::instance()->datfile();
if (datfile.has_history(m_driver))
m_items_list.emplace_back(_("History"), UI_HISTORY_LOAD, datfile.rev_history());
if (datfile.has_mameinfo(m_driver))
m_items_list.emplace_back(_("Mameinfo"), UI_MAMEINFO_LOAD, datfile.rev_mameinfo());
if (datfile.has_messinfo(m_driver))
m_items_list.emplace_back(_("Messinfo"), UI_MESSINFO_LOAD, datfile.rev_messinfo());
if (datfile.has_sysinfo(m_driver))
m_items_list.emplace_back(_("Sysinfo"), UI_SYSINFO_LOAD, datfile.rev_sysinfo());
if (datfile.has_story(m_driver))
m_items_list.emplace_back(_("Mamescore"), UI_STORY_LOAD, datfile.rev_storyinfo());
if (datfile.has_gameinit(m_driver))
m_items_list.emplace_back(_("Gameinit"), UI_GINIT_LOAD, datfile.rev_ginitinfo());
if (datfile.has_command(m_driver))
m_items_list.emplace_back(_("Command"), UI_COMMAND_LOAD, "");
}
} // namespace ui

View File

@ -51,7 +51,6 @@ private:
std::string m_list, m_short, m_long, m_parent;
void get_data();
void get_data_sw();
void init_items();
bool m_issoft;
struct list_items
{

View File

@ -12,7 +12,6 @@
#include "ui/ui.h"
#include "ui/dirmenu.h"
#include "ui/datfile.h"
#include "ui/utils.h"
#include "ui/optsmenu.h"
@ -79,7 +78,6 @@ menu_directory::~menu_directory()
{
ui().save_ui_options();
ui_globals::reset = true;
mame_machine_manager::instance()->datfile().reset_run();
}
//-------------------------------------------------
@ -369,7 +367,6 @@ void menu_add_change_folder::handle()
machine().options().set_value(s_folders[m_ref].option, m_current_path.c_str(), OPTION_PRIORITY_CMDLINE, error_string);
machine().options().mark_changed(s_folders[m_ref].option);
}
mame_machine_manager::instance()->datfile().reset_run();
}
else
{

View File

@ -12,6 +12,7 @@
#include "crsshair.h"
#include "emuopts.h"
#include "mame.h"
#include "luaengine.h"
#include "ui/menu.h"
#include "ui/filemngr.h"
#include "ui/barcode.h"
@ -29,7 +30,6 @@
#include "ui/videoopt.h"
#include "imagedev/cassette.h"
#include "machine/bcreader.h"
#include "ui/datfile.h"
#include "ui/inifile.h"
#include "ui/datmenu.h"
#include "ui/pluginopt.h"
@ -129,7 +129,7 @@ void menu_main::populate()
item_append(_("Plugin Options"), "", 0, (void *)PLUGINS);
// add dats menu
if (ui().options().enabled_dats() && mame_machine_manager::instance()->datfile().has_data())
if (ui().options().enabled_dats() && mame_machine_manager::instance()->lua()->call_plugin("", "data_list"))
item_append(_("External DAT View"), "", 0, (void *)EXTERNAL_DATS);
item_append(menu_item_type::SEPARATOR);

View File

@ -14,7 +14,6 @@
#include "ui/ui.h"
#include "ui/miscmenu.h"
#include "ui/datfile.h"
#include "ui/inifile.h"
#include "ui/datmenu.h"
#include "ui/optsmenu.h"
@ -33,23 +32,10 @@
#include "rendutil.h"
#include "softlist_dev.h"
#include "uiinput.h"
#include "luaengine.h"
extern const char UI_VERSION_TAG[];
namespace ui {
namespace {
char const *const dats_info[] = {
__("General Info"),
__("History"),
__("Mameinfo"),
__("Sysinfo"),
__("Messinfo"),
__("Command"),
__("Gameinit"),
__("Mamescore")
};
} // anonymous namespace
bool menu_select_game::first_start = true;
std::vector<const game_driver *> menu_select_game::m_sortedlist;
@ -61,10 +47,6 @@ int menu_select_game::m_isabios = 0;
menu_select_game::menu_select_game(mame_ui_manager &mui, render_container &container, const char *gamename)
: menu_select_launch(mui, container, false)
, m_info_buffer()
, m_info_driver(nullptr)
, m_info_software(nullptr)
, m_info_view(-1)
{
highlight = 0;
std::string error_string, last_filter, sub_filter;
@ -139,10 +121,11 @@ menu_select_game::menu_select_game(mame_ui_manager &mui, render_container &conta
mui.machine().options().set_value(OPTION_SOFTWARENAME, "", OPTION_PRIORITY_CMDLINE, error_string);
ui_globals::curimage_view = FIRST_VIEW;
ui_globals::curdats_view = UI_FIRST_LOAD;
ui_globals::curdats_view = 0;
ui_globals::switch_image = false;
ui_globals::default_image = true;
ui_globals::panels_status = moptions.hide_panels();
ui_globals::curdats_total = 1;
m_searchlist[0] = nullptr;
}
@ -270,7 +253,7 @@ void menu_select_game::handle()
if (!isfavorite())
{
const game_driver *drv = (const game_driver *)menu_event->itemref;
if ((FPTR)drv > skip_main_items && ui_globals::curdats_view > UI_FIRST_LOAD)
if ((FPTR)drv > skip_main_items && ui_globals::curdats_view > 0)
{
ui_globals::curdats_view--;
m_topline_datsview = 0;
@ -279,7 +262,7 @@ void menu_select_game::handle()
else
{
ui_software_info *drv = (ui_software_info *)menu_event->itemref;
if (drv->startempty == 1 && ui_globals::curdats_view > UI_FIRST_LOAD)
if (drv->startempty == 1 && ui_globals::curdats_view > 0)
{
ui_globals::curdats_view--;
m_topline_datsview = 0;
@ -308,7 +291,7 @@ void menu_select_game::handle()
if (!isfavorite())
{
const game_driver *drv = (const game_driver *)menu_event->itemref;
if ((FPTR)drv > skip_main_items && ui_globals::curdats_view < UI_LAST_LOAD)
if ((FPTR)drv > skip_main_items && ui_globals::curdats_view < ui_globals::curdats_total)
{
ui_globals::curdats_view++;
m_topline_datsview = 0;
@ -317,12 +300,12 @@ void menu_select_game::handle()
else
{
ui_software_info *drv = (ui_software_info *)menu_event->itemref;
if (drv->startempty == 1 && ui_globals::curdats_view < UI_LAST_LOAD)
if (drv->startempty == 1 && ui_globals::curdats_view < ui_globals::curdats_total)
{
ui_globals::curdats_view++;
m_topline_datsview = 0;
}
else if ((FPTR)drv > skip_main_items && ui_globals::cur_sw_dats_view < 1)
else if ((FPTR)drv > skip_main_items && ui_globals::cur_sw_dats_view < ui_globals::cur_sw_dats_total)
{
ui_globals::cur_sw_dats_view++;
m_topline_datsview = 0;
@ -362,19 +345,18 @@ void menu_select_game::handle()
if (!isfavorite())
{
const game_driver *driver = (const game_driver *)menu_event->itemref;
if ((FPTR)driver > skip_main_items && mame_machine_manager::instance()->datfile().has_data(driver))
if ((FPTR)driver > skip_main_items && mame_machine_manager::instance()->lua()->call_plugin(driver->name, "data_list"))
menu::stack_push<menu_dats_view>(ui(), container(), driver);
}
else
{
ui_software_info *ui_swinfo = (ui_software_info *)menu_event->itemref;
datfile_manager &mdat = mame_machine_manager::instance()->datfile();
if ((FPTR)ui_swinfo > skip_main_items)
{
if (ui_swinfo->startempty == 1 && mdat.has_history(ui_swinfo->driver))
if (ui_swinfo->startempty == 1 && mame_machine_manager::instance()->lua()->call_plugin(ui_swinfo->driver->name, "data_list"))
menu::stack_push<menu_dats_view>(ui(), container(), ui_swinfo->driver);
else if (mdat.has_software(ui_swinfo->listname, ui_swinfo->shortname, ui_swinfo->parentname) || !ui_swinfo->usage.empty())
else if (mame_machine_manager::instance()->lua()->call_plugin(std::string(ui_swinfo->shortname).append(1, ',').append(ui_swinfo->listname).c_str(), "data_list") || !ui_swinfo->usage.empty())
menu::stack_push<menu_dats_view>(ui(), container(), ui_swinfo);
}
}
@ -1272,7 +1254,7 @@ void menu_select_game::general_info(const game_driver *driver, std::string &buff
if (cloneof != -1)
util::stream_format(str, _("Driver is Clone of: %1$-.100s\n"), driver_list::driver(cloneof).description);
else
str << _("Driver is Parent\n");
str << _("Driver is Parent:\n");
if (driver->flags & MACHINE_NOT_WORKING)
str << _("Overall: NOT WORKING\n");
@ -1340,6 +1322,24 @@ void menu_select_game::general_info(const game_driver *driver, std::string &buff
else
str << _("Roms Audit Pass: Disabled\nSamples Audit Pass: Disabled\n");
std::istringstream istr(str.str());
std::string line;
float spacewid = ui().get_char_width(0x200a);
str.clear();
str.seekp(0);
str << "#jp\n";
while(std::getline(istr, line))
{
int nspace = floor((0.35 - ui().get_string_width(line.c_str())) / spacewid);
if(nspace < 5)
nspace = 5;
std::string newstr;
newstr.reserve((nspace * 3) + line.length());
newstr.append(line.substr(0, line.find(':')));
for(int i = 0; i < nspace; i++)
newstr.append("\xE2\x80\x8A");
str << newstr.append(line.substr(line.find(':') + 1, line.npos)).append("\n");
}
buffer = str.str();
}
@ -1660,312 +1660,6 @@ float menu_select_game::draw_left_panel(float x1, float y1, float x2, float y2)
}
}
//-------------------------------------------------
// draw infos
//-------------------------------------------------
void menu_select_game::infos_render(float origx1, float origy1, float origx2, float origy2)
{
float const line_height = ui().get_line_height();
float text_size = ui().options().infos_size();
std::vector<int> xstart;
std::vector<int> xend;
ui_software_info const *software;
game_driver const *driver;
get_selection(software, driver);
if (software && ((software->startempty != 1) || !driver))
{
m_info_driver = nullptr;
float gutter_width = 0.4f * line_height * machine().render().ui_aspect() * 1.3f;
float ud_arrow_width = line_height * machine().render().ui_aspect();
float oy1 = origy1 + line_height;
// apply title to right panel
if (software->usage.empty())
{
ui().draw_text_full(container(), _("History"), origx1, origy1, origx2 - origx1, ui::text_layout::CENTER, ui::text_layout::TRUNCATE,
mame_ui_manager::NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr);
ui_globals::cur_sw_dats_view = 0;
}
else
{
float title_size = 0.0f;
float txt_length = 0.0f;
std::string t_text[2];
t_text[0] = _("History");
t_text[1] = _("Usage");
for (auto & elem: t_text)
{
ui().draw_text_full(container(), elem.c_str(), origx1, origy1, origx2 - origx1, ui::text_layout::CENTER, ui::text_layout::TRUNCATE,
mame_ui_manager::NONE, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, &txt_length, nullptr);
txt_length += 0.01f;
title_size = (std::max)(txt_length, title_size);
}
rgb_t fgcolor = UI_TEXT_COLOR;
rgb_t bgcolor = UI_TEXT_BG_COLOR;
if (get_focus() == focused_menu::rightbottom)
{
fgcolor = rgb_t(0xff, 0xff, 0xff, 0x00);
bgcolor = rgb_t(0xff, 0xff, 0xff, 0xff);
}
float middle = origx2 - origx1;
if (bgcolor != UI_TEXT_BG_COLOR)
{
ui().draw_textured_box(container(), origx1 + ((middle - title_size) * 0.5f), origy1, origx1 + ((middle + title_size) * 0.5f),
origy1 + line_height, bgcolor, rgb_t(255, 43, 43, 43), hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE));
}
ui().draw_text_full(container(), t_text[ui_globals::cur_sw_dats_view].c_str(), origx1, origy1, origx2 - origx1,
ui::text_layout::CENTER, ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr);
draw_common_arrow(origx1, origy1, origx2, origy2, ui_globals::cur_sw_dats_view, 0, 1, title_size);
}
if (m_info_software != software || m_info_view != ui_globals::cur_sw_dats_view)
{
m_info_buffer.clear();
m_info_view = ui_globals::cur_sw_dats_view;
m_info_software = software;
if (ui_globals::cur_sw_dats_view == 0)
{
if (software->startempty == 1)
mame_machine_manager::instance()->datfile().load_data_info(software->driver, m_info_buffer, UI_HISTORY_LOAD);
else
mame_machine_manager::instance()->datfile().load_software_info(software->listname, m_info_buffer, software->shortname, software->parentname);
}
else
m_info_buffer = software->usage;
}
if (m_info_buffer.empty())
{
ui().draw_text_full(container(), _("No Infos Available"), origx1, (origy2 + origy1) * 0.5f, origx2 - origx1, ui::text_layout::CENTER,
ui::text_layout::WORD, mame_ui_manager::NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr);
return;
}
else
{
m_total_lines = ui().wrap_text(container(), m_info_buffer.c_str(), origx1, origy1, origx2 - origx1 - (2.0f * gutter_width), xstart, xend, text_size);
}
int r_visible_lines = floor((origy2 - oy1) / (line_height * text_size));
if (m_total_lines < r_visible_lines)
r_visible_lines = m_total_lines;
if (m_topline_datsview < 0)
m_topline_datsview = 0;
if (m_topline_datsview + r_visible_lines >= m_total_lines)
m_topline_datsview = m_total_lines - r_visible_lines;
for (int r = 0; r < r_visible_lines; ++r)
{
int itemline = r + m_topline_datsview;
std::string tempbuf(m_info_buffer.substr(xstart[itemline], xend[itemline] - xstart[itemline]));
// up arrow
if (r == 0 && m_topline_datsview != 0)
draw_info_arrow(0, origx1, origx2, oy1, line_height, text_size, ud_arrow_width);
// bottom arrow
else if (r == r_visible_lines - 1 && itemline != m_total_lines - 1)
draw_info_arrow(1, origx1, origx2, oy1, line_height, text_size, ud_arrow_width);
else
ui().draw_text_full(container(), tempbuf.c_str(), origx1 + gutter_width, oy1, origx2 - origx1, ui::text_layout::LEFT,
ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr, text_size);
oy1 += (line_height * text_size);
}
// return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow
right_visible_lines = r_visible_lines - (m_topline_datsview != 0) - (m_topline_datsview + r_visible_lines != m_total_lines);
}
else if (driver)
{
m_info_software = nullptr;
float gutter_width = 0.4f * line_height * machine().render().ui_aspect() * 1.3f;
float ud_arrow_width = line_height * machine().render().ui_aspect();
float oy1 = origy1 + line_height;
// MAMESCORE? Full size text
if (ui_globals::curdats_view == UI_STORY_LOAD)
text_size = 1.0f;
std::string snaptext(_(dats_info[ui_globals::curdats_view]));
// apply title to right panel
float title_size = 0.0f;
float txt_length = 0.0f;
for (int x = UI_FIRST_LOAD; x < UI_LAST_LOAD; ++x)
{
ui().draw_text_full(container(), _(dats_info[x]), origx1, origy1, origx2 - origx1, ui::text_layout::CENTER,
ui::text_layout::NEVER, mame_ui_manager::NONE, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, &txt_length, nullptr);
txt_length += 0.01f;
title_size = (std::max)(txt_length, title_size);
}
rgb_t fgcolor = UI_TEXT_COLOR;
rgb_t bgcolor = UI_TEXT_BG_COLOR;
if (get_focus() == focused_menu::rightbottom)
{
fgcolor = rgb_t(0xff, 0xff, 0xff, 0x00);
bgcolor = rgb_t(0xff, 0xff, 0xff, 0xff);
}
float middle = origx2 - origx1;
// check size
float sc = title_size + 2.0f * gutter_width;
float tmp_size = (sc > middle) ? ((middle - 2.0f * gutter_width) / sc) : 1.0f;
title_size *= tmp_size;
if (bgcolor != UI_TEXT_BG_COLOR)
{
ui().draw_textured_box(container(), origx1 + ((middle - title_size) * 0.5f), origy1, origx1 + ((middle + title_size) * 0.5f),
origy1 + line_height, bgcolor, rgb_t(255, 43, 43, 43), hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE));
}
ui().draw_text_full(container(), snaptext.c_str(), origx1, origy1, origx2 - origx1, ui::text_layout::CENTER,
ui::text_layout::NEVER, mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr, tmp_size);
draw_common_arrow(origx1, origy1, origx2, origy2, ui_globals::curdats_view, UI_FIRST_LOAD, UI_LAST_LOAD, title_size);
if (driver != m_info_driver || ui_globals::curdats_view != m_info_view)
{
m_info_buffer.clear();
m_info_driver = driver;
m_info_view = ui_globals::curdats_view;
m_topline_datsview = 0;
m_total_lines = 0;
std::vector<std::string> m_item;
if (ui_globals::curdats_view == UI_GENERAL_LOAD)
general_info(driver, m_info_buffer);
else if (ui_globals::curdats_view != UI_COMMAND_LOAD)
mame_machine_manager::instance()->datfile().load_data_info(driver, m_info_buffer, ui_globals::curdats_view);
else
mame_machine_manager::instance()->datfile().command_sub_menu(driver, m_item);
if (!m_item.empty() && ui_globals::curdats_view == UI_COMMAND_LOAD)
{
for (size_t x = 0; x < m_item.size(); ++x)
{
std::string t_buffer;
m_info_buffer.append(m_item[x]).append("\n");
mame_machine_manager::instance()->datfile().load_command_info(t_buffer, m_item[x]);
if (!t_buffer.empty())
m_info_buffer.append(t_buffer).append("\n");
}
convert_command_glyph(m_info_buffer);
}
}
if (m_info_buffer.empty())
{
ui().draw_text_full(container(), _("No Infos Available"), origx1, (origy2 + origy1) * 0.5f, origx2 - origx1, ui::text_layout::CENTER,
ui::text_layout::WORD, mame_ui_manager::NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr);
return;
}
else if (ui_globals::curdats_view != UI_STORY_LOAD && ui_globals::curdats_view != UI_COMMAND_LOAD)
m_total_lines = ui().wrap_text(container(), m_info_buffer.c_str(), origx1, origy1, origx2 - origx1 - (2.0f * gutter_width), xstart, xend, text_size);
else
m_total_lines = ui().wrap_text(container(), m_info_buffer.c_str(), 0.0f, 0.0f, 1.0f - (2.0f * gutter_width), xstart, xend, text_size);
int r_visible_lines = floor((origy2 - oy1) / (line_height * text_size));
if (m_total_lines < r_visible_lines)
r_visible_lines = m_total_lines;
if (m_topline_datsview < 0)
m_topline_datsview = 0;
if (m_topline_datsview + r_visible_lines >= m_total_lines)
m_topline_datsview = m_total_lines - r_visible_lines;
sc = origx2 - origx1 - (2.0f * UI_BOX_LR_BORDER);
for (int r = 0; r < r_visible_lines; ++r)
{
int itemline = r + m_topline_datsview;
std::string tempbuf(m_info_buffer.substr(xstart[itemline], xend[itemline] - xstart[itemline]));
// up arrow
if (r == 0 && m_topline_datsview != 0)
draw_info_arrow(0, origx1, origx2, oy1, line_height, text_size, ud_arrow_width);
// bottom arrow
else if (r == r_visible_lines - 1 && itemline != m_total_lines - 1)
draw_info_arrow(1, origx1, origx2, oy1, line_height, text_size, ud_arrow_width);
// special case for mamescore
else if (ui_globals::curdats_view == UI_STORY_LOAD)
{
// check size
float textlen = ui().get_string_width(tempbuf.c_str(), text_size);
float tmp_size2 = (textlen > sc) ? text_size * (sc / textlen) : text_size;
size_t last_underscore = tempbuf.find_last_of("_");
if (last_underscore == std::string::npos)
{
ui().draw_text_full(container(), tempbuf.c_str(), origx1, oy1, origx2 - origx1, ui::text_layout::CENTER,
ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr, tmp_size2);
}
else
{
float effective_width = origx2 - origx1 - gutter_width;
float effective_left = origx1 + gutter_width;
std::string last_part(tempbuf.substr(last_underscore + 1));
std::string first_part(tempbuf.substr(0, tempbuf.find("___")));
float item_width;
ui().draw_text_full(container(), first_part.c_str(), effective_left, oy1, effective_width,
ui::text_layout::LEFT, ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, &item_width, nullptr, tmp_size2);
ui().draw_text_full(container(), last_part.c_str(), effective_left + item_width, oy1,
origx2 - origx1 - 2.0f * gutter_width - item_width, ui::text_layout::RIGHT, ui::text_layout::TRUNCATE,
mame_ui_manager::NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr, tmp_size2);
}
}
// special case for command
else if (ui_globals::curdats_view == UI_COMMAND_LOAD || ui_globals::curdats_view == UI_GENERAL_LOAD)
{
// check size
float textlen = ui().get_string_width(tempbuf.c_str(), text_size);
float tmp_size3 = (textlen > sc) ? text_size * (sc / textlen) : text_size;
int first_dspace = (ui_globals::curdats_view == UI_COMMAND_LOAD) ? tempbuf.find(" ") : tempbuf.find(":");
if (first_dspace > 0)
{
float effective_width = origx2 - origx1 - gutter_width;
float effective_left = origx1 + gutter_width;
std::string first_part(tempbuf.substr(0, first_dspace));
std::string last_part(tempbuf.substr(first_dspace + 1));
strtrimspace(last_part);
ui().draw_text_full(container(), first_part.c_str(), effective_left, oy1, effective_width, ui::text_layout::LEFT,
ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr, tmp_size3);
ui().draw_text_full(container(), last_part.c_str(), effective_left, oy1, origx2 - origx1 - 2.0f * gutter_width,
ui::text_layout::RIGHT, ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr, tmp_size3);
}
else
{
ui().draw_text_full(container(), tempbuf.c_str(), origx1 + gutter_width, oy1, origx2 - origx1, ui::text_layout::LEFT,
ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr, tmp_size3);
}
}
else
{
ui().draw_text_full(container(), tempbuf.c_str(), origx1 + gutter_width, oy1, origx2 - origx1, ui::text_layout::LEFT,
ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr, text_size);
}
oy1 += (line_height * text_size);
}
// return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow
right_visible_lines = r_visible_lines - (m_topline_datsview != 0) - (m_topline_datsview + r_visible_lines != m_total_lines);
}
}
//-------------------------------------------------
@ -1986,7 +1680,6 @@ void menu_select_game::get_selection(ui_software_info const *&software, game_dri
}
}
void menu_select_game::make_topbox_text(std::string &line0, std::string &line1, std::string &line2) const
{
inifile_manager &inifile = mame_machine_manager::instance()->inifile();

View File

@ -43,11 +43,6 @@ private:
static int m_isabios;
int highlight;
std::string m_info_buffer;
game_driver const *m_info_driver;
ui_software_info const *m_info_software;
int m_info_view;
static std::vector<const game_driver *> m_sortedlist;
std::vector<const game_driver *> m_availsortedlist;
std::vector<const game_driver *> m_unavailsortedlist;
@ -88,9 +83,7 @@ private:
}
// General info
void general_info(const game_driver *driver, std::string &buffer);
virtual void infos_render(float x1, float y1, float x2, float y2) override;
virtual void general_info(const game_driver *driver, std::string &buffer) override;
// handlers
void inkey_select(const event *menu_event);

View File

@ -29,6 +29,7 @@
#include "rendutil.h"
#include "softlist.h"
#include "uiinput.h"
#include "luaengine.h"
#include <algorithm>
#include <cmath>
@ -153,6 +154,10 @@ menu_select_launch::menu_select_launch(mame_ui_manager &mui, render_container &c
, m_total_lines(0)
, m_topline_datsview(0)
, m_ui_error(false)
, m_info_driver(nullptr)
, m_info_software(nullptr)
, m_info_view(-1)
, m_info_buffer()
, m_cache()
, m_is_swlist(is_swlist)
, m_focus(focused_menu::main)
@ -493,7 +498,9 @@ void menu_select_launch::draw_common_arrow(float origx1, float origy1, float ori
}
// apply arrow
if (current == dmin)
if (dmax == dmin)
return;
else if (current == dmin)
draw_arrow(ar_x0, ar_y0, ar_x1, ar_y1, fgcolor_right, ROT90);
else if (current == dmax)
draw_arrow(al_x0, al_y0, al_x1, al_y1, fgcolor_left, ROT90 ^ ORIENTATION_FLIP_X);
@ -1871,4 +1878,211 @@ void menu_select_launch::exit(running_machine &machine)
s_caches.erase(&machine);
}
//-------------------------------------------------
// draw infos
//-------------------------------------------------
void menu_select_launch::infos_render(float origx1, float origy1, float origx2, float origy2)
{
float const line_height = ui().get_line_height();
float text_size = ui().options().infos_size();
std::vector<int> xstart;
std::vector<int> xend;
const char *first = "";
ui_software_info const *software;
game_driver const *driver;
int total;
get_selection(software, driver);
if (software && ((software->startempty != 1) || !driver))
{
m_info_driver = nullptr;
first = "Usage";
if (m_info_software != software || m_info_view != ui_globals::cur_sw_dats_view)
{
m_info_buffer.clear();
if (software == m_info_software)
{
m_info_view = ui_globals::cur_sw_dats_view;
}
else
{
m_info_view = 0;
m_info_software = software;
ui_globals::cur_sw_dats_view = 0;
ui_globals::cur_sw_dats_total = 1;
const char *lua_list = mame_machine_manager::instance()->lua()->call_plugin(std::string(software->shortname).append(1, ',').append(software->listname).c_str(), "data_list");
m_items_list.clear();
if(lua_list)
{
std::string list(lua_list);
char *token = strtok((char *)list.c_str(), ",");
while(token)
{
ui_globals::cur_sw_dats_total++;
m_items_list.emplace_back(token);
token = strtok(nullptr, ",");
}
}
}
if (m_info_view == 0)
m_info_buffer = software->usage;
else
m_info_buffer = mame_machine_manager::instance()->lua()->call_plugin(util::string_format("%d", m_info_view - 1).c_str(), "data");
}
total = ui_globals::cur_sw_dats_total;
}
else if (driver)
{
m_info_software = nullptr;
first = "General Info";
if (driver != m_info_driver || ui_globals::curdats_view != m_info_view)
{
m_info_buffer.clear();
if (driver == m_info_driver)
{
m_info_view = ui_globals::curdats_view;
}
else
{
m_info_driver = driver;
m_info_view = 0;
ui_globals::curdats_view = 0;
ui_globals::curdats_total = 1;
const char *lua_list = mame_machine_manager::instance()->lua()->call_plugin(driver->name, "data_list");
m_items_list.clear();
if(lua_list)
{
std::string list(lua_list);
char *token = strtok((char *)list.c_str(), ",");
while(token)
{
ui_globals::curdats_total++;
m_items_list.emplace_back(token);
token = strtok(nullptr, ",");
}
}
}
if (m_info_view == 0)
general_info(driver, m_info_buffer);
else
m_info_buffer = mame_machine_manager::instance()->lua()->call_plugin(util::string_format("%d", m_info_view - 1).c_str(), "data");
}
total = ui_globals::curdats_total;
}
else
return;
float gutter_width = 0.4f * line_height * machine().render().ui_aspect() * 1.3f;
float ud_arrow_width = line_height * machine().render().ui_aspect();
float oy1 = origy1 + line_height;
std::string snaptext;
if (m_info_view)
snaptext = _(m_items_list[m_info_view - 1].c_str());
else
snaptext = _(first);
// apply title to right panel
float title_size = 0.0f;
float txt_length = 0.0f;
for (int x = 0; x < ui_globals::curdats_total; ++x)
{
const char *name;
if(!x)
name = first;
else
name = m_items_list[x - 1].c_str();
ui().draw_text_full(container(), _(name), origx1, origy1, origx2 - origx1, ui::text_layout::CENTER,
ui::text_layout::NEVER, mame_ui_manager::NONE, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, &txt_length, nullptr);
txt_length += 0.01f;
title_size = (std::max)(txt_length, title_size);
}
rgb_t fgcolor = UI_TEXT_COLOR;
rgb_t bgcolor = UI_TEXT_BG_COLOR;
if (get_focus() == focused_menu::rightbottom)
{
fgcolor = rgb_t(0xff, 0xff, 0xff, 0x00);
bgcolor = rgb_t(0xff, 0xff, 0xff, 0xff);
}
float middle = origx2 - origx1;
// check size
float sc = title_size + 2.0f * gutter_width;
float tmp_size = (sc > middle) ? ((middle - 2.0f * gutter_width) / sc) : 1.0f;
title_size *= tmp_size;
if (bgcolor != UI_TEXT_BG_COLOR)
{
ui().draw_textured_box(container(), origx1 + ((middle - title_size) * 0.5f), origy1, origx1 + ((middle + title_size) * 0.5f),
origy1 + line_height, bgcolor, rgb_t(255, 43, 43, 43), hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE));
}
ui().draw_text_full(container(), snaptext.c_str(), origx1, origy1, origx2 - origx1, ui::text_layout::CENTER,
ui::text_layout::NEVER, mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr, tmp_size);
char justify = 'l'; // left justify
if ((m_info_buffer.length() >= 3) && (m_info_buffer[0] == '#'))
{
if (m_info_buffer[1] == 'j')
justify = m_info_buffer[2];
}
draw_common_arrow(origx1, origy1, origx2, origy2, m_info_view, 0, total - 1, title_size);
if (justify == 'f')
m_total_lines = ui().wrap_text(container(), m_info_buffer.c_str(), 0.0f, 0.0f, 1.0f - (2.0f * gutter_width), xstart, xend, text_size);
else
m_total_lines = ui().wrap_text(container(), m_info_buffer.c_str(), origx1, origy1, origx2 - origx1 - (2.0f * gutter_width), xstart, xend, text_size);
int r_visible_lines = floor((origy2 - oy1) / (line_height * text_size));
if (m_total_lines < r_visible_lines)
r_visible_lines = m_total_lines;
if (m_topline_datsview < 0)
m_topline_datsview = 0;
if (m_topline_datsview + r_visible_lines >= m_total_lines)
m_topline_datsview = m_total_lines - r_visible_lines;
sc = origx2 - origx1 - (2.0f * UI_BOX_LR_BORDER);
for (int r = 0; r < r_visible_lines; ++r)
{
int itemline = r + m_topline_datsview;
std::string tempbuf(m_info_buffer.substr(xstart[itemline], xend[itemline] - xstart[itemline]));
if (tempbuf[0] == '#')
continue;
// up arrow
if (r == 0 && m_topline_datsview != 0)
draw_info_arrow(0, origx1, origx2, oy1, line_height, text_size, ud_arrow_width);
// bottom arrow
else if (r == r_visible_lines - 1 && itemline != m_total_lines - 1)
draw_info_arrow(1, origx1, origx2, oy1, line_height, text_size, ud_arrow_width);
else if (justify == 'f' || justify == 'p') // full or partial justify
{
// check size
float textlen = ui().get_string_width(tempbuf.c_str(), text_size);
float tmp_size3 = (textlen > sc) ? text_size * (sc / textlen) : text_size;
ui().draw_text_full(container(), tempbuf.c_str(), origx1 + gutter_width, oy1, origx2 - origx1, ui::text_layout::LEFT,
ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr, tmp_size3);
}
else
{
ui().draw_text_full(container(), tempbuf.c_str(), origx1 + gutter_width, oy1, origx2 - origx1, ui::text_layout::LEFT,
ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr, text_size);
}
oy1 += (line_height * text_size);
}
// return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow
right_visible_lines = r_visible_lines - (m_topline_datsview != 0) - (m_topline_datsview + r_visible_lines != m_total_lines);
}
} // namespace ui

View File

@ -115,8 +115,15 @@ private:
// draw left panel
virtual float draw_left_panel(float x1, float y1, float x2, float y2) = 0;
game_driver const *m_info_driver;
ui_software_info const *m_info_software;
int m_info_view;
std::vector<std::string> m_items_list;
std::string m_info_buffer;
// draw infos
virtual void infos_render(float x1, float y1, float x2, float y2) = 0;
void infos_render(float x1, float y1, float x2, float y2);
virtual void general_info(const game_driver *driver, std::string &buffer) = 0;
// get selected software and/or driver
virtual void get_selection(ui_software_info const *&software, game_driver const *&driver) const = 0;

View File

@ -14,7 +14,6 @@
#include "ui/ui.h"
#include "ui/datmenu.h"
#include "ui/datfile.h"
#include "ui/inifile.h"
#include "ui/selector.h"
@ -26,6 +25,7 @@
#include "rendutil.h"
#include "softlist_dev.h"
#include "uiinput.h"
#include "luaengine.h"
namespace ui {
@ -142,7 +142,8 @@ menu_select_software::menu_select_software(mame_ui_manager &mui, render_containe
ui_globals::curimage_view = SNAPSHOT_VIEW;
ui_globals::switch_image = true;
ui_globals::cur_sw_dats_view = UI_FIRST_LOAD;
ui_globals::cur_sw_dats_view = 0;
ui_globals::cur_sw_dats_total = 1;
std::string error_string;
mui.machine().options().set_value(OPTION_SOFTWARENAME, "", OPTION_PRIORITY_CMDLINE, error_string);
@ -224,7 +225,7 @@ void menu_select_software::handle()
ui_globals::switch_image = true;
ui_globals::default_image = false;
}
else if (ui_globals::rpanel == RP_INFOS && ui_globals::cur_sw_dats_view < 1)
else if (ui_globals::rpanel == RP_INFOS && ui_globals::cur_sw_dats_view < ui_globals::cur_sw_dats_total)
{
// Infos
ui_globals::cur_sw_dats_view++;
@ -245,11 +246,10 @@ void menu_select_software::handle()
{
// handle UI_DATS
ui_software_info *ui_swinfo = (ui_software_info *)menu_event->itemref;
datfile_manager &mdat = mame_machine_manager::instance()->datfile();
if (ui_swinfo->startempty == 1 && mdat.has_history(ui_swinfo->driver))
if (ui_swinfo->startempty == 1 && mame_machine_manager::instance()->lua()->call_plugin(ui_swinfo->driver->name, "data_list"))
menu::stack_push<menu_dats_view>(ui(), container(), ui_swinfo->driver);
else if (mdat.has_software(ui_swinfo->listname, ui_swinfo->shortname, ui_swinfo->parentname) || !ui_swinfo->usage.empty())
else if (mame_machine_manager::instance()->lua()->call_plugin(std::string(ui_swinfo->shortname).append(1, ',').append(ui_swinfo->listname).c_str(), "data_list") || !ui_swinfo->usage.empty())
menu::stack_push<menu_dats_view>(ui(), container(), ui_swinfo);
}
else if (menu_event->iptkey == IPT_UI_LEFT_PANEL)
@ -339,7 +339,7 @@ void menu_select_software::handle()
ui_globals::switch_image = true;
ui_globals::default_image = false;
}
else if (ui_globals::rpanel == RP_INFOS && ui_globals::cur_sw_dats_view < 1)
else if (ui_globals::rpanel == RP_INFOS && ui_globals::cur_sw_dats_view < ui_globals::cur_sw_dats_total)
{
// Infos
ui_globals::cur_sw_dats_view++;
@ -1258,151 +1258,6 @@ float menu_select_software::draw_left_panel(float x1, float y1, float x2, float
}
}
//-------------------------------------------------
// draw infos
//-------------------------------------------------
void menu_select_software::infos_render(float origx1, float origy1, float origx2, float origy2)
{
float line_height = ui().get_line_height();
static std::string buffer;
std::vector<int> xstart;
std::vector<int> xend;
float text_size = ui().options().infos_size();
ui_software_info *soft = (get_selection_ref() != nullptr) ? (ui_software_info *)get_selection_ref() : ((m_prev_selected != nullptr) ? (ui_software_info *)m_prev_selected : nullptr);
static ui_software_info *oldsoft = nullptr;
static int old_sw_view = -1;
float gutter_width = 0.4f * line_height * machine().render().ui_aspect() * 1.3f;
float ud_arrow_width = line_height * machine().render().ui_aspect();
float oy1 = origy1 + line_height;
// apply title to right panel
if (soft != nullptr && soft->usage.empty())
{
float title_size = 0.0f;
ui().draw_text_full(container(), _("History"), origx1, origy1, origx2 - origx1, ui::text_layout::CENTER, ui::text_layout::TRUNCATE,
mame_ui_manager::NONE, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, &title_size, nullptr);
title_size += 0.01f;
rgb_t fgcolor = UI_TEXT_COLOR;
rgb_t bgcolor = UI_TEXT_BG_COLOR;
if (get_focus() == focused_menu::rightbottom)
{
fgcolor = rgb_t(0xff, 0xff, 0xff, 0x00);
bgcolor = rgb_t(0xff, 0xff, 0xff, 0xff);
}
float middle = origx2 - origx1;
if (bgcolor != UI_TEXT_BG_COLOR)
ui().draw_textured_box(container(), origx1 + ((middle - title_size) * 0.5f), origy1, origx1 + ((middle + title_size) * 0.5f),
origy1 + line_height, bgcolor, rgb_t(255, 43, 43, 43), hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE));
ui().draw_text_full(container(), _("History"), origx1, origy1, origx2 - origx1, ui::text_layout::CENTER, ui::text_layout::NEVER,
mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr);
ui_globals::cur_sw_dats_view = 0;
}
else
{
float title_size = 0.0f;
float txt_lenght = 0.0f;
std::string t_text[2];
t_text[0] = _("History");
t_text[1] = _("Usage");
for (auto & elem : t_text)
{
ui().draw_text_full(container(), elem.c_str(), origx1, origy1, origx2 - origx1, ui::text_layout::CENTER, ui::text_layout::NEVER,
mame_ui_manager::NONE, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, &txt_lenght, nullptr);
txt_lenght += 0.01f;
title_size = std::max(txt_lenght, title_size);
}
rgb_t fgcolor = UI_TEXT_COLOR;
rgb_t bgcolor = UI_TEXT_BG_COLOR;
if (get_focus() == focused_menu::rightbottom)
{
fgcolor = rgb_t(0xff, 0xff, 0xff, 0x00);
bgcolor = rgb_t(0xff, 0xff, 0xff, 0xff);
}
float middle = origx2 - origx1;
// check size
float sc = title_size + 2.0f * gutter_width;
float tmp_size = (sc > middle) ? ((middle - 2.0f * gutter_width) / sc) : 1.0f;
title_size *= tmp_size;
if (bgcolor != UI_TEXT_BG_COLOR)
ui().draw_textured_box(container(), origx1 + ((middle - title_size) * 0.5f), origy1, origx1 + ((middle + title_size) * 0.5f),
origy1 + line_height, bgcolor, rgb_t(255, 43, 43, 43), hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE));
ui().draw_text_full(container(), t_text[ui_globals::cur_sw_dats_view].c_str(), origx1, origy1, origx2 - origx1,
ui::text_layout::CENTER, ui::text_layout::NEVER, mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr, tmp_size);
draw_common_arrow(origx1, origy1, origx2, origy2, ui_globals::cur_sw_dats_view, 0, 1, title_size);
}
if (oldsoft != soft || old_sw_view != ui_globals::cur_sw_dats_view)
{
buffer.clear();
old_sw_view = ui_globals::cur_sw_dats_view;
oldsoft = soft;
if (ui_globals::cur_sw_dats_view == 0)
{
if (soft->startempty == 1)
mame_machine_manager::instance()->datfile().load_data_info(soft->driver, buffer, UI_HISTORY_LOAD);
else
mame_machine_manager::instance()->datfile().load_software_info(soft->listname, buffer, soft->shortname, soft->parentname);
}
else
buffer = soft->usage;
}
if (buffer.empty())
{
ui().draw_text_full(container(), _("No Infos Available"), origx1, (origy2 + origy1) * 0.5f, origx2 - origx1, ui::text_layout::CENTER,
ui::text_layout::WORD, mame_ui_manager::NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr);
return;
}
else
m_total_lines = ui().wrap_text(container(), buffer.c_str(), origx1, origy1, origx2 - origx1 - (2.0f * gutter_width), xstart, xend, text_size);
int r_visible_lines = floor((origy2 - oy1) / (line_height * text_size));
if (m_total_lines < r_visible_lines)
r_visible_lines = m_total_lines;
if (m_topline_datsview < 0)
m_topline_datsview = 0;
if (m_topline_datsview + r_visible_lines >= m_total_lines)
m_topline_datsview = m_total_lines - r_visible_lines;
for (int r = 0; r < r_visible_lines; ++r)
{
int itemline = r + m_topline_datsview;
std::string tempbuf;
tempbuf.assign(buffer.substr(xstart[itemline], xend[itemline] - xstart[itemline]));
// up arrow
if (r == 0 && m_topline_datsview != 0)
draw_info_arrow(0, origx1, origx2, oy1, line_height, text_size, ud_arrow_width);
// bottom arrow
else if (r == r_visible_lines - 1 && itemline != m_total_lines - 1)
draw_info_arrow(1, origx1, origx2, oy1, line_height, text_size, ud_arrow_width);
else
ui().draw_text_full(container(), tempbuf.c_str(), origx1 + gutter_width, oy1, origx2 - origx1,
ui::text_layout::LEFT, ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR,
nullptr, nullptr, text_size);
oy1 += (line_height * text_size);
}
// return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow
right_visible_lines = r_visible_lines - (m_topline_datsview != 0) - (m_topline_datsview + r_visible_lines != m_total_lines);
}
//-------------------------------------------------
// ctor
//-------------------------------------------------

View File

@ -61,11 +61,11 @@ private:
void find_matches(const char *str, int count);
void load_sw_custom_filters();
virtual void infos_render(float x1, float y1, float x2, float y2) override;
// handlers
void inkey_select(const event *menu_event);
void inkey_special(const event *menu_event);
virtual void general_info(const game_driver *driver, std::string &buffer) override {}
};
class software_parts : public menu

View File

@ -40,6 +40,8 @@ size_t sw_filters::length = ARRAY_LENGTH(sw_filters::text);
UINT8 ui_globals::rpanel = 0;
UINT8 ui_globals::curimage_view = 0;
UINT8 ui_globals::curdats_view = 0;
UINT8 ui_globals::cur_sw_dats_total = 0;
UINT8 ui_globals::curdats_total = 0;
UINT8 ui_globals::cur_sw_dats_view = 0;
bool ui_globals::switch_image = false;
bool ui_globals::default_image = true;

View File

@ -84,20 +84,6 @@ enum
HIDE_BOTH
};
enum
{
UI_FIRST_LOAD = 0,
UI_GENERAL_LOAD = UI_FIRST_LOAD,
UI_HISTORY_LOAD,
UI_MAMEINFO_LOAD,
UI_SYSINFO_LOAD,
UI_MESSINFO_LOAD,
UI_COMMAND_LOAD,
UI_GINIT_LOAD,
UI_STORY_LOAD,
UI_LAST_LOAD = UI_STORY_LOAD
};
enum : UINT16
{
UI_SW_FIRST = 0,
@ -202,7 +188,7 @@ struct c_year
// GLOBAL CLASS
struct ui_globals
{
static UINT8 curimage_view, curdats_view, cur_sw_dats_view, rpanel;
static UINT8 curimage_view, curdats_view, curdats_total, cur_sw_dats_view, cur_sw_dats_total, rpanel;
static bool switch_image, redraw_icon, default_image, reset;
static int visible_main_lines, visible_sw_lines;
static UINT16 panels_status;