displays coordinates, speed, hp, and other essential info on screen
local PAD_RIGHT = 180 -- width of strip on the right (prev: 68)
local TEXT_LM = 664 -- left margin inside panel (prev: 555)
local TEXT_TM = 0 -- top margin inside panel
local LINE_H = 14 -- line height for text
client.SetGameExtraPadding(0, 0, PAD_RIGHT, 0)
local function on_exit_cleanup()
client.SetGameExtraPadding(0, 0, 0, 0)
end
event.onexit(on_exit_cleanup) -- remove pad when script stops
local function pad_origin()
local bw, bh = client.bufferwidth(), client.bufferheight()
return (bw - PAD_RIGHT), 0, bw, bh
end
memory.usememorydomain("System Bus")
-- shorts for memory reads
local function u8(a) memory.usememorydomain("System Bus"); return memory.read_u8(a) end
local function u16(a) memory.usememorydomain("System Bus"); return memory.read_u16_le(a) end
local function u32(a) memory.usememorydomain("System Bus"); return memory.read_u32_le(a) end
local function s32(a) memory.usememorydomain("System Bus"); return memory.read_s32_le(a) end
local function q1616(v) return v / 65536.0 end
local function yn(b) return (b ~= 0) and "yes" or "no" end
local EWRAM_START, EWRAM_END = 0x02000000, 0x0203FFFF
local function is_ewram(a) return a >= EWRAM_START and a <= EWRAM_END end
local function in_block(a, size) return a >= EWRAM_START and (a + size - 1) <= EWRAM_END end
-- base = **(0x08026C40) + *(0x08026C48) + 0x0118
local function base_slot_addr()
local a = u32(0x08026C40)
local b = u32(0x08026C48)
return u32(a) + b + 0x0118
end
local function degreeconversion(dir16)
local u = dir16 % 1024
return (u * 360.0) / 1024.0
end
-- main loop
while true do
local slot = base_slot_addr() -- from block where level info lives
local actor = 0
if is_ewram(slot) and in_block(slot, 4) then -- prevent invalid memory reads
actor = u32(slot)
end
local valid = is_ewram(slot) and is_ewram(actor) and actor ~= 0
if valid then -- prevent invalid memory reads
local painkillers = u8(0x02000034)
local room, door_open, bullet_time, doorbyte = 0, 0, 0, 0
if in_block(slot - 0x10C, 1) then room = u8(slot - 0x10C) end
if in_block(slot - 0x109, 1) then
doorbyte = slot - 0x109
door_open = u8(doorbyte)
end
if in_block(slot + 0x120, 1) then bullet_time = u8(slot + 0x120) end
local x,y,z,vx,vy,vz,hp,direction = 0,0,0,0,0,0,0,0
if in_block(actor, 0x114) then
x = s32(actor + 0x2C)
y = s32(actor + 0x30)
z = s32(actor + 0x34)
vx = s32(actor + 0x38)
vy = s32(actor + 0x3C)
vz = s32(actor + 0x40)
direction = u16(actor + 0x50)
hp = s32(actor + 0x110)
end
local panelX, panelY, _, bh = pad_origin()
local tx = panelX + TEXT_LM
local ty = panelY + TEXT_TM
local function line(s) gui.text(tx, ty, s); ty = ty + LINE_H end
line("base slot: " .. string.format("%08X",slot))
line("actor: " .. string.format("%08X",actor))
line("weapons: " .. string.format("%08X",actor+0x1B0))
ty = ty + LINE_H -- extra gap
line(string.format("X: %.4f", q1616(x)))
line(string.format("Y: %.4f", q1616(y)))
line(string.format("Z: %.4f", q1616(z)))
line(string.format("dX: %.4f", q1616(vx)))
line(string.format("dY: %.4f", q1616(vy)))
line(string.format("hor_speed: %.4f", math.sqrt(q1616(vx)*q1616(vx) + q1616(vy)*q1616(vy))))
line(string.format("dZ: %.4f", q1616(vz)))
line(string.format("Dir: %.2f° (%04X)", degreeconversion(direction), direction))
line(string.format("HP: %d (%08X)", hp, actor + 0x110))
line(string.format("Shot queued: %s", yn(u8(actor + 0x1EE))))
line(string.format("Shot cooldown: %d", u8(actor + 0x1EC)))
line(string.format("Painkillers: %d", painkillers))
line(string.format("Room ID: %d", room))
line(string.format("Door open?(%08X)", doorbyte))
line(string.format(" --> %s",yn(door_open)))
line("Bullet time: " .. yn(bullet_time))
end
emu.frameadvance()
end