--Hitboxes and Watches v1.3 for GBC Devil Island (Emo Dao) by ThunderAxe31
local R2ub= memory.read_u16_be
local R2ul= memory.read_u16_le
local R1u= memory.read_u8
local white = 0xFFFFFFFF
local black = 0xFF000000
local player_x = R1u(0xD001)
local actions = R1u(0xD008)
local combined_x_old = -1
local combined_x_lagcount = 0
local framecount_old = -1
local function draw_watches()
local combined_x = player_x + R2ul(0xC122) --add level x
--count x lag
local framecount = emu.framecount()
if framecount_old ~= (framecount-1) then --if a state has been loaded, reset values
combined_x_lagcount = 0
combined_x_old = -1
end
if (combined_x_old > -1) and (combined_x_old == combined_x) then --checks if the x value is unchanged
combined_x_lagcount = combined_x_lagcount + 1 --updates the movement lag count
if combined_x_lagcount > 9999 then --reset counter
combined_x_lagcount = 0
end
end
combined_x_old = combined_x --updates the x value
framecount_old = framecount --updates the frame count
--exp stuff
local exp_amount = R2ub(0xCFF8)
local exp_next = 0
local attack = 0
if exp_amount < 3072 then
attack = 1
exp_next = 3072 - exp_amount
elseif exp_amount < 6144 then
attack = 2
exp_next = 6144 - exp_amount
elseif exp_amount < 8192 then
attack = 3
exp_next = 8192 - exp_amount
elseif exp_amount < 10240 then
attack = 4
exp_next = 10240 - exp_amount
elseif exp_amount < 12288 then
attack = 5
exp_next = 12288 - exp_amount
elseif exp_amount < 14336 then
attack = 6
exp_next = 14336 - exp_amount
elseif exp_amount < 16384 then
attack = 7
exp_next = 16384 - exp_amount
else
attack = 8
exp_next = 0
end
--display watches
if bit.band(actions, 128) ~= 128 then --if menu is open, don't display.
gui.pixelText(0, 0, "X_POS: EXP: ATK: \nX_LAG: NEXT: HP:", white, black)
gui.pixelText(24, 0, string.format("%4s", combined_x), white, black) --current X position in level
gui.pixelText(24, 7, string.format("%4s", combined_x_lagcount), white, black) --current movement X lag counted
gui.pixelText(60, 0, string.format("%5s", exp_amount), white, black) --experience total
gui.pixelText(64, 7, string.format("%4s", exp_next), white, black) --experience left for next level
gui.pixelText(100,0, attack, white, black) --attack level
gui.pixelText(96, 7, string.format("%2s", R1u(0xCFF5)), white, black) --player HP
gui.pixelText(108, 0, "$:" .. R2ul(0xCFF6), white, black) --money
end
end
local function fix_negative(value) --wrap negative coordinates correctly
if (value>212) then
return value-256
end
return value
end
local function enemy_hitboxes()
for i = 0, 3 do --yes, there are just 4 object slots
local addr = 0xC200+i*0x20 --data chunks for objects are 32 bytes long
if R1u(addr) ~= 0 then --enemy hitboxes
gui.drawRectangle(fix_negative(R1u(addr+0x01))+R1u(addr+0x12)-8, fix_negative(R1u(addr+0x02))+R1u(addr+0x14)-16, R1u(addr+0x13)-1, R1u(addr+0x15)-1)
local obj_type = R1u(addr+0x16)
local label = ""
if obj_type==0 then --if enemy, show HP
if R1u(addr+0x0F)~=255 then
label = R1u(addr+0x07)
end
elseif obj_type==1 then --if money, show how much
label = "$"..R1u(addr+0x17)
elseif obj_type==2 then --if health, display a simple hospital cross
label = "+"
elseif obj_type==3 then --if pass
label = "PASS"
elseif obj_type==4 then --if whip piece
label = "WHIP\nPIECE"
else --if unknown, just in case
label = "?"
end
gui.pixelText(fix_negative(R1u(addr+0x01))-7, fix_negative(R1u(addr+0x02))-15, label, white, black)
end
end
--since there is currently no better solution, we're simply gonna splat these bosses HP on the screen upper left...
local head_hp = R1u(0xC1B3)
local core_hp = R1u(0xC1B4)
local boss_hp = R1u(0xC1A5)
if head_hp > 0 then
gui.pixelText(0, 14, "HEAD HP: " .. head_hp, white, black)
end
if core_hp > 0 then
gui.pixelText(0, 21, "CORE HP: " .. core_hp, white, black)
end
if boss_hp > 0 then
gui.pixelText(0, 28, "BOSS HP: " .. boss_hp, white, black) --using a different Y cooradinate, just in case
end --and no, all other bosses use the regular enemy object structure. this would explain why only these three have an invicibility timer.
end
local function player_hitboxes()
local player_y = R1u(0xD000)
local whip_x = player_x + 8
local whip_y = player_y - 8
local player_height = 32
local whip_height = 32
if bit.band(actions, 4) == 4 then --if crouched
player_y = player_y + 8
player_height = 24
whip_y = whip_y + 8
whip_height = 40
end
gui.drawRectangle(player_x, player_y, 16, player_height) --player hitbox
if bit.band(actions, 2) == 2 then --if attacking
if R1u(0xD005) == 2 then --if facing left
whip_x = whip_x -16
end
gui.drawRectangle(whip_x, whip_y, 16, whip_height) --whip hitbox
end
end
while true do
player_x = R1u(0xD001)
actions = R1u(0xD008)
draw_watches()
enemy_hitboxes()
player_hitboxes()
emu.frameadvance()
end