User File #38508487412195834

Upload All User Files

#38508487412195834 - Zook Man ZX4 - Hitboxes reveal script

ZM_HitBox.lua
848 downloads
Uploaded 4/22/2017 5:21 AM by FatRatKnight (see all 245)
Shh... Secrets. Script #2, intended to be run second.
This script is the one with the hitboxes. All of them, player, projectile, enemies, and items. They are color coded, too. Enemies are colored based on HP, with zero or negative given a vastly different color. Player projectile is colored based on whether it does damage, rather important for the Muzzle Flash I'm sure you're all frustrated with by now. This is what the game was doing to detect all those hits. Also nice to know what's happening with the basic projectile when changing weapons.
Oh, and this script has rescaling, with M and N keys, so we can see off-screen enemies. Only problem is the other scripts aren't rescaling, so... Uh, enough embarrassment, and stand in awe of my ROM diving skills. Finding and then following pointers around can be fun.
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