User File #38748741023956734

Upload All User Files

#38748741023956734 - Zook Man ZX4 - Updated External Radar with spawn points.

ZM_ExternalRadar_v2.lua
753 downloads
Uploaded 5/3/2017 1:01 AM by FatRatKnight (see all 245)
Shh... Secrets. Which has no business being secret anyway. Making public any changes once I make them is hardly secret.
Some comments removal (code holdover from the hitboxes script), fixing the enemy coloring (variable name mismatch), and identifying the spawn locations. It will also recolor the spawn spot if it's in use.
The spawns was something I was looking for during the contest, but I didn't find it myself. I suppose I should thank Dacicus (or however the username is typed).
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 ROMmin,ROMmax= 0x08000000, 0x08000000+memory.getmemorydomainsize("ROM")

local cnv= gui.createcanvas(480,320)

--for k,v in pairs(cnv) do print(k,type(v)) end

--*****************************************************************************
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 Maps= {}

--*****************************************************************************
local function LoadMaps()
--*****************************************************************************
--This function tracks down every stage, every segment in each stage, every
--block in each segment, and every tile in each block. Then it stitches
--together the tiles as it would fit in the block.

  for Stage= 0, 16 do
    local StageMaps= {} --Construct new table

    local BlockSetPtr= R4u(0x3CD86C + 4*Stage,"ROM")
    local SegmentBase= R4u(0x3CD8B0 + 4*Stage,"ROM")
    local Segment= 0
    while true do
      local SegmentPtr= R4u(FetchAddrDomainGBA(SegmentBase + Segment*4))
      if (SegmentPtr < ROMmin) or (SegmentPtr >= ROMmax) then break end

      local SegX, SegY= R2s(FetchAddrDomainGBA(SegmentPtr)), R2s(FetchAddrDomainGBA(SegmentPtr+2))
      SegmentPtr= SegmentPtr+4

      local SegmentMap= {}
      for y= 0, SegY-1 do
        for x= 0, SegX-1 do
          local BlockIndex= R2u(FetchAddrDomainGBA(SegmentPtr + (y*SegX + x)*2))
          local BlockPtr= R4u(FetchAddrDomainGBA(BlockSetPtr + 4*BlockIndex))
          for yy= 0, 31 do
            for xx= 0, 31 do
              local i= xx + x*32 + yy*SegX*32 + y*SegX*1024
              SegmentMap[i]= R1u(FetchAddrDomainGBA(BlockPtr + 2 + xx + 32*yy))
            end
          end
        end
      end

      StageMaps[Segment]= SegmentMap
      Segment= Segment+1
    end

    Maps[Stage]= StageMaps --Stash what we've got!
    print("Loaded Stage " .. Stage)
  end
end
LoadMaps()

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
  cnv.DrawRectangle(x,y,w,h,bc,fc)
end

local TileClrs= {
[0]=0xFF000080,0xFF808080,0xFF801000,0xFF000000, --Air,Floor,Spike,Solid
    0xFF000000,0xFF008080,0xFF808040,0xFF808040, --nil,Wj,Sslope /
    0xFF808040,0xFF808040,0xFF808000,0xFF808000, --Sslope \,magnet
    0xFF808040,0xFF808040,0xFF808040,0xFF808040, --Gslope /
    0xFF808040,0xFF808040,0xFF808040,0xFF808040, --Gslope \
    0xFF006030,0xFF008000,0xFF006030,0xFF800080, --Ladder, sPlatform
    0xFF800080,0xFF800080,0xFF800080,0xFF800080, --sPlatform, Capsule
    0xFF800080,0xFF000000,0xFF000000,0xFF408080, --Capsule,nil,nil,AS end

  [0x60]=0xFF800080, [0x61]=0xFF800080, [0x62]=0xFF800080, [0x63]=0xFF800080,
  [0x64]=0xFF800080, [0x65]=0xFF800080, [0x66]=0xFF800080, [0x67]=0xFF800080,
  [0x68]=0xFF800080, [0x69]=0xFF800080, [0x6A]=0xFF800080, [0x6B]=0xFF800080,
  [0x6C]=0xFF800080, [0x6D]=0xFF800080, [0x6E]=0xFF800080, [0x6F]=0xFF800080,
  [0x70]=0xFF800080, [0x71]=0xFF800080, [0x72]=0xFF800080, [0x73]=0xFF800080,
  [0x74]=0xFF800080, [0x75]=0xFF800080, [0x76]=0xFF800080
}

local OffsetX,OffsetY= 120,80
--*****************************************************************************
local function CanvasTerrain()
--*****************************************************************************
  if Stage > 16 then return end
  local Area= Maps[Stage][Segment]; if not Area then return end

  local Left= math.max(
    math.floor((CamX-OffsetX)/8),     --Left edge
    0                                 --Segment left
  )
  local Top=  math.max(
    math.floor((CamY-OffsetY)/8),     --Top edge
    0                                 --Segment top
  )
  local Right= math.min(
    math.floor((CamX-OffsetX+480)/8), --Right edge
    SegX*32 - 1                       --Segment right
  )
  local Bottom= math.min(
    math.floor((CamY-OffsetY+320)/8), --Bottom edge
    SegY*32 - 1                       --Segment bottom
  )

  for Y= Top, Bottom do
    local DispY= Y*8 + OffsetY - CamY
    for X= Left, Right do
      local DispX= X*8 + OffsetX - CamX
      local tile= Area[X + Y*SegX*32]
      cnv.DrawRectangle(
        DispX,DispY,7,7,TileClrs[tile],TileClrs[tile]
      )
    end
  end
end

--*****************************************************************************
local function CanvasBorder()
--*****************************************************************************
  cnv.DrawRectangle(OffsetX,OffsetY,239,159,0x40FFFFFF)
end

--*****************************************************************************
local function CanvasSpawns()
--*****************************************************************************
--[[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
  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 CanvasPlayer()
--*****************************************************************************
  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 CanvasBullet()
--*****************************************************************************
  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 CanvasEnemy()
--*****************************************************************************
  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))
      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 CanvasObjects()
--*****************************************************************************
  CanvasPlayer()
  CanvasBullet()
  CanvasEnemy()
end

--*****************************************************************************
local function HandleCanvas()
--*****************************************************************************
  cnv.Clear(0xFF404040)
  UpdateStats()
  CanvasTerrain()
  CanvasBorder()
  CanvasSpawns()
  CanvasObjects()
  cnv.Refresh()
end

--*****************************************************************************
while true do
--*****************************************************************************
--Our overhead.
  HandleCanvas()
--  Fn()
--  DrawRescaledBorder()
--  EnemyHitboxes()
--  BulletHitboxes()
--  PlayerHitbox()

  emu.frameadvance()
end