memory.usememorydomain("IWRAM")
local R4u= memory.read_u32_le
local R4s= memory.read_s32_le
local R2u= memory.read_u16_le
local R2s= memory.read_s16_le
local R1s= memory.read_s8
local R4x= function(a) return string.format("%X",R4u(a)) end
local R2x= function(a) return string.format("%X",R2u(a)) end
--*****************************************************************************
local function PixelTextRight(x,y,t,c1,c2,f)
--*****************************************************************************
--Specify right pixel instead of left pixel to position our text.
--Should be handy in keeping our numbers relatively readable.
x= x - 4*(#tostring(t))
gui.pixelText(x,y,t,c1,c2,f)
end
--*****************************************************************************
local function FetchAddrDomainGBA(a,method)
--*****************************************************************************
--I am furious at the design away from the bus. It used to exist! Why remove?
--I do not want to code in removing offsets to pointers every time I read one.
--This function was made because I insist on full pointers. Has only what I know.
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("Unknown address " .. a,2)
end
end
--*****************************************************************************
local function FetchPosition()
--*****************************************************************************
local X= R4s(0x14F0) + R4s(0x1E58) --Cam and screen position, respectively
local Y= R4s(0x14F4) + R4s(0x1E5C) --Yeppers.
return X,Y
end
--*****************************************************************************
local function RecordMovement(T,v)
--*****************************************************************************
local diff= v - T.Last
diff= (diff+128)%256 - 128 --Arbitrarily trim within one signed byte
T[diff]= (T[diff] or 0) + 1
T.Last= v --Our new recorded position.
end
--*****************************************************************************
local function ResetMovements(T)
--*****************************************************************************
--Has a side-effect of nuking my last position, too.
for k,v in pairs(T) do
if type(v) == "number" then T[k]= nil end
end
end
--*****************************************************************************
local function ReadMovements(T)
--*****************************************************************************
local s= ""
for k,v in pairs(T) do
if (type(v) == "number") and (type(k) == "number") then
s= string.format("%s| %d:%d ",s,k,v)
end
end
return s .. "|"
end
--Might want a constructor function...
local MovedX= {Rec=RecordMovement, Reset=ResetMovements, Read=ReadMovements}
local MovedY= {Rec=RecordMovement, Reset=ResetMovements, Read=ReadMovements}
local StateMachine, AwaitIntro, BeginStage, StageWatch
local fc_StageBegin, fc_SegmentBegin= 0,0
local v_CurrentSegment= 0
--*****************************************************************************
AwaitIntro= function()
--*****************************************************************************
--Just waits for that beam-in state.
if R4s(0x15F0) ~= 1 then return end --Insist on the beam-in lock
StateMachine= BeginStage
--... And do nothing else
end
--*****************************************************************************
BeginStage= function()
--*****************************************************************************
if R4s(0x15F0) == 1 then return end --Insist the beam-in goes away
StateMachine= StageWatch
MovedX:Reset()
MovedY:Reset()
MovedX.Last,MovedY.Last= FetchPosition()
local cf= emu.framecount()
fc_StageBegin, fc_SegmentBegin= cf, cf
v_CurrentSegment= R4s(0x1530)
print(string.format("f%05d *** STAGE %d ***",
cf,
R4s(0x152C)
))
end
--*****************************************************************************
local function HandleBeamOut()
--*****************************************************************************
StateMachine= AwaitIntro
local cf= emu.framecount()
print(string.format("f%05d Segment%2d:%4d",
cf, --Current frame
v_CurrentSegment, --What segment we're on
cf - fc_SegmentBegin --Diff of current frame and when segment began
))
--I'm not going to spill our movement information here.
--All such cases where we beam out is in a stationary room anyway.
print(string.format("=== END OF STAGE %d (Frames: %d) ===",
R4s(0x152C),
cf - fc_StageBegin
))
end
--*****************************************************************************
local function HandleNewSeg()
--*****************************************************************************
local cf= emu.framecount()
print(string.format("f%05d Segment%2d:%4d",
cf, --Current frame
v_CurrentSegment, --What segment we're on
cf - fc_SegmentBegin --Diff of current frame and when segment began
))
--[[
print(string.format("(X)>%s###(Y)>%s",
MovedX:Read(),MovedY:Read()
))
]]--
v_CurrentSegment= R4s(0x1530)
fc_SegmentBegin= cf
MovedX:Reset()
MovedY:Reset()
MovedX.Last,MovedY.Last= FetchPosition()
end
--*****************************************************************************
local function HandleFrame()
--*****************************************************************************
local x,y= FetchPosition()
MovedX:Rec(x)
MovedY:Rec(y)
end
--*****************************************************************************
StageWatch= function()
--*****************************************************************************
HandleFrame()
if R4s(0x15F0) == 11 then HandleBeamOut() --Check beam-out
elseif R4s(0x1530) ~= v_CurrentSegment then HandleNewSeg() --Check segment
end
end
StateMachine= AwaitIntro
--*****************************************************************************
while true do
--*****************************************************************************
--Our overhead.
StateMachine()
emu.frameadvance()
end