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 R1u= memory.read_u8
local CrLf= string.char(0x0D,0x0A)
local ROMmin,ROMmax= 0x08000000, 0x08000000+memory.getmemorydomainsize("ROM")
--*****************************************************************************
local function FetchAddrDomainGBA(a)
--*****************************************************************************
--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(string.format("Unknown address %08X", a),2)
end
end
local ScaleDiv= 1
local OffsetX= 0
local OffsetY= 0
--*****************************************************************************
local function Rescale(v)
--*****************************************************************************
ScaleDiv= v
OffsetX= (240 - math.floor(240/v))/2
OffsetY= (160 - math.floor(160/v))/2
end
Rescale(ScaleDiv)
--*****************************************************************************
local function DrawRescaledBorder()
--*****************************************************************************
if ScaleDiv <= 1 then return end
gui.drawRectangle(
OffsetX,
OffsetY,
math.floor(240/ScaleDiv),
math.floor(160/ScaleDiv),
0x80C0C0C0 --Yay, border color
)
end
--*****************************************************************************
local function DrawScaledHitbox(x1,y1,x2,y2,fc,bc)
--*****************************************************************************
if x1 == x2 then return end
x1= x1/ScaleDiv+OffsetX
y1= y1/ScaleDiv+OffsetY
x2= x2/ScaleDiv+OffsetX
y2= y2/ScaleDiv+OffsetY
gui.drawBox(x1,y1,x2,y2,fc,bc)
end
local dbox= DrawScaledHitbox
--*****************************************************************************
local function PlayerHitbox()
--*****************************************************************************
local addr= 0x1DE4 + 0x74*1
local Spr= R2s(addr+0x08,"IWRAM")
local pX, pY= R4s(addr+0x00,"IWRAM"), R4s(addr+0x04,"IWRAM")
local BoxAddr= 0x087B64 + 0x10*Spr
local Left= R4u(BoxAddr+ 8,"ROM")
local Right= R4u(BoxAddr+12,"ROM")+Left
local Up= R4u(BoxAddr+ 0,"ROM")
local Down= R4u(BoxAddr+ 4,"ROM")+Up
dbox(pX+Left,pY+Up,pX+Right,pY+Down,0xFFFFFFFF,0x8000FFFF)
end
--*****************************************************************************
local function MakeBulletColor(addr)
--*****************************************************************************
--Colored based on damage.
if R2s(addr+0x48) == 0 then return 0xFF0000FF,0x60000000 end
return 0xFF00FFFF,0x6000FF00
end
--*****************************************************************************
local function BulletHitboxes()
--*****************************************************************************
--I'm hating these things.
for i= 11, 29 do --Player projectiles zone
local addr= 0x1DE4 + 0x74*i
local bSpr, bID= R2s(addr+0x08,"IWRAM"), R2u(0x15E4,"IWRAM") --Sprite, ID
if (bSpr ~= 0) and (bID < 9) then
local bX, bY= R4s(addr+0x00,"IWRAM"), R4s(addr+0x04,"IWRAM")
local HitBoxData
if bID == 0 then
HitBoxData= R4u(0x06EFDC + bSpr*4,"ROM")
--No error catch. Try not to run this with absurdly high Sprite ID.
else
local bPtr= R4u(0x07E36C + bID*4,"ROM")
HitBoxData= bPtr + 0x10*bSpr
end
local Left= R4u(FetchAddrDomainGBA(HitBoxData+ 8))
local Right= R4u(FetchAddrDomainGBA(HitBoxData+12))+Left
local Up= R4u(FetchAddrDomainGBA(HitBoxData+ 0))
local Down= R4u(FetchAddrDomainGBA(HitBoxData+ 4))+Up
local border,fill= MakeBulletColor(addr)
dbox(bX+Left,bY+Up,bX+Right,bY+Down,border,fill)
end
end
end
local eFill= {
0x60FF0000,0x60FF4000,0x60FF8000,0x60FFC000,0x60FFFF00
}
--*****************************************************************************
local function MakeEnemyColor(addr)
--*****************************************************************************
--Colored based on HP.
local HP= R2s(addr+0x2C)
local border= 0xFFFFFF00
local fill= eFill[HP]
if HP <= 0 then border= 0xFFFF00FF; fill= 0x60FF00FF end
return border,fill or 0x6080FF00
end
--*****************************************************************************
local function EnemyHitboxes()
--*****************************************************************************
--Found a grail. Not sure if it's holy.
local Stage= R4u(0x152C,"IWRAM"); if Stage > 16 then return end
local StagePtr= R4u(0x3CD5C4 + 4*Stage,"ROM")
for i= 30, 59 do --Enemies occupy these slots only
local addr= 0x1DE4 + 0x74*i
local eSpr, eID= R2s(addr+0x08,"IWRAM"), R2u(addr+0x0A,"IWRAM") --Sprite, ID
if (eSpr ~= 0) and (eID ~= 0) and (eID < 31) then
local eX, eY= R4s(addr+0x00,"IWRAM"), R4s(addr+0x04,"IWRAM")
local IsItem= (R2s(addr+0x3C,"IWRAM") == 2)
local EnemyPtr
if IsItem then
EnemyPtr= R4u(0x06885C + eID*4,"ROM")
else
EnemyPtr= R4u(FetchAddrDomainGBA(StagePtr+eID*4))
end
local HitBoxData= EnemyPtr + 0x10*eSpr
local Left= R4u(FetchAddrDomainGBA(HitBoxData+ 8))
local Right= R4u(FetchAddrDomainGBA(HitBoxData+12))+Left
local Up= R4u(FetchAddrDomainGBA(HitBoxData+ 0))
local Down= R4u(FetchAddrDomainGBA(HitBoxData+ 4))+Up
if Right ~= Left then
local border,fill= MakeEnemyColor(addr)
if IsItem then border,fill= 0xFF00FF00, 0x600000FF end
dbox(eX+Left,eY+Up,eX+Right,eY+Down,border,fill)
else
dbox(eX,eY,eX+3,eY+3,0xFFFF0000)
end
end
end
end
--*****************************************************************************
while true do
--*****************************************************************************
--Our overhead.
local Keys= input.get()
if Keys.M then Rescale(ScaleDiv+0.25) end
if Keys.N then Rescale(math.max(ScaleDiv-0.25,1)) end
DrawRescaledBorder()
EnemyHitboxes()
BulletHitboxes()
PlayerHitbox()
emu.frameadvance()
end