User File #638709699427364327

Upload All User Files

#638709699427364327 (unlisted) - [WIP] mmxscript

mmxscript.lua
Game: Mega Man X ( SNES, see all files )
4 downloads
Uploaded 11 days ago by warmCabin (see all 30)
I've been making some changes to mmxscript as I work with EZGames69 on Mega Man X Buster Only. I'm gonna post a final version when we're done with the movie, but I want to share this WIP.
  • Demystified player coordinates into room.pixel.subpixel
  • Custom lag indicator now updates lag counter and TAStudio red bars
  • Speed & dash timer display properly when in ride armor
FractalFusion did the initial BizHawk port. I think that version is floating around in Discord CDN hell.
By the way, why is this little function necessary? emu.setislagged should do all of this. I can't imagine why you would want the lag indicator, lag counter, and TAStudio red bars to have three distinct states.
 local function set_lag_good(flag)
     emu.setislagged(flag)
     if flag then emu.setlagcount(emu.lagcount() + 1) end
     tastudio.setlag(emu.framecount(), flag)
 end
--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