mirror of
https://github.com/a2-4am/4cade.git
synced 2026-10-24 10:02:31 +00:00
198 lines
5.8 KiB
Lua
198 lines
5.8 KiB
Lua
local replay = {}
|
|
|
|
local apple2 = require("apple2")
|
|
local test = require("test")
|
|
local util = require("util")
|
|
|
|
local GameDisplayNameAddr = 0x01fd9
|
|
local GameCountAddr = 0x01ff7
|
|
local AttractCounter = 0x0ffe4
|
|
|
|
mem = manager.machine.devices[':maincpu'].spaces['program']
|
|
a2 = { text = true, mixed = false, page2 = false, hires = false }
|
|
|
|
function handle_softsw(offset, data, mask)
|
|
local addr = offset
|
|
if addr == 0xC050 then a2.text = false
|
|
elseif addr == 0xC051 then a2.text = true
|
|
elseif addr == 0xC052 then a2.mixed = false
|
|
elseif addr == 0xC053 then a2.mixed = true
|
|
elseif addr == 0xC054 then a2.page2 = false
|
|
elseif addr == 0xC055 then a2.page2 = true
|
|
elseif addr == 0xC056 then a2.hires = false
|
|
elseif addr == 0xC057 then a2.hires = true
|
|
end
|
|
end
|
|
|
|
read_tap = mem:install_read_tap(0xC050, 0xC057, "a2_softsw_r", handle_softsw)
|
|
write_tap = mem:install_write_tap(0xC050, 0xC057, "a2_softsw_w", handle_softsw)
|
|
|
|
local last_shr_state = nil -- nil = unknown yet, forces first write to report
|
|
|
|
function handle_c029_write(offset, data, mask)
|
|
local shr_on = (data & 0x80) ~= 0
|
|
if shr_on ~= last_shr_state then
|
|
local pc = manager.machine.devices[':maincpu'].state['CURPC'].value
|
|
print(string.format("PC=%06X SHR graphics mode %s (C029=%02X)",
|
|
pc, shr_on and "shown" or "hidden", data))
|
|
last_shr_state = shr_on
|
|
end
|
|
end
|
|
|
|
c029_write_tap = mem:install_write_tap(0xC029, 0xC029, "c029_w", handle_c029_write)
|
|
|
|
function is_in_graphics_mode()
|
|
return not a2.text
|
|
end
|
|
|
|
function is_in_text_mode()
|
|
return a2.text
|
|
end
|
|
|
|
function replay.ScreenContains(s)
|
|
return apple2.GrabTextScreen():upper():find(s)
|
|
end
|
|
|
|
function replay.WaitForScreenContains(s, options)
|
|
util.WaitFor(
|
|
s,
|
|
function()
|
|
return replay.ScreenContains(s)
|
|
end,
|
|
options)
|
|
end
|
|
|
|
function replay.WaitForGraphicsMode(options, level)
|
|
if options == nil then options = {} end
|
|
if level == nil then level = 0 end
|
|
util.WaitFor("gfxmode", is_in_graphics_mode, options, level+1)
|
|
end
|
|
|
|
function replay.WaitForTextMode(options, level)
|
|
if options == nil then options = {} end
|
|
if level == nil then level = 0 end
|
|
util.WaitFor("textmode", is_in_text_mode, options, level+1)
|
|
end
|
|
|
|
function replay.WaitForAddressEquals(addr, val, options)
|
|
util.WaitFor(
|
|
"address",
|
|
function()
|
|
return apple2.ReadRAMDevice(addr) == val
|
|
end,
|
|
options)
|
|
end
|
|
|
|
function replay.GetGameCount()
|
|
local val = (apple2.ReadRAMDevice(GameCountAddr) - 0x30) * 100
|
|
val = val + (apple2.ReadRAMDevice(GameCountAddr+1) - 0x30) * 10
|
|
val = val + apple2.ReadRAMDevice(GameCountAddr+2) - 0x30
|
|
return val
|
|
end
|
|
|
|
function replay.GetSelectedGameDisplayName()
|
|
local addr = GameDisplayNameAddr
|
|
local len = 27
|
|
local str = ""
|
|
local c
|
|
for i = 1,len do
|
|
c = apple2.ReadRAMDevice(addr)
|
|
if c == 0x7f then break end
|
|
str = str .. string.char(c)
|
|
addr = addr + 1
|
|
end
|
|
return str:match'^()%s*$' and '' or str:match'^%s*(.*%S)'
|
|
|
|
end
|
|
|
|
-- Launch Total Replay, type to search, launch game, Ctrl-Reset
|
|
function replay.allgames(flagmask)
|
|
local games_f = assert(io.open(debug.getinfo(2, 'S').source:sub(2):match('(.*/)') .. "../res/GAMES.CONF", "r"))
|
|
local allgame_input = {}
|
|
local allgame_display = {}
|
|
io.input(games_f)
|
|
for line in io.lines() do
|
|
if not line:match("^#") then -- skip lines beginning with "#"
|
|
local flags, directory, display_name, year = line:match("([^,]+),([^=]+)=([^/]+)/?(.*)")
|
|
local include = true
|
|
if not flags then
|
|
include = false
|
|
else
|
|
if flagmask then
|
|
include = flags:match(flagmask)
|
|
end
|
|
end
|
|
if include then
|
|
-- Remove punctuation and spaces, and convert the remaining text to all uppercase letters
|
|
local input_name = display_name:gsub("%p", ""):gsub("%s", ""):upper()
|
|
allgame_input[#allgame_input + 1] = input_name
|
|
allgame_display[#allgame_display + 1] = (#allgame_display + 1) .. "/" .. display_name
|
|
end
|
|
end
|
|
end
|
|
assert(games_f:close())
|
|
--for k,v in pairs(allgame_display) do
|
|
-- print(k,v)
|
|
--end
|
|
local allgame_script = require("allgames-script")
|
|
test.Variants(
|
|
allgame_display,
|
|
function(idx, name)
|
|
name = name:gsub(idx .. "/", "")
|
|
replay.WaitForGraphicsMode()
|
|
local str = allgame_input[idx]
|
|
for i = 1, #str do
|
|
local c = str:sub(i, i)
|
|
apple2.Type(c)
|
|
emu.wait(1)
|
|
if replay.GetSelectedGameDisplayName() == name then break end
|
|
end
|
|
test.ExpectEquals(replay.GetSelectedGameDisplayName(), name, "display name")
|
|
apple2.ReturnKey()
|
|
replay.WaitForTextMode()
|
|
local game_script = allgame_script[name]
|
|
if game_script then
|
|
game_script()
|
|
else
|
|
emu.wait(1)
|
|
replay.WaitForGraphicsMode()
|
|
end
|
|
apple2.ControlReset()
|
|
emu.wait(1)
|
|
replay.WaitForGraphicsMode()
|
|
local display_name_after_reset = replay.GetSelectedGameDisplayName()
|
|
if display_name_after_reset ~= "Type to search, ? for help" then
|
|
test.ExpectEquals(display_name_after_reset, name, "display name after reset")
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
apple2.LeftArrowKey()
|
|
end
|
|
end)
|
|
end
|
|
|
|
return replay
|