local RAMwatch= {
{a1=0x0042,a2=0x0043,c=0xFFFFFFFF}, --Screen loader, right side
{a1=0x0046,a2=0x0047,c=0xFFFFFF00}, --Screen loader, left side
{a1=0x0051,a2=nil ,c=0xFFFFFFFF}, --Stage
{a1=0x04ED,a2=nil ,c=0xFFFF00FF}, --Scr
{a1=0x04EE,a2=nil ,c=0xFF00FFFF}, --Scr
{a1=0x00DA,a2=nil ,c=0xFF00FF00}, --Game State
{a1=0x008B,a2=nil ,c=0xFFFFFFFF}, --RNG
}
local SpeedCheck= {
{frame= 413, pos= 88, TgtSp= 4.5}, -- 1 Home Town
{frame= 1948, pos= 36, TgtSp= 4.5}, -- 2 Lake Side
{frame= 4264, pos= 36, TgtSp= 4.5}, -- 3 Forest
{frame= 6957, pos= 96, TgtSp= 1.0}, -- 4 Sky
{frame=10768, pos= 52, TgtSp= 16/7}, -- 5 Oasis
{frame=13759, pos= 52, TgtSp= 16/7}, -- 6 Cave
{frame=16332, pos= 68, TgtSp= 4.5}, -- 7 Pond
{frame=19859, pos= 36, TgtSp= 4.5}, -- 8 Harbor
{frame=21467, pos= 80, TgtSp= 2.0}, -- 9 Ocean
{frame=26125, pos= 52, TgtSp= 4.5}, --10 Ghost Town
{frame=28359, pos= 36, TgtSp= 16/7}, --11 Dark Forest
{frame=31111, pos= 52, TgtSp= 4.5}, --12 Castle
}
local r1u_ , r1s_= memory.read_u8 , memory.read_s8
local r1u= function(a) return r1u_(a,"System Bus") end
local R1U= function(a) return r1u_(a,"PRG ROM") end
local r1s= function(a) return r1s_(a,"System Bus") end
local r2u= function(a,b) return r1u(a) + r1u(b or a+1)*256 end
local r2s= function(a,b) return r1u(a) + r1s(b or a+1)*256 end
local Tx= gui.pixelText
local function Hex(v,l)
if l then return string.format("%0" .. tostring(l) .. "X", v) end
return (string.format("%X",v))
end
--*****************************************************************************
local function DecimalStr2(v)
--*****************************************************************************
--Converts to nice-looking decimal numbers.
--The appearance is inherently imprecise, as /100 doesn't align like /256.
--Still, you are a mere human, so you get this treatment.
local Negation= ""
if v < 0 then Negation= "-"; v= -v end
v= math.floor(v*100/256)
local s= string.format("%02d",v%100)
v= math.floor(v/100)
return string.format("%s%d.%s",Negation,v,s)
end
--*****************************************************************************
local function DecimalStr(v)
--*****************************************************************************
--Converts to nice-looking decimal numbers. Yay, copy/paste!
--The appearance is inherently imprecise, as /100 doesn't align like /256.
--Still, you are a mere human, so you get this treatment.
local Negation= ""
if v < 0 then Negation= "-"; v= -v end
v= math.floor(v*1000/256)
local s= string.format("%03d",v%1000)
v= math.floor(v/1000)
return string.format("%s%d.%s",Negation,v,s)
end
--*****************************************************************************
local function DisplayRAM()
--*****************************************************************************
local Y= 32
for i= 1, #RAMwatch do
local RAM= RAMwatch[i]
if RAM.a2 then
Tx(235,Y,string.format("%5d",r2u(RAM.a1,RAM.a2)),RAM.c)
else
Tx(243,Y,string.format("%3d",r1u(RAM.a1)) ,RAM.c)
end
Y= Y+7
end
end
local OldChanges= nil
--*****************************************************************************
local function ChangesHappened(...)
--*****************************************************************************
--Single instance function. Do not call in multiple places.
--Checks if things are different since the last frame.
if not OldChanges then
OldChanges= {...}
return true --Pretend things are fine
end
local Changes --Get recent into old, and hold the old just a little longer
Changes, OldChanges= OldChanges, {...}
for i= 1, #OldChanges do
if Changes[i] ~= OldChanges[i] then return true end
end
return false --No changes? Well, snap
end
--*****************************************************************************
local function CR_ChangesHappened(...)
--*****************************************************************************
--Doing something ridiculously complicated with coroutines.
--This is just so we can have arbitrary copies of this function.
--I'm not ready with this particular function. Need to study coroutines a bit.
local OldChanges= {...}
local c= true
while true do
local Changes
Changes, OldChanges= OldChanges, {coroutine.yield(c)}
c= false
for i= 1, #Changes do
c= (Changes[i] ~= OldChanges[i]) or c
end
end
end
--*****************************************************************************
local function AverageSpeed()
--*****************************************************************************
local Stage= r1u(0x0051)
local Check= SpeedCheck[Stage]
if not Check then return end
local Frames= (emu.framecount() - Check.frame)
if Frames <= 0 then return end
local TgtSp= Check.TgtSp
local PlX= r2u(0x0092,0x0091)
local CamX= r2s(0x00CC)
local Distance= PlX + CamX*256 - Check.pos*256
PlX= Distance - Frames*(TgtSp*0x100)
local clr= 0xFF00FF80
if PlX < 0 then PlX= -PlX; clr= 0xFFFF8000 end
Tx( 1, 40,string.format("%8s",DecimalStr(PlX)),clr)
PlX= math.floor(Distance/Frames)
Tx( 1, 33,string.format("%8s",DecimalStr(PlX)),0xFF00FF00)
end
-------------------------------------------------------------------------------
--*****************************************************************************
local function PaintHitbox(ID,CamX)
--*****************************************************************************
if r1u(0x04F3+ID) == 2 then
local ScrX= r2u(0x054B+ID,0x0543+ID)-CamX
local ScrY= r2u(0x0563+ID,0x055B+ID)
local W= r1u(0x0573+ID)
local H= r1u(0x057B+ID)
gui.drawBox(ScrX-W,ScrY-H,ScrX+W,ScrY+H,0xC0FFFF40,0x40000000)
end
end
--*****************************************************************************
local function ExistCheck(ID,CamX)
--*****************************************************************************
local clr= 0
if r1u(0x04F3+ID) ~= 0 then clr= 0xFFFFFF00 end
gui.drawRectangle(180+7*ID,32,5,5,0xFFFFFFFF,clr)
end
--*****************************************************************************
local function ObjScan()
--*****************************************************************************
--Should get every object out there.
--I think I got the hitboxes. At least, this looks sensible.
local CamX= r2u(0x00CC)
for i= 0, 7 do
PaintHitbox(i,CamX)
ExistCheck(i,CamX)
end
end
-------------------------------------------------------------------------------
--local PosChanged= coroutine.create(CR_ChangesHappened,0,0,0)
--*****************************************************************************
local function PlayerData()
--*****************************************************************************
--Position
local PlX, PlY= r2u(0x0092,0x0091), r2u(0x0094,0x0093)
local CamX= r2s(0x00CC)
local c= ChangesHappened(PlX,PlY,CamX)
local clr= 0xFFFFFFFF
if not c then clr= 0xFFFF4000 end
Tx(100, 8,string.format("CAMERA: %4s", CamX),clr)
Tx(100, 16,string.format("X%8s",DecimalStr(PlX + CamX*256)),clr)
Tx(100, 24,string.format("Y%8s",DecimalStr(PlY)),clr)
Tx( 80, 24,string.format("%3d",r1u(0x0095)),clr)
PlX,PlY= math.floor(PlX/256),math.floor(PlY/256)
gui.drawLine(PlX ,PlY ,PlX ,PlY+16,0xFF00FF00)
gui.drawLine(PlX+12,PlY ,PlX+12,PlY+16,0xFFFF8000)
gui.drawLine(PlX-12,PlY ,PlX-12,PlY+16,0xFFFF8000)
gui.drawBox( PlX- 6,PlY-14,PlX+ 6,PlY+14,0xC0FFFFFF,0x2000FF00)
--Speed
local BaseSpeed= r2s(0x0099,0x0098)
local Boost= r2s(0x00AA,0x00A9)
Tx(206, 8,string.format("Base: %6s",DecimalStr(BaseSpeed)),0xFFFFFF00)
Tx(206,14,string.format("Boost:%6s",DecimalStr(Boost)) ,0xFF00FFFF)
Tx(206,20,string.format("Total:%6s",DecimalStr(BaseSpeed+Boost)))
local SpeedY= r2s(0x009D,0x009C)
local JumpMode= r1u(0x00AB)
local JumpTime= r1u(0x00AC)
local clr= 0xFFC0C0C0 -- Light grey, nothing spectacular
if (JumpMode == 1) then
clr= 0xFF00FFFF
Tx(172,16,string.format("%2d",math.max(14-JumpTime,0)),0xFF00FF00)
end
if (JumpMode == 2) or (JumpTime >= 14) then clr= 0xFFFF8000 end
Tx(160, 8,string.format("%6s",DecimalStr(SpeedY)),clr)
--Apple check
if r1u(0x04F9) ~= 0 then
Tx(193,16,string.format("%3d",r1u(0x04D7)),0xFFFFFF00)
end
if r1u(0x04FA) ~= 0 then
Tx(193,24,string.format("%3d",r1u(0x04D8)),0xFFFFFF00)
end
if bit.band(r1u(0x00D4), 64) ~= 0 then
gui.drawEllipse(183,18,8,9,0xFFFF0000,0xFFFF0000)
gui.pixelText(185,19,"B",0xFFFFFFFF,0x00000000)
end
--Spawn check
PlX= r1u(0x0092)
local Spawnny= (CamX%128)*256 + PlX%256
local clr= 0xFFFFFFFF
if Spawnny < (4*256) then clr= 0xFFFF8000 end
Tx( 84,32,string.format("Spawn:%7s",DecimalStr(Spawnny)),clr)
--Other crud
if r1u(0x00D7) == 0 then gui.pixelText(193,8,"GO!") end
end
-------------------------------------------------------------------------------
--local OldRNG= r1u(0x008B)
--*****************************************************************************
local function BasicHUD()
--*****************************************************************************
--local RNG= r1u(0x008B)
--Tx(50,40,string.format("%3d",(RNG-OldRNG)%256))
--OldRNG= RNG
ObjScan()
PlayerData()
AverageSpeed()
DisplayRAM()
end
while true do
BasicHUD()
emu.frameadvance()
end
--[[
0091,2u - X position relative to screen, big endian
0098,2s - X Speed (Main), big endian
009A,2s - X Speed (?), big endian
00A9,2s - X Boost, big endian
009C,2s - Y speed, big endian
00AB,1x - Jump mode. 0=didn't jump, 1=Upward rise, 2=Falling part
00AC,1u - Jump timer. If it's 14 or more, A will not work.
00D7,1x - Control lock
0240-030F - Terrain (region 1)
0330-03FF - Terrain (region 2)
04D5,1u[2] - Apple timer 0-80
04D7,1x[2] - Apple
04D9,1x[2] - Apple
04F9,1x - Apple
Objects (8 addresses per)
04F3 - 0x02:Exist 0x01:Off-screen
0543 - (*256) Super X pos
054B - ( 1) X pos
0553 - (/256) Sub-X pos
055B - (*256) Super Y pos
0563 - ( 1) Y pos
056B - (/256) Sub-Y pos
0573 - Hitbox X
057B - Hitbox Y
0583 - X speed
058B - X sub-speed
0593 - Y speed
059B - Y sub-speed
local Y= 12 + 7*i
Tx( 90,Y,Hex(r1u(0x04F3+i),2),0xFFFFFFFF)
Tx(100,Y,Hex(r1u(0x0543+i),2),0xFFFFFFFF) --X
Tx(109,Y,Hex(r1u(0x054B+i),2),0xFFFFFFFF)
Tx(118,Y,Hex(r1u(0x0553+i),2),0xFFC0C0C0)
Tx(130,Y,Hex(r1u(0x055B+i),2),0xFFFFFFFF) --Y
Tx(139,Y,Hex(r1u(0x0563+i),2),0xFFFFFFFF)
Tx(148,Y,Hex(r1u(0x056B+i),2),0xFFC0C0C0)
Tx(160,Y,Hex(r1u(0x0573+i),2),0xFFFFFFFF)
Tx(169,Y,Hex(r1u(0x057B+i),2),0xFFFFFFFF)
Tx(178,Y,Hex(r1u(0x0583+i),2),0xFFFFFFFF)
Tx(187,Y,Hex(r1u(0x058B+i),2),0xFFFFFFFF)
Tx(196,Y,Hex(r1u(0x0593+i),2),0xFFFFFFFF)
Tx(205,Y,Hex(r1u(0x059B+i),2),0xFFFFFFFF)
Tx(214,Y,Hex(r1u(0x05A3+i),2),0xFFFFFFFF)
Tx(223,Y,Hex(r1u(0x05AB+i),2),0xFFFFFFFF)
]]