User File #40240881582843184

Upload All User Files

#40240881582843184 - Zook Man ZX4 - Casual display script

ZMZX4_CasualDisplay.lua
754 downloads
Uploaded 7/9/2017 5:48 AM by FatRatKnight (see all 245)
Well, now I'm done producing a status panel. Contents:
  • Barrier info, including HP and damage timer
  • Weapons, which ones I have and how much ammo. Negative display, too
  • Charge. Accounts for Arm Upgrade
  • Misc. info: Player state, damage invincibility, object invincibility, Heart Tanks, Ammo Tanks, and part upgrades
  • Map, boss, miniboss info, taking over the same spot depending on who's there
Well, I don't know how much realtime info I can put in there that makes sense to do so. I'm hoping the status panel is pretty, its intent is to feel like I'm giving useful information that can be understood, for the most part, without having to pause. The precision depicted is not useful for TASing, and it's not as though the information is all that vital, either. But hey, it's pretty. It's interesting. And it lets you know how much of each weapon I'm using.
--GBA Zook Man ZX4 - Casual Display script
--The display is intended to make sense for real-time viewing.
--For BizHawk
--FatRatKnight

local R4u,R4s= memory.read_u32_le,memory.read_s32_le
local R2u,R2s= memory.read_u16_le,memory.read_s16_le
local R1u,R1s= memory.read_u8    ,memory.read_s8

--Would stick function inside function. BizHawk seems to hate it.
local function BoxB(x,y,i,bc,fc) gui.drawRectangle(x-1+5*i,y+7,3,3,bc,fc) end
--*****************************************************************************
local function BarrierDisplay(x,y)
--*****************************************************************************
--37x16 - Displays barrier information in a pretty fashion.
--Squares for each HP. Changes color and shows a timer if barrier is hit.

  local BarrierHP = R4u(0x16B4,"IWRAM")
  local BarrierTmr= R4u(0x16B8,"IWRAM")

  if BarrierHP >  6 then return end --Panic
  if BarrierTmr> 48 then return end --Panic
  local clr= 0xFF808080
  if BarrierHP > 0 then
    clr= 0xFF00FFFF
    if BarrierTmr > 0 then
      BoxB(x,y,BarrierHP,0xFFFF8000,0xFFFFFF00)
      local X,Y= x+6,y+13
      gui.drawLine( X,Y,X+math.floor((BarrierTmr-1)/2),Y,0xFFFFFF00)
      gui.drawPixel(X,Y,0xFFFFFF00) --Because line doesn't draw coord1==coord2

      BarrierHP= BarrierHP-1
    end
    for i= 1, BarrierHP do
      BoxB(x,y,i,0xFF0080FF,0xFF0080FF)
    end
  end
  gui.pixelText(x+ 4,y   ,"Barrier",clr)
  gui.drawLine( x   ,y   ,x   ,y+15,clr)
  gui.drawLine( x+ 1,y+15,x+35,y+15,clr)
  gui.drawLine( x+36,y   ,x+36,y+15,clr)
end

local WpnClr= {
  0xFFFF2000,  --Flame
  0xFF00FF00,  --Whirlwind
  0xFFC08000,  --Dirt
  0xFF0040FF,  --Bubble
  0xFFC0FFFF,  --Missile
  0xFFFFFF00,  --Star
  0xFFFF00FF,  --Spikeball
  0xFF00FFFF   --Laser
}
local function BoxW(x,y,bc,fc) gui.drawRectangle(x,y,6,24,bc,fc) end
--*****************************************************************************
local function WeaponDisplay(x,y,w)
--*****************************************************************************
--6x24 - For a single weapon. Will display negative ammo as well.

  local HaveWpn= R1u(0x1668+w,"IWRAM") == 1
  if not HaveWpn then  BoxW(x,y,0xFF606060,0); return  end
  local clr= WpnClr[w] or 0xFFFFFFFF
  local WpnAmmo= R1s(0x165C+w,"IWRAM")
  local WpnSelect= R4u(0x15E4,"IWRAM")

  if WpnSelect == w then
    local FlashingClr= 0xFF008000 + 0x00FF7FFF * (math.floor(emu.framecount()/2)%2)
    BoxW(x,y,FlashingClr,0)
    WpnAmmo= R4s(0x163C,"IWRAM")  --There's an edge case where the array fails
  else                            --Specifically, refilling when ammo negative
    BoxW(x,y,clr,0)
  end

  if WpnAmmo > 11 then return end --Panic
  if WpnAmmo <-11 then return end --Panic

  if WpnAmmo < 0 then
    WpnAmmo= -WpnAmmo
    for i= 1, WpnAmmo do
      local X,Y= x+2,y+2*i
      gui.drawPixel(X  ,Y,0xFFFF0000)
      gui.drawPixel(X+2,Y,0xFFFF0000)
    end
  else
    for i= 1, WpnAmmo do
      local X,Y= x+2,y+24-2*i
      gui.drawLine(X,Y,X+2,Y,clr)
    end
  end
end

--*****************************************************************************
local function ChargeDisplay(x,y,h)
--*****************************************************************************
--4xh - Vertical charge display

  local Charge=    R4u(0x1608,"IWRAM")
  local WpnSelect= R4u(0x15E4,"IWRAM")
  local ArmUpgrade=R1u(0x1650,"IWRAM") == 1

  local clr= 0xFFC0C0C0
  if     (Charge >= 140) and ArmUpgrade and (WpnSelect == 0) then
    clr= 0xFF20FF20
    gui.drawLine(x+1,y+h,x+1,y  ,clr)
    gui.drawLine(x+2,y+h,x+2,y  ,clr)
  elseif (Charge >   60) and ArmUpgrade and (WpnSelect == 0) then
    clr= 0xFFFFFF00
    gui.drawLine(x+1,y+h,x+1,y  ,clr)
    local dist= math.floor(h/80 * (Charge-60))
    gui.drawLine(x+2,y+h,x+2,y+h-dist,0xFF20FF20)
  elseif (Charge >=  60) then
    clr= 0xFFFFFF00
    gui.drawLine(x+1,y,x+1,y+h,clr)
  elseif (Charge >    0) then
    local dist= math.floor(h/60 * Charge)
    gui.drawLine(x+1,y+h,x+1,y+h-dist,0xFFFFFF00)
  end
  gui.drawLine(x  ,y  ,x+2,y  ,clr)
  gui.drawLine(x  ,y+h,x+2,y+h,clr)
end

local PlayerStateText={
[0]= "Normal"  ,
     "Beam in" , -- 1
     "Ldr.Down", -- 2
     "Ldr.Up1" , -- 3
     "Ldr.Up2" , -- 4
     "Ouch!!"  , -- 5
     nil,
     nil,
     "On fire!", -- 8
     "Laser"   , -- 9
     "Pre-boss", --10
     "Beam out", --11
     nil,
     "Show off", --13
     "Capsule"   --14
}

local UpgradeLetter= {[0]="H","A","B","L"}
--*****************************************************************************
local function MiscDisplay(x,y)
--*****************************************************************************
--No idea what I'm putting here. Fun stuff, I suppose.

  local s= R4u(0x15F0,"IWRAM") --Player state
  local clr= 0xFFFFFFFF
  if s == 0 then clr= 0xFFC0C0C0 end
  gui.pixelText(x,y,PlayerStateText[s] or ("St " .. s),clr)
  y= y+7

  s= R1u(0x1EA4,"IWRAM")  --Flame charge timer
  if s > 0 then
    s= math.floor((64-s)/2)
    gui.drawLine( x,y,x+s,y,0xFFFFFF00)
    gui.drawPixel(x,y,      0xFFFFFF00)
  end
  y= y+4

  if R4u(0x1624,"IWRAM") ~= 0 then  --Full invincibility
    gui.pixelText(x,y,"D.Immune",0xFFFFFF00)
    s= R4u(0x1628,"IWRAM") --Invincibility timer
    if s <= 48 then
      s= math.floor(s/2)
      gui.drawLine( x,y+7,x+s,y+7,0xFFFFFF00)
      gui.drawPixel(x,y+7,        0xFFFFFF00)
    end --sanity
  else
    gui.pixelText(x,y,"No mercy",0xFF808080)
  end
  y= y+11

  if R4u(0x1618,"IWRAM") ~= 0 then  --Object invincibility
    gui.pixelText(x,y,"O.Immune",0xFF00FFFF)
  else
    gui.pixelText(x,y,"Wpn Inv.",0xFF808080)
  end
  y= y+11

  gui.pixelText(x   ,y,"HT:" .. R4u(0x1640,"IWRAM"),0xFFFF2000) --Heart Tanks
  gui.pixelText(x+20,y,"AT:" .. R4u(0x1644,"IWRAM"),0xFF0080FF) --Ammo Tanks
  y= y+11

  for i= 0, 3 do
    s= R4u(0x164C+4*i,"IWRAM") ~= 0  --Upgrades
    local clr= 0xFF808080
    if s then clr= 0xFF00FFFF end
    gui.pixelText(x+4+8*i,y,UpgradeLetter[i],clr)
  end

end

local BossModeText= {
[0]={"Not"     ," here,"  ,"  silly!"},
    {"Loading.","Please"  ," wait..."},
    {"Wild"    ," BOSS"   ,"appears!"},
    {"Shoot"   ," him"    ,"already!"},
    {"Opening" ," his big","  mouth."},
    {"Yappin',"," not"    ,"rappin'."},
    {"Uh, I"   ," should" ,"show HP."}, --6, I really should show HP instead!
    {"The 'no" ," damage'","  state."}, --7, another moment to show HP.
    {"How did" ,"you read","this?"   },
    {"Took"    ," long"   ,"enough." }
}

--*****************************************************************************
local function BossDisplay(x,y)
--*****************************************************************************
--Gives a status on the current affairs of the boss.

  local BossState= R4u(0x16F4,"IWRAM")

  if (BossState ~= 6) and (BossState ~= 7) then  --Show silly text
    local t= BossModeText[BossState]
    if t then
      gui.pixelText(x,y   ,t[1],0xFF00FF00)
      gui.pixelText(x,y+ 7,t[2],0xFF00FF00)
      gui.pixelText(x,y+14,t[3],0xFF00FF00)
    else
      gui.pixelText(x,y   ,"I didn't",0xFFC0C0C0) --I thought I covered all
      gui.pixelText(x,y+ 7,"see this",0xFFC0C0C0) --the BossState numbers!
      gui.pixelText(x,y+14,"coming." ,0xFFC0C0C0) --But just in case...
    end

  else  --Boss fighty mode!
    local BossHP = R4u(0x1708,"IWRAM")
    local BossSub= R4s(0x170C,"IWRAM")  --Sub HP units
    local BossInv= R4u(0x16F8,"IWRAM")

    if BossHP > 11 then return end --Panic
    for i= 1, BossHP do
      local X= x + ((i-1)%6)*5
      local Y= y + 14 - 7*math.floor((i-1)/6)
      local v= math.max(0,math.min(5,BossHP*5 + BossSub - i*5))
      if BossState == 7 then  --Need a better immunity check.
        gui.pixelText(x,y,"Immune:",0xFFFF8000)
      else
        gui.pixelText(x,y,"Boss HP:")
      end
      gui.pixelText(X,Y,v)
    end

    if BossInv > 96 then return end --Panic
    if BossInv >  0 then
      local Y= y+21
      local len= math.floor(BossInv/3)
      gui.drawLine( x,Y,x+len,Y,0xFFFFFF00)
      gui.drawPixel(x,Y,        0xFFFFFF00)
    end
  end
end

local mBossModeText= {
[0]={"Wrong"   ,"function"," bub."   },
    {"Generate"," one"    ,"miniboss"},
    {"Please"  ," hit me" ,"  now!!" },
    {"Strange" ," state." ,"What?"   },
    {"We hit." ,"Wait 60" ," frames."},
    {"Ooh..."  ," pretty" ,"  booms."}
}

--*****************************************************************************
local function MinibossDisplay(x,y)
--*****************************************************************************
--Informs us on what's happening with the miniboss.

  local mBossState= R4u(0x16DC,"IWRAM")

  if (mBossState < 2) or (mBossState > 4) then
    local t= mBossModeText[mBossState]
    if t then
      gui.pixelText(x,y   ,t[1],0xFFFFFF00)
      gui.pixelText(x,y+ 7,t[2],0xFFFFFF00)
      gui.pixelText(x,y+14,t[3],0xFFFFFF00)
    else
      gui.pixelText(x,y   ,"What is" ,0xFFC0C0C0) --Never assume. Always have
      gui.pixelText(x,y+ 7,"this"    ,0xFFC0C0C0) --a fallback in case of
      gui.pixelText(x,y+14,"thing?"  ,0xFFC0C0C0) --unexpected numbers.
    end

  else
    local mBossHP
    local addr= 0x2BA8   --1DE4, objSize=0x74, 30th object, offset+0x2C
    repeat  --My miniboss detector is whoever has more than zero HP...
      mBossHP= R2s(addr)
      if mBossHP > 0 then break end
      addr= addr+0x74
    until addr >= 0x3914  --Panic

    local mBossInv= R4u(0x16E0,"IWRAM")

    gui.pixelText(x,y   ,"Miniboss")
    gui.pixelText(x,y+ 7,mBossHP)
    
    if mBossInv > 60 then return end --Panic
    if mBossInv >  0 then
      local Y= y+14
      local len= math.floor((60-mBossInv)/2)
      gui.drawLine( x,Y,x+len,Y,0xFFFFFF00)
      gui.drawPixel(x,Y,        0xFFFFFF00)
    end

  end

--  gui.pixelText(x,y,mBossState)
end

local MapClrCycle= {
  0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
  0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
  0xFFFF0000,0xFFFF0000,0xFF00FF00,0xFF00FF00,0xFF0000FF,
  0xFF0000FF,0xFF00FF00,0xFF00FF00,0xFFFF00FF,0xFFFF00FF,
}

--*****************************************************************************
local function MapDisplay(x,y)
--*****************************************************************************
--38x?? - Intended to be... Really basic. We only have 40 pixels width.
--Segments are as wide as 18 blocks. We ain't got a lot o' room.

--Segment rectangle
  local Width=  R4u(0x153C,"IWRAM")
  local Height= R4u(0x1540,"IWRAM")
  if Width > 18 then return end           --Panic
  if Height > (160 - y)/2 then return end --Panic
  gui.drawRectangle(x,y,Width*2+1,Height*2+1,0xFFC0C0C0,0)

--Player position (1:128 scale ratio)
  local clr= MapClrCycle[emu.framecount()%(#MapClrCycle)+1]
  local X= x + 1 + math.floor((R4s(0x1500,"IWRAM")+R4s(0x1E58,"IWRAM") + 8)/128)
  local Y= y + 1 + math.floor((R4s(0x1504,"IWRAM")+R4s(0x1E5C,"IWRAM") +24)/128)
  gui.drawPixel(X,Y,clr)
end


client.SetGameExtraPadding(0,0,40,0)
--*****************************************************************************
while true do
--*****************************************************************************
--Our overhead.

  BarrierDisplay(242,2)
  for i= 1, 8 do
    local X= 245+((i-1)%4)*9
    local Y= 20 + math.floor((i-1)/4)*27
    WeaponDisplay(X,Y,i)
  end
  ChargeDisplay(241,20,51)
  MiscDisplay(241,74)

  if R4u(0x16F4,"IWRAM") ~= 0 then
    BossDisplay(241,130)

  elseif R4u(0x16DC,"IWRAM") ~= 0 then
    MinibossDisplay(241,130)

  else
    gui.pixelText(241,130,string.format("St%2d:%2d",
      R4u(0x152C,"IWRAM"), --Stage
      R4u(0x1530,"IWRAM")  --Segment
    ))
    MapDisplay(241,137)
  end
  emu.frameadvance()
end