Created
December 15, 2021 23:34
-
-
Save lagomorph/bdd8de3a85f4b04fa2381c720433dbf3 to your computer and use it in GitHub Desktop.
Updated ghost_ai.lua that works on newer versions of MAME
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- 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