daily pastebin goal
81%
SHARE
TWEET

modified init.lua

a guest Dec 21st, 2018 70 in 54 days
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- license:BSD-3-Clause
  2. -- copyright-holders:Carl
  3. -- This includes a library of functions to be used at the Lua console as cf.getspaces() etc...
  4. local exports = {}
  5. exports.name = "cheatfind"
  6. exports.version = "0.0.1"
  7. exports.description = "Cheat finder helper library"
  8. exports.license = "The BSD 3-Clause License"
  9. exports.author = { name = "Carl" }
  10.  
  11. local cheatfind = exports
  12.  
  13. function cheatfind.startplugin()
  14.     local cheat = {}
  15.  
  16.     -- return table of devices and spaces
  17.     function cheat.getspaces()
  18.         local spaces = {}
  19.         for tag, device in pairs(manager:machine().devices) do
  20.             if device.spaces then
  21.                 spaces[tag] = {}
  22.                 for name, space in pairs(device.spaces) do
  23.                     spaces[tag][name] = space
  24.                 end
  25.             end
  26.         end
  27.         return spaces
  28.     end
  29.  
  30.     -- return table of ram devices
  31.     function cheat.getram()
  32.         local ram = {}
  33.         for tag, device in pairs(manager:machine().devices) do
  34.             if device:shortname() == "ram" then
  35.                 ram[tag] = {}
  36.                 ram[tag].dev = device
  37.                 ram[tag].size = emu.item(device.items["0/m_size"]):read(0)
  38.             end
  39.         end
  40.         return ram
  41.     end
  42.  
  43.     -- return table of share regions
  44.     function cheat.getshares()
  45.         local shares = {}
  46.         for tag, share in pairs(manager:machine():memory().shares) do
  47.             shares[tag] = share
  48.         end
  49.         return shares
  50.     end
  51.  
  52.     -- save data block
  53.     function cheat.save(space, start, size)
  54.         local data = { block = "", start = start, size = size, space = space, shift = 0 }
  55.         if getmetatable(space).__name:match("addr_space") then
  56.             data.shift = space.shift
  57.         end
  58.         if getmetatable(space).__name:match("device_t") then
  59.             if space:shortname() == "ram" then
  60.                 data.block = emu.item(space.items["0/m_pointer"]):read_block(start, size)
  61.                 if not data.block then
  62.                     return nil
  63.                 end
  64.             end
  65.         else
  66.             local block = ""
  67.             local temp = {}
  68.             local j = 1
  69.             if data.shift >= 0 then -- region or byte wide space
  70.                 for i = start, start + (size << data.shift), 1 << data.shift do
  71.                     if j < 65536 then
  72.                         temp[j] = string.pack("B", space:read_u8(i))
  73.                         j = j + 1
  74.                     else
  75.                         block = block .. table.concat(temp) .. string.pack("B", space:read_u8(i))
  76.                         temp = {}
  77.                         j = 1
  78.                     end
  79.                 end
  80.             elseif data.shift < 0 then
  81.                 local s = -data.shift
  82.                 local read = (s == 1) and space.read_u16 or (s == 2) and space.read_u32 or (s == 3) and space.read_u64 or space.read_u8
  83.                 local pack = (s == 1) and "<I2" or (s == 2) and "<I4" or (s == 3) and "<I8" or "B"
  84.                 for i = start, start + (size >> s) do
  85.                     if j < 65536 then
  86.                         temp[j] = string.pack(pack, read(space, i))
  87.                         j = j + 1
  88.                     else
  89.                         block = block .. table.concat(temp) .. string.pack(pack, read(space, i))
  90.                         temp = {}
  91.                         j = 1
  92.                     end
  93.                 end
  94.             end
  95.             block = block .. table.concat(temp)
  96.             data.block = block
  97.         end
  98.         return data
  99.     end
  100.  
  101.     -- compare two data blocks, format is as lua string.unpack, bne and beq val is table of masks, step is address increment value
  102.     function cheat.comp(newdata, olddata, oper, format, val, bcd, step)
  103.         local ret = {}
  104.         local ref = {} -- this is a helper for comparing two match lists
  105.         local bitmask = nil
  106.         if not step or step <= 0 then
  107.             step = 1
  108.         end
  109.  
  110.         local cfoper = {
  111.             lt = function(a, b, val) return (a < b and val == 0) or (val > 0 and (a + val) == b) end,
  112.             gt = function(a, b, val) return (a > b and val == 0) or (val > 0 and (a - val) == b) end,
  113.             eq = function(a, b, val) return a == b end,
  114.             ne = function(a, b, val) return (a ~= b and val == 0) or
  115.                 (val > 0 and ((a - val) == b or (a + val) == b)) end,
  116.             ltv = function(a, b, val) return a < val end,
  117.             gtv = function(a, b, val) return a > val end,
  118.             eqv = function(a, b, val) return a == val end,
  119.             nev = function(a, b, val) return a ~= val end }
  120.  
  121.         function cfoper.bne(a, b, val, addr)
  122.             if type(val) ~= "table" then
  123.                 bitmask = a ~ b
  124.                 return bitmask ~= 0
  125.             elseif not val[addr] then
  126.                 return false
  127.             else
  128.                 bitmask = (a ~ b) & val[addr]
  129.                 return bitmask ~= 0
  130.             end
  131.         end
  132.  
  133.         function cfoper.beq(a, b, val, addr)
  134.             if type(val) ~= "table" then
  135.                 bitmask = ~a ~ b
  136.                 return bitmask ~= 0
  137.             elseif not val[addr] then
  138.                 return false
  139.             else
  140.                 bitmask = (~a ~ b) & val[addr]
  141.                 return bitmask ~= 0
  142.             end
  143.         end
  144.  
  145.  
  146.         local function check_bcd(val)
  147.             local a = val + 0x0666666666666666
  148.             a = a ~ val
  149.             return (a & 0x1111111111111110) == 0
  150.         end
  151.  
  152.         local function frombcd(val)
  153.             local result = 0
  154.             local mul = 1
  155.             while val ~= 0 do
  156.                 result = result + ((val % 16) * mul)
  157.                 val = val >> 4
  158.                 mul = mul * 10
  159.             end
  160.             return result
  161.         end
  162.  
  163.         if not newdata and oper:sub(3, 3) == "v" then
  164.             newdata = olddata
  165.         end
  166.         if olddata.start ~= newdata.start or olddata.size ~= newdata.size or not cfoper[oper] then
  167.             return {}
  168.         end
  169.         if not val then
  170.             val = 0
  171.         end
  172.  
  173.         for i = 1, olddata.size, step do
  174.             local oldstat, old = pcall(string.unpack, format, olddata.block, i)
  175.             local newstat, new = pcall(string.unpack, format, newdata.block, i)
  176.             if oldstat and newstat then
  177.                 local oldc, newc = old, new
  178.                 local comp = false
  179.                 local addr = i - 1
  180.                 if olddata.shift ~= 0 then
  181.                     local s = olddata.shift
  182.                     addr = (s < 0) and addr >> -s or (s > 0) and addr << s
  183.                 end
  184.                 addr = addr + olddata.start
  185.                 if not bcd or (check_bcd(old) and check_bcd(new)) then
  186.                     if bcd then
  187.                         oldc = frombcd(old)
  188.                         newc = frombcd(new)
  189.                     end
  190.                     if cfoper[oper](newc, oldc, val, addr) then
  191.                         ret[#ret + 1] = { addr = addr,
  192.                         oldval = old,
  193.                         newval = new,
  194.                         bitmask = bitmask }
  195.                         ref[ret[#ret].addr] = #ret
  196.                     end
  197.                 end
  198.             end
  199.         end
  200.         return ret, ref
  201.     end
  202.  
  203.     local function check_val(oper, val, matches)
  204.         if oper ~= "beq" and oper ~= "bne" then
  205.             return val
  206.         elseif not matches or not matches[1].bitmask then
  207.             return nil
  208.         end
  209.         local masks = {}
  210.         for num, match in pairs(matches) do
  211.             masks[match.addr] = match.bitmask
  212.         end
  213.         return masks
  214.     end
  215.  
  216.     -- compare two blocks and filter by table of previous matches
  217.     function cheat.compnext(newdata, olddata, oldmatch, oper, format, val, bcd, step)
  218.         local matches, refs = cheat.comp(newdata, olddata, oper, format, check_val(oper, val, oldmatch), bcd, step)
  219.         local nonmatch = {}
  220.         local oldrefs = {}
  221.         for num, match in pairs(oldmatch) do
  222.             oldrefs[match.addr] = num
  223.         end
  224.         for addr, ref in pairs(refs) do
  225.             if not oldrefs[addr] then
  226.                 nonmatch[ref] = true
  227.                 refs[addr] = nil
  228.             else
  229.                 matches[ref].oldval = oldmatch[oldrefs[addr]].oldval
  230.             end
  231.         end
  232.         local resort = {}
  233.         for num, match in pairs(matches) do
  234.             if not nonmatch[num] then
  235.                 resort[#resort + 1] = match
  236.             end
  237.         end
  238.         return resort
  239.     end
  240.  
  241.  
  242.     -- compare a data block to the current state
  243.     function cheat.compcur(olddata, oper, format, val, bcd, step)
  244.         local newdata = cheat.save(olddata.space, olddata.start, olddata.size, olddata.space)
  245.         return cheat.comp(newdata, olddata, oper, format, val, bcd, step)
  246.     end
  247.  
  248.     -- compare a data block to the current state and filter
  249.     function cheat.compcurnext(olddata, oldmatch, oper, format, val, bcd, step)
  250.         local newdata = cheat.save(olddata.space, olddata.start, olddata.size, olddata.space)
  251.         return cheat.compnext(newdata, olddata, oldmatch, oper, format, val, bcd, step)
  252.     end
  253.  
  254.  
  255.     _G.cf = cheat
  256.  
  257.     local devtable = {}
  258.     local devsel = 1
  259.     local devcur = 1
  260.     local formtable = { " I1", " i1", "<I2", ">I2", "<i2", ">i2", "<I4", ">I4", "<i4", ">i4", "<I8", ">I8", "<i8", ">i8", }-- " <f", " >f", " <d", " >d" }
  261.     local formname = { "u8", "s8", "little u16", "big u16", "little s16", "big s16",
  262.                "little u32", "big u32", "little s32", "big s32", "little u64", "big u64", "little s64", "big s64", }
  263.                -- "little float", "big float", "little double", "big double" }
  264.     local width = 1
  265.     local bcd = 0
  266.     local align = 0
  267.     local optable = { "lt", "gt", "eq", "ne", "beq", "bne", "ltv", "gtv", "eqv", "nev" }
  268.     local opsel = 1
  269.     local value = 0
  270.     local leftop = 1
  271.     local rightop = 1
  272.     local leftop_text = "Slot 1"
  273.     local rightop_text = "Slot 1"
  274.     local value_text = ""
  275.     local expression_text = "Slot 1 < Slot 1"
  276.     local matches = {}
  277.     local matchsel = 0
  278.     local matchpg = 0
  279.     local menu_blocks = {}
  280.     local watches = {}
  281.     local menu_func
  282.  
  283.     local cheat_save
  284.     local name = 1
  285.     local name_player = 1
  286.     local name_type = 1
  287.  
  288.     local function start()
  289.         devtable = {}
  290.         devsel = 1
  291.         devcur = 1
  292.         width = 1
  293.         bcd = 0
  294.         opsel = 1
  295.         value = 0
  296.         leftop = 2
  297.         rightop = 1
  298.         matches = {}
  299.         matchsel = 0
  300.         matchpg = 0
  301.         menu_blocks = {}
  302.         watches = {}
  303.  
  304.         local space_table = cheat.getspaces()
  305.         for tag, list in pairs(space_table) do
  306.             for name, space in pairs(list) do
  307.                 local ram = {}
  308.                 for num, entry in pairs(space.map) do
  309.                     if entry.writetype == "ram" then
  310.                         ram[#ram + 1] = { offset = entry.offset, size = entry.endoff - entry.offset }
  311.                         if space.shift > 0 then
  312.                             ram[#ram].size = ram[#ram].size >> space.shift
  313.                         elseif space.shift < 0 then
  314.                             ram[#ram].size = ram[#ram].size << -space.shift
  315.                         end
  316.                     end
  317.                 end
  318.                 if next(ram) then
  319.                     if tag == ":maincpu" and name == "program" then
  320.                         table.insert(devtable, 1, { name = tag .. ", " .. name, tag = tag, sname = name, space = space, ram = ram })
  321.                     else
  322.                         devtable[#devtable + 1] = { name = tag .. ", " .. name, tag = tag, sname = name, space = space, ram = ram }
  323.                     end
  324.                 end
  325.             end
  326.         end
  327.         space_table = cheat.getram()
  328.         for tag, ram in pairs(space_table) do
  329.             devtable[#devtable + 1] = { tag = tag, name = "ram", space = ram.dev, ram = {{ offset = 0, size = ram.size }} }
  330.         end
  331.         space_table = cheat.getshares()
  332.         for tag, share in pairs(space_table) do
  333.             devtable[#devtable + 1] = { tag = tag, name = tag, space = share, ram = {{ offset = 0, size = share.size }} }
  334.         end
  335.     end
  336.  
  337.     emu.register_start(start)
  338.  
  339.     local function menu_populate()
  340.         local menu = {}
  341.  
  342.         local function menu_prepare()
  343.             local menu_list = {}
  344.             menu_func = {}
  345.             for num, func in ipairs(menu) do
  346.                 local item, f = func()
  347.                 if item then
  348.                     menu_list[#menu_list + 1] = item
  349.                     menu_func[#menu_list] = f
  350.                 end
  351.             end
  352.             return menu_list
  353.         end
  354.  
  355.         local function menu_lim(val, min, max, menuitem)
  356.             if min == max then
  357.                 menuitem[3] = 0
  358.             elseif val == min then
  359.                 menuitem[3] = "r"
  360.             elseif val == max then
  361.                 menuitem[3] = "l"
  362.             else
  363.                 menuitem[3] = "lr"
  364.             end
  365.         end
  366.  
  367.         local function incdec(event, val, min, max)
  368.             local ret
  369.             if event == "left" and val ~= min then
  370.                 val = val - 1
  371.                 ret = true
  372.             elseif event == "right" and val ~= max then
  373.                 val = val + 1
  374.                 ret = true
  375.             end
  376.             return val, ret
  377.         end
  378.  
  379.         if cheat_save then
  380.             local cplayer = { "All", "P1", "P2", "P3", "P4" }
  381.             local ctype = { "Infinite Credits", "Infinite Time", "Infinite Lives", "Infinite Energy", "Infinite Ammo", "Infinite Bombs", "Invincibility" }
  382.             menu[#menu + 1] = function() return { _("Save Cheat"), "", "off" }, nil end
  383.             menu[#menu + 1] = function() return { "---", "", "off" }, nil end
  384.             menu[#menu + 1] = function()
  385.                 local c = { _("Default"), _("Custom") }
  386.                 local m = { _("Cheat Name"), c[name], 0 }
  387.                 menu_lim(name, 1, #c, m)
  388.                 local function f(event)
  389.                     local r
  390.                     name, r = incdec(event, name, 1, #c)
  391.                     if (event == "select" or event == "comment") and name == 1 then
  392.                         manager:machine():popmessage(string.format(_("Default name is %s"), cheat_save.name))
  393.                     end
  394.                     return r
  395.                 end
  396.                 return m, f
  397.             end
  398.             if name == 2 then
  399.                 menu[#menu + 1] = function()
  400.                     local m = { _("Player"), cplayer[name_player], 0 }
  401.                     menu_lim(name_player, 1, #cplayer, m)
  402.                     return m, function(event) local r name_player, r = incdec(event, name_player, 1, #cplayer) return r end
  403.                 end
  404.                 menu[#menu + 1] = function()
  405.                     local m = { _("Type"), ctype[name_type], 0 }
  406.                     menu_lim(name_type, 1, #ctype, m)
  407.                     return m, function(event) local r name_type, r = incdec(event, name_type, 1, #ctype) return r end
  408.                 end
  409.             end
  410.             menu[#menu + 1] = function()
  411.                 local m = { _("Save"), "", 0 }
  412.                 local function f(event)
  413.                     if event == "select" then
  414.                         local desc
  415.                         local written = false
  416.                         if name == 2 then
  417.                             if cplayer[name_player] == "All" then
  418.                                 desc = ctype[name_type]
  419.                             else
  420.                                 desc = cplayer[name_player] .. " " .. ctype[name_type]
  421.                             end
  422.                         else
  423.                             desc = cheat_save.name
  424.                         end
  425.                         local filename = cheat_save.filename .. "_" .. desc
  426.                         local file = io.open(filename .. ".json", "w")
  427.                         if file then
  428.                             file:write(string.format(cheat_save.json, desc))
  429.                             file:close()
  430.                             -- xml or simple are program space only
  431.                             if not getmetatable(devtable[devcur].space).__name:match("device_t") and devtable[devcur].sname == "program" then
  432.                                 file = io.open(filename .. ".xml", "w")
  433.                                 file:write(string.format(cheat_save.xml, desc))
  434.                                 file:close()
  435.                                 file = io.open(cheat_save.path .. "/cheat.simple", "a")
  436.                                 file:write(string.format(cheat_save.simple, desc))
  437.                                 -- old cheat .dat format, write support only and defaults to setting all type bits to 0
  438.                                 file:write(string.format(cheat_save.dat, desc))
  439.                                 file:close()
  440.                                 manager:machine():popmessage(string.format(_("Cheat written to %s and added to cheat.simple"), filename))
  441.                             end
  442.                             written = true
  443.                         elseif not getmetatable(devtable[devcur].space).__name:match("device_t") and devtable[devcur].sname == "program" then
  444.                             file = io.open(cheat_save.path .. "/cheat.simple", "a")
  445.                             if file then
  446.                                 file:write(string.format(cheat_save.simple, desc))
  447.                                 file:close()
  448.                                 manager:machine():popmessage(_("Cheat added to cheat.simple"))
  449.                                 written = true
  450.                             end
  451.                         end
  452.                         if not written then
  453.                             manager:machine():popmessage(_("Unable to write file\nEnsure that cheatpath folder exists"))
  454.                         end
  455.                         cheat_save = nil
  456.                         return true
  457.                     end
  458.                     return false
  459.                 end
  460.                 return m, f
  461.             end
  462.             menu[#menu + 1] = function() return { _("Cancel"), "", 0 }, function(event) if event == "select" then cheat_save = nil return true end end end
  463.             return menu_prepare()
  464.         end
  465.  
  466.         menu[#menu + 1] = function()
  467.             local m = { _("CPU or RAM"), devtable[devsel].name, 0 }
  468.             menu_lim(devsel, 1, #devtable, m)
  469.             local function f(event)
  470.                 if (event == "left" or event == "right") and #menu_blocks ~= 0 then
  471.                     manager:machine():popmessage(_("Changes to this only take effect when \"Start new search\" is selected"))
  472.                 end
  473.                 devsel = incdec(event, devsel, 1, #devtable)
  474.                 return true
  475.             end
  476.             return m, f
  477.         end
  478.  
  479.         menu[#menu + 1] = function()
  480.             local function f(event)
  481.                 local ret = false
  482.                 if event == "select" then
  483.                     menu_blocks = {}
  484.                     matches = {}
  485.                     devcur = devsel
  486.                     for num, region in ipairs(devtable[devcur].ram) do
  487.                         menu_blocks[num] = {}
  488.                         menu_blocks[num][1] = cheat.save(devtable[devcur].space, region.offset, region.size)
  489.                     end
  490.                     manager:machine():popmessage(_("All slots cleared and current state saved to Slot 1"))
  491.                     watches = {}
  492.                     opsel = 1
  493.                     value = 0
  494.                     leftop = 1
  495.                     rightop = 1
  496.                     leftop_text = "Slot 1"
  497.                     rightop_text = "Slot 1"
  498.                     value_text = ""
  499.                     expression_text = "Slot 1 < Slot 1"                        
  500.                     matchsel = 0
  501.                     return true
  502.                 end
  503.             end
  504.                 local opsel = 1
  505.             return { _("Start new search"), "", 0 }, f
  506.         end
  507.         if #menu_blocks ~= 0 then
  508.             menu[#menu + 1] = function() return { "---", "", "off" }, nil end
  509.             menu[#menu + 1] = function()
  510.                 local function f(event)
  511.                     if event == "select" then
  512.                         for num, region in ipairs(devtable[devcur].ram) do
  513.                             menu_blocks[num][#menu_blocks[num] + 1] = cheat.save(devtable[devcur].space, region.offset, region.size)
  514.                         end
  515.                         manager:machine():popmessage(_("Memory State saved to Slot ").. #menu_blocks[1])
  516.                         if (leftop == #menu_blocks[1] - 1 and rightop == #menu_blocks[1] - 2 ) then
  517.                             leftop = #menu_blocks[1]
  518.                             rightop = #menu_blocks[1]-1
  519.                         elseif (leftop == #menu_blocks[1] - 2 and rightop == #menu_blocks[1] - 1 ) then
  520.                             leftop = #menu_blocks[1]-1
  521.                             rightop = #menu_blocks[1]
  522.                         elseif (leftop == #menu_blocks[1] - 1 ) then
  523.                             leftop = #menu_blocks[1]
  524.                         elseif (rightop == #menu_blocks[1] - 1) then   
  525.                             rightop = #menu_blocks[1]
  526.                         end
  527.                         devsel = devcur
  528.                         return true
  529.                     end
  530.                 end
  531.                 return { _("Save Current Memory State to Slot ") .. #menu_blocks[1] + 1, "", 0 }, f
  532.             end
  533.             menu[#menu + 1] = function() return { "---", "", "off" }, nil end
  534.             menu[#menu + 1] = function()
  535.                 local function f(event)
  536.                     if event == "select" then
  537.                         local count = 0
  538.                         local step = align == 1 and formtable[width]:sub(3, 3) or "1"
  539.                         if step == "f" then
  540.                             step = 4
  541.                         elseif step == "d" then
  542.                             step = 8
  543.                         else
  544.                             step = tonumber(step)
  545.                         end
  546.                         if #matches == 0 then
  547.                             matches[1] = {}
  548.                             for num = 1, #menu_blocks do
  549.                                 matches[1][num] = cheat.comp(menu_blocks[num][leftop], menu_blocks[num][rightop],
  550.                                 optable[opsel], formtable[width], value, bcd == 1, step)
  551.                                 count = count + #matches[1][num]
  552.                             end
  553.                         else
  554.                             lastmatch = matches[#matches]
  555.                             matches[#matches + 1] = {}
  556.                             for num = 1, #menu_blocks do
  557.                                 matches[#matches][num] = cheat.compnext(menu_blocks[num][leftop], menu_blocks[num][rightop],
  558.                                 lastmatch[num], optable[opsel], formtable[width], value, bcd == 1, step)
  559.                                 count = count + #matches[#matches][num]
  560.                             end
  561.                         end
  562.                         manager:machine():popmessage(string.format(_("%d total matches found"), count))
  563.                         matches[#matches].count = count
  564.                         matchpg = 0
  565.                         devsel = devcur
  566.                         return true
  567.                     end
  568.                 end
  569.                
  570.                 if optable[opsel] == "lt" then
  571.                     if (value == 0 ) then
  572.                         expression_text = leftop_text .. " < " .. rightop_text
  573.                     else
  574.                         expression_text = leftop_text .. " + " .. value .. " == " .. rightop_text
  575.                     end
  576.                 elseif optable[opsel] == "gt" then
  577.                     if (value == 0 ) then
  578.                         expression_text = leftop_text .. " > " .. rightop_text
  579.                     else
  580.                         expression_text = leftop_text .. " - " .. value .. " == " .. rightop_text
  581.                     end
  582.                 elseif optable[opsel] == "eq" then
  583.                     expression_text = leftop_text .. " == " .. rightop_text
  584.                 elseif optable[opsel] == "ne" then
  585.                     if (value == 0 ) then
  586.                         expression_text = leftop_text .. " != " .. rightop_text
  587.                     else
  588.                         expression_text = leftop_text .. " != " .. rightop_text .. " ~ " .. value
  589.                     end
  590.                 elseif optable[opsel] == "beq" then
  591.                     expression_text = leftop_text .. " BITWISE== " .. rightop_text
  592.                 elseif optable[opsel] == "bne" then
  593.                     expression_text = leftop_text .. " BITWISE!= " .. rightop_text
  594.                 elseif optable[opsel] == "ltv" then
  595.                     expression_text = leftop_text .. " < " .. value
  596.                 elseif optable[opsel] == "gtv" then
  597.                     expression_text = leftop_text .. " > " .. value
  598.                 elseif optable[opsel] == "eqv" then
  599.                     expression_text = leftop_text .. " == " .. value
  600.                 elseif optable[opsel] == "nev" then
  601.                     expression_text = leftop_text .. " != " .. value
  602.                 end    
  603.                 return { _("Perform Compare  :  ") .. expression_text, "", 0 }, f
  604.             end
  605.             menu[#menu + 1] = function() return { "---", "", "off" }, nil end
  606.             menu[#menu + 1] = function()
  607.                 local m = { _(leftop), "", 0 }
  608.                 menu_lim(leftop, 1, #menu_blocks[1], m)
  609.                 m[1] = "Slot " .. leftop
  610.                 leftop_text = m[1]
  611.                 return m, function(event) local r leftop, r = incdec(event, leftop, 1, #menu_blocks[1]) return r end
  612.             end
  613.             menu[#menu + 1] = function()
  614.                 local m = { _(optable[opsel]), "", 0 }
  615.                 menu_lim(opsel, 1, #optable, m)
  616.                 local function f(event)
  617.                     local r
  618.                     opsel, r = incdec(event, opsel, 1, #optable)
  619.                     if event == "left" or event == "right" or event == "comment" then
  620.                         if optable[opsel] == "lt" then
  621.                             manager:machine():popmessage(_("Left less than right, value is difference"))
  622.                         elseif optable[opsel] == "gt" then
  623.                             manager:machine():popmessage(_("Left greater than right, value is difference"))
  624.                         elseif optable[opsel] == "eq" then
  625.                             manager:machine():popmessage(_("Left equal to right"))
  626.                         elseif optable[opsel] == "ne" then
  627.                             manager:machine():popmessage(_("Left not equal to right, value is difference"))
  628.                         elseif optable[opsel] == "beq" then
  629.                             manager:machine():popmessage(_("Left equal to right with bitmask"))
  630.                         elseif optable[opsel] == "bne" then
  631.                             manager:machine():popmessage(_("Left not equal to right with bitmask"))
  632.                         elseif optable[opsel] == "ltv" then
  633.                             manager:machine():popmessage(_("Left less than value"))
  634.                         elseif optable[opsel] == "gtv" then
  635.                             manager:machine():popmessage(_("Left greater than value"))
  636.                         elseif optable[opsel] == "eqv" then
  637.                             manager:machine():popmessage(_("Left equal to value"))
  638.                         elseif optable[opsel] == "nev" then
  639.                             manager:machine():popmessage(_("Left not equal to value"))
  640.                         end
  641.                     end
  642.                     return r
  643.                 end
  644.                 return m, f
  645.             end
  646.             menu[#menu + 1] = function()
  647.                 if optable[opsel]:sub(3, 3) == "v" then
  648.                     return nil
  649.                 end
  650.                 local m = { _(rightop), "", 0 }
  651.                 menu_lim(rightop, 1, #menu_blocks[1], m)
  652.                 m[1] = "Slot " .. rightop
  653.                 rightop_text = m[1]
  654.                 return m, function(event) local r rightop, r = incdec(event, rightop, 1, #menu_blocks[1]) return r end
  655.             end
  656.             menu[#menu + 1] = function()
  657.                 if optable[opsel] == "bne" or optable[opsel] == "beq" or optable[opsel] == "eq" then
  658.                     return nil
  659.                 end
  660.                 local m = { _("Value"), value, "" }
  661.                 local max = 100 -- max value?
  662.                 menu_lim(value, 0, max, m)
  663.                 if value == 0 and optable[opsel]:sub(3, 3) ~= "v" then
  664.                     m[2] = _("Any")
  665.                 end
  666.                 return m, function(event) local r value, r = incdec(event, value, 0, max) return r end
  667.             end
  668.             menu[#menu + 1] = function() return { "---", "", "off" }, nil end
  669.             menu[#menu + 1] = function()
  670.                 local m = { _("Data Format"), formname[width], 0 }
  671.                 menu_lim(width, 1, #formtable, m)
  672.                 return m, function(event) local r width, r = incdec(event, width, 1, #formtable) return r end
  673.             end
  674.             menu[#menu + 1] = function()
  675.                 if optable[opsel] == "bne" or optable[opsel] == "beq" then
  676.                     return nil
  677.                 end
  678.                 local m = { "BCD", _("Off"), 0 }
  679.                 menu_lim(bcd, 0, 1, m)
  680.                 if bcd == 1 then
  681.                     m[2] = _("On")
  682.                 end
  683.                 return m, function(event) local r bcd, r = incdec(event, bcd, 0, 1) return r end
  684.             end
  685.             menu[#menu + 1] = function()
  686.                 if formtable[width]:sub(3, 3) == "1" then
  687.                     return nil
  688.                 end
  689.                 local m = { "Aligned only", _("Off"), 0 }
  690.                 menu_lim(align, 0, 1, m)
  691.                 if align == 1 then
  692.                     m[2] = _("On")
  693.                 end
  694.                 return m, function(event) local r align, r = incdec(event, align, 0, 1) return r end
  695.             end
  696.             if #matches ~= 0 then
  697.                 menu[#menu + 1] = function()
  698.                     local function f(event)
  699.                         if event == "select" then
  700.                             matches[#matches] = nil
  701.                             matchpg = 0
  702.                             return true
  703.                         end
  704.                     end
  705.                     return { _("Undo last search -- #") .. #matches, "", 0 }, f
  706.                 end
  707.                 menu[#menu + 1] = function() return { "---", "", "off" }, nil end
  708.                 menu[#menu + 1] = function()
  709.                     local m = { _("Match block"), matchsel, "" }
  710.                     menu_lim(matchsel, 0, #matches[#matches], m)
  711.                     if matchsel == 0 then
  712.                         m[2] = _("All")
  713.                     end
  714.                     local function f(event)
  715.                         local r
  716.                         matchsel, r = incdec(event, matchsel, 0, #matches[#matches])
  717.                         if r then
  718.                             matchpg = 0
  719.                         end
  720.                         return r
  721.                     end
  722.                     return m, f
  723.                 end
  724.                 local function mpairs(sel, list, start)
  725.                     if #list == 0 then
  726.                         return function() end, nil, nil
  727.                     end
  728.                     if sel ~= 0 then
  729.                         list = {list[sel]}
  730.                     end
  731.                     local function mpairs_it(list, i)
  732.                         local match
  733.                         i = i + 1
  734.                         local sel = i + start
  735.                         for j = 1, #list do
  736.                             if sel <= #list[j] then
  737.                                 match = list[j][sel]
  738.                                 break
  739.                             else
  740.                                 sel = sel - #list[j]
  741.                             end
  742.                         end
  743.                         if not match then
  744.                             return
  745.                         end
  746.                         return i, match
  747.                     end
  748.                     return mpairs_it, list, 0
  749.                 end
  750.                 local bitwidth = formtable[width]:sub(3, 3)
  751.                 if bitwidth == "2" then
  752.                     bitwidth = " %04x"
  753.                 elseif bitwidth == "4" then
  754.                     bitwidth = " %08x"
  755.                 elseif bitwidth == "8" then
  756.                     bitwidth = " %016x"
  757.                 elseif bitwidth == "f" or bitwidth == "d" then
  758.                     bitwidth = " %010f"
  759.                 else
  760.                     bitwidth = " %02x"
  761.                 end
  762.  
  763.                 local function match_exec(match)
  764.                     local dev = devtable[devcur]
  765.                     local cheat = { desc = string.format(_("Test cheat at addr %08X"), match.addr), script = {} }
  766.                     local wid = formtable[width]:sub(3, 3)
  767.                     local widchar
  768.                     local form
  769.                     if wid == "2" then
  770.                         wid = "u16"
  771.                         form = "%08x %04x"
  772.                         widchar = "w"
  773.                     elseif wid == "4" then
  774.                         wid = "u32"
  775.                         form = "%08x %08x"
  776.                         widchart = "d"
  777.                     elseif wid == "8" then
  778.                         wid = "u64"
  779.                         form = "%08x %016x"
  780.                         widchar = "q"
  781.                     elseif wid == "f" then
  782.                         wid = "u32"
  783.                         form = "%08x %f"
  784.                         widchar = "d"
  785.                     elseif wid == "d" then
  786.                         wid = "u64"
  787.                         form = "%08x %f"
  788.                         widchar = "q"
  789.                     else
  790.                         wid = "u8"
  791.                         form = "%08x %02x"
  792.                         widchar = "b"
  793.                     end
  794.  
  795.  
  796.                     if getmetatable(dev.space).__name:match("device_t") then
  797.                         cheat.ram = { ram = dev.tag }
  798.                         cheat.script.run = "ram:write(" .. match.addr .. "," .. match.newval .. ")"
  799.                     elseif getmetatable(dev.space).__name:match("memory_share") then
  800.                         cheat.share = { share = dev.tag }
  801.                         cheat.script.run = "share:write_" .. wid .. "(" .. match.addr .. "," .. match.newval .. ")"
  802.                     else
  803.                         cheat.space = { cpu = { tag = dev.tag, type = dev.sname } }
  804.                         cheat.script.run = "cpu:write_" .. wid .. "(" .. match.addr .. "," .. match.newval .. ")"
  805.                     end
  806.                     if match.mode == 1 then
  807.                         if not _G.ce then
  808.                             manager:machine():popmessage(_("Cheat engine not available"))
  809.                         else
  810.                             _G.ce.inject(cheat)
  811.                         end
  812.                     elseif match.mode == 2 then
  813.                         cheat_save = {}
  814.                         menu = 1
  815.                         menu_player = 1
  816.                         menu_type = 1
  817.                         local setname = emu.romname()
  818.                         if emu.softname() ~= "" then
  819.                             if emu.softname():find(":") then
  820.                                 filename = emu.softname():gsub(":", "/")
  821.                             else
  822.                                 for name, image in pairs(manager:machine().images) do
  823.                                     if image:exists() and image:software_list_name() ~= "" then
  824.                                         setname = image:software_list_name() .. "/" .. emu.softname()
  825.                                     end
  826.                                 end
  827.                             end
  828.                         end
  829.                         -- lfs.env_replace is defined in boot.lua
  830.                         cheat_save.path = lfs.env_replace(manager:machine():options().entries.cheatpath:value()):match("([^;]+)")
  831.                         cheat_save.filename = string.format("%s/%s", cheat_save.path, setname)
  832.                         cheat_save.name = cheat.desc
  833.                         local json = require("json")
  834.                         cheat.desc = "%s"
  835.                         cheat_save.json = json.stringify({[1] = cheat}, {indent = true})
  836.                         cheat_save.xml = string.format("<mamecheat version=\"1\">\n<cheat desc=\"%%s\">\n<script state=\"run\">\n<action>%s.p%s@%X=%X</action>\n</script>\n</cheat>\n</mamecheat>", dev.tag:sub(2), widchar, match.addr, match.newval)
  837.                         cheat_save.simple = string.format("%s,%s,%X,%s,%X,%%s\n", setname, dev.tag, match.addr, widchar, match.newval)
  838.                         cheat_save.dat = string.format(":%s:00000000:%X:%08X:FFFFFFFF:%%s\n", setname,  match.addr, match.newval)          
  839.                         manager:machine():popmessage(string.format(_("Default name is %s"), cheat_save.name))
  840.                         return true
  841.                     else
  842.                         local func = "return space:read"
  843.                         local env = { space = devtable[devcur].space }
  844.                         if not getmetatable(dev.space).__name:match("device_t") then
  845.                             func = func .. "_" .. wid
  846.                         end
  847.                         func = func .. "(" .. match.addr .. ")"
  848.                         watches[#watches + 1] = { addr = match.addr, func = load(func, func, "t", env), format = form }
  849.                         return true
  850.                     end
  851.                     return false
  852.                 end
  853.  
  854.                 for num2, match in mpairs(matchsel, matches[#matches], matchpg * 100) do
  855.                     if num2 > 100 then
  856.                         break
  857.                     end
  858.                     menu[#menu + 1] = function()
  859.                         if not match.mode then
  860.                             match.mode = 1
  861.                         end
  862.                         local modes = { _("Test"), _("Write"), _("Watch") }
  863.                         local m = { string.format("%08x" .. bitwidth .. bitwidth, match.addr, match.oldval,
  864.                                                       match.newval), modes[match.mode], 0 }
  865.                         menu_lim(match.mode, 1, #modes, m)
  866.                         local function f(event)
  867.                             local r
  868.                             match.mode, r = incdec(event, match.mode, 1, 3)
  869.                             if event == "select" then
  870.                                 r = match_exec(match)
  871.                             end
  872.                             return r
  873.                         end
  874.                         return m, f
  875.                     end
  876.                 end
  877.                 if matches[#matches].count > 100 then
  878.                     menu[#menu + 1] = function()
  879.                         local m = { _("Page"), matchpg, 0 }
  880.                         local max
  881.                         if matchsel == 0 then
  882.                             max = math.ceil(matches[#matches].count / 100)
  883.                         else
  884.                             max = #matches[#matches][matchsel]
  885.                         end
  886.                         menu_lim(matchpg, 0, max, m)
  887.                         local function f(event)
  888.                             matchpg, r = incdec(event, matchpg, 0, max)
  889.                             return r
  890.                         end
  891.                         return m, f
  892.                     end
  893.                 end
  894.             end
  895.             if #watches ~= 0 then
  896.                 menu[#menu + 1] = function()
  897.                     return { _("Clear Watches"), "", 0 }, function(event) if event == "select" then watches = {} return true end end
  898.                 end
  899.             end
  900.         end
  901.         return menu_prepare()
  902.     end
  903.  
  904.     local function menu_callback(index, event)
  905.         return menu_func[index](event)
  906.     end
  907.     emu.register_menu(menu_callback, menu_populate, _("Cheat Finder"))
  908.     emu.register_frame_done(function ()
  909.             local tag, screen = next(manager:machine().screens)
  910.             local height = mame_manager:ui():get_line_height()
  911.             for num, watch in ipairs(watches) do
  912.                 screen:draw_text("left", num * height, string.format(watch.format, watch.addr, watch.func()))
  913.             end
  914.         end)
  915. end
  916.  
  917. return exports
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top