User File #33375453760541627

Upload All User Files

#33375453760541627 - (NES) Mega Man 5 RNG display (for FCEUX)

MM5_RNG_FCEUX.lua
1041 downloads
Uploaded 9/3/2016 1:19 AM by FatRatKnight (see all 245)
But I like the canvas. Well, aside from the fact it acts slow on my laptop, anyway. This display runs rather smoothly here on FCEUX rather than the floating BizHawk canvas.
I still have not identified which color goes to what item, but I can assure you that the different colors go to different items. If I take the time to look, I'll update this description. I've spent said time to transplant the script to FCEUX without nasty hiccups.
I made a quick change and am uploading it right away. Quick tests show its working well enough.
--Renaming. I like the descriptive names, but I want something shorter.
--I'm also selecting functions I think I'll need.
--Turns out I needed to swap emulators. Yay, I just have one spot to change!
local R1u= memory.readbyte

--Don't like gui.text, so here's my number drawings.

--*****************************************************************************
Draw= {}   --Draw[button]( x , y , c )
--*****************************************************************************
--Coordinates is the top-left pixel of the 3x5 digit.
--Used for drawing compact, colored numbers.

local Px,Li= gui.pixel, gui.line

Draw[0]= function(x,y,c) -- ###
    Li(x  ,y  ,x  ,y+4,c)-- # #
    Li(x+2,y  ,x+2,y+4,c)-- # #
    Px(x+1,y  ,c)        -- # #
    Px(x+1,y+4,c)        -- ###
end

Draw[1]= function(x,y,c) --  #
    Li(x  ,y+4,x+2,y+4,c)-- ##
    Li(x+1,y  ,x+1,y+3,c)--  #
    Px(x  ,y+1,c)        --  #
end                      -- ###

Draw[2]= function(x,y,c) -- ###
    Li(x  ,y  ,x+2,y  ,c)--   #
    Li(x  ,y+3,x+2,y+1,c)-- ###
    Li(x  ,y+4,x+2,y+4,c)-- #
    Px(x  ,y+2,c)        -- ###
    Px(x+2,y+2,c)
end

Draw[3]= function(x,y,c) -- ###
    Li(x  ,y  ,x+1,y  ,c)--   #
    Li(x  ,y+2,x+1,y+2,c)-- ###
    Li(x  ,y+4,x+1,y+4,c)--   #
    Li(x+2,y  ,x+2,y+4,c)-- ###
end

Draw[4]= function(x,y,c) -- # #
    Li(x  ,y  ,x  ,y+2,c)-- # #
    Li(x+2,y  ,x+2,y+4,c)-- ###
    Px(x+1,y+2,c)        --   #
end                      --   #

Draw[5]= function(x,y,c) -- ###
    Li(x  ,y  ,x+2,y  ,c)-- #
    Li(x  ,y+1,x+2,y+3,c)-- ###
    Li(x  ,y+4,x+2,y+4,c)--   #
    Px(x  ,y+2,c)        -- ###
    Px(x+2,y+2,c)
end

Draw[6]= function(x,y,c) -- ###
    Li(x  ,y  ,x+2,y  ,c)-- #
    Li(x  ,y+1,x  ,y+4,c)-- ###
    Li(x+2,y+2,x+2,y+4,c)-- # #
    Px(x+1,y+2,c)        -- ###
    Px(x+1,y+4,c)
end
                         -- ###
Draw[7]= function(x,y,c) --   #
    Li(x  ,y  ,x+1,y  ,c)--  ##
    Li(x+2,y  ,x+1,y+4,c)--  #
end                      --  #

Draw[8]= function(x,y,c) -- ###
    Li(x  ,y  ,x  ,y+4,c)-- # #
    Li(x+2,y  ,x+2,y+4,c)-- ###
    Px(x+1,y  ,c)        -- # #
    Px(x+1,y+2,c)        -- ###
    Px(x+1,y+4,c)
end

Draw[9]= function(x,y,c) -- ###
    Li(x  ,y  ,x  ,y+2,c)-- # #
    Li(x+2,y  ,x+2,y+3,c)-- ###
    Li(x  ,y+4,x+2,y+4,c)--   #
    Px(x+1,y  ,c)        -- ###
    Px(x+1,y+2,c)
end

Draw[10]=function(x,y,c) --  #
    Li(x  ,y+1,x  ,y+4,c)-- # #
    Li(x+2,y+1,x+2,y+4,c)-- # #
    Px(x+1,y  ,c)        -- ###
    Px(x+1,y+3,c)        -- # #
end

Draw[11]=function(x,y,c) -- ##
    Li(x  ,y  ,x  ,y+4,c)-- # #
    Li(x+1,y  ,x+2,y+1,c)-- ##
    Li(x+1,y+4,x+2,y+3,c)-- # #
    Px(x+1,y+2,c)        -- ##
end

Draw[12]=function(x,y,c) --  #
    Li(x  ,y+1,x  ,y+3,c)-- # #
    Li(x+1,y  ,x+2,y+1,c)-- #
    Li(x+1,y+4,x+2,y+3,c)-- # #
end                      --  #

Draw[13]=function(x,y,c) -- ##
    Li(x  ,y  ,x  ,y+4,c)-- # #
    Li(x+2,y+1,x+2,y+3,c)-- # #
    Px(x+1,y  ,c)        -- # #
    Px(x+1,y+4,c)        -- ##
end

Draw[14]=function(x,y,c) -- ###
    Li(x  ,y  ,x  ,y+4,c)-- #
    Li(x+1,y  ,x+2,y  ,c)-- ##
    Li(x+1,y+4,x+2,y+4,c)-- #
    Px(x+1,y+2,c)        -- ###
end

Draw[15]=function(x,y,c) -- ###
    Li(x  ,y  ,x  ,y+4,c)-- #
    Li(x+1,y  ,x+2,y  ,c)-- ##
    Px(x+1,y+2,c)        -- #
end                      -- #

--*****************************************************************************
local function __DN_AnyBase(right, y, Number, c, bkgnd, div)
--*****************************************************************************
-- Works with any base from 2 to 16. Paints the input number.
-- Returns the x position where it would paint another digit.
-- It only works with integers. Rounds fractions toward zero.

    if div < 2 then return end  -- Prevents the function from never returning.

    local Digit= {}
    local Negative= false
    if Number < 0 then
        Number= -Number
        Negative= true
    end

    Number= math.floor(Number)
    c= c or "white"
    bkgnd= bkgnd or "clear"

    local i= 0
    if Number < 1 then
        Digit[1]= 0
        i= 1
    end

    while (Number >= 1) do
        i= i+1
        Digit[i]= Number % div
        Number= math.floor(Number/div)
    end

    if Negative then  i= i+1  end
    local x= right - i*4
    gui.box(x+1, y-1, right+1, y+5,bkgnd,bkgnd)

    i= 1
    while Draw[Digit[i]] do
        Draw[Digit[i]](right-2,y,c)
        right= right-4
        i=i+1
    end

    if Negative then
        gui.line(right, y+2,right-2,y+2,c)
        right= right-4
    end
    return right
end


--*****************************************************************************
local function DrawNum(right, y, Number, c, bkgnd)
--*****************************************************************************
-- Paints the input number as right-aligned. Decimal version.

    return __DN_AnyBase(right, y, Number, c, bkgnd, 10)
end

--*****************************************************************************
local function DrawNumx(right, y, Number, c, bkgnd)
--*****************************************************************************
-- Paints the input number as right-aligned. Hexadecimal version.

    return __DN_AnyBase(right, y, Number, c, bkgnd, 16)
end


--#############################################################################
--Handle RNG

--Data structure expected:
--  RNG_Table
--    [1] 00E4  R0
--    [2] 00E5  R1
--    [3] 00E6  R2
--    [4] 00E7  R3
--    TA  0092  Timer_Always
--    TL  009D  Timer_Lagged

--These six values are what's required to know the output.
--If a rename is suggested, I'll probably listen.

--Because lag shifts the RNG, it's not precisely possible to know what the
--future RNG will hold, although knowing the underlying numbers may help to
--know what to expect as lag frames "shift" the RNG a little.

--In addition, whenever the RNG is called, R2 is modified using a different
--formula than the standard RNG shift, so if an enemy needs to "think", or an
--item is about to drop, the RNG can be "unpredictably" modified for the next
--16 frames. Since R2 is shifted out entirely after 16 frames, without any
--effect on the standard shifts, the change is only local to this call.
--It still happens more frequently than would be desired.



--*****************************************************************************
local function Roll(T)
--*****************************************************************************
--Gets the next RNG value. This is the "shift" calculation.
--In-place modification to the table. Make a copy first if you want the old.
--Will not modify timers, even though Timer_Always also updates with it.

    local v= bit.band(0x02,bit.bxor(T[1],T[2])) / 2
    for i= 1, 4 do
        T[i]= T[i]+256*v
        v= T[i]%2
        T[i]= math.floor(T[i]/2)
    end
end

--*****************************************************************************
local function LoadRNG(T)
--*****************************************************************************
--Reads the RNG values from memory.
--You can feed a table (it'll modify) or let it construct one itself.
--Returns the initialized table.

    T= T or {}

    T[1]= R1u(0x00E4)  --R0
    T[2]= R1u(0x00E5)  --R1
    T[3]= R1u(0x00E6)  --R2
    T[4]= R1u(0x00E7)  --R3
    T.TA= R1u(0x0092)  --Timer_Always
    T.TL= R1u(0x009D)  --Timer_Lagged

    return T
end

--*****************************************************************************
local function CalculateRNG(RNG)
--*****************************************************************************
--Gets the calculated RNG value. This is the "call" calculation.
--Returns three values: The RNG output, and the new R2.
--  Number: RNG output (value used for whatever RNG stuff is needed)
--  Number: What R2 is replaced with after the call is done
--This function will not do in-place modification. That's up to the caller.
--Take note that R2 and R3 both are modified. R3 takes the RNG output.

--[[
Carry is always set upon entry (add +1 to what you see)

0E:AE64 LDA $00E6    R2
0E:AE66 ADC $00E7    R3
0E:AE68 ADC $0000    #$59 (used for function call)
0E:AE6A SBC $009D    Frame timer (affected by lag)
0E:AE6C STA $00E6    Modify R2 right away
0E:AE6E ADC $0001    #$AE (used for function call)
0E:AE70 SBC $00E5    R1
0E:AE72 ADC $0092    Frame timer (always runs)
0E:AE74 STA $00E7    R3
]]--

    local RNG_Output= (( --Also New_R3
        8
        + RNG[3] --R2
        + RNG[4] --R3
        - RNG.TL --Timer_Lagged
        - RNG[2] --R1
      )%255 + 1
      + RNG.TA   --Timer_Always
    )%256

    local New_R2= ((
        0x59
        + RNG[3] --R2
        + RNG[4] --R3
      )%255 + 1
      + (255 - RNG.TL)
    )%256

    return RNG_Output, New_R2
end

local BigNum= 0xFFFFFFFF + 1  --The 80red glitch handler

local Item1= 0xFFFFFFFF - BigNum
local Item2= 0x00FFFFFF
local Item3= 0x0080FFFF
local Item4= 0xFF8000FF - BigNum
local Item5= 0xFF0000FF - BigNum
local NoItem=0x808080FF - BigNum

local ItemThresholds= {
[0]=Item1,Item1,
    Item2,
    Item3,Item3,Item3,Item3,Item3,
    Item4,Item4,
    Item5,Item5,Item5,Item5
}

--*****************************************************************************
local function ItemColor(v)
--*****************************************************************************
    return ItemThresholds[v%50] or NoItem
end


--#############################################################################
--GUI

local RNG= {{},{}}  --For sake of calling the table constructor just once
--*****************************************************************************
local function RNG_HUD()
--*****************************************************************************
--To display some basic RNG information.

    LoadRNG(RNG[1]) --If you never call the RNG, this is what you get
    LoadRNG(RNG[2]) --If called just once at this moment, what you get
    RNG[2][4],RNG[2][3]= CalculateRNG(RNG[2]) --To show effects of RNG call

    for i= 1, 37 do
        for r= 1, 2 do
            local v= CalculateRNG(RNG[r])
            local clr= ItemColor(v)

            DrawNum(252 - 14*(r-1),6*i+3,v,clr,"black")

            Roll(RNG[r])
            RNG[r].TL= (RNG[r].TL+1)%256
            RNG[r].TA= (RNG[r].TA+1)%256
        end
    end
end
gui.register(RNG_HUD)