User File #12531497925152203

Upload All User Files

#12531497925152203 - My Solar Jetman info script (w/ TASEditor helper code)

SJ_and_TASEditor_Helper.lua
1239 downloads
Uploaded 2/7/2014 8:11 AM by FatRatKnight (see all 245)
Exact script I've been using in my TAS of Solar Jetman. Wait, why didn't I upload this earlier?
Can be run without TASEditor engaged. The display works fine without it, don't worry.
Shows the following:
  • Top-left corner: Tether position, tether speed (but not direction), in hexadecimal
  • Bottom-left corner: Wall invincibility timer (dec), Fuel remaining (hex), weapon power remaining (hex)
  • Top: RNG information. The 1s and 0s is simply showing the right four-digit hex number in binary. Hard to describe these RNGs here.
  • Top-right corner: Object counts: Player, your bullets, item, enemy bullets, enemy type A, enemy type B
  • Bottom-right corner: Facing, Speed, and position, all in hex. There's also a frame counter down there, also in hex.
  • Dot radar shows existing objects, using pixels with distances scaled down for off-screen detection. Hold Z to blackout the screen to see these dots better.
If you're going to complain about the fact I use hexadecimal often, I do it because it is not intuitive for me to recall that the maximum speed is 768 rather than 0x300, and 768 does not instantly tell me that it's 3 pixels per frame, while 0x300 does. It gets really bad on screen space if I decide to divide 768 by 256 so I see 3 at max speed but 2.99609375 when I'm really close. Also, if I do divide by 256, how am I supposed to memorize that 0.00390625 is the smallest unit? How much of a full pixel if I see a decimal 98, anyway?
If the numbers line up cleanly in decimal, I would have used it. Most of them don't, for my purposes. So I read them in hexadecimal. Makes sense to me. This is the exact script I'm using, specifically for my use, except TASe_XOR_SJ.lua is the filename I use. This is likely the final version of this script, as my TASing attempts for Solar Jetman is near its end.
--[[  Leeland Kirwan (FatRatKnight), 2013
Allows user input to "mix" with TAS Editor using XOR logic.
If Recording is checked, this script will do its intended job.

Tap a P1 key to toggle input. If "All" is selected, will use other player keys
for related player. If an individual player is selected, uses P1 controls. You
can hold down a key to affect multiple frames, toggling the key on each frame.

For reference, Superimpose uses OR logic, and does not allow user input to
clear stored input. A great inconvience for those wishing to use the keyboard
to toggle individual input rather than mouse.
]]--

local z= "none"

local btnstr= {A = "A", B   = "B", select= "S", start= "T",
               up= "U", down= "D", left  = "L", right= "R"}
local btnval= {A = 0x01, B   = 0x02, select= 0x04, start= 0x08,
               up= 0x10, down= 0x20, left  = 0x40, right= 0x80}
local plval= {["1P"]= 1, ["2P"]= 2, ["3P"]= 3, ["4P"]= 4}
local OldJoy= {{},{},{},{}}
--*****************************************************************************
local function InputToggle()
--*****************************************************************************
--Needs readonly mode to work, but won't interfere too much otherwise.
--Toggles inputs recorded in TAS Editor.

    if not taseditor.engaged() then return end  -- Escape

    taseditor.clearinputchanges() -- Guessing something horrible w/o this.

    local frame= emu.framecount()

    local plSel= plval[taseditor.getrecordermode()]
    local plLow = plSel or 1   -- Get the for loop range!
    local plHigh= plSel or 4   -- Hardcoded 4 doesn't appear harmful...

    local P1joy= nil                                -- If one player, get P1.
    if plSel then P1joy= joypad.getimmediate(1) end -- Otherwise, get all.

    local changed= false  -- Flag, so I don't interfere too much
    local History= ""     -- Information for TASer in History list

    for pl= plLow, plHigh do
        local pad= taseditor.getinput(frame,pl)
        local joy= P1joy or joypad.getimmediate(pl) -- Pick out the joypad

        local mask= 0                     -- Convert messy table to numbers
        for btn,pressed in pairs(joy) do
            if pressed and not OldJoy[pl][btn] then
                mask= bit.bor(mask,btnval[btn])
                History= History .. pl .. btnstr[btn]
            end
        end

        taseditor.submitinputchange(frame,pl,bit.bxor(pad,mask))
        OldJoy[pl]= joy  -- To avoid repeated triggers
        changed= changed or (mask ~= 0) -- If the bitmask did something, apply!
    end

    if changed then taseditor.applyinputchanges(History) end
end
taseditor.registerauto(InputToggle)


--#############################################################################
--#############################################################################
local R1u, R1s= memory.readbyte, memory.readbytesigned
--*****************************************************************************
local function R2u(a) return R1u(a) + R1u(a+1)*256 end
local function R2s(a) return R1u(a) + R1s(a+1)*256 end
--*****************************************************************************

local lastkeys, keys= input.get(), input.get()
--*****************************************************************************
local function UpdateKeys()  lastkeys= keys; keys= input.get()    end
--*****************************************************************************
local function Limits(V,l,h)  return math.max(math.min(V,h),l) end
--*****************************************************************************

--*****************************************************************************
local Draw= {}
--*****************************************************************************
--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

local OC= {
[0]= "white",
     "white",
     "white",
     "green",
     "green",
     "green",
     "green",
     "green",
     "green",
     "green",
     "green",
     "grey",
     "grey",
     "grey",
     "grey",
     "red",
     "red",
     "red",
     "red",
     "red",
     "red",
     "red",
     "red",
     "orange",
     "orange",
     "orange",
     "yellow",
     "yellow",
     "yellow",
     "yellow",
     "yellow"
}


--[[
local cc,cn= 0,0
local WantedStr= {
[0]=0x9D,0xBA,0x02,0xA9,0x01,0x9D,0x36,0x03,
    0x20,0xD6,0xB9,0xA9,0x80,0x9D,0x22,0x04}
--*****************************************************************************
local function EnemyCheck()
--*****************************************************************************
    for i= 0, 15 do
        if R1u(0xC000 + i) ~= WantedStr[i] then  cn= cn+1; return  end
    end
    cc= cc+1
end

memory.registerexec(0xC5E8,EnemyCheck)
]]--

--*****************************************************************************
local function RNGRead()
--*****************************************************************************
    local rM, rS= R1u(0x005A), R1u(0x005B)*256 + R1u(0x005C)

    gui.box(139,8,171,14,"blue")
    gui.box(172,8,203,14,"black")
    for i= 0, 15 do
        local b= bit.band(1,bit.rshift(rS,i))
        Draw[b](200-4*i,9,"white")
    end
    DrawNumx(202,16,rS,"white","black")
    DrawNumx(170,16,rM,"white","black")

    local b= bit.band(1,bit.bxor(  bit.rshift(rM,3),bit.rshift(rM,6)  ))
    Draw[b](204,9,"grey")
end

--*****************************************************************************
local function ObjRadar(Factor)  -- What factor to scale radar?
--*****************************************************************************
    local CamX, CamY= R2u(0x004C), R2u(0x004E)
    local OffX= math.floor((1-1/Factor)*128)
    local OffY= math.floor((1-1/Factor)*100)

    local count= 0
    for i= 0, 0x1E do
        if R1u(0x0317+i) ~= 0 then
            count= count+1
            gui.pixel(
                math.floor((R1u(0x0200+i)+R1s(0x021F+i)*256-CamX)/Factor + OffX),
                math.floor((R1u(0x025D+i)+R1s(0x027C+i)*256-CamY)/Factor + OffY),
                OC[i]
            )
        end
    end
--    DrawNum(90,12,count)
end

--*****************************************************************************
local function ObjCount()
--*****************************************************************************
    local P, B, E, A, I, S= 0,0,0,0,0,0

    for i=  0,  2 do
        if R1u(0x0317+i) ~= 0 then
            P= P+1
        end
    end
    for i=  3, 10 do
        if R1u(0x0317+i) ~= 0 then
            B= B+1
        end
    end
    for i= 11, 14 do
        if R1u(0x0317+i) ~= 0 then
            E= E+1
        end
    end
    for i= 15, 22 do
        if R1u(0x0317+i) ~= 0 then
            A= A+1
        end
    end
    for i= 23, 25 do
        if R1u(0x0317+i) ~= 0 then
            I= I+1
        end
    end
    for i= 26, 30 do
        if R1u(0x0317+i) ~= 0 then
            S= S+1
        end
    end

    gui.box(244,8,255,56,"black",0)
    Draw[P](246,10,"white");    Draw[3](251,10,"white")
    Draw[B](246,18,"white");    Draw[8](251,18,"white")
    Draw[E](246,26,"white");    Draw[4](251,26,"white")
    Draw[A](246,34,"white");    Draw[8](251,34,"white")
    Draw[I](246,42,"white");    Draw[3](251,42,"white")
    Draw[S](246,50,"white");    Draw[5](251,50,"white")
end




local DirX={
[0]=  0,  3,  6,  8, 11, 13, 14, 15,
     16, 15, 14, 13, 11,  8,  6,  3,
      0, -3, -6, -8,-11,-13,-14,-15,
    -16,-15,-14,-13,-11, -8, -6, -3
}
local DirX2={
[0]=  0, 12, 24, 35, 45, 53, 59, 62,
     64, 62, 59, 53, 45, 35, 24, 12,
      0,-12,-24,-35,-45,-53,-59,-62,
    -64,-62,-59,-53,-45,-35,-24,-12
}
--*****************************************************************************
local function DirPow(v)
--*****************************************************************************
    return DirX[v], DirX[(v+8)%32]
end

-- 0  1  2  3  4  5  6  7  8
-- 0  3  6  8 11 13 14 15 16
--*****************************************************************************
local function Fn()
--*****************************************************************************
    UpdateKeys()

--BlackBox, to see the dot radar better.
    if keys.Z then gui.box(-1,7,256,200,"black",0) end

--BasicHUD
    DrawNumx(254,226,R2u(0x005D),"white","black") -- Timer
    DrawNumx( 20,196,R2u(0x00C6),"white","black") -- Fuel
    DrawNumx( 40,196,R2u(0x00C8),"white","black") -- Weapon left
    DrawNumx(254,188,R1u(0x0374),"white","black") -- Direction
--    DrawNum( 230, 10,R2u(0x004C),"white","black") -- Cam X
    DrawNum(  20,189,R1u(0x0099),"white","black") -- Wall invincibility timer

--Position
    local N=  1 - bit.band(R1u(0x0336),1)*2 --X
    DrawNumx(254,196,(R1u(0x029B)+R1u(0x02BA)*256)*N,"white","black") --Vel
    DrawNumx(228,196, R1u(0x0200)+R1u(0x021F)*256   ,"white","black") --Pos
    DrawNumx(236,196, R1u(0x0197)                   ,"grey" ,"black") --Sub

    N= -1 + bit.band(R1u(0x0355),1)*2 --Y
    DrawNumx(254,204,(R1u(0x02D9)+R1u(0x02F8)*256)*N,"white","black") --Vel
    DrawNumx(228,204, R1u(0x025D)+R1u(0x027C)*256   ,"white","black") --Pos
    DrawNumx(236,204, R1u(0x023E)                   ,"grey" ,"black") --Sub

    ObjRadar(3)
    ObjCount()

--Tether
    N= "green"
    if R1u(0x0066) == 0 then N= "grey" end
    DrawNumx(18, 9,R2u(0x0068),N,"black")
    DrawNumx(18,16,R2u(0x006B),N,"black")

    RNGRead()
--    DrawNum(20, 8,cc,"white","black")
--    DrawNum(20,16,cn,"white","black")
end
gui.register(Fn)

--*****************************************************************************
local function DumpStats()
--*****************************************************************************
    for obj= 0, 0x1E do
        local color= "white"
        if R1u(0x0200+obj+0x1F*9) == 0 then color= "grey" end
        for st= 0, 16 do
            DrawNumx(9+st*10, 9+obj*7, R1u(0x0200+obj+st*0x1F),color,"black")
        end
    end
end
--gui.register(DumpStats)

--#############################################################################
--#############################################################################
-- Ugh, need this loop on the very bottom...

--*****************************************************************************
while true do
--*****************************************************************************
-- Exists to detect frame advances, and thus clear the OldJoy array.
    for i= 1, 4 do OldJoy[i]= {} end -- Retrigger keys
    cc=0
    cn=0
    emu.frameadvance()
end