BizHawk/Assets/Lua/Doom/things-lines.lua

702 lines
14 KiB
Lua

-- feos, 2025
-- CONSTANTS
local NULL_OBJECT = 0x88888888 -- no object at that index
local OUT_OF_BOUNDS = 0xFFFFFFFF -- no such index
local MINIMAL_ZOOM = 0.0001 -- ???
local ZOOM_FACTOR = 0.02
local PAN_FACTOR = 10
local CHAR_WIDTH = 10
local CHAR_HEIGHT = 16
local NEGATIVE_MAXIMUM = 1 << 63
local POSITIVE_MAXIMUM = ~NEGATIVE_MAXIMUM
-- sizes in bytes
local SHORT = 2
local INT = 4
local POINTER = 8
local LINE_SIZE = 256 -- sizeof(line_t) is 232, but we padded it for niceness
local MOBJ_SIZE = 512 -- sizeof(mobj_t) is 464, but we padded it for niceness
-- shortcuts
local rl = memory.read_u32_le
local rw = memory.read_u16_le
local rb = memory.read_u8_le
local rls = memory.read_s32_le
local rws = memory.read_s16_le
local rbs = memory.read_s8_le
local text = gui.text
local box = gui.drawBox
local line = gui.drawLine
--local text = gui.pixelText -- INSANELY SLOW
-- TOP LEVEL VARIABLES
local Zoom = 1
local LastSize = 0
local Init = true
-- tables
-- view offset
local Pan = {
x = 0,
y = 0
}
-- object positions bounds
local OB = {
top = POSITIVE_MAXIMUM,
left = POSITIVE_MAXIMUM,
bottom = NEGATIVE_MAXIMUM,
right = NEGATIVE_MAXIMUM
}
local LastScreenSize = {
w = client.screenwidth(),
h = client.screenheight()
}
-- forward declarations
local Offsets = {} -- mobj member offsets in bytes
local MobjType = {}
local SpriteNumber = {}
local Objects = {}
--gui.defaultPixelFont("fceux")
gui.use_surface("client")
local function mapify_x(coord)
return math.floor(((coord / 0xffff)+Pan.x)*Zoom)
end
local function mapify_y(coord)
return math.floor(((coord / 0xffff)+Pan.y)*Zoom)
end
local function in_range(var, minimum, maximum)
return var >= minimum and var <= maximum
end
local function reset_view()
Init = true
update_zoom()
end
local function zoom_out()
local newZoom = Zoom * (1 - ZOOM_FACTOR)
if newZoom < MINIMAL_ZOOM then return end
Zoom = newZoom
end
local function zoom_in()
Zoom = Zoom * (1 + ZOOM_FACTOR)
end
local function pan_left()
Pan.x = Pan.x + PAN_FACTOR/Zoom/2
end
local function pan_right()
Pan.x = Pan.x - PAN_FACTOR/Zoom/2
end
local function pan_up()
Pan.y = Pan.y + PAN_FACTOR/Zoom/2
end
local function pan_down()
Pan.y = Pan.y - PAN_FACTOR/Zoom/2
end
local function add_offset(size, name)
Offsets[name] = LastSize
-- print(name, string.format("%X \t\t %X", size, LastSize))
LastSize = size + LastSize
end
function maybe_swap(left, right)
if left > right then
local smallest = right
right = left
left = smallest
end
end
local function get_line_count(str)
local lines = 1
local longest = 0
local size = 0
for i = 1, #str do
local c = str:sub(i, i)
if c == '\n' then
lines = lines + 1
if size > longest then
longest = size
size = -1
end
end
size = size + 1
end
if size > longest then longest = size end
return lines, longest
end
local function iterate()
if Init then return end
for _, addr in ipairs(Objects) do
local x = rls(addr + Offsets.x)
local y = rls(addr + Offsets.y) * -1
local health = rls(addr + Offsets.health)
local radius = math.floor((rls(addr + Offsets.radius) >> 16) * Zoom)
local sprite = SpriteNumber[rls(addr + Offsets.sprite)]
local type = rl(addr + Offsets.type)
local pos = { x = mapify_x(x), y = mapify_y(y) }
local color = "white"
if type == 0
then type = "PLAYER" print("PLAYER")
else type = MobjType[type]
end
if health <= 0 then color = "red" end
--[[--
local z = rls(addr + Offsets.z) / 0xffff
local index = rl (addr + Offsets.index)
local tics = rl (addr + Offsets.tics)
--]]--
if in_range(pos.x, 0, client.screenwidth())
and in_range(pos.y, 0, client.screenheight())
then
text(pos.x, pos.y, string.format("%s", type), color)
box(pos.x - radius, pos.y - radius, pos.x + radius, pos.y + radius, color)
end
end
for i = 0, 100000 do
local addr = i * LINE_SIZE
if addr > 0xFFFFFF then break end
local id = rl(addr, "Lines") & 0xFFFFFFFF
if id == OUT_OF_BOUNDS then break end
if id ~= NULL_OBJECT then
local vertices_offset = 0xe8
local v1 = { x = rls(addr+vertices_offset , "Lines"),
y = -rls(addr+vertices_offset+ 4, "Lines") }
local v2 = { x = rls(addr+vertices_offset+ 8, "Lines"),
y = -rls(addr+vertices_offset+12, "Lines") }
line(
mapify_x(v1.x),
mapify_y(v1.y),
mapify_x(v2.x),
mapify_y(v2.y),
0xffcccccc)
end
end
end
local function init_objects()
for i = 0, 100000 do
local addr = i * MOBJ_SIZE
if addr > 0xFFFFFF then break end
local thinker = rl(addr) & 0xFFFFFFFF -- just to check if mobj is there
if thinker == OUT_OF_BOUNDS then break end
if thinker ~= NULL_OBJECT then
local x = rls(addr + Offsets.x) / 0xffff
local y = rls(addr + Offsets.y) / 0xffff * -1
local type = rl (addr + Offsets.type)
if type == 0
then type = "PLAYER" print("PLAYER")
else type = MobjType[type]
end
-- print(string.format("%d %f %f %02X", index, x, y, type))
if type
and not string.find(type, "MISC")
then
if x < OB.left then OB.left = x end
if x > OB.right then OB.right = x end
if y < OB.top then OB.top = y end
if y > OB.bottom then OB.bottom = y end
-- cache the Objects we need
table.insert(Objects, addr)
end
end
end
end
function update_zoom()
if not Init
and LastScreenSize.w == client.screenwidth()
and LastScreenSize.h == client.screenheight()
then return end
if OB.top ~= POSITIVE_MAXIMUM
and OB.left ~= POSITIVE_MAXIMUM
and OB.right ~= NEGATIVE_MAXIMUM
and OB.bottom ~= NEGATIVE_MAXIMUM
and not emu.islagged()
then
maybe_swap(OB.right, OB.left)
maybe_swap(OB.top, OB.bottom)
local span = { x = OB.right-OB.left+200, y = OB.bottom-OB.top+200 }
local scale = { x = client.screenwidth()/span.x, y = client.screenheight()/span.y }
local spanCenter = { x = OB.left+span.x/2, y = OB.top+span.y/2 }
Zoom = math.min(scale.x, scale.y)
local sreenCenter = { x = client.screenwidth()/Zoom/2, y = client.screenheight()/Zoom/2 }
Pan.x = -math.floor(spanCenter.x - sreenCenter.x)
Pan.y = -math.floor(spanCenter.y - sreenCenter.y)
Init = false
end
end
local function make_button(x, y, name, func)
local boxWidth = CHAR_WIDTH
local boxHeight = CHAR_HEIGHT
local lineCount, longest = get_line_count(name)
local textWidth = longest *CHAR_WIDTH
local textHeight = lineCount*CHAR_HEIGHT
local colors = { 0x66bbddff, 0xaabbddff, 0xaa88aaff }
local colorIndex = 1
if textWidth + 10 > boxWidth then boxWidth = textWidth + 10 end
if textHeight + 10 > boxHeight then boxHeight = textHeight + 10 end
local textX = x + boxWidth /2 - textWidth /2
local textY = y + boxHeight/2 - textHeight/2 - boxHeight
local mouse = input.getmouse()
local mousePos = client.transformPoint(mouse.X, mouse.Y)
if in_range(mousePos.x, x, x+boxWidth)
and in_range(mousePos.y, y-boxHeight, y ) then
if mouse.Left then
colorIndex = 3
func()
else colorIndex = 2 end
end
box(x, y, x+boxWidth, y-boxHeight, 0xaaffffff, colors[colorIndex])
text(textX, textY, name, colors[colorIndex] | 0xff000000) -- full alpha
end
--[[--
thinker 30 0
x 4 30
y 4 34
z 4 38
snext 8 3C
sprev 8 44
angle 4 4C
sprite 4 50
frame 4 54
bnext 8 58
bprev 8 60
subsector 8 68
floorz 4 70
ceilingz 4 74
dropoffz 4 78
radius 4 7C
height 4 80
momx 4 84
momy 4 88
momz 4 8C
validcount 4 90
type 4 94
info 8 98
tics 4 A0
state 8 A4
flags 8 AC
intflags 4 B4
health 4 B8
movedir 2 BC
movecount 2 BE
strafecount 2 C0
target 8 C2
reactiontime 2 CA
threshold 2 CC
pursuecount 2 CE
gear 2 D0
player 8 D2
lastlook 2 DA
spawnpoint 3A DC
tracer 8 116
lastenemy 8 11E
friction 4 126
movefactor 4 12A
touching_sectorlist 8 12E
PrevX 4 136
PrevY 4 13A
PrevZ 4 13E
pitch 4 142
index 4 146
patch_width 2 14A
iden_nums 4 14C
--]]--
add_offset(48, "thinker")
add_offset(INT, "x")
add_offset(INT, "y")
add_offset(INT, "z")
add_offset(INT, "padding1")
add_offset(POINTER, "snext")
add_offset(POINTER, "sprev")
add_offset(INT, "angle")
add_offset(INT, "sprite")
add_offset(INT, "frame")
add_offset(INT, "padding2")
add_offset(POINTER, "bnext")
add_offset(POINTER, "bprev")
add_offset(POINTER, "subsector")
add_offset(INT, "floorz")
add_offset(INT, "ceilingz")
add_offset(INT, "dropoffz")
add_offset(INT, "radius")
add_offset(INT, "height")
add_offset(INT, "momx")
add_offset(INT, "momy")
add_offset(INT, "momz")
add_offset(INT, "validcount")
add_offset(INT, "type")
add_offset(POINTER, "info")
add_offset(INT, "tics")
add_offset(INT, "padding3")
add_offset(POINTER, "state")
add_offset(8, "flags")
add_offset(INT, "intflags")
add_offset(INT, "health")
add_offset(SHORT, "movedir")
add_offset(SHORT, "movecount")
add_offset(SHORT, "strafecount")
add_offset(SHORT, "padding4")
add_offset(POINTER, "target")
add_offset(SHORT, "reactiontime")
add_offset(SHORT, "threshold")
add_offset(SHORT, "pursuecount")
add_offset(SHORT, "gear")
add_offset(POINTER, "player")
add_offset(SHORT, "lastlook")
add_offset(58, "spawnpoint")
add_offset(INT, "padding5") -- unsure where this one should be exactly
add_offset(POINTER, "tracer")
add_offset(POINTER, "lastenemy")
add_offset(INT, "friction")
add_offset(INT, "movefactor")
add_offset(POINTER, "touching_sectorlist")
add_offset(INT, "PrevX")
add_offset(INT, "PrevY")
add_offset(INT, "PrevZ")
add_offset(INT, "pitch")
add_offset(INT, "index")
add_offset(SHORT, "patch_width")
add_offset(INT, "iden_nums")
-- the rest are non-doom
-- print(Offsets)
MobjType = {
-- "NULL" = -1,
-- "ZERO",
-- "PLAYER = ZERO",
"POSSESSED",
"SHOTGUY",
"VILE",
"FIRE",
"UNDEAD",
"TRACER",
"SMOKE",
"FATSO",
"FATSHOT",
"CHAINGUY",
"TROOP",
"SERGEANT",
"SHADOWS",
"HEAD",
"BRUISER",
"BRUISERSHOT",
"KNIGHT",
"SKULL",
"SPIDER",
"BABY",
"CYBORG",
"PAIN",
"WOLFSS",
"KEEN",
"BOSSBRAIN",
"BOSSSPIT",
"BOSSTARGET",
"SPAWNSHOT",
"SPAWNFIRE",
"BARREL",
"TROOPSHOT",
"HEADSHOT",
"ROCKET",
"PLASMA",
"BFG",
"ARACHPLAZ",
"PUFF",
"BLOOD",
"TFOG",
"IFOG",
"TELEPORTMAN",
"EXTRABFG",
"MISC0",
"MISC1",
"MISC2",
"MISC3",
"MISC4",
"MISC5",
"MISC6",
"MISC7",
"MISC8",
"MISC9",
"MISC10",
"MISC11",
"MISC12",
"INV",
"MISC13",
"INS",
"MISC14",
"MISC15",
"MISC16",
"MEGA",
"CLIP",
"MISC17",
"MISC18",
"MISC19",
"MISC20",
"MISC21",
"MISC22",
"MISC23",
"MISC24",
"MISC25",
"CHAINGUN",
"MISC26",
"MISC27",
"MISC28",
"SHOTGUN",
"SUPERSHOTGUN",
"MISC29",
"MISC30",
"MISC31",
"MISC32",
"MISC33",
"MISC34",
"MISC35",
"MISC36",
"MISC37",
"MISC38",
"MISC39",
"MISC40",
"MISC41",
"MISC42",
"MISC43",
"MISC44",
"MISC45",
"MISC46",
"MISC47",
"MISC48",
"MISC49",
"MISC50",
"MISC51",
"MISC52",
"MISC53",
"MISC54",
"MISC55",
"MISC56",
"MISC57",
"MISC58",
"MISC59",
"MISC60",
"MISC61",
"MISC62",
"MISC63",
"MISC64",
"MISC65",
"MISC66",
"MISC67",
"MISC68",
"MISC69",
"MISC70",
"MISC71",
"MISC72",
"MISC73",
"MISC74",
"MISC75",
"MISC76",
"MISC77",
"MISC78",
"MISC79",
"MISC80",
"MISC81",
"MISC82",
"MISC83",
"MISC84",
"MISC85",
"MISC86",
"PUSH",
"PULL",
"DOGS",
"PLASMA1",
"PLASMA2"
}
SpriteNumber = {
-- "TROO",
"SHTG",
"PUNG",
"PISG",
"PISF",
"SHTF",
"SHT2",
"CHGG",
"CHGF",
"MISG",
"MISF",
"SAWG",
"PLSG",
"PLSF",
"BFGG",
"BFGF",
"BLUD",
"PUFF",
"BAL1",
"BAL2",
"PLSS",
"PLSE",
"MISL",
"BFS1",
"BFE1",
"BFE2",
"TFOG",
"IFOG",
"PLAY",
"POSS",
"SPOS",
"VILE",
"FIRE",
"FATB",
"FBXP",
"SKEL",
"MANF",
"FATT",
"CPOS",
"SARG",
"HEAD",
"BAL7",
"BOSS",
"BOS2",
"SKUL",
"SPID",
"BSPI",
"APLS",
"APBX",
"CYBR",
"PAIN",
"SSWV",
"KEEN",
"BBRN",
"BOSF",
"ARM1",
"ARM2",
"BAR1",
"BEXP",
"FCAN",
"BON1",
"BON2",
"BKEY",
"RKEY",
"YKEY",
"BSKU",
"RSKU",
"YSKU",
"STIM",
"MEDI",
"SOUL",
"PINV",
"PSTR",
"PINS",
"MEGA",
"SUIT",
"PMAP",
"PVIS",
"CLIP",
"AMMO",
"ROCK",
"BROK",
"CELL",
"CELP",
"SHEL",
"SBOX",
"BPAK",
"BFUG",
"MGUN",
"CSAW",
"LAUN",
"PLAS",
"SHOT",
"SGN2",
"COLU",
"SMT2",
"GOR1",
"POL2",
"POL5",
"POL4",
"POL3",
"POL1",
"POL6",
"GOR2",
"GOR3",
"GOR4",
"GOR5",
"SMIT",
"COL1",
"COL2",
"COL3",
"COL4",
"CAND",
"CBRA",
"COL6",
"TRE1",
"TRE2",
"ELEC",
"CEYE",
"FSKU",
"COL5",
"TBLU",
"TGRN",
"TRED",
"SMBT",
"SMGT",
"SMRT",
"HDB1",
"HDB2",
"HDB3",
"HDB4",
"HDB5",
"HDB6",
"POB1",
"POB2",
"BRS1",
"TLMP",
"TLP2",
"TNT1",
"DOGS",
"PLS1",
"PLS2",
"BON3",
"BON4",
"BLD2"
}
while true do
if Init then init_objects() end
iterate()
update_zoom()
make_button( 10, client.screenheight()-70, "Zoom\nIn", zoom_in )
make_button( 10, client.screenheight()-10, "Zoom\nOut", zoom_out )
make_button( 80, client.screenheight()-40, "Pan\nLeft", pan_left )
make_button(150, client.screenheight()-70, "Pan \nUp", pan_up )
make_button(150, client.screenheight()-10, "Pan\nDown", pan_down )
make_button(220, client.screenheight()-40, "Pan\nRight", pan_right )
make_button(300, client.screenheight()-10, "Reset\nView", reset_view)
text(10, client.screenheight()-170, string.format(
"Zoom: %.4f\nPanX: %s\nPanY: %s",
Zoom, Pan.x, Pan.y), 0xffbbddff)
LastScreenSize.w = client.screenwidth()
LastScreenSize.h = client.screenheight()
emu.frameadvance()
end