--Script based on FatRatKnight's ExternalRadar script.
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 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 Stage, Segment, SegX, SegY, CamX, CamY
--*****************************************************************************
local function UpdateStats()
--*****************************************************************************
Stage= R4u(0x152C) --Which stage we're playing
Segment= R4s(0x1530) --What part in that stage
SegX,SegY= R4s(0x153C),R4s(0x1540) --Size of that part
CamX,CamY= R4s(0x14F0),R4s(0x14F4) --Camera location
end
--*****************************************************************************
local function SafishRect(x,y,w,h,bc,fc)
--*****************************************************************************
if x < 0 then return end
if y < 0 then return end
if x+w > 479 then return end
if y+h > 319 then return end
gui.drawRectangle(x,y,w,h,bc,fc)
end
local OffsetX,OffsetY= 120,80
--*****************************************************************************
local function DrawSpawns()
--*****************************************************************************
--[[Spawn list offsets:
+00,2 - X position
+02,2 - Y position
+04,2 - Does it exist (?)
+06,2 - Enemy to spawn (?)
+08,2 -
+0A,2 -
+0C,4 - ? What, there's some apparently random numbers here...
+10,2 -
]]--
if Stage > 16 then return end --Just in case
-- CanvasSpawnBorders()
local ptr= R4u(0x3CCF68+4*Stage,"ROM") --Getting stage pointer
ptr= R4u(FetchAddrDomainGBA(ptr+4*Segment)) --Getting Segment pointer of stage
local Xpos= R2s(FetchAddrDomainGBA(ptr))
local SpIndex= 0
while Xpos ~= -1 do --For whatever reason, this offset is double-burdened as a magic end marker
if R2s(FetchAddrDomainGBA(ptr+4)) ~= 0 then --Apparently it's 1 if it exists
local Ypos= R2s(FetchAddrDomainGBA(ptr+2))
local clr= 0xFFFFFFFF --White
if R1u(0x7C24+SpIndex,"IWRAM") ~= 0 then clr= 0xFFC08080 end --Reddish
Xpos= Xpos - CamX + OffsetX
Ypos= Ypos - CamY + OffsetY
SafishRect(Xpos-3,Ypos-3,2,2,clr)
SafishRect(Xpos-3,Ypos+1,2,2,clr)
SafishRect(Xpos+1,Ypos-3,2,2,clr)
SafishRect(Xpos+1,Ypos+1,2,2,clr)
end
SpIndex= SpIndex+1; if SpIndex >= 32 then return end --Something's wrong. Don't crash script.
ptr= ptr+18
Xpos= R2s(FetchAddrDomainGBA(ptr))
end
end
--*****************************************************************************
local function DrawSpawnBorders()
--*****************************************************************************
gui.drawBox(80, 40, 420, 280, 0x80FFFFFF)
gui.drawBox(88, 48, 368, 248, 0x80FFFFFF)
gui.drawRectangle(81, 79, 6, 1, 0x80FFFFFF)
gui.drawRectangle(81, 240, 6, 1, 0x80FFFFFF)
gui.drawRectangle(119, 249, 1, 30, 0x80FFFFFF)
gui.drawRectangle(360, 249, 1, 30, 0x80FFFFFF)
gui.drawRectangle(369, 240, 50, 1, 0x80FFFFFF)
gui.drawRectangle(369, 79, 50, 1, 0x80FFFFFF)
gui.drawRectangle(360, 41, 1, 6, 0x80FFFFFF)
gui.drawRectangle(119, 41, 1, 6, 0x80FFFFFF)
end
--*****************************************************************************
local function DrawPlayer()
--*****************************************************************************
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")
local Up= R4u(BoxAddr+ 0,"ROM")
local Down= R4u(BoxAddr+ 4,"ROM")
SafishRect(pX+Left+OffsetX,pY+Up+OffsetY,Right,Down,0xFFFFFFFF,0x8000FFFF)
end
--*****************************************************************************
local function DrawBullet()
--*****************************************************************************
local bID= R4u(0x15E4,"IWRAM")
for i= 11, 29 do --Player projectiles zone
local addr= 0x1DE4 + 0x74*i
local bSpr= R2s(addr+0x08,"IWRAM") --Sprite
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))
local Up= R4u(FetchAddrDomainGBA(HitBoxData+ 0))
local Down= R4u(FetchAddrDomainGBA(HitBoxData+ 4))
SafishRect(bX+Left+OffsetX,bY+Up+OffsetY,Right,Down,0xFF00FFFF,0x8000FF00)
end
end
end
local eFill= {
0x60FF0000,0x60FF4000,0x60FF8000,0x60FFC000,0x60FFFF00
}
--*****************************************************************************
local function MakeEnemyColor(addr)
--*****************************************************************************
--Colored based on HP.
local HP= R2s(addr+0x2C,"IWRAM")
local border= 0xFFFFFF00
local fill= eFill[HP]
if HP <= 0 then border= 0xFFFF00FF; fill= 0x60FF00FF end
return border,fill or 0x6080FF00
end
--*****************************************************************************
local function DrawEnemy()
--*****************************************************************************
if Stage > 16 then return end
local StagePtr= R4u(0x3CD5C4 + 4*Stage,"ROM")
EnemyHP= 0
EnemYInv= 0
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))
EnemyHP= R2s(addr+0x2C)
EnemYInv= R2s(addr+0x58)
if EnemyHP ~= 0 then
gui.pixelText(eX+OffsetX,eY+OffsetY ,EnemyHP)
if EnemYInv ~= 0 then
gui.pixelText(eX+OffsetX,eY+OffsetY+7,EnemYInv)
end
end
end
local HitBoxData= EnemyPtr + 0x10*eSpr
local Left= R4u(FetchAddrDomainGBA(HitBoxData+ 8))
local Right= R4u(FetchAddrDomainGBA(HitBoxData+12))
local Up= R4u(FetchAddrDomainGBA(HitBoxData+ 0))
local Down= R4u(FetchAddrDomainGBA(HitBoxData+ 4))
if (Right ~= 0) and (Down ~= 0) then
local bClr,fClr= MakeEnemyColor(addr)
if IsItem then bClr,fClr= 0xFF00FF00, 0x600000FF end
SafishRect(eX+Left+OffsetX,eY+Up+OffsetY,Right,Down,bClr,fClr)
else
SafishRect(eX+OffsetX,eY+OffsetY,3,3,0xFFFF8000)
end
end
end
end
--*****************************************************************************
local function DrawObjects()
--*****************************************************************************
DrawPlayer()
DrawBullet()
DrawEnemy()
end
client.SetGameExtraPadding(120, 80, 120, 80)
--*****************************************************************************
while true do
--*****************************************************************************
UpdateStats()
DrawSpawnBorders()
DrawSpawns()
DrawObjects()
emu.frameadvance()
end