Skip to content

Instantly share code, notes, and snippets.

@lagomorph
Created December 15, 2021 23:34
Show Gist options
  • Save lagomorph/bdd8de3a85f4b04fa2381c720433dbf3 to your computer and use it in GitHub Desktop.
Save lagomorph/bdd8de3a85f4b04fa2381c720433dbf3 to your computer and use it in GitHub Desktop.
Updated ghost_ai.lua that works on newer versions of MAME
-- Pac-Man ghost AI viewer v1.2
-- Shows ghost target tiles and projected paths of ghosts
-- You can change this to make the paths shorter or longer:
PATHDIST = 20
s = manager.machine.screens[":screen"]
mem = manager.machine.devices[":maincpu"].spaces["program"]
XMAX = s.width - 1
YMAX = s.height - 1
function onframe()
getvalues()
draw()
end
function getvalues()
pacmanX = mem:read_i8(0x4D39)
pacmanY = mem:read_i8(0x4D3A)
pacmanD = mem:read_i8(0x4D3C)
blinkyX = mem:read_i8(0x4D0A)
blinkyY = mem:read_i8(0x4D0B)
blinkyD = mem:read_i8(0x4D2C)
blinkyF = mem:read_i8(0x4DA7)
blinkyE = mem:read_i8(0x4DAC)
pinkyX = mem:read_i8(0x4D0C)
pinkyY = mem:read_i8(0x4D0D)
pinkyD = mem:read_i8(0x4D2D)
pinkyF = mem:read_i8(0x4DA8)
pinkyE = mem:read_i8(0x4DAD)
inkyX = mem:read_i8(0x4D0E)
inkyY = mem:read_i8(0x4D0F)
inkyD = mem:read_i8(0x4D2E)
inkyF = mem:read_i8(0x4DA9)
inkyE = mem:read_i8(0x4DAE)
clydeX = mem:read_i8(0x4D10)
clydeY = mem:read_i8(0x4D11)
clydeD = mem:read_i8(0x4D2F)
clydeF = mem:read_i8(0x4DAA)
clydeE = mem:read_i8(0x4DAF)
chaseMode = mem:read_i8(0x4DC1)
unknownTimer = mem:read_i8(0x4E04)
fewDotsLeft = mem:read_i8(0x4DB6)
end
function draw()
if (not disable_trail(blinkyX, blinkyY, blinkyF, blinkyE)) then
draw_blinky_ai()
end
if (not disable_trail(pinkyX, pinkyY, pinkyF, pinkyE)) then
draw_pinky_ai()
end
if (not disable_trail(inkyX, inkyY, inkyF, inkyE)) then
draw_inky_ai()
end
if (not disable_trail(clydeX, clydeY, clydeF, clydeE)) then
draw_clyde_ai()
end
end
function draw_blinky_ai()
g = tile_to_screen(blinkyX, blinkyY)
t = {0x1D, 0x22}
if (
(chaseMode & 1) == 1 or
unknownTimer ~= 3 or
fewDotsLeft ~= 0
) then
t = {pacmanX, pacmanY}
end
if (blinkyE == 1) then
t = {0x2C, 0x2E}
end
draw_next_movements(blinkyX, blinkyY, blinkyD, blinkyE, t[1], t[2], blinkyE == 1, 0x40FF0000)
t = tile_to_screen(t[1], t[2])
s:draw_box(g[1]-4, g[2]-4, g[1]+4, g[2]+4, 0, 0x40FF0000)
s:draw_box(t[1]-2, t[2]-2, t[1]+2, t[2]+2, 0, 0xFFFF0000)
end
function draw_pinky_ai()
g = tile_to_screen(pinkyX, pinkyY)
t = {0x1D, 0x39}
if (
(chaseMode & 1) == 1 or
unknownTimer ~= 3
) then
px = pacmanX
py = pacmanY
if (pacmanD == 0) then
py = py - 4
elseif (pacmanD == 1) then
px = px + 4
elseif (pacmanD == 2) then
py = py + 4
elseif (pacmanD == 3) then
py = py + 4 -- oof
px = px - 4
end
t = {px, py}
end
if (pinkyE == 1) then
t = {0x2C, 0x2E}
end
draw_next_movements(pinkyX, pinkyY, pinkyD, pinkyE, t[1], t[2], pinkyE == 1, 0x40FFB8FF)
t = tile_to_screen(t[1], t[2])
s:draw_box(g[1]-4, g[2]-4, g[1]+4, g[2]+4, 0, 0x40FFB8FF)
s:draw_box(t[1]-2, t[2]-2, t[1]+2, t[2]+2, 0, 0xFFFFB8FF)
end
function draw_inky_ai()
g = tile_to_screen(inkyX, inkyY)
t = {0x40, 0x20}
if (
(chaseMode & 1) == 1 or
unknownTimer ~= 3
) then
px = pacmanX
py = pacmanY
if (pacmanD == 0) then
py = py - 2
elseif (pacmanD == 1) then
px = px + 2
elseif (pacmanD == 2) then
py = py + 2
elseif (pacmanD == 3) then
py = py + 2 -- oof
px = px - 2
end
px = px + (px - blinkyX)
py = py + (py - blinkyY)
t = {px, py}
end
if (inkyE == 1) then
t = {0x2C, 0x2E}
end
draw_next_movements(inkyX, inkyY, inkyD, inkyE, t[1], t[2], inkyE == 1, 0x4000FFFF)
t = tile_to_screen(t[1], t[2])
s:draw_box(g[1]-4, g[2]-4, g[1]+4, g[2]+4, 0, 0x4000FFFF)
s:draw_box(t[1]-2, t[2]-2, t[1]+2, t[2]+2, 0, 0xFF00FFFF)
end
function draw_clyde_ai()
g = tile_to_screen(clydeX, clydeY)
t = {0x40, 0x3B}
if (
dist2(pacmanX, pacmanY, clydeX, clydeY) >= 0x40 and
((chaseMode & 1) == 1 or
unknownTimer ~= 3)
) then
t = {pacmanX, pacmanY}
end
if (clydeE == 1) then
t = {0x2C, 0x2E}
end
draw_next_movements(clydeX, clydeY, clydeD, clydeE, t[1], t[2], clydeE == 1, 0x40FFB851)
t = tile_to_screen(t[1], t[2])
s:draw_box(g[1]-4, g[2]-4, g[1]+4, g[2]+4, 0, 0x40FFB851)
s:draw_box(t[1]-2, t[2]-2, t[1]+2, t[2]+2, 0, 0xFFFFB851)
end
function draw_next_movements(x, y, d, e, tx, ty, stop, c)
if (d == 0) then
y = y - 1
elseif (d == 1) then
x = x + 1
elseif (d == 2) then
y = y + 1
else
x = x - 1
end
local ll = {x, y, d}
local i = 0
bs = tile_to_screen(ll[1], ll[2])
s:draw_box(bs[1]-4, bs[2]-4, bs[1]+4, bs[2]+4, 0, c)
while (i < PATHDIST) and not ((ll[1] == pacmanX and ll[2] == pacmanY) or (stop and ll[1] == tx and ll[2] == ty)) do
lll = get_next_movement(ll[1], ll[2], ll[3], e, tx, ty)
bs = tile_to_screen(lll[1], lll[2])
s:draw_box(bs[1]-4, bs[2]-4, bs[1]+4, bs[2]+4, 0, c)
ll = {lll[1], lll[2], lll[3]}
i = i + 1
end
end
function get_next_movement(x, y, d, e, tx, ty) -- d = R D L U
if (not ((e == 0) and (x == 0x2C or x == 0x38) and (y <= 0x30 and y >= 0x2B) and (d == 0 or d == 2))) then
dirs = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}
local minL = 99999
local minI = 1
local i = 1
while (i <= 4) do
if (not ((i == 1 and d == 1) or (i == 2 and d == 0) or (i == 3 and d == 3) or (i == 4 and d == 2))) then
local nx = x + dirs[i][1]
local ny = y + dirs[i][2]
if (is_tile_empty(nx, ny)) then
local l = dist2(nx, ny, tx, ty)
if (l < minL) then
minL = l
minI = i
end
end
end
i = i + 1
end
d = 4 - minI
end
local result = {x, y, d}
if (d == 0) then
result = {x, y - 1, d}
elseif (d == 1) then
result = {x + 1, y, d}
elseif (d == 2) then
result = {x, y + 1, d}
else
result = {x - 1, y, d}
end
if (result[2] == 0x3E) then
result[2] = 0x1E
elseif (result[2] == 0x1D) then
result[2] = 0x3D
end
return result
end
function disable_trail(x, y, fright, eyes)
if (x == 0x2F and y >= 0x2B and y <= 0x30) then
return true
elseif (eyes == 1) then
if (x >= 0x2C and x <= 0x30 and y >= 0x2C and y <= 0x2F) then
return true
end
elseif (fright == 1) then
return true
end
return false
end
function is_tile_empty(x, y)
if (y >= 0x3C or y <= 0x1F) then
return x == 0x2F
end
vid = mem:read_i8(0x4040 +
0x20 * (y - 0x20) +
(x - 0x20))
return vid > 0 or vid < -0x70
end
function dist2(x1, y1, x2, y2)
return ((x2-x1)*(x2-x1))+((y2-y1)*(y2-y1))
end
function tile_to_screen(x, y)
return {
8*(x-30)+4,
8*(y-32)+4
}
end
emu.register_frame_done(onframe, "frame")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment