--[[
This script displays hitboxes for Kuros, Kuros's weapon, and active items in
Wizards & Warriors X: The Fortress of Fear. It also displays HP of items.
Several notes:
- HP values are decimal numbers.
- The weapon only has a hitbox during certain animation states. It only causes
damage when it has a hitbox.
- Damage appears to be 1 HP per frame of contact with the enemy.
- Some items, like keys, remain in an active state even after being collected.
Feel free to improve upon this as desired.
Dacicus 2020/12/03
--]]
memory.usememorydomain("System Bus")
local item_offset, item_x, item_y, item_pointer, item_value, item_hp
local hit_x_lo, hit_x_hi, hit_y_low, hit_y_hi
local kuros_y, kuros_animation, kuros_y_mod
local weapon_pointer, weapon_x_lo, weapon_x_hi, weapon_y_lo, weapon_y_hi
local color_item = 0xFFFF0000
local color_kuros = 0xFF0000FF
local color_weapon = 0xFFFF00FF
local addr_current_spawns = 0xC200
local addr_rom_bank = 0xC2FB
local addr_kuros_animation = 0xFFD8
local addr_kuros_y = 0xFFD9
local addr_kuros_weapon = 0xFFDC
--[[
These modifier values are not from the ROM. They were determined
empirically in order to make the hitboxes match up with the graphics
on screen. Set them to 0 in order to use just the data from the ROM.
--]]
local x_mod, y_mod = 0x08, 0x10
-- All constants in the functions below are based on values hardcoded or calculated in the ROM.
local function draw_kuros_hitbox(y_pos, animation)
if animation < 0x1C then
kuros_y_mod = 0x10
elseif animation < 0x24 then
kuros_y_mod = 0x1B
elseif animation < 0x34 then
kuros_y_mod = 0x10
else
kuros_y_mod = 0x1B
end
gui.drawBox(0x4B - x_mod, y_pos + kuros_y_mod - y_mod, 0x56 - x_mod, y_pos + 0x30 - y_mod, color_kuros)
end
local function draw_weapon_hitbox(addr, y_pos, animation)
if ((animation >= 0x15) and (animation < 0x1c) and (animation ~= 0x18)) or
(animation == 0x1F) or (animation == 0x23) or (animation == 0x31) or (animation == 0x33) then
weapon_pointer = memory.read_u16_le(addr) + 0x1C
weapon_x_lo = memory.read_u8(weapon_pointer)
weapon_x_hi = memory.read_u8(weapon_pointer + 2)
weapon_y_lo = memory.read_u8(weapon_pointer + 1) + y_pos
weapon_y_hi = memory.read_u8(weapon_pointer + 3) + y_pos
gui.drawBox(weapon_x_lo - x_mod, weapon_y_lo - y_mod, weapon_x_hi - x_mod, weapon_y_hi - y_mod, color_weapon)
end
end
local function draw_item_hitbox(addr)
for curr_slot = 0, 18 do
item_offset = addr + curr_slot * 6
if memory.read_u8(item_offset + 3) ~= 0xFE then -- 0xFE: slot is inactive
item_x = memory.read_u8(item_offset)
item_y = memory.read_u8(item_offset + 1)
item_hp = memory.read_u8(item_offset + 4)
item_pointer = memory.read_u16_le(item_offset + 2)
item_value = memory.read_u8(item_pointer + 2)
item_pointer = item_pointer + 6 + item_value
while memory.read_u8(item_pointer) ~= 0xFF do
item_pointer = item_pointer + 1
end
item_pointer = item_pointer + 2
hit_x_lo = item_x + memory.read_u8(item_pointer)
hit_y_lo = item_y + memory.read_u8(item_pointer + 1)
hit_x_hi = item_x + memory.read_u8(item_pointer + 2)
hit_y_hi = item_y + memory.read_u8(item_pointer + 3)
gui.drawBox(hit_x_lo - x_mod, hit_y_lo - y_mod, hit_x_hi - x_mod, hit_y_hi - y_mod, color_item)
gui.pixelText(item_x, item_y, item_hp)
end
end
end
while true do
if memory.read_u8(addr_rom_bank) == 3 then -- Avoid slowdown between levels.
kuros_y = memory.read_u8(addr_kuros_y)
kuros_animation = memory.read_u8(addr_kuros_animation)
draw_kuros_hitbox(kuros_y, kuros_animation)
draw_weapon_hitbox(addr_kuros_weapon, kuros_y, kuros_animation)
draw_item_hitbox(addr_current_spawns)
end
emu.frameadvance()
end