User File #41798024491519300

Upload All User Files

#41798024491519300 - Zook Man ZX4 - External Enemy Radar

ZM_ExternalEnemyRadar.lua
818 downloads
Uploaded 9/17/2017 8:50 AM by ThunderAxe31 (see all 111)
Based on FatRatKnight's ExternalRadar script.
It's a light script that enlarges screen in order to show, outside of game screen:
  • spawning borders
  • enemy spawns
  • hitboxes
  • enemy HP and invincibility time
Useful for fighting enemies when they are still outside of screen, and thus also managing Minibosses and Bosses skips.
--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