Skip to content

Instantly share code, notes, and snippets.

@karmic64
Created January 21, 2022 02:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save karmic64/36e57bfcda0fd5f92ff591ead2e2fbeb to your computer and use it in GitHub Desktop.
Save karmic64/36e57bfcda0fd5f92ff591ead2e2fbeb to your computer and use it in GitHub Desktop.
Bill & Ted NES Mesen lua script
-- bill & ted NES Mesen lua script
-- coded by karmic, jan 18-20, 2022
figure_names = {"Cleopatra","Confucius","King Arthur","Christopher Columbus","Paul Revere","Jesse James","Al Capone","Elvis","Julius Caesar","Robin Hood","Rembrandt","William Shakespeare","George Washington","Sitting Bull","Thomas Edison","Marilyn Monroe","A stranger"}
bait_names = {"Major credit card","Fortune cookie","Holy grail","Compass","Megaphone","Uzi","Book of lawyer stuff","Headstone","Salad dressing","Bag-o-money","Paint roller","Stage prop","Pair of choppers","Lawn chair","Compact disc","Rose","Some stuff"}
good_stuff_names = {"Pudding","Firecracker","Textbook","Cassette tape","Coin","Key"}
-- helper functions
function concat11(lo, hi)
return lo | (hi << 8)
end
function readcpu(addr)
return emu.read(addr, emu.memType.cpuDebug, false)
end
function getprg(bank,addr)
if addr < 0xc000 then bank = 0 end
return (bank*0x4000)+(addr&0x3fff)
end
function readprg(bank, addr)
return emu.read(getprg(bank,addr), emu.memType.prgRom, false)
end
function readprglittle(bank,addr)
return emu.readWord(getprg(bank,addr), emu.memType.prgRom, false)
end
function readprgbig(bank, addr)
return concat11(readprg(bank,addr+1), readprg(bank,addr))
end
-- ingame functions
function convert_coord(primary,secondary,cam,persp)
-- get point at secondary=0
local offs = primary-cam
local x = offs*2 + 128
local y
if persp & 0x80 == 0x80 then
-- horizontal --
y = offs + 160
else
-- vertical --
y = 160 - offs
end
-- adjust point for secondary
if persp & 0x80 == 0x80 then
x = x - (secondary*2)
else
x = x + (secondary*2)
end
y = y + secondary
return x,y
end
-- main function
framecount = 0
function main()
emu.clearScreen();
-- only run if nmi vector is to main game
if emu.readWord(0x09, emu.memType.cpuDebug, false) ~= 0xa9cd then return end
-- get game state information
local level = readcpu(0x1c)
local world = readcpu(0x26)
local bait_index = readcpu(0x03c8)
local last_char = readcpu(0x0195)
local last_item = readcpu(0x0196)
local teleport_block = readcpu(0x0198)
local bait_flags = emu.readWord(0x03c5,emu.memType.cpuDebug,false)
local correct_figure = readcpu(0x03c7)
local correct_figure_index = readcpu(0x03c9)
local cam_coord_full = emu.readWord(0xd6,emu.memType.cpuDebug, false)
local cam_coord = cam_coord_full & 0xfff
local cam_sector = cam_coord_full >> 12
local world_base = readprglittle(2, 0xcf56 + world*2)
local sector_screens = readcpu(0xda)
local sector_persp = sector_screens & 0x80
sector_screens = sector_screens & 0x7f
local sector_cmds = readcpu(0x06e8)
local sector_cmd_base = emu.readWord(0x06e9,emu.memType.cpuDebug,false)
-- draw sector commands
do
local cmdptr = sector_cmd_base
local cmds = sector_cmds
while cmds > 0 do
local cmdid = readprg(2,cmdptr)
if cmdid > 0x0f then break end
local cmd_coord_full = readprgbig(2,cmdptr+1)
local cmd_sector = cmd_coord_full >> 12
local cmd_coord = cmd_coord_full & 0xfff
-- get more detailed command info
local sec_coord = 0
local direction = nil
local diameter = nil
-- secondary coordinate?
if cmdid == 5 or cmdid == 6 or cmdid == 7 or cmdid >= 9 then
sec_coord = emu.read(getprg(2,cmdptr+3),emu.memType.prgRom,true)
end
-- direction?
if cmdid == 3 then
direction = readprg(2,cmdptr+3)
elseif cmdid >= 9 then
direction = readprg(2,cmdptr+4)
end
-- diameter?
if cmdid == 6 or cmdid == 7 then
diameter = readprg(2,cmdptr+4)
end
if diameter then
-- draw a box with diameter
local x1,y1 = convert_coord(cmd_coord-diameter,sec_coord-diameter,cam_coord,sector_persp)
local x2,y2 = convert_coord(cmd_coord+diameter,sec_coord-diameter,cam_coord,sector_persp)
local x3,y3 = convert_coord(cmd_coord+diameter,sec_coord+diameter,cam_coord,sector_persp)
local x4,y4 = convert_coord(cmd_coord-diameter,sec_coord+diameter,cam_coord,sector_persp)
emu.drawLine(x1,y1, x2,y2, 0xff00ff)
emu.drawLine(x2,y2, x3,y3, 0xff00ff)
emu.drawLine(x3,y3, x4,y4, 0xff00ff)
emu.drawLine(x4,y4, x1,y1, 0xff00ff)
-- draw string describing the item
local strx = math.min(x1,x2,x3,x4)+2
local stry = math.min(y1,y2,y3,y4)-12
local item = readprg(2,cmdptr+5)
local str
local strbg = 0x7f000000
local strcol = 0xffffff
if cmdid == 6 then
local bait = readcpu(0x019a+item+bait_index)
if bait > 0x0f then
str = "Already got"
else
str = bait_names[bait+1]
end
if bait == correct_figure and framecount % 20 >= 10 then
strbg = 0x7fbfbf00
end
elseif cmdid == 7 then
local unav = item == last_item
item = item & 0x7f
if item > 0x06 then
str = "Invalid"
else
str = good_stuff_names[item+1]
end
if unav then
strx = strx - 20
str = str.." (unavailable)"
end
end
emu.drawString(strx,stry,str,strcol,strbg)
elseif direction then
-- draw an arrow
local x,y = convert_coord(cmd_coord,sec_coord,cam_coord,sector_persp)
local xend,yend
local xa1,ya1,xa2,ya2
if sector_persp == 0x80 then direction = (direction+2)&7 end
if direction == 0 then
-- north
xend = x + 20
yend = y - 10
xa1 = xend - 8
ya1 = yend + 2
xa2 = xend - 4
ya2 = yend + 5
elseif direction == 2 then
-- east
xend = x + 20
yend = y + 10
xa1 = xend - 8
ya1 = yend - 2
xa2 = xend - 4
ya2 = yend - 5
elseif direction == 4 then
-- south
xend = x - 20
yend = y + 10
xa1 = xend + 8
ya1 = yend - 2
xa2 = xend + 4
ya2 = yend - 5
elseif direction == 6 then
-- west
xend = x - 20
yend = y - 10
xa1 = xend + 8
ya1 = yend + 2
xa2 = xend + 4
ya2 = yend + 5
end
emu.drawLine(x,y,xend,yend,0xff00ff)
emu.drawLine(xend,yend,xa1,ya1,0xff00ff)
emu.drawLine(xend,yend,xa2,ya2,0xff00ff)
-- output string
local strx = math.min(x,xend) - 10
local stry = math.min(y,yend) - 12
local str
local strbg = 0x7f000000
local strcol = 0xffffff
if cmdid == 0x0b then
str = "Blocked"
elseif cmdid == 0x0c then
str = "Exit"
elseif cmdid == 0x0d then
str = "Jail exit"
elseif cmdid == 0x0e then
if teleport_block == 0x0a then
str = "Teleporter"
else
strx = strx - 10
str = string.format("Blocked teleporter (%02X)",teleport_block)
end
elseif cmdid == 0x0f then
str = "Unknown door $f"
elseif cmdid == 0x09 then
local charid = readprg(2,cmdptr+0x0e)
if last_char == charid then
strx = strx - 20
str = "Unavailable character"
else
str = "Character"
end
elseif cmdid == 0x0a then
local figix = readprg(2,cmdptr+0x0d)
if figix == correct_figure_index and framecount % 20 >= 10 then
strbg = 0x7f00ffff
end
strx = strx - 10
if figix == correct_figure_index then
strx = strx - 10
if bait_flags & (1<<correct_figure) == 0 and framecount % 150 >= 75 then
strx = strx - 20
str = "...but you need a " .. bait_names[correct_figure+1] .. "."
else
str = figure_names[correct_figure+1] .. " is here!"
end
else
str = "Historical figure"
end
end
emu.drawString(strx,stry,str,strcol,strbg)
elseif cmdid ~= 8 then
-- otherwise just draw a line through the thing (ignore crossroads)
local x,y = convert_coord(cmd_coord,sec_coord,cam_coord,sector_persp)
if sector_persp == 0x80 then
emu.drawLine(x-512,y+256,x+512,y-256,0xff00ff)
else
emu.drawLine(x-512,y-256,x+512,y+256,0xff00ff)
end
emu.drawString(x,y-12,cmdid,0xffffff,0x000000)
end
-- next command
cmdptr = cmdptr + readcpu(0xafc1 + cmdid)
cmds = cmds-1
end
end
-- camera info
emu.drawString(4,212,string.format("Camera: %i:%03X",cam_sector,cam_coord),0xffffff,0x9f0000ff)
framecount = framecount + 1
end
-- init
emu.addEventCallback(main, emu.eventType.startFrame)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment