Advertisement
Guest User

init.lua (modified)

a guest
Jan 27th, 2019
190
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 36.74 KB | None | 0 0
  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.         if (olddata.shift < 0) and (step < (1 << -olddata.shift)) then
  110.             step = 1 << -olddata.shift;
  111.         end
  112.         local cfoper = {
  113.             lt = function(a, b, val) return (a < b and val == 0) or (val > 0 and (a + val) == b) end,
  114.             gt = function(a, b, val) return (a > b and val == 0) or (val > 0 and (a - val) == b) end,
  115.             eq = function(a, b, val) return a == b end,
  116.             ne = function(a, b, val) return (a ~= b and val == 0) or
  117.                 (val > 0 and ((a - val) == b or (a + val) == b)) end,
  118.             ltv = function(a, b, val) return a < val end,
  119.             gtv = function(a, b, val) return a > val end,
  120.             eqv = function(a, b, val) return a == val end,
  121.             nev = function(a, b, val) return a ~= val end }
  122.  
  123.         function cfoper.bne(a, b, val, addr)
  124.             if type(val) ~= "table" then
  125.                 bitmask = a ~ b
  126.                 return bitmask ~= 0
  127.             elseif not val[addr] then
  128.                 return false
  129.             else
  130.                 bitmask = (a ~ b) & val[addr]
  131.                 return bitmask ~= 0
  132.             end
  133.         end
  134.  
  135.         function cfoper.beq(a, b, val, addr)
  136.             if type(val) ~= "table" then
  137.                 bitmask = ~a ~ b
  138.                 return bitmask ~= 0
  139.             elseif not val[addr] then
  140.                 return false
  141.             else
  142.                 bitmask = (~a ~ b) & val[addr]
  143.                 return bitmask ~= 0
  144.             end
  145.         end
  146.  
  147.  
  148.         local function check_bcd(val)
  149.             local a = val + 0x0666666666666666
  150.             a = a ~ val
  151.             return (a & 0x1111111111111110) == 0
  152.         end
  153.  
  154.         local function frombcd(val)
  155.             local result = 0
  156.             local mul = 1
  157.             while val ~= 0 do
  158.                 result = result + ((val % 16) * mul)
  159.                 val = val >> 4
  160.                 mul = mul * 10
  161.             end
  162.             return result
  163.         end
  164.  
  165.         if not newdata and oper:sub(3, 3) == "v" then
  166.             newdata = olddata
  167.         end
  168.         if olddata.start ~= newdata.start or olddata.size ~= newdata.size or not cfoper[oper] then
  169.             return {}
  170.         end
  171.         if not val then
  172.             val = 0
  173.         end
  174.  
  175.         for i = 1, olddata.size, step do
  176.             local oldstat, old = pcall(string.unpack, format, olddata.block, i)
  177.             local newstat, new = pcall(string.unpack, format, newdata.block, i)
  178.             if oldstat and newstat then
  179.                 local oldc, newc = old, new
  180.                 local comp = false
  181.                 local addr = i - 1
  182.                 if olddata.shift ~= 0 then
  183.                     local s = olddata.shift
  184.                     addr = (s < 0) and addr >> -s or (s > 0) and addr << s
  185.                 end
  186.                 addr = addr + olddata.start
  187.                 if not bcd or (check_bcd(old) and check_bcd(new)) then
  188.                     if bcd then
  189.                         oldc = frombcd(old)
  190.                         newc = frombcd(new)
  191.                     end
  192.                     if cfoper[oper](newc, oldc, val, addr) then
  193.                         ret[#ret + 1] = { addr = addr,
  194.                         oldval = old,
  195.                         newval = new,
  196.                         bitmask = bitmask }
  197.                         ref[addr] = #ret
  198.                     end
  199.                 end
  200.             end
  201.         end
  202.         return ret, ref
  203.     end
  204.  
  205.     local function check_val(oper, val, matches)
  206.         if oper ~= "beq" and oper ~= "bne" then
  207.             return val
  208.         elseif not matches or not matches[1].bitmask then
  209.             return nil
  210.         end
  211.         local masks = {}
  212.         for num, match in pairs(matches) do
  213.             masks[match.addr] = match.bitmask
  214.         end
  215.         return masks
  216.     end
  217.  
  218.     -- compare two blocks and filter by table of previous matches
  219.     function cheat.compnext(newdata, olddata, oldmatch, oper, format, val, bcd, step)
  220.         local matches, refs = cheat.comp(newdata, olddata, oper, format, check_val(oper, val, oldmatch), bcd, step)
  221.         local nonmatch = {}
  222.         local oldrefs = {}
  223.         for num, match in pairs(oldmatch) do
  224.             oldrefs[match.addr] = num
  225.         end
  226.         for addr, ref in pairs(refs) do
  227.             if not oldrefs[addr] then
  228.                 nonmatch[ref] = true
  229.                 refs[addr] = nil
  230.             else
  231.                 matches[ref].oldval = oldmatch[oldrefs[addr]].oldval
  232.             end
  233.         end
  234.         local resort = {}
  235.         for num, match in pairs(matches) do
  236.             if not nonmatch[num] then
  237.                 resort[#resort + 1] = match
  238.             end
  239.         end
  240.         return resort
  241.     end
  242.  
  243.  
  244.     -- compare a data block to the current state
  245.     function cheat.compcur(olddata, oper, format, val, bcd, step)
  246.         local newdata = cheat.save(olddata.space, olddata.start, olddata.size, olddata.space)
  247.         return cheat.comp(newdata, olddata, oper, format, val, bcd, step)
  248.     end
  249.  
  250.     -- compare a data block to the current state and filter
  251.     function cheat.compcurnext(olddata, oldmatch, oper, format, val, bcd, step)
  252.         local newdata = cheat.save(olddata.space, olddata.start, olddata.size, olddata.space)
  253.         return cheat.compnext(newdata, olddata, oldmatch, oper, format, val, bcd, step)
  254.     end
  255.  
  256.  
  257.     _G.cf = cheat
  258.  
  259.     local devtable = {}
  260.     local devsel = 1
  261.     local devcur = 1
  262.    
  263.    
  264.     --local formtable = { " I1", " i1", "<I2", ">I2", "<i2", ">i2", "<I4", ">I4", "<i4", ">i4", "<I8", ">I8", "<i8", ">i8", }-- " <f", " >f", " <d", " >d" }
  265.     --local formname = { "u8", "s8", "little u16", "big u16", "little s16", "big s16",
  266.     --         "little u32", "big u32", "little s32", "big s32", "little u64", "big u64", "little s64", "big s64", }
  267.     --         -- "little float", "big float", "little double", "big double" }
  268.     -- Reordered into likelyhood of use order: unsigned byte by big endian unsigned by little endian unsigned then unsigned in same order
  269.     local formtable = { " I1", ">I2", ">I4", ">I8", "<I2", "<I4", "<I8", " i1", ">i2", ">i4", ">i8", "<i2", "<i4", "<i8", }-- " <f", " >f", " <d", " >d" }
  270.     local formname = { "u8", "big u16", "big u32", "big u64", "little u16", "little u32",
  271.                "little u64", "s8", "big s16", "big s32", "big s64", "little s16", "little s32", "little s64", }        
  272.                
  273.     local width = 1
  274.     local bcd = 0
  275.     local align = 0
  276.     local optable = { "lt", "gt", "eq", "ne", "beq", "bne", "ltv", "gtv", "eqv", "nev" }
  277.     local opsel = 1
  278.     local value = 0
  279.     local leftop = 1
  280.     local rightop = 1
  281.     local leftop_text = "Slot 1"
  282.     local rightop_text = "Slot 1"
  283.     local value_text = ""
  284.     local expression_text = "Slot 1 < Slot 1"
  285.     local pausetable = { "Automatic", "Manual" }
  286.     local pausesel = 1
  287.     local pokevaltable = { "Slot 1 Value", "Last Slot Value", "0x00", "0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "0x07", "0x08", "0x09", "0x63 (Decimal 99)", "0x99 (BCD 99)",
  288.                             "0xFF (Decimal 255)" , "0x3E7 (Decimal 999)", "0x999 (BCD 999)", "0x270F (Decimal 9999)", "0x9999 (BCD 9999)", "0xFFFF (Decimal 65535)" }
  289.     local pokevalsel = 1
  290.    
  291.     local matches = {}
  292.     local matchsel = 0
  293.     local matchpg = 0
  294.     local menu_blocks = {}
  295.     local watches = {}
  296.     local menu_func
  297.  
  298.     local cheat_save
  299.     local name = 1
  300.     local name_player = 1
  301.     local name_type = 1
  302.  
  303.     local function start()
  304.         devtable = {}
  305.         devsel = 1
  306.         devcur = 1
  307.         width = 1
  308.         bcd = 0
  309.         opsel = 1
  310.         value = 0
  311.         leftop = 1
  312.         rightop = 1
  313.         matches = {}
  314.         matchsel = 0
  315.         matchpg = 0
  316.         menu_blocks = {}
  317.         watches = {}
  318.  
  319.         local space_table = cheat.getspaces()
  320.         for tag, list in pairs(space_table) do
  321.             for name, space in pairs(list) do
  322.                 local ram = {}
  323.                 for num, entry in pairs(space.map) do
  324.                     if entry.writetype == "ram" then
  325.                         ram[#ram + 1] = { offset = entry.offset, size = entry.endoff - entry.offset }
  326.                         if space.shift > 0 then
  327.                             ram[#ram].size = ram[#ram].size >> space.shift
  328.                         elseif space.shift < 0 then
  329.                             ram[#ram].size = ram[#ram].size << -space.shift
  330.                         end
  331.                     end
  332.                 end
  333.                 if next(ram) then
  334.                     if tag == ":maincpu" and name == "program" then
  335.                         table.insert(devtable, 1, { name = tag .. ", " .. name, tag = tag, sname = name, space = space, ram = ram })
  336.                     else
  337.                         devtable[#devtable + 1] = { name = tag .. ", " .. name, tag = tag, sname = name, space = space, ram = ram }
  338.                     end
  339.                 end
  340.             end
  341.         end
  342.         space_table = cheat.getram()
  343.         for tag, ram in pairs(space_table) do
  344.             devtable[#devtable + 1] = { tag = tag, name = "ram", space = ram.dev, ram = {{ offset = 0, size = ram.size }} }
  345.         end
  346.         space_table = cheat.getshares()
  347.         for tag, share in pairs(space_table) do
  348.             devtable[#devtable + 1] = { tag = tag, name = tag, space = share, ram = {{ offset = 0, size = share.size }} }
  349.         end
  350.     end
  351.  
  352.     emu.register_start(start)
  353.    
  354.     local menu_is_showing = false
  355.     local tabbed_out = false
  356.    
  357.     local function menu_populate()
  358.         if pausesel == 1 then
  359.             emu.pause()
  360.             menu_is_showing = true
  361.         end
  362.         local menu = {}
  363.  
  364.         local function menu_prepare()
  365.             local menu_list = {}
  366.             menu_func = {}
  367.             for num, func in ipairs(menu) do
  368.                 local item, f = func()
  369.                 if item then
  370.                     menu_list[#menu_list + 1] = item
  371.                     menu_func[#menu_list] = f
  372.                 end
  373.             end
  374.             return menu_list
  375.         end
  376.  
  377.         local function menu_lim(val, min, max, menuitem)
  378.             if min == max then
  379.                 menuitem[3] = 0
  380.             elseif val == min then
  381.                 menuitem[3] = "r"
  382.             elseif val == max then
  383.                 menuitem[3] = "l"
  384.             else
  385.                 menuitem[3] = "lr"
  386.             end
  387.         end
  388.  
  389.         local function incdec(event, val, min, max)
  390.             local ret
  391.             if event == "left" and val ~= min then
  392.                 val = val - 1
  393.                 ret = true
  394.             elseif event == "right" and val ~= max then
  395.                 val = val + 1
  396.                 ret = true
  397.             end
  398.             return val, ret
  399.         end
  400.  
  401.         if cheat_save then
  402.             local cplayer = { "All", "P1", "P2", "P3", "P4" }
  403.             local ctype = { "Infinite Credits", "Infinite Time", "Infinite Lives", "Infinite Energy", "Infinite Ammo", "Infinite Bombs", "Invincibility" }
  404.             menu[#menu + 1] = function() return { _("Save Cheat"), "", "off" }, nil end
  405.             menu[#menu + 1] = function() return { "---", "", "off" }, nil end
  406.             menu[#menu + 1] = function()
  407.                 local c = { _("Default"), _("Custom") }
  408.                 local m = { _("Cheat Name"), c[name], 0 }
  409.                 menu_lim(name, 1, #c, m)
  410.                 local function f(event)
  411.                     local r
  412.                     name, r = incdec(event, name, 1, #c)
  413.                     if (event == "select" or event == "comment") and name == 1 then
  414.                         manager:machine():popmessage(string.format(_("Default name is %s"), cheat_save.name))
  415.                     end
  416.                     return r
  417.                 end
  418.                 return m, f
  419.             end
  420.             if name == 2 then
  421.                 menu[#menu + 1] = function()
  422.                     local m = { _("Player"), cplayer[name_player], 0 }
  423.                     menu_lim(name_player, 1, #cplayer, m)
  424.                     return m, function(event) local r name_player, r = incdec(event, name_player, 1, #cplayer) return r end
  425.                 end
  426.                 menu[#menu + 1] = function()
  427.                     local m = { _("Type"), ctype[name_type], 0 }
  428.                     menu_lim(name_type, 1, #ctype, m)
  429.                     return m, function(event) local r name_type, r = incdec(event, name_type, 1, #ctype) return r end
  430.                 end
  431.             end
  432.             menu[#menu + 1] = function()
  433.                 local m = { _("Save"), "", 0 }
  434.                 local function f(event)
  435.                     if event == "select" then
  436.                         local desc
  437.                         local written = false
  438.                         if name == 2 then
  439.                             if cplayer[name_player] == "All" then
  440.                                 desc = ctype[name_type]
  441.                             else
  442.                                 desc = cplayer[name_player] .. " " .. ctype[name_type]
  443.                             end
  444.                         else
  445.                             desc = cheat_save.name
  446.                         end
  447.                         local filename = cheat_save.filename .. "_" .. desc
  448.                         local file = io.open(filename .. ".json", "w")
  449.                         if file then
  450.                             file:write(string.format(cheat_save.json, desc))
  451.                             file:close()
  452.                             -- xml or simple are program space only
  453.                             if not getmetatable(devtable[devcur].space).__name:match("device_t") and devtable[devcur].sname == "program" then
  454.                                 file = io.open(filename .. ".xml", "w")
  455.                                 file:write(string.format(cheat_save.xml, desc))
  456.                                 file:close()
  457.                                 file = io.open(cheat_save.path .. "/cheat.simple", "a")
  458.                                 file:write(string.format(cheat_save.simple, desc))
  459.                                 -- old cheat .dat format, write support only (for cheat forum posting of new cheats if posted in simple format)
  460.                                 file:write(string.format(cheat_save.dat, desc))
  461.                                 file:close()
  462.                                 manager:machine():popmessage(string.format(_("Cheat written to %s and added to cheat.simple"), filename))
  463.                             end
  464.                             written = true
  465.                         elseif not getmetatable(devtable[devcur].space).__name:match("device_t") and devtable[devcur].sname == "program" then
  466.                             file = io.open(cheat_save.path .. "/cheat.simple", "a")
  467.                             if file then
  468.                                 file:write(string.format(cheat_save.simple, desc))
  469.                                 -- old cheat .dat format, write support only (for cheat forum posting of new cheats if posted in simple format)
  470.                                 file:write(string.format(cheat_save.dat, desc))
  471.                                 file:close()
  472.                                 manager:machine():popmessage(_("Cheat added to cheat.simple"))
  473.                                 written = true
  474.                             end
  475.                         end
  476.                         if not written then
  477.                             manager:machine():popmessage(_("Unable to write file\nEnsure that cheatpath folder exists"))
  478.                         end
  479.                         cheat_save = nil
  480.                         return true
  481.                     end
  482.                     return false
  483.                 end
  484.                 return m, f
  485.             end
  486.             menu[#menu + 1] = function() return { _("Cancel"), "", 0 }, function(event) if event == "select" then cheat_save = nil return true end end end
  487.             return menu_prepare()
  488.         end
  489.  
  490.         menu[#menu + 1] = function()
  491.             local m = { _("CPU or RAM"), devtable[devsel].name, 0 }
  492.             menu_lim(devsel, 1, #devtable, m)
  493.             local function f(event)
  494.                 if (event == "left" or event == "right") and #menu_blocks ~= 0 then
  495.                     manager:machine():popmessage(_("Changes to this only take effect when \"Start new search\" is selected"))
  496.                 end
  497.                 devsel = incdec(event, devsel, 1, #devtable)
  498.                 return true
  499.             end
  500.             return m, f
  501.         end
  502.  
  503.         menu[#menu + 1] = function()
  504.             local m = { _("Pause Mode"), pausetable[pausesel], 0 }
  505.             menu_lim(pausesel, 1, pausetable, m)
  506.             local function f(event)
  507.                 if (event == "left" or event == "right") then                  
  508.                     if pausesel == 1 then
  509.                         pausesel = 2
  510.                         menu_is_showing = false
  511.                         manager:machine():popmessage(_("Manually pause & unpause the game when needed with the pause hotkey"))
  512.                     else
  513.                         pausesel = 1
  514.                         emu.pause()
  515.                     end
  516.                 end
  517.  
  518.                 return true
  519.             end
  520.             return m, f        
  521.         end
  522.  
  523.        
  524.        
  525.         menu[#menu + 1] = function()
  526.             local function f(event)
  527.                 local ret = false
  528.                 if event == "select" then
  529.                     menu_blocks = {}
  530.                     matches = {}
  531.                     devcur = devsel
  532.                     for num, region in ipairs(devtable[devcur].ram) do
  533.                         menu_blocks[num] = {}
  534.                         menu_blocks[num][1] = cheat.save(devtable[devcur].space, region.offset, region.size)
  535.                     end
  536.                     manager:machine():popmessage(_("All slots cleared and current state saved to Slot 1"))
  537.                     watches = {}
  538.                     opsel = 1
  539.                     value = 0
  540.                     leftop = 1
  541.                     rightop = 1
  542.                     leftop_text = "Slot 1"
  543.                     rightop_text = "Slot 1"
  544.                     value_text = ""
  545.                     expression_text = "Slot 1 < Slot 1"                        
  546.                     matchsel = 0
  547.                     return true
  548.                 end
  549.             end
  550.                 local opsel = 1
  551.             return { _("Start new search"), "", 0 }, f
  552.         end
  553.        
  554.  
  555.        
  556.         if #menu_blocks ~= 0 then
  557.             menu[#menu + 1] = function() return { "---", "", "off" }, nil end
  558.             menu[#menu + 1] = function()
  559.                 local function f(event)
  560.                     if event == "select" then
  561.                         for num, region in ipairs(devtable[devcur].ram) do
  562.                             menu_blocks[num][#menu_blocks[num] + 1] = cheat.save(devtable[devcur].space, region.offset, region.size)
  563.                         end
  564.                         manager:machine():popmessage(_("Memory State saved to Slot ").. #menu_blocks[1])
  565.                         if (leftop == #menu_blocks[1] - 1 and rightop == #menu_blocks[1] - 2 ) then
  566.                             leftop = #menu_blocks[1]
  567.                             rightop = #menu_blocks[1]-1
  568.                         elseif (leftop == #menu_blocks[1] - 2 and rightop == #menu_blocks[1] - 1 ) then
  569.                             leftop = #menu_blocks[1]-1
  570.                             rightop = #menu_blocks[1]
  571.                         elseif (leftop == #menu_blocks[1] - 1 ) then
  572.                             leftop = #menu_blocks[1]
  573.                         elseif (rightop == #menu_blocks[1] - 1) then   
  574.                             rightop = #menu_blocks[1]
  575.                         end
  576.                         leftop_text = "Slot " .. leftop
  577.                         rightop_text = "Slot " .. rightop
  578.                         devsel = devcur
  579.                         return true
  580.                     end
  581.                 end
  582.                 return { _("Save Current Memory State to Slot ") .. #menu_blocks[1] + 1, "", 0 }, f
  583.             end
  584.             menu[#menu + 1] = function() return { "---", "", "off" }, nil end
  585.             menu[#menu + 1] = function()
  586.                 local function f(event)
  587.                     if event == "select" then
  588.                         local count = 0
  589.                         local step = align == 1 and formtable[width]:sub(3, 3) or "1"
  590.                         if step == "f" then
  591.                             step = 4
  592.                         elseif step == "d" then
  593.                             step = 8
  594.                         else
  595.                             step = tonumber(step)
  596.                         end
  597.                         if #matches == 0 then
  598.                             matches[1] = {}
  599.                             for num = 1, #menu_blocks do
  600.                                 matches[1][num] = cheat.comp(menu_blocks[num][leftop], menu_blocks[num][rightop],
  601.                                 optable[opsel], formtable[width], value, bcd == 1, step)
  602.                                 count = count + #matches[1][num]
  603.                             end
  604.                         else
  605.                             lastmatch = matches[#matches]
  606.                             matches[#matches + 1] = {}
  607.                             for num = 1, #menu_blocks do
  608.                                 matches[#matches][num] = cheat.compnext(menu_blocks[num][leftop], menu_blocks[num][rightop],
  609.                                 lastmatch[num], optable[opsel], formtable[width], value, bcd == 1, step)
  610.                                 count = count + #matches[#matches][num]
  611.                             end
  612.                         end
  613.                         manager:machine():popmessage(string.format(_("%d total matches found"), count))
  614.                         matches[#matches].count = count
  615.                         matchpg = 0
  616.                         devsel = devcur
  617.                         return true
  618.                     end
  619.                 end
  620.                
  621.                 if optable[opsel] == "lt" then
  622.                     if (value == 0 ) then
  623.                         expression_text = leftop_text .. " < " .. rightop_text
  624.                     else
  625.                         expression_text = leftop_text .. " == " .. rightop_text .. " - " .. value
  626.                     end
  627.                 elseif optable[opsel] == "gt" then
  628.                     if (value == 0 ) then
  629.                         expression_text = leftop_text .. " > " .. rightop_text
  630.                     else
  631.                         expression_text = leftop_text .. " == " .. rightop_text .. " + " .. value
  632.                     end
  633.                 elseif optable[opsel] == "eq" then
  634.                     expression_text = leftop_text .. " == " .. rightop_text
  635.                 elseif optable[opsel] == "ne" then
  636.                     if (value == 0 ) then
  637.                         expression_text = leftop_text .. " != " .. rightop_text
  638.                     else
  639.                         expression_text = leftop_text .. " == " .. rightop_text .. " +/- " .. value
  640.                     end
  641.                 elseif optable[opsel] == "beq" then
  642.                     expression_text = leftop_text .. " BITWISE== " .. rightop_text
  643.                 elseif optable[opsel] == "bne" then
  644.                     expression_text = leftop_text .. " BITWISE!= " .. rightop_text
  645.                 elseif optable[opsel] == "ltv" then
  646.                     expression_text = leftop_text .. " < " .. value
  647.                 elseif optable[opsel] == "gtv" then
  648.                     expression_text = leftop_text .. " > " .. value
  649.                 elseif optable[opsel] == "eqv" then
  650.                     expression_text = leftop_text .. " == " .. value
  651.                 elseif optable[opsel] == "nev" then
  652.                     expression_text = leftop_text .. " != " .. value
  653.                 end    
  654.                 return { _("Perform Compare  :  ") .. expression_text, "", 0 }, f
  655.             end
  656.             menu[#menu + 1] = function() return { "---", "", "off" }, nil end
  657.             menu[#menu + 1] = function()
  658.                 local m = { _(leftop), "", 0 }
  659.                 menu_lim(leftop, 1, #menu_blocks[1], m)
  660.                 m[1] = "Slot " .. leftop
  661.                 return m, function(event) local r leftop, r = incdec(event, leftop, 1, #menu_blocks[1]) leftop_text = "Slot " .. leftop return r end
  662.             end
  663.             menu[#menu + 1] = function()
  664.                 local m = { _(optable[opsel]), "", 0 }
  665.                 menu_lim(opsel, 1, #optable, m)
  666.                 local function f(event)
  667.                     local r
  668.                     opsel, r = incdec(event, opsel, 1, #optable)
  669.                     if event == "left" or event == "right" or event == "comment" then
  670.                         if optable[opsel] == "lt" then
  671.                             manager:machine():popmessage(_("Left less than right"))
  672.                         elseif optable[opsel] == "gt" then
  673.                             manager:machine():popmessage(_("Left greater than right"))
  674.                         elseif optable[opsel] == "eq" then
  675.                             manager:machine():popmessage(_("Left equal to right"))
  676.                         elseif optable[opsel] == "ne" then
  677.                             manager:machine():popmessage(_("Left not equal to right"))
  678.                         elseif optable[opsel] == "beq" then
  679.                             manager:machine():popmessage(_("Left equal to right with bitmask"))
  680.                         elseif optable[opsel] == "bne" then
  681.                             manager:machine():popmessage(_("Left not equal to right with bitmask"))
  682.                         elseif optable[opsel] == "ltv" then
  683.                             manager:machine():popmessage(_("Left less than value"))
  684.                         elseif optable[opsel] == "gtv" then
  685.                             manager:machine():popmessage(_("Left greater than value"))
  686.                         elseif optable[opsel] == "eqv" then
  687.                             manager:machine():popmessage(_("Left equal to value"))
  688.                         elseif optable[opsel] == "nev" then
  689.                             manager:machine():popmessage(_("Left not equal to value"))
  690.                         end
  691.                     end
  692.                     return r
  693.                 end
  694.                 return m, f
  695.             end
  696.             menu[#menu + 1] = function()
  697.                 if optable[opsel]:sub(3, 3) == "v" then
  698.                     return nil
  699.                 end
  700.                 local m = { _(rightop), "", 0 }
  701.                 menu_lim(rightop, 1, #menu_blocks[1], m)
  702.                 m[1] = "Slot " .. rightop
  703.                 return m, function(event) local r rightop, r = incdec(event, rightop, 1, #menu_blocks[1]) rightop_text = "Slot " .. rightop return r end
  704.             end
  705.             menu[#menu + 1] = function()
  706.                 if optable[opsel] == "bne" or optable[opsel] == "beq" or optable[opsel] == "eq" then
  707.                     return nil
  708.                 end
  709.                 local m
  710.                 if optable[opsel] == "ltv" or optable[opsel] == "gtv" or optable[opsel] == "eqv" or optable[opsel] == "nev" then
  711.                     m = { _("Value"), value, "" }
  712.                 else
  713.                     m = { _("Difference"), value, "" }
  714.                 end
  715.                 local max = 100 -- max value?
  716.                 menu_lim(value, 0, max, m)
  717.                 if value == 0 and optable[opsel]:sub(3, 3) ~= "v" then
  718.                     m[2] = _("Any")
  719.                 end
  720.                 return m, function(event) local r value, r = incdec(event, value, 0, max) return r end
  721.             end
  722.             menu[#menu + 1] = function() return { "---", "", "off" }, nil end
  723.             menu[#menu + 1] = function()
  724.                 local m = { _("Data Format"), formname[width], 0 }
  725.                 menu_lim(width, 1, #formtable, m)
  726.                 return m, function(event) local r width, r = incdec(event, width, 1, #formtable) return r end
  727.             end
  728.                    
  729.             menu[#menu + 1] = function()
  730.                 local m = { _("Test/Write Poke Value"), pokevaltable[pokevalsel], 0 }
  731.                 menu_lim(pokevalsel, 1, #pokevaltable, m)
  732.                 local function f(event)
  733.                     local r
  734.                     pokevalsel, r = incdec(event, pokevalsel, 1, #pokevaltable)
  735.                     if event == "left" or event == "right" or event == "comment" then
  736.                         if pokevalsel == 1 then
  737.                             manager:machine():popmessage(_("Use this if you want to poke the Slot 1 value (eg. You started with something but lost it)"))
  738.                         elseif pokevalsel == 2 then
  739.                             manager:machine():popmessage(_("Use this if you want to poke the Last Slot value (eg. You started without an item but finally got it)"))
  740.                         elseif pokevalsel == 3 then
  741.                             manager:machine():popmessage(_("Use this if you want to poke 0x00"))
  742.                         elseif pokevalsel == 4 then
  743.                             manager:machine():popmessage(_("Use this if you want to poke 0x01"))   
  744.                         elseif pokevalsel == 5 then
  745.                             manager:machine():popmessage(_("Use this if you want to poke 0x02"))
  746.                         elseif pokevalsel == 6 then
  747.                             manager:machine():popmessage(_("Use this if you want to poke 0x03"))   
  748.                         elseif pokevalsel == 7 then
  749.                             manager:machine():popmessage(_("Use this if you want to poke 0x04"))
  750.                         elseif pokevalsel == 8 then
  751.                             manager:machine():popmessage(_("Use this if you want to poke 0x05"))   
  752.                         elseif pokevalsel == 9 then
  753.                             manager:machine():popmessage(_("Use this if you want to poke 0x06"))
  754.                         elseif pokevalsel == 10 then
  755.                             manager:machine():popmessage(_("Use this if you want to poke 0x07"))   
  756.                         elseif pokevalsel == 11 then
  757.                             manager:machine():popmessage(_("Use this if you want to poke 0x08"))
  758.                         elseif pokevalsel == 12 then
  759.                             manager:machine():popmessage(_("Use this if you want to poke 0x09"))
  760.                         elseif pokevalsel == 13 then
  761.                             manager:machine():popmessage(_("Use this if you want to poke 0x63 (Decimal 99)"))
  762.                         elseif pokevalsel == 14 then
  763.                             manager:machine():popmessage(_("Use this if you want to poke 0x99 (BCD 99)"))
  764.                         elseif pokevalsel == 15 then
  765.                             manager:machine():popmessage(_("Use this if you want to poke 0xFF (Decimal 255)")) 
  766.                         elseif pokevalsel == 16 then
  767.                             manager:machine():popmessage(_("Use this if you want to poke 0x3E7 (Decimal 999)"))
  768.                         elseif pokevalsel == 17 then
  769.                             manager:machine():popmessage(_("Use this if you want to poke 0x999 (BCD 999)"))
  770.                         elseif pokevalsel == 18 then
  771.                             manager:machine():popmessage(_("Use this if you want to poke 0x270F (Decimal 9999)"))
  772.                         elseif pokevalsel == 19 then
  773.                             manager:machine():popmessage(_("Use this if you want to poke 0x9999 (BCD 9999)"))
  774.                         elseif pokevalsel == 20 then
  775.                             manager:machine():popmessage(_("Use this if you want to poke 0xFFFF (Decimal 65535)"))     
  776.                         end
  777.                     end
  778.                     return r
  779.                 end
  780.                 return m, f
  781.             end
  782.            
  783.            
  784.             menu[#menu + 1] = function()
  785.                 if optable[opsel] == "bne" or optable[opsel] == "beq" then
  786.                     return nil
  787.                 end
  788.                 local m = { "BCD", _("Off"), 0 }
  789.                 menu_lim(bcd, 0, 1, m)
  790.                 if bcd == 1 then
  791.                     m[2] = _("On")
  792.                 end
  793.                 return m, function(event) local r bcd, r = incdec(event, bcd, 0, 1) return r end
  794.             end
  795.             menu[#menu + 1] = function()
  796.                 if formtable[width]:sub(3, 3) == "1" then
  797.                     return nil
  798.                 end
  799.                 local m = { "Aligned only", _("Off"), 0 }
  800.                 menu_lim(align, 0, 1, m)
  801.                 if align == 1 then
  802.                     m[2] = _("On")
  803.                 end
  804.                 return m, function(event) local r align, r = incdec(event, align, 0, 1) return r end
  805.             end
  806.             if #matches ~= 0 then
  807.                 menu[#menu + 1] = function()
  808.                     local function f(event)
  809.                         if event == "select" then
  810.                             matches[#matches] = nil
  811.                             matchpg = 0
  812.                             return true
  813.                         end
  814.                     end
  815.                     return { _("Undo last search -- #") .. #matches, "", 0 }, f
  816.                 end
  817.                 menu[#menu + 1] = function() return { "---", "", "off" }, nil end
  818.                 menu[#menu + 1] = function()
  819.                     local m = { _("Match block"), matchsel, "" }
  820.                     menu_lim(matchsel, 0, #matches[#matches], m)
  821.                     if matchsel == 0 then
  822.                         m[2] = _("All")
  823.                     end
  824.                     local function f(event)
  825.                         local r
  826.                         matchsel, r = incdec(event, matchsel, 0, #matches[#matches])
  827.                         if r then
  828.                             matchpg = 0
  829.                         end
  830.                         return r
  831.                     end
  832.                     return m, f
  833.                 end
  834.                 local function mpairs(sel, list, start)
  835.                     if #list == 0 then
  836.                         return function() end, nil, nil
  837.                     end
  838.                     if sel ~= 0 then
  839.                         list = {list[sel]}
  840.                     end
  841.                     local function mpairs_it(list, i)
  842.                         local match
  843.                         i = i + 1
  844.                         local sel = i + start
  845.                         for j = 1, #list do
  846.                             if sel <= #list[j] then
  847.                                 match = list[j][sel]
  848.                                 break
  849.                             else
  850.                                 sel = sel - #list[j]
  851.                             end
  852.                         end
  853.                         if not match then
  854.                             return
  855.                         end
  856.                         return i, match
  857.                     end
  858.                     return mpairs_it, list, 0
  859.                 end
  860.                 local bitwidth = formtable[width]:sub(3, 3)
  861.                 if bitwidth == "2" then
  862.                     bitwidth = " %04x"
  863.                 elseif bitwidth == "4" then
  864.                     bitwidth = " %08x"
  865.                 elseif bitwidth == "8" then
  866.                     bitwidth = " %016x"
  867.                 elseif bitwidth == "f" or bitwidth == "d" then
  868.                     bitwidth = " %010f"
  869.                 else
  870.                     bitwidth = " %02x"
  871.                 end
  872.  
  873.                 local function match_exec(match)
  874.                     local dev = devtable[devcur]
  875.                    
  876.                     local wid = formtable[width]:sub(3, 3)
  877.                     local widchar
  878.                     local pokevalue
  879.                     local form
  880.                    
  881.                     if  pokevalsel == 1 then
  882.                         pokevalue = match.oldval
  883.                     elseif  pokevalsel == 2 then
  884.                         pokevalue = match.newval
  885.                     elseif  pokevalsel == 3 then
  886.                         pokevalue = 0
  887.                     elseif  pokevalsel == 4 then
  888.                         pokevalue = 1
  889.                     elseif  pokevalsel == 5 then
  890.                         pokevalue = 2
  891.                     elseif  pokevalsel == 6 then
  892.                         pokevalue = 3
  893.                     elseif  pokevalsel == 7 then
  894.                         pokevalue = 4
  895.                     elseif  pokevalsel == 8 then
  896.                         pokevalue = 5
  897.                     elseif  pokevalsel == 9 then
  898.                         pokevalue = 6
  899.                     elseif  pokevalsel == 10 then
  900.                         pokevalue = 7
  901.                     elseif  pokevalsel == 11 then
  902.                         pokevalue = 8
  903.                     elseif  pokevalsel == 12 then
  904.                         pokevalue = 9
  905.                     elseif  pokevalsel == 13 then
  906.                         pokevalue = 99
  907.                     elseif  pokevalsel == 14 then
  908.                         pokevalue = 153
  909.                     elseif  pokevalsel == 15 then
  910.                         pokevalue = 255
  911.                     elseif  pokevalsel == 16 and wid == "1" then
  912.                         pokevalue = 99
  913.                     elseif  pokevalsel == 17 and wid == "1" then
  914.                         pokevalue = 153
  915.                     elseif  pokevalsel == 18 and wid == "1" then
  916.                         pokevalue = 99 
  917.                     elseif  pokevalsel == 19 and wid == "1" then
  918.                         pokevalue = 153
  919.                     elseif  pokevalsel == 20 and wid == "1" then
  920.                         pokevalue = 255
  921.                     elseif  pokevalsel == 16 then
  922.                         pokevalue = 999      
  923.                     elseif  pokevalsel == 17 then
  924.                         pokevalue = 2457    
  925.                     elseif  pokevalsel == 18 then
  926.                         pokevalue = 9999         
  927.                     elseif  pokevalsel == 19 then
  928.                         pokevalue = 39321    
  929.                     elseif  pokevalsel == 20 then
  930.                         pokevalue = 65535                          
  931.                     end
  932.                    
  933.                     local cheat = { desc = string.format(_("Test Cheat %08X:%02X"), match.addr, pokevalue), script = {} }
  934.                    
  935.                     if wid == "2" then
  936.                         wid = "u16"
  937.                         form = "%08x %04x"
  938.                         widchar = "w"
  939.                     elseif wid == "4" then
  940.                         wid = "u32"
  941.                         form = "%08x %08x"
  942.                         widchar = "d"
  943.                     elseif wid == "8" then
  944.                         wid = "u64"
  945.                         form = "%08x %016x"
  946.                         widchar = "q"
  947.                     elseif wid == "f" then
  948.                         wid = "u32"
  949.                         form = "%08x %f"
  950.                         widchar = "d"
  951.                     elseif wid == "d" then
  952.                         wid = "u64"
  953.                         form = "%08x %f"
  954.                         widchar = "q"
  955.                     else
  956.                         wid = "u8"
  957.                         form = "%08x %02x"
  958.                         widchar = "b"
  959.                     end
  960.                                        
  961.                     if getmetatable(dev.space).__name:match("device_t") then
  962.                         cheat.ram = { ram = dev.tag }
  963.                         cheat.script.run = "ram:write(" .. match.addr .. "," .. pokevalue .. ")"
  964.                     elseif getmetatable(dev.space).__name:match("memory_share") then
  965.                         cheat.share = { share = dev.tag }
  966.                         cheat.script.run = "share:write_" .. wid .. "(" .. match.addr .. "," .. pokevalue .. ")"
  967.                     else
  968.                         cheat.space = { cpu = { tag = dev.tag, type = dev.sname } }
  969.                         cheat.script.run = "cpu:write_" .. wid .. "(" .. match.addr .. "," .. pokevalue .. ")"
  970.                     end
  971.                     if match.mode == 1 then
  972.                         if not _G.ce then
  973.                             manager:machine():popmessage(_("Cheat engine not available"))
  974.                         else
  975.                             _G.ce.inject(cheat)
  976.                         end
  977.                     elseif match.mode == 2 then
  978.                         cheat_save = {}
  979.                         menu = 1
  980.                         menu_player = 1
  981.                         menu_type = 1
  982.                         local setname = emu.romname()
  983.                         if emu.softname() ~= "" then
  984.                             if emu.softname():find(":") then
  985.                                 filename = emu.softname():gsub(":", "/")
  986.                             else
  987.                                 for name, image in pairs(manager:machine().images) do
  988.                                     if image:exists() and image:software_list_name() ~= "" then
  989.                                         setname = image:software_list_name() .. "/" .. emu.softname()
  990.                                     end
  991.                                 end
  992.                             end
  993.                         end
  994.                         -- lfs.env_replace is defined in boot.lua
  995.                         cheat_save.path = lfs.env_replace(manager:machine():options().entries.cheatpath:value()):match("([^;]+)")
  996.                         cheat_save.filename = string.format("%s/%s", cheat_save.path, setname)
  997.                         cheat_save.name = cheat.desc
  998.                         local json = require("json")
  999.                         cheat.desc = "%s"
  1000.                         cheat_save.json = json.stringify({[1] = cheat}, {indent = true})
  1001.                         cheat_save.xml = string.format("<mamecheat version=\"1\">\n  <cheat desc=\"%%s\">\n    <script state=\"run\">\n      <action>%s.pp%s@%X=%X</action>\n    </script>\n  </cheat>\n</mamecheat>", dev.tag:sub(2), widchar, match.addr, match.newval)
  1002.                         cheat_save.simple = string.format("%s,%s,%X,%s,%X,%%s\n", setname, dev.tag, match.addr, widchar, pokevalue)
  1003.                         cheat_save.dat = string.format(":%s:40000000:%X:%08X:FFFFFFFF:%%s\n", setname,  match.addr, pokevalue)         
  1004.                         manager:machine():popmessage(string.format(_("Default name is %s"), cheat_save.name))
  1005.                         return true
  1006.                     else
  1007.                         local func = "return space:read"
  1008.                         local env = { space = devtable[devcur].space }
  1009.                         if not getmetatable(dev.space).__name:match("device_t") then
  1010.                             func = func .. "_" .. wid
  1011.                         end
  1012.                         func = func .. "(" .. match.addr .. ")"
  1013.                         watches[#watches + 1] = { addr = match.addr, func = load(func, func, "t", env), format = form }
  1014.                         return true
  1015.                     end
  1016.                     return false
  1017.                 end
  1018.  
  1019.                 for num2, match in mpairs(matchsel, matches[#matches], matchpg * 100) do
  1020.                     if num2 > 100 then
  1021.                         break
  1022.                     end
  1023.                     menu[#menu + 1] = function()
  1024.                         if not match.mode then
  1025.                             match.mode = 1
  1026.                         end
  1027.                         local modes = { _("Test"), _("Write"), _("Watch") }
  1028.                         local m = { string.format("%08x" .. bitwidth .. bitwidth, match.addr, match.oldval,
  1029.                                                       match.newval), modes[match.mode], 0 }
  1030.                         menu_lim(match.mode, 1, #modes, m)
  1031.                         local function f(event)
  1032.                             local r
  1033.                             match.mode, r = incdec(event, match.mode, 1, 3)
  1034.                             if event == "select" then
  1035.                                 r = match_exec(match)
  1036.                             end
  1037.                             return r
  1038.                         end
  1039.                         return m, f
  1040.                     end
  1041.                 end
  1042.                 if matches[#matches].count > 100 then
  1043.                     menu[#menu + 1] = function()
  1044.                         local m = { _("Page"), matchpg, 0 }
  1045.                         local max
  1046.                         if matchsel == 0 then
  1047.                             max = math.ceil(matches[#matches].count / 100) - 1
  1048.                         else
  1049.                             max = #matches[#matches][matchsel]
  1050.                         end
  1051.                         menu_lim(matchpg, 0, max, m)
  1052.                         local function f(event)
  1053.                             matchpg, r = incdec(event, matchpg, 0, max)
  1054.                             return r
  1055.                         end
  1056.                         return m, f
  1057.                     end
  1058.                 end
  1059.             end
  1060.             if #watches ~= 0 then
  1061.                 menu[#menu + 1] = function()
  1062.                     return { _("Clear Watches"), "", 0 }, function(event) if event == "select" then watches = {} return true end end
  1063.                 end
  1064.             end
  1065.         end
  1066.         return menu_prepare()
  1067.     end
  1068.  
  1069.     local function menu_callback(index, event)
  1070.         if event == "cancel" and pausesel == 1 then
  1071.             emu.unpause()
  1072.             menu_is_showing = false
  1073.             return {0,0,0}
  1074.         end
  1075.         return menu_func[index](event)
  1076.     end
  1077.     emu.register_menu(menu_callback, menu_populate, _("Cheat Finder"))
  1078.     emu.register_frame_done(function ()
  1079.             local tag, screen = next(manager:machine().screens)
  1080.             local height = mame_manager:ui():get_line_height()
  1081.             for num, watch in ipairs(watches) do
  1082.                 screen:draw_text("left", num * height, string.format(watch.format, watch.addr, watch.func()))
  1083.             end        
  1084.             if tabbed_out and manager:ui():is_menu_active()  then
  1085.                 emu.pause()
  1086.                 menu_is_showing = true
  1087.                 tabbed_out = false
  1088.             end                
  1089.         end)
  1090.     emu.register_periodic(function ()
  1091.         if menu_is_showing and not manager:ui():is_menu_active() then
  1092.             emu.unpause()
  1093.             menu_is_showing = false
  1094.             tabbed_out = true
  1095.         end
  1096.     end)   
  1097. end
  1098.  
  1099. return exports
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement