From 52bdebfc8117d585756e595f2f3194798c41c562 Mon Sep 17 00:00:00 2001 From: empathicqubit Date: Mon, 3 May 2021 03:23:04 -0400 Subject: [PATCH] Find the exits by moving the characters and camera in a grid pattern --- .gitignore | 2 + README.md | 1 + game.lua | 171 ++++++++++++++++++++++++++++++++++- mem.lua | 8 ++ runner-process.lua | 3 +- runner-wrapper.lua | 4 +- runner.lua | 149 +++++++++++++------------------ spritelist.lua | 188 +++++++++++++++++++++------------------ state-test.lua | 22 +++-- tools/status-overlay.lua | 2 +- 10 files changed, 365 insertions(+), 185 deletions(-) diff --git a/.gitignore b/.gitignore index b5f1d50..03eefcb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +*.lsmv +!pool/*.lsmv *.log catchem/ state/ diff --git a/README.md b/README.md index dc8d837..ce1ce72 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ Located at [tools/bsnes-launcher.lua](tools/bsnes-launcher.lua), this script giv * [Serpent](https://github.com/pkulchenko/serpent) * [LibDeflate](https://github.com/SafeteeWoW/LibDeflate) * [watchexec](https://github.com/watchexec/watchexec/blob/main/LICENSE) +* [Billiam's Promise library](https://github.com/Billiam/promise.lua) ## TODO diff --git a/game.lua b/game.lua index ccdc267..0f06dc4 100644 --- a/game.lua +++ b/game.lua @@ -1,12 +1,14 @@ --Notes here -local memory, bit, memory2, input = memory, bit, memory2, input +local memory, bit, memory2, input, callback, movie = memory, bit, memory2, input, callback, movie local base = string.gsub(@@LUA_SCRIPT_FILENAME@@, "(.*[/\\])(.*)", "%1") +local Promise = nil + +local util = nil local mathFunctions = dofile(base.."/mathFunctions.lua") local config = dofile(base.."/config.lua") local spritelist = dofile(base.."/spritelist.lua") -local util = dofile(base.."/util.lua")() local mem = dofile(base.."/mem.lua") local _M = { leader = 0, @@ -39,6 +41,27 @@ function _M.getPositions() _M.screenY = (_M.partyY-256-_M.cameraY)*2 end +function _M.setPartyPosition(x, y) + memory.writeword(mem.addr.partyX, x) + memory.writeword(mem.addr.partyY, y) + _M.setSpritePosition(0, x, y) + _M.setSpritePosition(1, x, y) +end + +function _M.setCameraPosition(x, y) + memory.writeword(mem.addr.cameraX, x) + memory.writeword(mem.addr.cameraY, y) + memory.writeword(mem.addr.cameraX2, x) + memory.writeword(mem.addr.cameraY2, y) +end + +function _M.setSpritePosition(index, x, y) + local offsets = mem.offset.sprite + local spriteBase = mem.addr.spriteBase + index * mem.size.sprite + memory.writeword(spriteBase + offsets.x, x) + memory.writeword(spriteBase + offsets.y, y) +end + function _M.getBananas() local bananas = memory.readword(0x7e08bc) return bananas @@ -54,6 +77,126 @@ function _M.getKremCoins() return krem end +function _M.getAreaWidth() + return memory.readword(mem.addr.areaWidth) + 256 +end + +function _M.getAreaHeight() + return memory.readword(mem.addr.areaHeight) +end + +function _M.getAreaLength() + return memory.readword(mem.addr.areaLength) +end + +local onFrameAdvancedQueue = {} +function _M.advanceFrame() + local promise = Promise.new() + table.insert(onFrameAdvancedQueue, promise) + return promise +end + +local function processFrameAdvanced() + for i=#onFrameAdvancedQueue,1,-1 do + table.remove(onFrameAdvancedQueue, i):resolve() + end +end + +local onSetRewindQueue = {} +function _M.setRewindPoint() + local promise = Promise.new() + table.insert(onSetRewindQueue, promise) + movie.unsafe_rewind() + return promise +end + +local function processSetRewind(state) + for i=#onSetRewindQueue,1,-1 do + table.remove(onSetRewindQueue, i):resolve(state) + end +end + +local onRewindQueue = {} +function _M.rewind(rew) + local promise = Promise.new() + movie.unsafe_rewind(rew) + table.insert(onRewindQueue, promise) + return promise +end + +local function processRewind() + for i=#onRewindQueue,1,-1 do + local promise = table.remove(onRewindQueue, i) + promise:resolve() + end +end + +local function findPreferredExitLoop(frame, searchX, searchY, found, uniqueExits) + return _M.advanceFrame():next(function() + frame = frame + 1 + if frame % 2 ~=0 then + return + end + + local areaWidth = _M.getAreaWidth() + memory.writebyte(0x7e19ce, 0x16) + memory.writebyte(0x7e0e12, 0x99) + memory.writebyte(0x7e0e70, 0x99) + local sprites = _M.getSprites() + for i=1,#sprites,1 do + local sprite = sprites[i] + local name = spritelist.SpriteNames[sprite.control] + if sprite.control == spritelist.GoodSprites.goalTarget or + sprite.control == spritelist.GoodSprites.areaExit then + found = true + uniqueExits[sprite.y * areaWidth + sprite.x] = sprite + end + end + _M.setPartyPosition(searchX, searchY) + _M.setCameraPosition(searchX, searchY) + searchX = searchX + 0x100 + + if searchX > areaWidth then + searchX = 0 + searchY = searchY + 0xe0 + if searchY > _M.getAreaHeight() then + table.sort(uniqueExits, function(a, b) + return a.control < b.control + end) + + -- Return upper right corner if we can't find anything + if found then + for id,sprite in pairs(uniqueExits) do + return { x = sprite.x, y = sprite.y } + end + else + return { x = areaWidth, y = 0} + end + end + end + end):next(function(ret) + if ret == nil then + return findPreferredExitLoop(frame, searchX, searchY, found, uniqueExits) + else + return ret + end + end) +end + +function _M.findPreferredExit() + local point = nil + local result = nil + return _M.setRewindPoint():next(function(p) + point = p + return findPreferredExitLoop(0, 0, 0, false, {}) + end):next(function(r) + result = r + return _M.rewind(point) + end):next(function() + return result + end) +end + function _M.getGoalHit() local sprites = _M.getSprites() for i=1,#sprites,1 do @@ -454,7 +597,16 @@ local function registerHandler(space, regname, addr, callback) }) end +local inputHandler = nil +local setRewindHandler = nil +local rewindHandler = nil function _M.unregisterHandlers() + callback.unregister('input', inputHandler) + callback.unregister('set_rewind', setRewindHandler) + callback.unregister('post_rewind', rewindHandler) + inputHandler = nil + setRewindHandler = nil + rewindHandler = nil for i=#handlers,1,-1 do local handler = table.remove(handlers, i) handler.unregisterFn(handler.space, handler.addr, handler.fn) @@ -462,6 +614,13 @@ function _M.unregisterHandlers() end function _M.registerHandlers() + if inputHandler ~= nil then + error("Only call register handlers once") + end + + inputHandler = callback.register('input', processFrameAdvanced) + setRewindHandler = callback.register('set_rewind', processSetRewind) + rewindHandler = callback.register('post_rewind', processRewind) registerHandler(memory2.BUS, 'registerwrite', 0xb517b2, processAreaLoad) registerHandler(memory2.WRAM, 'registerread', 0x06b1, processMapLoad) for i=2,22,1 do @@ -469,4 +628,10 @@ function _M.registerHandlers() end end -return _M +return function(promise) + Promise = promise + if util == nil then + util = dofile(base.."/util.lua")(Promise) + end + return _M +end \ No newline at end of file diff --git a/mem.lua b/mem.lua index 2f194dd..d31fb50 100644 --- a/mem.lua +++ b/mem.lua @@ -6,8 +6,16 @@ local _M = { verticalPointer = 0xc414, tiledataPointer = 0x7e0098, haveBoth = 0x7e08c2, + ---Height in game units for vertical levels, width for horizontal + areaLength = 0x7e17b4, + ---This is always the traditional width no matter the level type + areaWidth = 0x7e0afc, + ---This is always the traditional height no matter the level type + areaHeight = 0x7e0afe, cameraX = 0x7e17ba, cameraY = 0x7e17c0, + cameraX2 = 0x7e0ad7, + cameraY2 = 0x7e0adb, leadChar = 0x7e08a4, partyX = 0x7e0a2a, partyY = 0x7e0a2c, diff --git a/runner-process.lua b/runner-process.lua index b164db8..87c982c 100644 --- a/runner-process.lua +++ b/runner-process.lua @@ -169,5 +169,6 @@ outFile:close() print(string.format('Wrote init to output at %d', ts)) waiter:next(waitLoop):catch(function(error) - print('ERROR: '..error) + print('Runner process error: '..error) + io.stderr:write('Runner process error: '..error..'\n') end) diff --git a/runner-wrapper.lua b/runner-wrapper.lua index 6793c69..ccfe051 100644 --- a/runner-wrapper.lua +++ b/runner-wrapper.lua @@ -102,7 +102,9 @@ end return function(promise) -- FIXME Should this be a global??? Promise = promise - util = dofile(base.."/util.lua")(Promise) + if util == nil then + util = dofile(base.."/util.lua")(Promise) + end -- FIXME Maybe don't do this in the "constructor"? if util.isWin then util.downloadFile('https://github.com/watchexec/watchexec/releases/download/1.13.1/watchexec-1.13.1-x86_64-pc-windows-gnu.zip', base..'/watchexec.zip') diff --git a/runner.lua b/runner.lua index 8ca6b4a..4034ad5 100644 --- a/runner.lua +++ b/runner.lua @@ -5,7 +5,7 @@ local base = string.gsub(@@LUA_SCRIPT_FILENAME@@, "(.*[/\\])(.*)", "%1") local Promise = nil local config = dofile(base.."/config.lua") -local game = dofile(base.."/game.lua") +local game = nil local mathFunctions = dofile(base.."/mathFunctions.lua") local util = dofile(base.."/util.lua")() @@ -216,18 +216,6 @@ local function displayGenome(genome) gui.renderctx.setnull() end -local function advanceFrame(_M) - local promise = Promise.new() - table.insert(_M.onFrameAdvancedHandler, promise) - return promise -end - -local function processFrameAdvanced(_M) - for i=#_M.onFrameAdvancedHandler,1,-1 do - table.remove(_M.onFrameAdvancedHandler, i):resolve() - end -end - local buttons = nil local buttonCtx = gui.renderctx.new(500, 70) local function displayButtons(_M) @@ -286,10 +274,11 @@ local function displayForm(_M) formCtx:clear() gui.rectangle(0, 0, 500, guiHeight, 1, 0x00ffffff, 0xbb000000) --gui.circle(game.screenX-84, game.screenY-84, 192 / 2, 1, 0x50000000) - - local rightmost = _M.rightmost[_M.currentArea] - if rightmost == nil then - rightmost = 0 + + local areaInfo = _M.areaInfo[_M.currentArea] + local distanceTraversed = 0 + if areaInfo ~= nil then + distanceTraversed = areaInfo.startDistance - areaInfo.shortest end gui.text(5, 30, "Timeout: " .. _M.timeout) @@ -307,7 +296,7 @@ local function displayForm(_M) gui.text(230, 65, "Damage: " .. _M.partyHitCounter) gui.text(230, 80, "PowerUp: " .. _M.powerUpCounter) gui.text(320, 65, string.format("Current Area: %04x", _M.currentArea)) - gui.text(320, 80, "Rightmost: "..rightmost) + gui.text(320, 80, string.format("Traveled: %d", distanceTraversed)) displayButtons(_M) formCtx:set() @@ -417,24 +406,6 @@ local function fitnessAlreadyMeasured(_M) return genome.fitness ~= 0 end -local rewinds = {} -local rew = movie.to_rewind(config.NeatConfig.Filename) -local function rewind() - local promise = Promise.new() - movie.unsafe_rewind(rew) - table.insert(rewinds, promise) - return promise -end - -local function rewound() - frame = 0 - lastFrame = 0 - for i=#rewinds,1,-1 do - local promise = table.remove(rewinds, i) - promise:resolve() - end -end - local function newNeuron() local neuron = {} neuron.incoming = {} @@ -481,6 +452,13 @@ local function generateNetwork(genome) genome.network = network end +local rew = movie.to_rewind(config.NeatConfig.Filename) +local function rewind() + return game.rewind(rew):next(function() + frame = 0 + lastFrame = 0 + end) +end local function initializeRun(_M) settings.set_speed("turbo") @@ -493,7 +471,7 @@ local function initializeRun(_M) exec('enable-sound '..enableSound) gui.subframe_update(false) - return rewind():next(function() + return rewind():next(function(preferredExit) if config.StartPowerup ~= nil then game.writePowerup(config.StartPowerup) end @@ -520,18 +498,49 @@ local function initializeRun(_M) _M.powerUpBefore = game.getBoth() _M.currentArea = game.getCurrentArea() _M.lastArea = _M.currentArea - _M.rightmost = { [_M.currentArea] = 0 } - _M.upmost = { [_M.currentArea] = 0 } + + for areaId,areaInfo in pairs(_M.areaInfo) do + areaInfo.shortest = areaInfo.startDistance + end + local genome = _M.currentSpecies.genomes[_M.currentGenomeIndex] generateNetwork(genome) evaluateCurrent(_M) end) end +local function getDistanceTraversed(areaInfo) + local distanceTraversed = 0 + for areaId,areaInfo in pairs(areaInfo) do + distanceTraversed = areaInfo.startDistance - areaInfo.shortest + end + return distanceTraversed +end + local function mainLoop(_M, genome) - return advanceFrame(_M):next(function() + return game.advanceFrame():next(function() + local nextArea = game.getCurrentArea() + if nextArea ~= _M.lastArea then + _M.lastArea = nextArea + game.onceAreaLoaded(function() + _M.timeout = _M.timeout + 60 * 5 + _M.currentArea = nextArea + _M.lastArea = _M.currentArea + end) + elseif _M.currentArea == _M.lastArea and _M.areaInfo[_M.currentArea] == nil then + message(_M, 'Searching for the main exit in this area') + return game.findPreferredExit():next(function(preferredExit) + local startDistance = math.floor(math.sqrt((preferredExit.y - game.partyY) ^ 2 + (preferredExit.x - game.partyX) ^ 2)) + _M.areaInfo[_M.currentArea] = { + startDistance = startDistance, + preferredExit = preferredExit, + shortest = startDistance, + } + end) + end + end):next(function() if lastFrame + 1 ~= frame then - message(_M, string.format("We missed %d frames", frame - lastFrame), 0x00990000) + message(_M, string.format("We missed %d frames", frame - lastFrame), 0x00ff0000) end lastFrame = frame @@ -566,37 +575,16 @@ local function mainLoop(_M, genome) end end - local nextArea = game.getCurrentArea() - if nextArea ~= _M.lastArea then - _M.lastArea = nextArea - game.onceAreaLoaded(function() - _M.timeout = _M.timeout + 60 * 5 - _M.currentArea = nextArea - _M.lastArea = _M.currentArea - if _M.rightmost[_M.currentArea] == nil then - _M.rightmost[_M.currentArea] = 0 - _M.upmost[_M.currentArea] = 0 - end - end) - end - - if not game.vertical then - if game.partyX > _M.rightmost[_M.currentArea] then - _M.rightmost[_M.currentArea] = game.partyX - if _M.timeout < timeoutConst then - _M.timeout = timeoutConst - end - end - else - if game.partyY > _M.upmost[_M.currentArea] then - _M.upmost[_M.currentArea] = game.partyY + local areaInfo = _M.areaInfo[_M.currentArea] + if areaInfo ~= nil then + local exitDist = math.floor(math.sqrt((areaInfo.preferredExit.y - game.partyY) ^ 2 + (areaInfo.preferredExit.x - game.partyX) ^ 2)) + if exitDist < areaInfo.shortest then + areaInfo.shortest = exitDist if _M.timeout < timeoutConst then _M.timeout = timeoutConst end end end - -- FIXME Measure distance to target / area exit - -- We might not always be horizontal local hitTimer = game.getHitTimer(_M.lastBoth) @@ -651,20 +639,9 @@ local function mainLoop(_M, genome) local bumpPenalty = _M.bumps * 100 local powerUpBonus = _M.powerUpCounter * 100 - local most = 0 - if not game.vertical then - for k,v in pairs(_M.rightmost) do - most = most + v - end - most = most - _M.currentFrame / 2 - else - for k,v in pairs(_M.upmost) do - most = most + v - end - most = most - _M.currentFrame / 2 - end - - local fitness = bananaCoinsFitness - bumpPenalty - hitPenalty + powerUpBonus + most + game.getJumpHeight() / 100 + local distanceTraversed = getDistanceTraversed(_M.areaInfo) - _M.currentFrame / 2 + + local fitness = bananaCoinsFitness - bumpPenalty - hitPenalty + powerUpBonus + distanceTraversed + game.getJumpHeight() / 100 local lives = game.getLives() @@ -855,13 +832,11 @@ local function run(_M, species, generationIdx, genomeCallback) register(_M, 'input', function() frame = frame + 1 updateController() - processFrameAdvanced(_M) saveLoadInput(_M) end) register(_M, 'keyhook', function(key, state) keyhook(_M, key, state) end) - register(_M, 'post_rewind', rewound) input.keyhook("1", true) input.keyhook("4", true) @@ -885,6 +860,9 @@ end return function(promise) Promise = promise + if game == nil then + game = dofile(base.."/game.lua")(Promise) + end local _M = { currentGenerationIndex = 1, currentSpecies = nil, @@ -912,16 +890,13 @@ return function(promise) powerUpBefore = 0, currentArea = 0, lastArea = 0, - rightmost = {}, - upmost = {}, + areaInfo = {}, lastBoth = 0, onMessageHandler = {}, onSaveHandler = {}, onLoadHandler = {}, onRenderFormHandler = {}, - onFrameAdvancedHandler = {}, - } _M.onRenderForm = function(handler) diff --git a/spritelist.lua b/spritelist.lua index 31bacbb..bf62233 100644 --- a/spritelist.lua +++ b/spritelist.lua @@ -4,100 +4,114 @@ _M.Sprites = {} -- Make sure this list is sorted before initialization. _M.NeutralSprites = { - 0x0020, -- Krow egg fragments - 0x0060, -- Barrel fragments - 0x0064, -- Barrel fragments + krowEggFragments = 0x0020, + barrelFragments = 0x0060, + barrelFragments2 = 0x0064, -- Our heroes - 0x00e4, -- Diddy - 0x00e8, -- Dixie - 0x0100, -- Stars + diddy = 0x00e4, + dixie = 0x00e8, + stars = 0x0100, -- Items that require too much interaction - 0x01a4, -- Barrel - 0x01b0, -- Cannonball (immobile) - 0x01c0, -- Chest - 0x01bc, -- Small crate - 0x011c, -- Barrel - 0x013c, -- Cannon - 0x014c, -- Hook - 0x01b8, -- TNT + barrel = 0x01a4, -- Barrel + cannonball = 0x01b0, + chest = 0x01c0, + smallCrate = 0x01bc, + barrel2 = 0x011c, + cannon = 0x013c, + hook = 0x014c, + tnt = 0x01b8, -- Inert - 0x0168, -- Goal pole - 0x016c, -- Goal roulette - 0x0160, -- Goal base - 0x0164, -- Goal barrel + goalPole = 0x0168, + goalroulette = 0x016c, + goalBase = 0x0160, + goalBarrel = 0x0164, - 0x0238, -- Pow - 0x023c, -- Exploding crate - 0x0258, -- No Animals Sign + pow = 0x0238, + explodingCrate = 0x023c, + noAnimalsSign = 0x0258, } -- Make sure this list is sorted before initialization. _M.GoodSprites = { -- Destinations - 0x0094, -- Area exit - 0x00b0, -- Goal target + areaExit = 0x0094, + goalTarget = 0x00b0, - 0x0120, -- Bonus barrel - 0x0128, -- Hot air balloon - 0x0140, -- Launch barrel - 0x0148, -- Animal crate - 0x0150, -- Invincibility barrel - 0x0154, -- Midpoint - 0x015c, -- Banana Coin/Kremkoin/DK Coin - 0x0170, -- Banana bunch - 0x0174, -- KONG letters - 0x0178, -- xUP balloon + bonusBarrel = 0x0120, + hotAirBalloon = 0x0128, + launchBarrel = 0x0140, + animalCrate = 0x0148, + invincibilityBarrel = 0x0150, + midpoint = 0x0154, + allCoins = 0x015c, -- Banana Coin/Kremkoin/DK Coin + bananaBunch = 0x0170, + kongLetter = 0x0174, + upBalloon = 0x0178, -- xUP balloon -- Animals - 0x0190, -- Squitter - 0x0194, -- Rattly - 0x0198, -- Squawks - 0x019c, -- Rambi - 0x0304, -- Clapper + squitter = 0x0190, + rattly = 0x0194, + squawks = 0x0198, + rambi = 0x019c, + clapper = 0x0304, - 0x01a8, -- DK Barrel label + dkBarrelLabel = 0x01a8, - 0x01b4, -- Krow's eggs + krowEgg = 0x01b4, - 0x0220, -- Flitter (used as unavoidable platforms in some levels) - 0x02d4, -- Krochead (red and green) + flitter = 0x0220, + krocheadAllColors = 0x02d4, } -- Currently not used. _M.BadSprites = { -- Baddies - 0x006c, -- Kannon - 0x01ac, -- Klobber (yellow and green) - 0x01d0, -- Kannon's fodder (Ball/barrel) - 0x01d8, -- Krusha - 0x01dc, -- Click-Clack - 0x01e4, -- Neek - 0x01ec, -- Klomp - 0x01e8, -- Klobber (awake) - 0x01f0, -- Klampon - 0x01f8, -- Flotsam - 0x0200, -- Klinger - 0x0208, -- Puftup - 0x0218, -- Zinger (red and yellow) - 0x0214, -- Mini-Necky - 0x020c, -- Lockjaw - 0x021c, -- Kaboing - 0x0224, -- Krow (Boss) - 0x025c, -- Krook (very large) + kannon = 0x006c, + klobberAllColors = 0x01ac, + kannonFodder = 0x01d0, + krusha = 0x01d8, + clickClack = 0x01dc, + neek = 0x01e4, + klomp = 0x01ec, + klobberAwake = 0x01e8, + klampon = 0x01f0, + flotsam = 0x01f8, + klinger = 0x0200, + puftup = 0x0208, + zingerAllColors = 0x0218, + miniNecky = 0x0214, + lockjaw = 0x020c, + kaboing = 0x021c, + krow = 0x0224, -- Boss + krook = 0x025c, } +_M.SpriteNames = {} + +function _M.InitSpriteNames() + for v,k in pairs(_M.GoodSprites) do + _M.SpriteNames[k] = v + end + for v,k in pairs(_M.BadSprites) do + _M.SpriteNames[k] = v + end + for v,k in pairs(_M.NeutralSprites) do + _M.SpriteNames[k] = v + end +end + function _M.InitSpriteList() - for i=1,#_M.GoodSprites,1 do - _M.Sprites[_M.GoodSprites[i]] = 1 + for k,v in pairs(_M.GoodSprites) do + _M.extSprites[v] = 1 end - for i=1,#_M.BadSprites,1 do - _M.Sprites[_M.BadSprites[i]] = -1 + for k,v in pairs(_M.BadSprites) do + _M.extSprites[v] = -1 end - for i=1,#_M.NeutralSprites,1 do - _M.Sprites[_M.NeutralSprites[i]] = 0 + for k,v in pairs(_M.NeutralSprites) do + _M.extSprites[v] = 0 end end @@ -108,21 +122,21 @@ _M.ExtNeutralSprites = { } _M.ExtGoodSprites = { - 0xe0, -- banana - 0xe1, -- banana - 0xe2, -- banana - 0xe3, -- banana - 0xe4, -- banana - 0xe5, -- banana - 0xe6, -- banana - 0xe7, -- banana - 0xe8, -- banana - 0xe9, -- banana - 0xea, -- banana - 0xeb, -- banana - 0xec, -- banana - 0xed, -- banana - 0xee, -- banana + banana01 = 0xe0, -- banana + banana02 = 0xe1, -- banana + banana03 = 0xe2, -- banana + banana04 = 0xe3, -- banana + banana05 = 0xe4, -- banana + banana06 = 0xe5, -- banana + banana07 = 0xe6, -- banana + banana08 = 0xe7, -- banana + banana09 = 0xe8, -- banana + banana10 = 0xe9, -- banana + banana11 = 0xea, -- banana + banana12 = 0xeb, -- banana + banana13 = 0xec, -- banana + banana14 = 0xed, -- banana + banana15 = 0xee, -- banana } -- Currently not used. @@ -130,14 +144,14 @@ _M.ExtBadSprites = { } function _M.InitExtSpriteList() - for i=1,#_M.ExtGoodSprites,1 do - _M.extSprites[_M.ExtGoodSprites[i]] = 1 + for k,v in pairs(_M.ExtGoodSprites) do + _M.extSprites[v] = 1 end - for i=1,#_M.ExtBadSprites,1 do - _M.extSprites[_M.ExtBadSprites[i]] = -1 + for k,v in pairs(_M.ExtBadSprites) do + _M.extSprites[v] = -1 end - for i=1,#_M.ExtNeutralSprites,1 do - _M.extSprites[_M.ExtNeutralSprites[i]] = 0 + for k,v in pairs(_M.ExtNeutralSprites) do + _M.extSprites[v] = 0 end end diff --git a/state-test.lua b/state-test.lua index 641ed81..8286489 100644 --- a/state-test.lua +++ b/state-test.lua @@ -1,6 +1,18 @@ -print(string.hex(bit.compose(0xef, 0xbe))) -local base = string.gsub(@@LUA_SCRIPT_FILENAME@@, "(.*[/\\])(.*)", "%1") -local game = dofile(base.."/game.lua") +local memory, movie, utime, callback, set_timer_timeout = memory, movie, utime, callback, set_timer_timeout -function on_input() -end \ No newline at end of file +local base = string.gsub(@@LUA_SCRIPT_FILENAME@@, "(.*[/\\])(.*)", "%1") +local Promise = dofile(base.."/promise.lua") +callback.register('timer', function() + Promise.update() + set_timer_timeout(1) +end) +set_timer_timeout(1) +local game = dofile(base.."/game.lua")(Promise) +local util = dofile(base.."/util.lua")(Promise) + +game.registerHandlers() + +game.findPreferredExit():next(function(exit) + io.stderr:write(util.table_to_string(exit)) + io.stderr:write('\n') +end) \ No newline at end of file diff --git a/tools/status-overlay.lua b/tools/status-overlay.lua index aa4e221..460994c 100644 --- a/tools/status-overlay.lua +++ b/tools/status-overlay.lua @@ -9,7 +9,7 @@ print(warn) local util = dofile(base.."/util.lua")() local mem = dofile(base.."/mem.lua") local spritelist = dofile(base.."/spritelist.lua") -local game = dofile(base.."/game.lua") +local game = dofile(base.."/game.lua")() local config = dofile(base.."/config.lua") spritelist.InitSpriteList()