User File #39660220375676218

Upload All User Files

#39660220375676218 - GBA F-Zero: Maximum Velocity - Changes tracker

FZMV_BizHawk_v5.lua
924 downloads
Uploaded 6/13/2017 2:12 AM by FatRatKnight (see all 245)
This script now records positions and whether things exist. After playing parts of the run, rewind and do different things. The script will state whether things existed or not, and if they did, whether they changed position from the last time it got to that frame. The script will dumbly record into its memory every time you go back over a part, so if you just rerun the new input again, it will claim everything is present or absent exactly as they were.
The purpose, mainly, is so we can more easily tell if the CPU did something different when doing random crud.
Oh, and I changed the order of the player ghost functions. It'll record your new position after displaying what it has. Previously, it recorded, then displayed the recording, which will always coincide with the player's immediate position. At least this way, if you leave the ghost recorder on, that you can see the immediate local changes you're making, though it really isn't smart. Thanks to core resets killing lua variables, and one being triggered every time you play a new movie, cross-movie checks with this type of ghost stuff are impossible without file IO.
I do need a better frame detection (it doesn't like start of races). I also need a better way to detect whether a thing exists.
--GBA F-Zero: Maximum Velocity - General script
--Lower-left is the north-oriented display
--Lower-right is the facing-oriented display
--For use with BizHawk
--FatRatKnight

--Setup
local flag_RecordGhost= true
local key_ToggleGhostRecord= "M"

local StaticX,StaticY=  60,220 --Center position
local StaticR= 60              --Radius
local StaticS= 0x0400          --Scale

local RotateX,RotateY= 180,220 --Center position
local RotateR= 60              --Radius
local RotateS= 0x0200          --Scale

local RadarColors= {
[0]=0xFFFFFFFF, --White   Note, the player can be any of first four.
    0xFF00FF00, --Green   Depends on which spot the machine starts in.
    0xFFFFFF00, --Yellow
    0xFF00FFFF, --Cyan    I advise bright colors and distinct hues.
    0xFFFF40FF  --Purple
}

client.SetGameExtraPadding(0,0,0,120) -- Yay, bottom border


--##############################################################################
--General

local R4u , R4s= memory.read_u32_le , memory.read_s32_le
local R2u , R2s= memory.read_u16_le , memory.read_s16_le
local R1u , R1s= memory.read_u8     , memory.read_s8

local SqrtTwo= math.sqrt(2) -- A constant, so I avoid recalculating it.

local InternalFrame= R4u(0x15998,"EWRAM")

--*****************************************************************************
local function FetchAddrDomainGBA(a)
--*****************************************************************************
--Stand-in for System Bus. Highly desired when you got a full pointer.
--I don't know all regions, though.

    if     (a >= 0x02000000) and (a < (0x02000000+memory.getmemorydomainsize("EWRAM"))) then
        return a-0x02000000, "EWRAM"
    elseif (a >= 0x03000000) and (a < (0x03000000+memory.getmemorydomainsize("IWRAM"))) then
        return a-0x03000000, "IWRAM"
    elseif (a >= 0x08000000) and (a < (0x08000000+memory.getmemorydomainsize("ROM"))) then
        return a-0x08000000, "ROM"
    else
        error(string.format("Unknown address %08X", a),1)
    end
end

--*****************************************************************************
local function HexPlusMinus(v,digits)
--*****************************************************************************
--String.format does not append a - for hexadecimal values, instead using a
--twos complement of the value. This function is to inject that sign.

  local str= "+"
  if v < 0 then str= "-"; v= -v end
  return string.format(str .. "%" .. digits .. "X",v)
end

--*****************************************************************************
local function WordToAngle(v) --revision 3
--*****************************************************************************
-- Input: Angle in 1/65536 of a revolution per unit, clockwise, no offset
-- Output: Angle in radians, clockwise, no offset
-- Well, Y increases as it goes down, so leave things like that.

    return (v/32768)*math.pi
end

--*****************************************************************************
local function PartialFillTable(T,x,y,r,s)
--*****************************************************************************
--Exists mainly to relocate or rescale drawing area without re-fetching stats.

  T.x= x; T.y= y; T.r= r; T.s= s
  T.Left= x-r; T.Top= y-r; T.Right= x+r; T.Bottom= y+r
end

--*****************************************************************************
local function FillTable(T,x,y,r,s,pl)
--*****************************************************************************
--This exists so I only have to do one calculation for multiple uses.
--I pay in table dereferencing, though.

  T= T or {} --construct, in case we were fed nil as first parameter

--Most of these won't change frame by frame. Possibly wasteful to retry.
  T.x= x; T.y= y; T.r= r; T.s= s; T.pl= pl
  T.Left= x-r; T.Top= y-r; T.Right= x+r; T.Bottom= y+r

--Player stats...
  local a= 0x12D60 + pl*0xCC --"EWRAM", can't I use 0x02012D60 and be done?
  T.Addr= a  --Address, in case there are special stats I did not get here.

  T.PlX= R4s(a+0x00,"EWRAM")  --Player X
  T.PlY= R4s(a+0x04,"EWRAM")  --Player Y
  local Facing= R2u(a+0x78,"EWRAM")
  T.Facing= Facing
  Facing= WordToAngle(Facing) --Convert to mathematical angle
  T.AngleF= Facing

  T.Sine= math.sin(Facing); T.Cosine= math.cos(Facing)

  return T --If we were fed the table, the caller doesn't need to handle this
end

--*****************************************************************************
local function InBounds(T,x,y)
--*****************************************************************************
--Returns true or false, generally for drawing area.

  return (x >= T.Left) and (x <= T.Right) and (y >= T.Top) and (y <= T.Bottom)
end

local GhostX,GhostY= {},{}
--*****************************************************************************
local function RecordGhost(pl,frame)
--*****************************************************************************
  local addr= 0x12D60 + 0xCC*pl
  GhostX[frame]= R4s(addr+0x00,"EWRAM") --x
  GhostY[frame]= R4s(addr+0x04,"EWRAM") --y
end

--*****************************************************************************
local function FetchGhost(frame)
--*****************************************************************************
  return GhostX[frame], GhostY[frame]
end


--##############################################################################
--Static

--*****************************************************************************
local function GetStaticDisplayLoc(sT,PosX,PosY)
--*****************************************************************************
--Apply offsets. Apply scaling. End.

  local x= math.floor((PosX - sT.PlX)/sT.s+0.5) + sT.x
  local y= math.floor((PosY - sT.PlY)/sT.s+0.5) + sT.y

  return x,y
end


--*****************************************************************************
local function GridUnderlayS(sT)
--*****************************************************************************
--Might be nice to have a dark colored map underneath the radar.
--For now, have these grid lines.

  local range= (sT.r+0.5) * sT.s

--Vertical lines
  local Vline= (math.ceil((sT.PlX - range)/0x4000)*0x4000 - sT.PlX) / sT.s + sT.x
  while Vline <= sT.Right do
    gui.drawLine(Vline,sT.Top,Vline,sT.Bottom,0xFF404040)
    Vline= Vline + 0x4000/sT.s
  end

--Horizontal lines
  local Hline= (math.ceil((sT.PlY - range)/0x4000)*0x4000 - sT.PlY) / sT.s + sT.y
  while Hline <= sT.Bottom do
    gui.drawLine(sT.Left,Hline,sT.Right,Hline,0xFF404040)
    Hline= Hline + 0x4000/sT.s
  end

end

--*****************************************************************************
local function MomentumCompass(sT)
--*****************************************************************************
--Yay, compass! In case you're lost! ... Somehow?


--Facing first. So its line is painted under the momentum line.
--    local z= sT.AngleF
    local z= WordToAngle(R2s(sT.Addr+0x78,"EWRAM"))
    local x= sT.x + sT.r*math.cos(z)
    local y= sT.y + sT.r*math.sin(z)
    gui.drawLine(sT.x, sT.y,x,y,0xFFFF00FF)

--Momentum second.
    z= WordToAngle(R2s(sT.Addr+0x7A,"EWRAM")) --Momentum
    x= sT.x + sT.r*math.cos(z)
    y= sT.y + sT.r*math.sin(z)
    gui.drawLine(sT.x, sT.y,x,y,0xFF00FF00)
end

--*****************************************************************************
local function RivalRadarNorth(sT)
--*****************************************************************************
--Watches for rivals around.
--It is oriented northward, by the way.

  local OriginX,OriginY= sT.PlX,sT.PlY

  for i= 0, 4 do --We will paint the player as a side-effect here.
    local a= 0x12D60 + i*0xCC
    local MachineX,MachineY= R4s(a+0,"EWRAM"),R4s(a+4,"EWRAM")
    if (R1s(a+0xB6,"EWRAM") ~= -1) then
      local X= math.floor((MachineX-OriginX)/sT.s+0.5) + sT.x
      local Y= math.floor((MachineY-OriginY)/sT.s+0.5) + sT.y
      if InBounds(sT , X,Y) then
        local clr= RadarColors[i] or 0xFFC0C0C0  --Fallback shouldn't happen...
        gui.drawLine(X-4,Y  ,X+4,Y  ,clr)
        gui.drawLine(X  ,Y-4,X  ,Y+4,clr)
      end
    end
  end
end

--*****************************************************************************
local function PlayerTrailS(sT)
--*****************************************************************************
--Well, the game keeps a short list of old positions. Let's display them!

  for i= 0, 3 do
    local x= R4s(sT.Addr+0x10 + 8*i,"EWRAM")
    local y= R4s(sT.Addr+0x14 + 8*i,"EWRAM")
    x,y= GetStaticDisplayLoc(sT,x,y)
    gui.drawPixel(x,y,0xFFC0C0C0)
  end
end

--*****************************************************************************
local function PlayerGhostStatic(sT)
--*****************************************************************************
--Would be cool to know what we did so we know how we're doing now.

  local x,y= FetchGhost(InternalFrame)
  if not x then return end
  x,y= GetStaticDisplayLoc(sT,x,y)
  if InBounds(sT,x,y) then --Draw ye X, rather than +.
    gui.drawLine(x-3,y-3,x+3,y+3,0xFFC0C0C0)
    gui.drawLine(x-3,y+3,x+3,y-3,0xFFC0C0C0)
  end
end

--#############################################################################
--Rotating

--*****************************************************************************
local function GetRotateDisplayLoc(rT,PosX,PosY)
--*****************************************************************************
--Rotatey stuff.

  local x= PosX - rT.PlX
  local y= PosY - rT.PlY

  x,y= -rT.Sine*x+rT.Cosine*y, -rT.Cosine*x-rT.Sine*y
  x= math.floor(x/rT.s+0.5) + rT.x
  y= math.floor(y/rT.s+0.5) + rT.y

  return x,y
end

--*****************************************************************************
local function GridUnderlayR(rT)
--*****************************************************************************
--Rotated underlay. Now that should be a fun exercise in trig.
--Incomplete function. I'm seriously out of practice in my math, and am not
--getting the Y lines to behave. Do not use this function.
--I have tackled this for a while. It appears outside my capacity to debug.
--I may scrap the function and rewrite from scratch.

--Get our triangle sides
  local Angle= WordToAngle(rT.Facing%0x4000 - 0x2000) --45 degree offset
  local Hypotinuse= rT.r * rT.s * SqrtTwo --Radius, scale, to corner of square

  local LongSide=  math.cos(Angle) * Hypotinuse
  local ShortSide= math.sin(Angle) * Hypotinuse

  local Xx= {v= math.ceil((rT.PlX - LongSide)/0x4000)*0x4000, min= rT.PlX - LongSide, max= rT.PlX + LongSide, left= rT.PlX - ShortSide, right= rT.PlX + ShortSide}
  local Yy= {v= math.ceil((rT.PlY - LongSide)/0x4000)*0x4000, min= rT.PlY - LongSide, max= rT.PlY + LongSide, left= rT.PlY - ShortSide, right= rT.PlY + ShortSide}

  Angle= WordToAngle(rT.Facing%4000) -- Don't need the diagonal now
  local Sine=   math.sin(Angle)
  local Cosine= math.cos(Angle)

  local Tangent  = math.tan(rT.AngleF)
--  local Cotangent= math.cot(rT.AngleF)

--  while x < MaxX do

--    Xx.v= Xx.v + 0x4000
--  end

  while Yy.v < Yy.max do
    local x1,y1 , x2,y2
    if Yy.v > Yy.left then
      x1,y1= GetRotateDisplayLoc(rT,
--        rT.PlX - (Yy.v-Yy.min)*Cosine/Sine,
        rT.PlX + (Yy.v-Yy.max),
        Yy.v)
    else
      if Angle ~= 0 then
        x1,y1= GetRotateDisplayLoc(rT,
          rT.PlX,
--          rT.PlX + (Yy.v-Yy.min)*rT.Cosine/rT.Sine,
--          rT.PlX - (Yy.v-Yy.min)*rT.Cosine/rT.Sine,
--          rT.PlX + (Yy.v-Yy.min)*rT.Sine/rT.Cosine,
--          rT.PlX - (Yy.v-Yy.min)*rT.Sine/rT.Cosine,
          Yy.v)
      end
    end
    if Yy.v > Yy.right then
      if Angle ~= 0 then
        x2,y2= GetRotateDisplayLoc(rT,
          rT.PlX + 0x2000,
--          rT.PlX + (Yy.v-Yy.max)*Cosine/Sine,
          Yy.v)
      end
    else
      x2,y2= GetRotateDisplayLoc(rT,
        rT.PlX + 0x2000,
--        rT.PlX + (Yy.v-Yy.min)*Sine/Cosine,
        Yy.v)
    end
    if x1 and x2 then gui.drawLine(x1,y1,x2,y2,0xFF404040) end
    Yy.v= Yy.v + 0x4000
  end

end

--*****************************************************************************
local function MomentumAngle(rT)
--*****************************************************************************
--Always facing forward, so omit the facing line. Only our momentum line counts
--Might as well note north, though.

  local a= rT.Addr
  local Facing= R2u(a+0x78,"EWRAM")
  local Momentum= R2u(a+0x7A,"EWRAM")
  local Diff= (Facing - Momentum + 0x8000)%0x10000 - 0x8000

--North
  local Angle= WordToAngle(Facing)
  local HalfR= rT.r/2
  local x= rT.x - HalfR*math.cos(Angle)
  local y= rT.y + HalfR*math.sin(Angle)
  gui.drawLine(x-1,y  ,x+1,y  ,0xFF808080)
  gui.drawLine(x  ,y-1,x  ,y+1,0xFF808080)

--Momentum, relative to facing
  Angle= WordToAngle(Diff)
  x= rT.x - rT.r*math.sin(Angle)
  y= rT.y - rT.r*math.cos(Angle)
  gui.drawLine(rT.x,rT.y,x,y,0xFF00FF00)
end

--*****************************************************************************
local function RivalRadarFacing(rT)
--*****************************************************************************
--The rival watch.
--Oriented based on player's machine facing.

  local OriginX,OriginY= rT.PlX, rT.PlY
  local Sine=   rT.Sine
  local Cosine= rT.Cosine

  for i= 0, 4 do --We will paint the player as a side-effect here.
    local a= 0x12D60 + i*0xCC
    local MachineX,MachineY= R4s(a+0,"EWRAM"),R4s(a+4,"EWRAM")
    if (R1s(a+0xB6,"EWRAM") ~= -1) then
      local X,Y= GetRotateDisplayLoc(rT,MachineX,MachineY)
--      local X,Y= MachineX-OriginX,MachineY-OriginY
--      X,Y= -Sine*X+Cosine*Y, -Cosine*X-Sine*Y
--      X= math.floor(X/rT.s+0.5) + rT.x
--      Y= math.floor(Y/rT.s+0.5) + rT.y

      if InBounds(rT , X,Y) then
        local clr= RadarColors[i] or 0xFFC0C0C0  --Fallback shouldn't happen...
        gui.drawLine(X-4,Y  ,X+4,Y  ,clr)
        gui.drawLine(X  ,Y-4,X  ,Y+4,clr)
      end
    end
  end
end

--*****************************************************************************
local function PlayerTrailR(rT)
--*****************************************************************************
--Rotating things around for the player's trail.

  for i= 0, 3 do
    local x= R4s(rT.Addr+0x10 + 8*i,"EWRAM")
    local y= R4s(rT.Addr+0x14 + 8*i,"EWRAM")
    x,y= GetRotateDisplayLoc(rT,x,y)
    gui.drawPixel(x,y,0xFFC0C0C0)
  end
end

--*****************************************************************************
local function PlayerGhostRotate(rT)
--*****************************************************************************
--You are your own worst enemy. If you can beat yourself, overcome anything!
--Just don't beat yourself up on this.

  local x,y= FetchGhost(InternalFrame)
  if not x then return end
  x,y= GetRotateDisplayLoc(rT,x,y)
  if InBounds(rT,x,y) then --Draw ye X, rather than +.
    gui.drawLine(x-3,y-3,x+3,y+3,0xFFC0C0C0)
    gui.drawLine(x-3,y+3,x+3,y-3,0xFFC0C0C0)
  end
end


--#############################################################################
--Misc display

--*****************************************************************************
local function ClrBySign(v)
--*****************************************************************************
  if v < 0 then return 0xFFFFFF00 end
  if v > 0 then return 0xFF00FFFF end
  return 0xFFFF00FF
end

local DispX,DispY= 0,244
local OldPos= {}; for i= 0, 4 do OldPos[i]= {x={},y={},Exist={}} end
--*****************************************************************************
local function AlertChanges(frame)
--*****************************************************************************
--Tracks all machines. It will report on screen for any changes.

  for pl= 0, 4 do
--Fetch stuff.
    local addr= 0x12D60 + 0xCC*pl
    local Old= OldPos[pl]
    local x,y,Exist= R4s(addr+0x00,"EWRAM"),R4s(addr+0x04,"EWRAM"),R1s(addr+0xB6,"EWRAM") ~= -1

--Here we display changes made
    if Old.Exist[frame] ~= Exist then
      if Old.Exist[frame] == nil then      --Never saw it before, nothing special.
        local str= "REC:not"
        if Exist then str= "REC:here" end
        gui.pixelText(DispX,DispY+7*pl,str,0xFF808080)
      elseif Old.Exist[frame] == true then --Used to exist, but not now.
        gui.pixelText(DispX,DispY+7*pl,"It's gone!",RadarColors[pl])
      else --Didn't exist before, but now we suddenly see it.
        gui.pixelText(DispX,DispY+7*pl,"Appeared!",RadarColors[pl])
      end
    else -- Both false or both true. Figure it out.
      if Exist == false then  --Well, if we didn't exist, and still don't...
        gui.pixelText(DispX,DispY+7*pl,"Absent",0xFF808080)
      else --Finally, we've confirmed both are existing... Position compares!
        if (Old.x[frame] == x) and (Old.y[frame] == y) then
          gui.pixelText(DispX,DispY+7*pl,"Present",0xFF808080)
        else --Show diffs in position
          local DiffX= Old.x[frame] - x
          local DiffY= Old.y[frame] - y
          local str= HexPlusMinus(DiffX,5) .. " " .. HexPlusMinus(DiffY,5)
          gui.pixelText(DispX,DispY+7*pl,str,RadarColors[pl])
        end
      end
    end

--And here we update
    Old.x[frame]= x
    Old.y[frame]= y
    Old.Exist[frame]= Exist
  end
end

--*****************************************************************************
local function MachineHUD(n)
--*****************************************************************************
  local a= 0x12D60 + n*0xCC

  local x, y= R4s(a+0x00,"EWRAM"), R4s(a+0x04,"EWRAM")
  local Facing, Momentum= R2u(a+0x78,"EWRAM"), R2u(a+0x7A,"EWRAM")

  gui.pixelText(  0,  0,string.format("%8X",x))
  gui.pixelText(  0,  7,string.format("%8X",y))
  gui.pixelText(  0, 16,string.format("%8X",R2s(a+0x74,"EWRAM")))  --Speed
--  gui.pixelText(  0, 21,string.format("%8X",R4s(a+0x78,"EWRAM")))  --Facing & Momentum

  x= x - R4s(a+0x08,"EWRAM")
  y= y - R4s(a+0x0C,"EWRAM")
  gui.pixelText( 33,  0,string.format("%4X",math.abs(x)),ClrBySign(x))
  gui.pixelText( 33,  7,string.format("%4X",math.abs(y)),ClrBySign(y))
  local v= math.floor(math.sqrt(x*x + y*y)) -- Distance formula
  gui.pixelText(  0, 23,string.format("%8X",v),0xFF00FFFF) -- Change in position

--Facing, momentum, and their difference.
  gui.pixelText(  0,160,string.format("%4X",Facing)  ,0xFFFF00FF)
  gui.pixelText(  0,167,string.format("%4X",Momentum),0xFF00FF00)
  v= (Facing - Momentum + 0x8000)%0x10000 - 0x8000
  gui.pixelText(  0,174,string.format("%4X",math.abs(v)),ClrBySign(v))

--Elevation
  local Height,VertVel= R4s(a+0x54,"EWRAM"),R2s(a+0x84,"EWRAM")
--  gui.pixelText(207, 21,string.format("%8d",Height))
--  gui.pixelText(207, 28,string.format("%8d",VertVel))
--Acceleration: -12 per frame. -16 if not holding down after some point.
--I assume it's always -12, so you know the farthest you can go.
  if Height > 0 then
    v= math.ceil((VertVel + math.sqrt(VertVel*VertVel + 4*6*Height))/12)
  else v= 0
  end
  gui.pixelText(224, 14,string.format("%4d",v))

  gui.pixelText(224,  0,string.format("%4X",R2u(a+0x8A,"EWRAM")))  --Pow
  gui.pixelText(224,  7,string.format("%4d",R1u(a+0xA2,"EWRAM")))  --Lap seg

  gui.pixelText(224,153,string.format("%4d",R2u(a+0x8C,"EWRAM")))  --Boost timer
  gui.pixelText(224,145,string.format("%4d",R1u(a+0xA1,"EWRAM")))  --Trigger timer
end

local ImportantMachineBackClr= {[21]=0x400000FF,[22]=0x400000FF,[23]=0x60FFFFFF}
--*****************************************************************************
local function BasicHUD()
--*****************************************************************************
--Generally for basic calculations and all that.
--Also a scratch field for various tests.

  for i= 0, 4 do
    local addr= 0x12D60 + 0xCC*i
    local v= R1s(addr+0xB6,"EWRAM")
    local machine= R1s(addr+0xB0,"EWRAM")
    local clr= RadarColors[i]
    if v == -1 then clr= 0xFFA0A0A0 end
    local bclr= ImportantMachineBackClr[machine]
--    gui.pixelText(231,160+7*i,string.format("%2d",v),clr)
    gui.pixelText(227,160+7*i,string.format("%3d",R1u(addr+0xA2,"EWRAM")),clr,bclr)
  end

--[[
  for x= 0, 4 do
    for y= 0, 22 do
      local addr= 0x12D60 + 0xCC*x + 4*y + 0x80
      gui.pixelText(36*x,7*y,string.format("%08X",R4u(addr,"EWRAM")),RadarColors[x])
    end
  end
]]--

--  for i= 0, 4 do
--    local addr= 0x12D60 + 0xCC*x + 4*y + 0x80
--  end

end

--#############################################################################
--Management

--*****************************************************************************
local function StaticHUD(sT)
--*****************************************************************************
-- Oriented so north is toward the top. Fun stuff.

  GridUnderlayS(sT)
  MomentumCompass(sT)
  PlayerGhostStatic(sT)
  RivalRadarNorth(sT)
  PlayerTrailS(sT)

end

--*****************************************************************************
local function RotatingHUD(rT)
--*****************************************************************************
-- Oriented so player facing is toward the top.

--  GridUnderlayR(rT)
  MomentumAngle(rT)
  PlayerGhostRotate(rT)
  RivalRadarFacing(rT)
  PlayerTrailR(rT)

end


--Immediate
local StatsTbl= {}


--*****************************************************************************
while true do
--*****************************************************************************
--Our overhead.

  InternalFrame= R4u(0x15998,"EWRAM")

  local keyboard= input.get()
  if keyboard[key_ToggleGhostRecord] then flag_RecordGhost= not flag_RecordGhost end
  local Player= R1u(0x2B63,"IWRAM")
  if Player < 5 then
    FillTable(       StatsTbl,StaticX,StaticY,StaticR,StaticS,Player)
    StaticHUD(StatsTbl)
    PartialFillTable(StatsTbl,RotateX,RotateY,RotateR,RotateS)
    RotatingHUD(StatsTbl)
    MachineHUD(Player)
  end
  if flag_RecordGhost then 
    RecordGhost(Player,InternalFrame)
    gui.pixelText(120,160,"REC",0xFFFF2000)
  end
  AlertChanges(InternalFrame)
  BasicHUD()

  emu.frameadvance()
end

--#############################################################################
--eof. Well, extra data on hand below.

--[[
IWRAM:106C,4u - Timer (?)
IWRAM:2B62,1u - Player machine ID
IWRAM:2B63,1u - Player machine memory internal position

EWRAM:0A100,1x[Count=0x4000?] Input log history (4.5 minutes)

EWRAM:0E560,2x[x=64][y=64] An array of track block index
EWRAM:10560,?

12D60 12E2C 12EF8 12FC4 13090
EWRAM:12D60[Size=0xCC][Count=5] Machine data
  +00,4s - X position (main)
  +04,4s - Y position (main)
  +08,4s - X position (1 frame  ago)
  +0C,4s - Y position (1 frame  ago)
  +10,4s - X position (1 frame  ago)
  +14,4s - Y position (1 frame  ago)
  +18,4s - X position (2 frames ago)
  +1C,4s - Y position (2 frames ago)
  +20,4s - X position (3 frames ago)
  +24,4s - Y position (3 frames ago)
  +28,4s - X position (4 frames ago)
  +2C,4s - Y position (4 frames ago)
  +54,4s - Elevation
  +74,2s - Speed
  +78,2x - Facing
  +7A,2x - Momentum
  +84,2s - Vertical velocity
  +8A,2u - Power
  +8C,2u - Boost timer
  +8E,2u - Boost timer (mirror)
  +94,4x - Apparent health (for that visual health meter?)
  +9F,1u - ? Internal reference ID?
  +A1,1u - Timer for holding down boost
  +A2,1u - Lap segment
  +B0,1x - Machine identifer (what it is; 23 is a mine)
  +B6,1s - ID?
EWRAM:131CF,1u - ? Player machine selection related?
EWRAM:15998,4u - Frame count
EWRAM:1599C,4u - Frame count
]]--