--Author Pasky13, FractalFusion, & warmCabin
bit = (require "migration_helpers").EmuHawk_pre_2_9_bit();
gui.addmessage("Loaded MMX script")
local hexdigit = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" }
local lastval = 0xD37
---------------
----GLOBALS----
---------------
local pbase = 0xBA8
local px = 0xBAD
local py = 0xBB0
local psx = 0xBAC
local psy = 0xBAF
local cx = 0x0000B4
local cy = 0x0000B6
fontSize = 100
---------------
----TOGGLES----
---------------
local draw_megaman = true
local draw_enemies = true
local draw_hpvalues = true
local draw_projectiles = true
--local draw_instantbox = false -- Bizhawk doesnt support breakpoints
local xm
local ym
local xmoff
local ymoff
local thislagind
local prevlagind = 0
local prevframecount = 0
local function text(a, b, c)
gui.text(a * xm + xmoff, b * ym + ymoff, c)
end
local function hexstr(val)
str = ""
for _ = 1, 4 do
str = hexdigit[val % 16 + 1] .. str
val = math.floor(val / 16)
end
return str
end
local function textf(x, y, format, ...)
gui.text(x, y, string.format(format, ...))
end
memory.usememorydomain("CARTROM")
local function megaman()
local camx = mainmemory.read_u16_le(cx)
local camy = mainmemory.read_u16_le(cy)
local x = mainmemory.read_u16_le(px) - camx
local y = mainmemory.read_u16_le(py) - camy
local facing = mainmemory.read_u8(pbase + 0x11)
local boxpointer = mainmemory.read_u16_le(pbase + 0x20) + 0x28000
local xoff = memory.read_s8(boxpointer + 0)
local yoff = memory.read_s8(boxpointer + 1)
local xrad = memory.read_u8(boxpointer + 2)
local yrad = memory.read_u8(boxpointer + 3)
if facing > 0x45 then
xoff = xoff * -1
end
gui.drawBox(x + xoff + xrad, y + yoff + yrad, x + xoff - xrad, y + yoff - yrad, 0xFF0000FF, 0x400000FF)
end
local function enemies()
local x
local xoff
local xrad
local y
local yoff
local yrad
local camx = mainmemory.read_u16_le(cx)
local camy = mainmemory.read_u16_le(cy)
local base
local boxpointer
local facing
local fill
local outl
local start = 0xE68
local oend = 11
if draw_projectiles then
oend = 63
end
for i = 0, oend, 1 do
if i < 48 then
base = start + (i * 0x40)
else
base = 0x1628 + (i - 48) * 0x30
end
--if i == 0 then
-- base = start
--end
if mainmemory.read_u8(base) ~= 0 then
if i >= 15 and i < 21 then
if draw_projectiles == true then
-- TODO: Find a way to detect dash lemons. They're tied to sprite slot.
fill = 0x40FFFFFF
outl = 0xFFFFFFFF
else
fill = 0x00000000
outl = 0x00000000
end
else
fill = 0x40FF0000
outl = 0xFFFF0000
end
if i >= 21 then
fill = 0x40FFFF00
outl = 0xFFFFFF00
end
if i >= 48 then
fill = 0x4000FFFF
outl = 0xFF00FFFF
end
facing = mainmemory.read_u8(base + 0x11)
x = mainmemory.read_u16_le(base + 5) - camx
y = mainmemory.read_u16_le(base + 8) - camy
boxpointer = mainmemory.read_u16_le(base + 0x20) + 0x28000
xoff = memory.read_s8(boxpointer + 0)
yoff = memory.read_s8(boxpointer + 1)
xrad = memory.read_u8(boxpointer + 2)
yrad = memory.read_u8(boxpointer + 3)
if facing > 0x45 then
xoff = xoff * -1
end
--Breakpoints not yet implemented in Bizhawk
-- if draw_instantbox == true then
-- memory.registerwrite(0x7E0000 + base + 0x20,2,function ()
-- draw_instabox(memory.getregister("D"))
-- end)
-- end
--gui.text(x,y,string.format("%X",base)) -- Debug
if xrad < 60 and yrad < 60 then
gui.drawBox(x + xoff + xrad, y + yoff + yrad, x + xoff - xrad, y + yoff - yrad, outl, fill)
end
if draw_hpvalues == true and mainmemory.read_u8(base + 0x27) > 0 then
if i < 8 then
text((x - 5), (y - 5), "HP: " .. mainmemory.read_u8(base + 0x27) % 128)
end
end
end
end
end
local function scaler()
xmoff = client.borderwidth()
ymoff = client.borderheight()
xm = (client.screenwidth() - 2 * xmoff) / 256
ym = (client.screenheight() - 2 * ymoff) / 224
end
-- This loops infinitely at power on. I guess the RNG sequence never hits 0?
local function get_rng_index(rngval)
local val = 0xD37
local c = 0
while val ~= rngval do
val = bit.band(val * 3, 0xFF00) + bit.band(math.floor(val * 3 / 256) + val, 0x00FF)
c = c + 1
end
return c
end
-- Lag Indicator
local function set_lag_good(flag)
emu.setislagged(flag)
if flag then emu.setlagcount(emu.lagcount() + 1) end
tastudio.setlag(emu.framecount(), flag)
end
local function lagcheck()
thislagind = mainmemory.read_u16_le(0x0B9B)
if emu.framecount() - prevframecount == 1 and thislagind == prevlagind then
-- text(100, 10, "LAG WARNING")
set_lag_good(true)
end
prevlagind = thislagind
end
while true do
scaler()
if draw_megaman == true then
megaman()
end
if draw_enemies == true then
enemies()
end
--[[
A few assorted states:
14 - hitstun
44 - In Ride Armor
]]
local x_state = mainmemory.read_u8(0xBAA)
-- Positions
-- high byte stores screen.pixel (1 byte each)
-- low byte stores subpixel (256ths of a pixel)
mmx = mainmemory.read_s16_le(px); -- X Position
mmy = mainmemory.read_s16_le(py); -- Y Position
mmsx = mainmemory.read_u8(psx) -- X Subpixel Position
mmsy = mainmemory.read_u8(psy) -- X Subpixel Position
text(5, 140, string.format("X Pos:%02X.%02X.%02X", mmx >> 8, mmx & 255, mmsx))
text(5, 148, string.format("Y Pos:%02X.%02X.%02X", mmy >> 8, mmy & 255, mmsy))
-- Speeds
-- Stores pixel.subpixel (1 byte each)
-- Ride armor uses its own separate physics, so check if we're in one and use the appropriate speed & dash timer values.
-- X's position is updated by the armor, so those values are usable.
local dash, xspd, yspd
if x_state == 44 then
dash = mainmemory.read_s8(0x0E44);
xspd = mainmemory.read_s16_le(0x0E32);
yspd = mainmemory.read_s16_le(0x0E34);
else
dash = mainmemory.read_s8(0x0BFA);
xspd = mainmemory.read_s16_le(0x0BC2);
yspd = mainmemory.read_s16_le(0x0BC4);
end
text(10, 156, "Dash:" .. dash);
text(5, 172, string.format("X Spd:%2d.%02X", xspd // 256, xspd & 255))
text(5, 180, string.format("Y Spd:%2d.%02X", yspd // 256, yspd & 255))
-- HP
hp = mainmemory.read_s8(0x0BCF); -- HP
text(10, 95, hp);
-- Buster Charge
btimer = mainmemory.read_u8(0x0BFF); -- Buster Timer
stype = mainmemory.read_u8(0x0C03)
if btimer > 149 then
strcharge = string.format("%02u", btimer - 150)
elseif btimer > 79 then
strcharge = "00 " .. string.format("%02u", btimer - 79)
elseif btimer > 1 then
strcharge = "00 00 " .. string.format("%02u", btimer - 1)
else
strcharge = "00 00 00"
end
text(0, 164, "Buster:" .. strcharge);
-- RNG
rngval = mainmemory.read_u16_le(0x0BA6)
text(220, 60, hexstr(rngval))
nextval = rngval
for i = 0, 10 do
drop = nextval % 256
if drop < 158 then
droptxt = " "
elseif drop < 190 then
droptxt = "le"
elseif drop < 222 then
droptxt = "LE"
elseif drop < 238 then
droptxt = "we"
elseif drop < 254 then
droptxt = "WE"
else
droptxt = "XL"
end
text(220, 60 + i * 8, hexstr(nextval) .. " " .. droptxt)
-- text(220, 60 + i * 8, hexstr(nextval) .. " " .. droptxt .. " #" .. get_rng_index(nextval))
nextval = bit.band(nextval * 3, 0xFF00) + bit.band(math.floor(nextval * 3 / 256) + nextval, 0x00FF)
end
text(180, 60, "Current")
if lastval ~= rngval then
for i = 1, 5 do
text(220, 8 * i, hexstr(lastval))
-- text(220, 8 * i, hexstr(lastval) .. " #" .. get_rng_index(lastval))
lastval = bit.band(lastval * 3, 0xFF00) + bit.band(math.floor(lastval * 3 / 256) + lastval, 0x00FF)
if lastval == rngval then
text(160, 0, "Values since: " .. i)
break
end
if i == 5 then
text(160, 0, "Values since: >5")
text(220, 8 * 6, "...")
end
end
else
text(160, 0, "Values since: 0")
end
text(190, 8, "Last")
lastval = rngval
--Misc. info object display
text(80, 200, "Misc. data:")
for i = 0, 15 do
if mainmemory.read_u8(0x1628 + i * 0x30) == 1 then
text(140 + 6 * i, 200, "1")
else
text(140 + 6 * i, 200, "0")
end
end
lagcheck()
prevframecount = emu.framecount()
emu.frameadvance()
end