Stage rulers. Try to hijack algorithm used to determine tile location
of characters.
This commit is contained in:
parent
c63f6a9325
commit
ee2198b93f
9 changed files with 1687 additions and 1542 deletions
5
.editorconfig
Normal file
5
.editorconfig
Normal file
|
@ -0,0 +1,5 @@
|
|||
[*]
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,3 +1,5 @@
|
|||
*.lsmv
|
||||
*.log
|
||||
catchem/
|
||||
state/
|
||||
crashsave*
|
||||
*.backup
|
||||
|
|
137
config.lua
137
config.lua
|
@ -1,69 +1,70 @@
|
|||
local _M = {}
|
||||
|
||||
--[[
|
||||
Change BizhawkDir to your BizHawk directory.
|
||||
--]]
|
||||
--_M.BizhawkDir = "C:/Users/mmill/Downloads/BizHawk-2.2/"
|
||||
_M.BizhawkDir = "X:/B2_BizHawkLab/BizHawk-2.2.2/"
|
||||
|
||||
_M.StateDir = _M.BizhawkDir .. "Lua/SNES/neat-mario/state/"
|
||||
_M.PoolDir = _M.BizhawkDir .. "Lua/SNES/neat-mario/pool/"
|
||||
|
||||
--[[
|
||||
At the moment the first in list will get loaded.
|
||||
Rearrange for other savestates. (will be redone soon)
|
||||
--]]
|
||||
_M.State = {
|
||||
"DP1.state", -- Donut Plains 1
|
||||
"YI1.state", -- Yoshi's Island 1
|
||||
"YI2.state", -- Yoshi's Island 2
|
||||
}
|
||||
|
||||
--[[
|
||||
Start game with specific powerup.
|
||||
0 = No powerup
|
||||
1 = Mushroom
|
||||
2 = Feather
|
||||
3 = Flower
|
||||
Comment out to disable.
|
||||
--]]
|
||||
_M.StartPowerup = 0
|
||||
|
||||
_M.NeatConfig = {
|
||||
--Filename = "DP1.state",
|
||||
Filename = _M.PoolDir .. _M.State[1],
|
||||
Population = 300,
|
||||
DeltaDisjoint = 2.0,
|
||||
DeltaWeights = 0.4,
|
||||
DeltaThreshold = 1.0,
|
||||
StaleSpecies = 15,
|
||||
MutateConnectionsChance = 0.25,
|
||||
PerturbChance = 0.90,
|
||||
CrossoverChance = 0.75,
|
||||
LinkMutationChance = 2.0,
|
||||
NodeMutationChance = 0.50,
|
||||
BiasMutationChance = 0.40,
|
||||
StepSize = 0.1,
|
||||
DisableMutationChance = 0.4,
|
||||
EnableMutationChance = 0.2,
|
||||
TimeoutConstant = 20,
|
||||
MaxNodes = 1000000,
|
||||
}
|
||||
|
||||
_M.ButtonNames = {
|
||||
"A",
|
||||
"B",
|
||||
"X",
|
||||
"Y",
|
||||
"Up",
|
||||
"Down",
|
||||
"Left",
|
||||
"Right",
|
||||
}
|
||||
|
||||
_M.BoxRadius = 6
|
||||
_M.InputSize = (_M.BoxRadius*2+1)*(_M.BoxRadius*2+1)
|
||||
|
||||
_M.Running = false
|
||||
|
||||
local _M = {}
|
||||
|
||||
--[[
|
||||
Change script dir to your script directory
|
||||
--]]
|
||||
_M.ScriptDir = "/media/removable/Main/user1000/neat-donk"
|
||||
|
||||
_M.StateDir = _M.ScriptDir .. "/state/"
|
||||
_M.PoolDir = _M.ScriptDir .. "/pool/"
|
||||
|
||||
--[[
|
||||
At the moment the first in list will get loaded.
|
||||
Rearrange for other savestates. (will be redone soon)
|
||||
--]]
|
||||
_M.State = {
|
||||
"PiratePanic.lsmv",
|
||||
}
|
||||
|
||||
--[[
|
||||
Start game with specific powerup.
|
||||
0 = No powerup
|
||||
1 = Mushroom
|
||||
2 = Feather
|
||||
3 = Flower
|
||||
Comment out to disable.
|
||||
--]]
|
||||
_M.StartPowerup = 0
|
||||
|
||||
_M.NeatConfig = {
|
||||
--Filename = "DP1.state",
|
||||
Filename = _M.PoolDir .. _M.State[1],
|
||||
Population = 300,
|
||||
DeltaDisjoint = 2.0,
|
||||
DeltaWeights = 0.4,
|
||||
DeltaThreshold = 1.0,
|
||||
StaleSpecies = 15,
|
||||
MutateConnectionsChance = 0.25,
|
||||
PerturbChance = 0.90,
|
||||
CrossoverChance = 0.75,
|
||||
LinkMutationChance = 2.0,
|
||||
NodeMutationChance = 0.50,
|
||||
BiasMutationChance = 0.40,
|
||||
StepSize = 0.1,
|
||||
DisableMutationChance = 0.4,
|
||||
EnableMutationChance = 0.2,
|
||||
TimeoutConstant = 20,
|
||||
MaxNodes = 1000000,
|
||||
}
|
||||
|
||||
_M.ButtonNames = {
|
||||
"B",
|
||||
"Y",
|
||||
"Select",
|
||||
"Start",
|
||||
"Up",
|
||||
"Down",
|
||||
"Left",
|
||||
"Right",
|
||||
"A",
|
||||
"X",
|
||||
"L",
|
||||
"R",
|
||||
}
|
||||
|
||||
_M.BoxRadius = 6
|
||||
_M.InputSize = (_M.BoxRadius*2+1)*(_M.BoxRadius*2+1)
|
||||
|
||||
_M.Running = true
|
||||
|
||||
return _M
|
330
donkutil.lua
330
donkutil.lua
|
@ -1,63 +1,65 @@
|
|||
util = require "util"
|
||||
|
||||
FG_COLOR = 0x00ffffff
|
||||
BG_COLOR = 0x99000000
|
||||
TILEDATA_POINTER = 0x7e0098
|
||||
TILE_SIZE = 32
|
||||
TILE_RADIUS = 4
|
||||
SPRITE_BASE = 0x7e0de2
|
||||
SOLID_LESS_THAN = 0x7e00a0
|
||||
DIDDY_X_VELOCITY = 0x7e0e02
|
||||
DIDDY_Y_VELOCITY = 0x7e0e06
|
||||
DIXIE_X_VELOCITY = 0x7e0e60
|
||||
DIXIE_Y_VELOCITY = 0x7e0e64
|
||||
CAMERA_X = 0x7e17ba
|
||||
CAMERA_Y = 0x7e17c0
|
||||
CAMERA_MODE = 0x7e054f
|
||||
TILE_COLLISION_MATH_POINTER = 0x7e17b2
|
||||
VERTICAL_POINTER = 0xc414
|
||||
PARTY_X = 0x7e0a2a
|
||||
PARTY_Y = 0x7e0a2c
|
||||
|
||||
count = 0
|
||||
detailsidx = -1
|
||||
jumping = false
|
||||
helddown = false
|
||||
floatmode = false
|
||||
rulers = true
|
||||
pokemon = false
|
||||
pokecount = 0
|
||||
showhelp = false
|
||||
locked = false
|
||||
lockdata = nil
|
||||
incsprite = 0
|
||||
fgcolor = 0x00ffffff
|
||||
bgcolor = 0x99000000
|
||||
function table_to_string(tbl)
|
||||
local result = "{"
|
||||
local keys = {}
|
||||
for k in pairs(tbl) do
|
||||
table.insert(keys, k)
|
||||
end
|
||||
table.sort(keys)
|
||||
for _, k in ipairs(keys) do
|
||||
local v = tbl[k]
|
||||
if type(v) == "number" and v == 0 then
|
||||
goto continue
|
||||
end
|
||||
party_tile_offset = 0
|
||||
party_y_ground = 0
|
||||
|
||||
-- Check the key type (ignore any numerical keys - assume its an array)
|
||||
if type(k) == "string" then
|
||||
result = result.."[\""..k.."\"]".."="
|
||||
end
|
||||
last_called = 0
|
||||
function set_party_tile_offset (val)
|
||||
if party_tile_offset_debounce == val then
|
||||
return
|
||||
end
|
||||
local sec, usec = utime()
|
||||
last_called = sec * 1000000 + usec
|
||||
party_tile_offset_debounce = val
|
||||
end
|
||||
|
||||
-- Check the value type
|
||||
if type(v) == "table" then
|
||||
result = result..table_to_string(v)
|
||||
elseif type(v) == "boolean" then
|
||||
result = result..tostring(v)
|
||||
else
|
||||
result = result.."\""..v.."\""
|
||||
end
|
||||
result = result..",\n"
|
||||
::continue::
|
||||
end
|
||||
-- Remove leading commas from the result
|
||||
if result ~= "" then
|
||||
result = result:sub(1, result:len()-1)
|
||||
end
|
||||
return result.."}"
|
||||
function text(x, y, msg)
|
||||
gui.text(x, y, msg, FG_COLOR, BG_COLOR)
|
||||
end
|
||||
|
||||
function on_keyhook (key, state)
|
||||
if not helddown and state["value"] == 1 then
|
||||
if not helddown and state.value == 1 then
|
||||
if key == "1" and not locked then
|
||||
helddown = true
|
||||
detailsidx = detailsidx - 1
|
||||
if detailsidx < -1 then
|
||||
detailsidx = 20
|
||||
detailsidx = 22
|
||||
end
|
||||
elseif key == "2" and not locked then
|
||||
helddown = true
|
||||
detailsidx = detailsidx + 1
|
||||
if detailsidx > 20 then
|
||||
if detailsidx > 22 then
|
||||
detailsidx = -1
|
||||
end
|
||||
elseif key == "3" then
|
||||
|
@ -80,89 +82,90 @@ function on_keyhook (key, state)
|
|||
elseif key == "7" then
|
||||
helddown = true
|
||||
floatmode = not floatmode
|
||||
elseif key == "8" then
|
||||
helddown = true
|
||||
rulers = not rulers
|
||||
elseif key == "0" then
|
||||
showhelp = true
|
||||
end
|
||||
elseif state["value"] == 0 then
|
||||
elseif state.value == 0 then
|
||||
helddown = false
|
||||
showhelp = false
|
||||
end
|
||||
end
|
||||
|
||||
function on_input (subframe)
|
||||
jumping = input.get(0,0) ~= 0
|
||||
|
||||
if floatmode then
|
||||
memory.writebyte(0x7e19ce, 0x16)
|
||||
memory.writebyte(0x7e0e12, 0x99)
|
||||
memory.writebyte(0x7e0e70, 0x99)
|
||||
if input.get(0, 6) == 1 then
|
||||
memory.writeword(0x7e0e02, -0x5ff)
|
||||
memory.writeword(0x7e0e60, -0x5ff)
|
||||
memory.writeword(DIDDY_X_VELOCITY, -0x5ff)
|
||||
memory.writeword(DIXIE_X_VELOCITY, -0x5ff)
|
||||
|
||||
memory.writeword(0x7e0e06, 0)
|
||||
memory.writeword(0x7e0e64, 0)
|
||||
memory.writeword(DIDDY_Y_VELOCITY, 0)
|
||||
memory.writeword(DIXIE_Y_VELOCITY, 0)
|
||||
elseif input.get(0, 7) == 1 then
|
||||
memory.writeword(0x7e0e02, 0x5ff)
|
||||
memory.writeword(0x7e0e60, 0x5ff)
|
||||
memory.writeword(DIDDY_X_VELOCITY, 0x5ff)
|
||||
memory.writeword(DIXIE_X_VELOCITY, 0x5ff)
|
||||
|
||||
memory.writeword(0x7e0e06, 0)
|
||||
memory.writeword(0x7e0e64, 0)
|
||||
memory.writeword(DIDDY_Y_VELOCITY, 0)
|
||||
memory.writeword(DIXIE_Y_VELOCITY, 0)
|
||||
end
|
||||
|
||||
if input.get(0, 4) == 1 then
|
||||
memory.writeword(0x7e0e06, -0x05ff)
|
||||
memory.writeword(0x7e0e64, -0x05ff)
|
||||
memory.writeword(DIDDY_Y_VELOCITY, -0x05ff)
|
||||
memory.writeword(DIXIE_Y_VELOCITY, -0x05ff)
|
||||
elseif input.get(0, 5) == 1 then
|
||||
memory.writeword(0x7e0e06, 0x5ff)
|
||||
memory.writeword(0x7e0e64, 0x5ff)
|
||||
memory.writeword(DIDDY_Y_VELOCITY, 0x5ff)
|
||||
memory.writeword(DIXIE_Y_VELOCITY, 0x5ff)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function file_exists(name)
|
||||
local f=io.open(name,"r")
|
||||
if f~=nil then io.close(f) return true else return false end
|
||||
end
|
||||
|
||||
function get_sprite(base_addr)
|
||||
return {
|
||||
["control"] = memory.readword(base_addr),
|
||||
["draworder"] = memory.readword(base_addr + 0x02),
|
||||
["x"] = memory.readword(base_addr + 0x06),
|
||||
["y"] = memory.readword(base_addr + 0x0a),
|
||||
["jumpheight"] = memory.readword(base_addr + 0x0e),
|
||||
["style"] = memory.readword(base_addr + 0x12),
|
||||
["currentframe"] = memory.readword(base_addr + 0x18),
|
||||
["nextframe"] = memory.readword(base_addr + 0x1a),
|
||||
["state"] = memory.readword(base_addr + 0x1e),
|
||||
["velox"] = memory.readsword(base_addr + 0x20),
|
||||
["veloy"] = memory.readsword(base_addr + 0x24),
|
||||
["velomaxx"] = memory.readsword(base_addr + 0x26),
|
||||
["velomaxy"] = memory.readsword(base_addr + 0x2a),
|
||||
["motion"] = memory.readword(base_addr + 0x2e),
|
||||
["attr"] = memory.readword(base_addr + 0x30),
|
||||
["animnum"] = memory.readword(base_addr + 0x36),
|
||||
["remainingframe"] = memory.readword(base_addr + 0x38),
|
||||
["animcontrol"] = memory.readword(base_addr + 0x3a),
|
||||
["animreadpos"] = memory.readword(base_addr + 0x3c),
|
||||
["animcontrol2"] = memory.readword(base_addr + 0x3e),
|
||||
["animformat"] = memory.readword(base_addr + 0x40),
|
||||
["damage1"] = memory.readword(base_addr + 0x44),
|
||||
["damage2"] = memory.readword(base_addr + 0x46),
|
||||
["damage3"] = memory.readword(base_addr + 0x48),
|
||||
["damage4"] = memory.readword(base_addr + 0x4a),
|
||||
["damage5"] = memory.readword(base_addr + 0x4c),
|
||||
["damage6"] = memory.readword(base_addr + 0x4e),
|
||||
["spriteparam"] = memory.readword(base_addr + 0x58),
|
||||
base_addr = string.format("%04x", base_addr),
|
||||
control = memory.readword(base_addr),
|
||||
draworder = memory.readword(base_addr + 0x02),
|
||||
x = memory.readword(base_addr + 0x06),
|
||||
y = memory.readword(base_addr + 0x0a),
|
||||
jumpheight = memory.readword(base_addr + 0x0e),
|
||||
style = memory.readword(base_addr + 0x12),
|
||||
currentframe = memory.readword(base_addr + 0x18),
|
||||
nextframe = memory.readword(base_addr + 0x1a),
|
||||
state = memory.readword(base_addr + 0x1e),
|
||||
velox = memory.readsword(base_addr + 0x20),
|
||||
veloy = memory.readsword(base_addr + 0x24),
|
||||
velomaxx = memory.readsword(base_addr + 0x26),
|
||||
velomaxy = memory.readsword(base_addr + 0x2a),
|
||||
motion = memory.readword(base_addr + 0x2e),
|
||||
attr = memory.readword(base_addr + 0x30),
|
||||
animnum = memory.readword(base_addr + 0x36),
|
||||
remainingframe = memory.readword(base_addr + 0x38),
|
||||
animcontrol = memory.readword(base_addr + 0x3a),
|
||||
animreadpos = memory.readword(base_addr + 0x3c),
|
||||
animcontrol2 = memory.readword(base_addr + 0x3e),
|
||||
animformat = memory.readword(base_addr + 0x40),
|
||||
damage1 = memory.readword(base_addr + 0x44),
|
||||
damage2 = memory.readword(base_addr + 0x46),
|
||||
damage3 = memory.readword(base_addr + 0x48),
|
||||
damage4 = memory.readword(base_addr + 0x4a),
|
||||
damage5 = memory.readword(base_addr + 0x4c),
|
||||
damage6 = memory.readword(base_addr + 0x4e),
|
||||
spriteparam = memory.readword(base_addr + 0x58),
|
||||
}
|
||||
end
|
||||
|
||||
function sprite_details(idx)
|
||||
local base_addr = idx * 94 + 0x7e0e9e
|
||||
local base_addr = idx * 94 + SPRITE_BASE
|
||||
|
||||
local sprite = get_sprite(base_addr)
|
||||
|
||||
if sprite["control"] == 0 then
|
||||
gui.text(0, 0, "Sprite "..idx.." (Empty)", fgcolor, bgcolor)
|
||||
if sprite.control == 0 then
|
||||
text(0, 0, "Sprite "..idx.." (Empty)")
|
||||
incsprite = 0
|
||||
locked = false
|
||||
lockdata = nil
|
||||
|
@ -170,7 +173,7 @@ function sprite_details(idx)
|
|||
end
|
||||
|
||||
if incsprite ~= 0 then
|
||||
memory.writeword(base_addr + 0x36, sprite["animnum"] + incsprite)
|
||||
memory.writeword(base_addr + 0x36, sprite.animnum + incsprite)
|
||||
|
||||
lockdata = nil
|
||||
incsprite = 0
|
||||
|
@ -184,7 +187,7 @@ function sprite_details(idx)
|
|||
memory.writeregion(base_addr, 94, lockdata)
|
||||
end
|
||||
|
||||
gui.text(0, 0, "Sprite "..idx..(locked and " (Locked)" or "")..":\n\n"..table_to_string(sprite), fgcolor, bgcolor)
|
||||
text(0, 0, "Sprite "..idx..(locked and " (Locked)" or "")..":\n\n"..util.table_to_string(sprite))
|
||||
end
|
||||
|
||||
function on_paint (not_synth)
|
||||
|
@ -193,7 +196,7 @@ function on_paint (not_synth)
|
|||
local guiWidth, guiHeight = gui.resolution()
|
||||
|
||||
if showhelp then
|
||||
gui.text(0, 0, [[
|
||||
text(0, 0, [[
|
||||
Keyboard Help
|
||||
===============
|
||||
|
||||
|
@ -207,70 +210,156 @@ Sprite Details:
|
|||
|
||||
[6] Enable / Disable Pokemon mode (take screenshots of enemies)
|
||||
[7] Enable / Disable float mode (fly with up/down)
|
||||
]], fgcolor, bgcolor)
|
||||
[8] Enable / Disable stage tile rulers
|
||||
]])
|
||||
return
|
||||
end
|
||||
|
||||
gui.text(guiWidth - 75, 0, "Help [0]", fgcolor, bgcolor)
|
||||
|
||||
local stats = ""
|
||||
local toggles = ""
|
||||
|
||||
if pokemon then
|
||||
stats = stats.."Pokemon: "..pokecount.."\n"
|
||||
toggles = toggles..string.format("Pokemon: %d\n", pokecount)
|
||||
end
|
||||
|
||||
if floatmode then
|
||||
stats = stats.."Float on\n"
|
||||
toggles = toggles.."Float on\n"
|
||||
end
|
||||
|
||||
gui.text(0, guiHeight - 40, stats, fgcolor, bgcolor)
|
||||
text(0, guiHeight - 40, toggles)
|
||||
|
||||
stats = stats.."\nPokemon: "..pokecount
|
||||
local directions = {
|
||||
"Standard",
|
||||
"Blur",
|
||||
"Up"
|
||||
}
|
||||
|
||||
local cameraX = memory.readword(0x7e17ba) - 256
|
||||
local cameraY = memory.readword(0x7e17c0) - 256
|
||||
local cameraX = memory.readword(CAMERA_X) - 256
|
||||
local cameraY = memory.readword(CAMERA_Y) - 256
|
||||
local cameraDir = memory.readbyte(CAMERA_MODE)
|
||||
|
||||
local partyScreenX = (memory.readword(0x7e0a2a) - 256 - cameraX) * 2
|
||||
local partyScreenY = (memory.readword(0x7e0a2c) - 256 - cameraY) * 2
|
||||
local direction = directions[cameraDir+1]
|
||||
|
||||
if detailsidx ~= -1 then
|
||||
sprite_details(detailsidx)
|
||||
else
|
||||
gui.text(0, 0, "[1] <- Sprite Details Off -> [2]", fgcolor, bgcolor)
|
||||
end
|
||||
local vertical = memory.readword(TILE_COLLISION_MATH_POINTER) == VERTICAL_POINTER
|
||||
|
||||
gui.text(guiWidth - 200, guiHeight - 20, "Camera: "..tostring(cameraX)..","..tostring(cameraY), fgcolor, bgcolor)
|
||||
local stats = string.format([[
|
||||
%s camera %d,%d
|
||||
Vertical: %s
|
||||
Tile offset: %04x
|
||||
]], direction, cameraX, cameraY, vertical, party_tile_offset)
|
||||
|
||||
gui.text(partyScreenX, partyScreenY, "Party", fgcolor, bgcolor)
|
||||
text(guiWidth - 200, guiHeight - 60, stats)
|
||||
|
||||
local partyX = memory.readword(PARTY_X) - 256
|
||||
local partyY = memory.readword(PARTY_Y) - 256
|
||||
|
||||
text((partyX - cameraX) * 2, (partyY - cameraY) * 2 + 20, "Party")
|
||||
|
||||
local sprites = {}
|
||||
for idx = 0,20,1 do
|
||||
local base_addr = idx * 94 + 0x7e0e9e
|
||||
for idx = 0,22,1 do
|
||||
local base_addr = idx * 94 + SPRITE_BASE
|
||||
|
||||
local sprite = get_sprite(base_addr)
|
||||
|
||||
sprites[idx] = sprite
|
||||
|
||||
if sprite["control"] == 0 then
|
||||
if sprite.control == 0 then
|
||||
goto continue
|
||||
end
|
||||
|
||||
local spriteScreenX = (sprite["x"] - 256 - cameraX) * 2
|
||||
local spriteScreenY = (sprite["y"] - 256 - cameraY) * 2
|
||||
local spriteScreenX = (sprite.x - 256 - cameraX) * 2
|
||||
local spriteScreenY = (sprite.y - 256 - cameraY) * 2
|
||||
|
||||
local sprcolor = bgcolor
|
||||
local sprcolor = BG_COLOR
|
||||
if detailsidx == idx then
|
||||
sprcolor = 0x00ff0000
|
||||
end
|
||||
gui.text(spriteScreenX, spriteScreenY, sprite["animnum"]..","..sprite["attr"], fgcolor, sprcolor)
|
||||
gui.text(spriteScreenX, spriteScreenY, sprite.control..","..sprite.animnum..","..sprite.attr, FG_COLOR, sprcolor)
|
||||
|
||||
local filename = os.getenv("HOME").."/neat-donk/catchem/"..sprite["animnum"]..","..sprite["attr"]..".png"
|
||||
if pokemon and spriteScreenX > (guiWidth / 4) and spriteScreenX < (guiWidth / 4) * 3 and spriteScreenY > (guiHeight / 3) and spriteScreenY < guiHeight and not file_exists(filename) then
|
||||
local filename = os.getenv("HOME").."/neat-donk/catchem/"..sprite.animnum..","..sprite.attr..".png"
|
||||
if pokemon and spriteScreenX > (guiWidth / 4) and spriteScreenX < (guiWidth / 4) * 3 and spriteScreenY > (guiHeight / 3) and spriteScreenY < guiHeight and not util.file_exists(filename) then
|
||||
gui.screenshot(filename)
|
||||
pokecount = pokecount + 1
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
|
||||
if rulers and cameraX >= 0 then
|
||||
local halfWidth = math.floor(guiWidth / 2)
|
||||
local halfHeight = math.floor(guiHeight / 2)
|
||||
|
||||
local cameraTileX = math.floor(cameraX / TILE_SIZE)
|
||||
gui.line(0, halfHeight, guiWidth, halfHeight, BG_COLOR)
|
||||
for i = cameraTileX, cameraTileX + guiWidth / TILE_SIZE / 2,1 do
|
||||
gui.text((i * TILE_SIZE - cameraX) * 2, halfHeight, tostring(i), FG_COLOR, BG_COLOR)
|
||||
end
|
||||
|
||||
local cameraTileY = math.floor(cameraY / TILE_SIZE)
|
||||
gui.line(halfWidth, 0, halfWidth, guiHeight, BG_COLOR)
|
||||
for i = cameraTileY, cameraTileY + guiHeight / TILE_SIZE / 2,1 do
|
||||
gui.text(halfWidth, (i * TILE_SIZE - cameraY) * 2, tostring(i), FG_COLOR, BG_COLOR)
|
||||
end
|
||||
end
|
||||
|
||||
local tilePtr = memory.readhword(TILEDATA_POINTER)
|
||||
local solidLessThan = memory.readword(SOLID_LESS_THAN)
|
||||
|
||||
for x = -TILE_RADIUS, TILE_RADIUS, 1 do
|
||||
for y = -TILE_RADIUS, TILE_RADIUS, 1 do
|
||||
local offset = 0
|
||||
if vertical then
|
||||
offset = party_tile_offset + (y * 24 + x) * 2
|
||||
else
|
||||
offset = party_tile_offset + (x * 16 + y) * 2
|
||||
end
|
||||
|
||||
local tile = memory.readword(tilePtr + offset)
|
||||
|
||||
if tile == 0 or tile >= solidLessThan then
|
||||
goto continue
|
||||
end
|
||||
|
||||
local tileX = (math.floor(partyX / TILE_SIZE + x) * TILE_SIZE - cameraX)
|
||||
local tileY = (math.floor(party_y_ground / TILE_SIZE + y) * TILE_SIZE - cameraY)
|
||||
gui.text(tileX * 2, tileY * 2, string.format("%04x,%02x", offset & 0xffff, tile), FG_COLOR, 0x66888800)
|
||||
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
if detailsidx ~= -1 then
|
||||
sprite_details(detailsidx)
|
||||
else
|
||||
text(0, 20, "[1] <- Sprite Details Off -> [2]")
|
||||
end
|
||||
|
||||
text(guiWidth - 125, 20, "Help [Hold 0]")
|
||||
end
|
||||
|
||||
function tile_retrieval()
|
||||
local tile = math.floor(memory.getregister("y") / 2) * 2
|
||||
local newX = memory.readword(0x7e00a6)
|
||||
local partyX = memory.readword(PARTY_X)
|
||||
local oldX = partyX & 0x1f
|
||||
local partyY = memory.readword(PARTY_Y)
|
||||
|
||||
if oldX - 5 < newX and newX < oldX + 5 and
|
||||
not jumping and
|
||||
memory.readword(0x7e0034) == partyY then
|
||||
set_party_tile_offset(tile)
|
||||
party_y_ground = partyY - 256
|
||||
end
|
||||
end
|
||||
|
||||
function on_timer()
|
||||
local sec, usec = utime()
|
||||
local now = sec * 1000000 + usec
|
||||
if last_called + 100 * 1000 < now then
|
||||
party_tile_offset = party_tile_offset_debounce
|
||||
end
|
||||
|
||||
set_timer_timeout(100 * 1000)
|
||||
end
|
||||
|
||||
input.keyhook("1", true)
|
||||
|
@ -280,4 +369,9 @@ input.keyhook("4", true)
|
|||
input.keyhook("5", true)
|
||||
input.keyhook("6", true)
|
||||
input.keyhook("7", true)
|
||||
input.keyhook("0", true)
|
||||
input.keyhook("8", true)
|
||||
input.keyhook("0", true)
|
||||
|
||||
memory2.BUS:registerexec(TILE_RETRIEVAL, tile_retrieval)
|
||||
|
||||
set_timer_timeout(100 * 1000)
|
325
game.lua
325
game.lua
|
@ -1,164 +1,161 @@
|
|||
--Notes here
|
||||
config = require "config"
|
||||
spritelist = require "spritelist"
|
||||
local _M = {}
|
||||
|
||||
function _M.getPositions()
|
||||
partyX = memory.readword(0x7e0a2a) - 256
|
||||
partyY = memory.readword(0x7e0a2c) - 256
|
||||
|
||||
local cameraX = memory.readword(0x7e17ba) - 256
|
||||
local cameraY = memory.readword(0x7e17c0) - 256
|
||||
|
||||
_M.screenX = partyX-layer1x
|
||||
_M.screenY = partyY-layer1y
|
||||
end
|
||||
|
||||
function _M.getBananas()
|
||||
local bananas = memory.readword(0x7e08bc)
|
||||
return bananas
|
||||
end
|
||||
|
||||
function _M.getCoins()
|
||||
local coins = memory.readword(0x7e08ca)
|
||||
return coins
|
||||
end
|
||||
|
||||
function _M.getLives()
|
||||
local lives = memory.readsbyte(0x7e08be) + 1
|
||||
return lives
|
||||
end
|
||||
|
||||
function _M.writeLives(lives)
|
||||
memory.writebyte(0x7e08be, lives - 1)
|
||||
memory.writebyte(0x7e08c0, lives - 1)
|
||||
end
|
||||
|
||||
function _M.getPowerup()
|
||||
return 0
|
||||
end
|
||||
|
||||
function _M.writePowerup(powerup)
|
||||
return
|
||||
-- memory.writebyte(0x0019, powerup)
|
||||
end
|
||||
|
||||
|
||||
function _M.getHit(alreadyHit)
|
||||
return not alreadyHit and memory.readbyte(0x7e08be) < memory.readbyte(0x7e08c0)
|
||||
end
|
||||
|
||||
function _M.getHitTimer()
|
||||
return memory.readbyte(0x7e08c0) - memory.readbyte(0x7e08be)
|
||||
end
|
||||
|
||||
function _M.getTile(dx, dy)
|
||||
local partyScreenX = (partyX - cameraX) * 2
|
||||
local partyScreenY = (partyY - cameraY) * 2
|
||||
|
||||
x = math.floor((partyX+dx+8)/16)
|
||||
y = math.floor((partyY+dy)/16)
|
||||
|
||||
return memory.readbyte(0x1C800 + math.floor(x/0x10)*0x1B0 + y*0x10 + x%0x10)
|
||||
end
|
||||
|
||||
function _M.getSprites()
|
||||
local sprites = {}
|
||||
for slot=0,11 do
|
||||
local status = memory.readbyte(0x14C8+slot)
|
||||
if status ~= 0 then
|
||||
spritex = memory.readbyte(0xE4+slot) + memory.readbyte(0x14E0+slot)*256
|
||||
spritey = memory.readbyte(0xD8+slot) + memory.readbyte(0x14D4+slot)*256
|
||||
sprites[#sprites+1] = {["x"]=spritex, ["y"]=spritey, ["good"] = spritelist.Sprites[memory.readbyte(0x009e + slot) + 1]}
|
||||
end
|
||||
end
|
||||
|
||||
return sprites
|
||||
end
|
||||
|
||||
function _M.getExtendedSprites()
|
||||
local extended = {}
|
||||
for slot=0,11 do
|
||||
local number = memory.readbyte(0x170B+slot)
|
||||
if number ~= 0 then
|
||||
spritex = memory.readbyte(0x171F+slot) + memory.readbyte(0x1733+slot)*256
|
||||
spritey = memory.readbyte(0x1715+slot) + memory.readbyte(0x1729+slot)*256
|
||||
extended[#extended+1] = {["x"]=spritex, ["y"]=spritey, ["good"] = spritelist.extSprites[memory.readbyte(0x170B + slot) + 1]}
|
||||
end
|
||||
end
|
||||
|
||||
return extended
|
||||
end
|
||||
|
||||
function _M.getInputs()
|
||||
_M.getPositions()
|
||||
|
||||
sprites = _M.getSprites()
|
||||
extended = _M.getExtendedSprites()
|
||||
|
||||
local inputs = {}
|
||||
local inputDeltaDistance = {}
|
||||
|
||||
local layer1x = memory.read_s16_le(0x1A);
|
||||
local layer1y = memory.read_s16_le(0x1C);
|
||||
|
||||
|
||||
for dy=-config.BoxRadius*16,config.BoxRadius*16,16 do
|
||||
for dx=-config.BoxRadius*16,config.BoxRadius*16,16 do
|
||||
inputs[#inputs+1] = 0
|
||||
inputDeltaDistance[#inputDeltaDistance+1] = 1
|
||||
|
||||
tile = _M.getTile(dx, dy)
|
||||
if tile == 1 and partyY+dy < 0x1B0 then
|
||||
inputs[#inputs] = 1
|
||||
end
|
||||
|
||||
for i = 1,#sprites do
|
||||
distx = math.abs(sprites[i]["x"] - (partyX+dx))
|
||||
disty = math.abs(sprites[i]["y"] - (partyY+dy))
|
||||
if distx <= 8 and disty <= 8 then
|
||||
inputs[#inputs] = sprites[i]["good"]
|
||||
|
||||
local dist = math.sqrt((distx * distx) + (disty * disty))
|
||||
if dist > 8 then
|
||||
inputDeltaDistance[#inputDeltaDistance] = mathFunctions.squashDistance(dist)
|
||||
--gui.drawLine(screenX, screenY, sprites[i]["x"] - layer1x, sprites[i]["y"] - layer1y, 0x50000000)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1,#extended do
|
||||
distx = math.abs(extended[i]["x"] - (partyX+dx))
|
||||
disty = math.abs(extended[i]["y"] - (partyY+dy))
|
||||
if distx < 8 and disty < 8 then
|
||||
|
||||
--console.writeline(screenX .. "," .. screenY .. " to " .. extended[i]["x"]-layer1x .. "," .. extended[i]["y"]-layer1y)
|
||||
inputs[#inputs] = extended[i]["good"]
|
||||
local dist = math.sqrt((distx * distx) + (disty * disty))
|
||||
if dist > 8 then
|
||||
inputDeltaDistance[#inputDeltaDistance] = mathFunctions.squashDistance(dist)
|
||||
--gui.drawLine(screenX, screenY, extended[i]["x"] - layer1x, extended[i]["y"] - layer1y, 0x50000000)
|
||||
end
|
||||
--if dist > 100 then
|
||||
--dw = mathFunctions.squashDistance(dist)
|
||||
--console.writeline(dist .. " to " .. dw)
|
||||
--gui.drawLine(screenX, screenY, extended[i]["x"] - layer1x, extended[i]["y"] - layer1y, 0x50000000)
|
||||
--end
|
||||
--inputs[#inputs] = {["value"]=-1, ["dw"]=dw}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return inputs, inputDeltaDistance
|
||||
end
|
||||
|
||||
function _M.clearJoypad()
|
||||
controller = {}
|
||||
for b = 1,#config.ButtonNames do
|
||||
controller["P1 " .. config.ButtonNames[b]] = false
|
||||
end
|
||||
joypad.set(controller)
|
||||
end
|
||||
|
||||
return _M
|
||||
--Notes here
|
||||
config = require "config"
|
||||
spritelist = require "spritelist"
|
||||
local _M = {}
|
||||
|
||||
function _M.getPositions()
|
||||
partyX = memory.readword(0x7e0a2a) - 256
|
||||
partyY = memory.readword(0x7e0a2c) - 256
|
||||
|
||||
local cameraX = memory.readword(0x7e17ba) - 256
|
||||
local cameraY = memory.readword(0x7e17c0) - 256
|
||||
|
||||
_M.screenX = (partyX-cameraX)*2
|
||||
_M.screenY = (partyY-cameraY)*2
|
||||
end
|
||||
|
||||
function _M.getBananas()
|
||||
local bananas = memory.readword(0x7e08bc)
|
||||
return bananas
|
||||
end
|
||||
|
||||
function _M.getCoins()
|
||||
local coins = memory.readword(0x7e08ca)
|
||||
return coins
|
||||
end
|
||||
|
||||
function _M.getLives()
|
||||
local lives = memory.readsbyte(0x7e08be) + 1
|
||||
return lives
|
||||
end
|
||||
|
||||
function _M.writeLives(lives)
|
||||
memory.writebyte(0x7e08be, lives - 1)
|
||||
memory.writebyte(0x7e08c0, lives - 1)
|
||||
end
|
||||
|
||||
function _M.getPowerup()
|
||||
return 0
|
||||
end
|
||||
|
||||
function _M.writePowerup(powerup)
|
||||
return
|
||||
-- memory.writebyte(0x0019, powerup)
|
||||
end
|
||||
|
||||
|
||||
function _M.getHit(alreadyHit)
|
||||
return not alreadyHit and memory.readbyte(0x7e08be) < memory.readbyte(0x7e08c0)
|
||||
end
|
||||
|
||||
function _M.getHitTimer()
|
||||
return memory.readbyte(0x7e08c0) - memory.readbyte(0x7e08be)
|
||||
end
|
||||
|
||||
function _M.getTile(dx, dy)
|
||||
local partyScreenX = (partyX - cameraX) * 2
|
||||
local partyScreenY = (partyY - cameraY) * 2
|
||||
|
||||
x = math.floor((partyX+dx+8)/16)
|
||||
y = math.floor((partyY+dy)/16)
|
||||
|
||||
return memory.readbyte(0x1C800 + math.floor(x/0x10)*0x1B0 + y*0x10 + x%0x10)
|
||||
end
|
||||
|
||||
function _M.getSprites()
|
||||
local sprites = {}
|
||||
for slot=0,11 do
|
||||
local status = memory.readbyte(0x14C8+slot)
|
||||
if status ~= 0 then
|
||||
spritex = memory.readbyte(0xE4+slot) + memory.readbyte(0x14E0+slot)*256
|
||||
spritey = memory.readbyte(0xD8+slot) + memory.readbyte(0x14D4+slot)*256
|
||||
sprites[#sprites+1] = {["x"]=spritex, ["y"]=spritey, ["good"] = spritelist.Sprites[memory.readbyte(0x009e + slot) + 1]}
|
||||
end
|
||||
end
|
||||
|
||||
return sprites
|
||||
end
|
||||
|
||||
function _M.getExtendedSprites()
|
||||
local extended = {}
|
||||
for slot=0,11 do
|
||||
local number = memory.readbyte(0x170B+slot)
|
||||
if number ~= 0 then
|
||||
spritex = memory.readbyte(0x171F+slot) + memory.readbyte(0x1733+slot)*256
|
||||
spritey = memory.readbyte(0x1715+slot) + memory.readbyte(0x1729+slot)*256
|
||||
extended[#extended+1] = {["x"]=spritex, ["y"]=spritey, ["good"] = spritelist.extSprites[memory.readbyte(0x170B + slot) + 1]}
|
||||
end
|
||||
end
|
||||
|
||||
return extended
|
||||
end
|
||||
|
||||
function _M.getInputs()
|
||||
_M.getPositions()
|
||||
|
||||
sprites = _M.getSprites()
|
||||
extended = _M.getExtendedSprites()
|
||||
|
||||
local inputs = {}
|
||||
local inputDeltaDistance = {}
|
||||
|
||||
local layer1x = memory.readword(0x7f0000);
|
||||
local layer1y = memory.read_s16_le(0x1C);
|
||||
|
||||
for dy=-config.BoxRadius*16,config.BoxRadius*16,16 do
|
||||
for dx=-config.BoxRadius*16,config.BoxRadius*16,16 do
|
||||
inputs[#inputs+1] = 0
|
||||
inputDeltaDistance[#inputDeltaDistance+1] = 1
|
||||
|
||||
tile = _M.getTile(dx, dy)
|
||||
if tile == 1 and partyY+dy < 0x1B0 then
|
||||
inputs[#inputs] = 1
|
||||
end
|
||||
|
||||
for i = 1,#sprites do
|
||||
distx = math.abs(sprites[i]["x"] - (partyX+dx))
|
||||
disty = math.abs(sprites[i]["y"] - (partyY+dy))
|
||||
if distx <= 8 and disty <= 8 then
|
||||
inputs[#inputs] = sprites[i]["good"]
|
||||
|
||||
local dist = math.sqrt((distx * distx) + (disty * disty))
|
||||
if dist > 8 then
|
||||
inputDeltaDistance[#inputDeltaDistance] = mathFunctions.squashDistance(dist)
|
||||
--gui.drawLine(screenX, screenY, sprites[i]["x"] - layer1x, sprites[i]["y"] - layer1y, 0x50000000)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1,#extended do
|
||||
distx = math.abs(extended[i]["x"] - (partyX+dx))
|
||||
disty = math.abs(extended[i]["y"] - (partyY+dy))
|
||||
if distx < 8 and disty < 8 then
|
||||
|
||||
--console.writeline(screenX .. "," .. screenY .. " to " .. extended[i]["x"]-layer1x .. "," .. extended[i]["y"]-layer1y)
|
||||
inputs[#inputs] = extended[i]["good"]
|
||||
local dist = math.sqrt((distx * distx) + (disty * disty))
|
||||
if dist > 8 then
|
||||
inputDeltaDistance[#inputDeltaDistance] = mathFunctions.squashDistance(dist)
|
||||
--gui.drawLine(screenX, screenY, extended[i]["x"] - layer1x, extended[i]["y"] - layer1y, 0x50000000)
|
||||
end
|
||||
--if dist > 100 then
|
||||
--dw = mathFunctions.squashDistance(dist)
|
||||
--console.writeline(dist .. " to " .. dw)
|
||||
--gui.drawLine(screenX, screenY, extended[i]["x"] - layer1x, extended[i]["y"] - layer1y, 0x50000000)
|
||||
--end
|
||||
--inputs[#inputs] = {["value"]=-1, ["dw"]=dw}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return inputs, inputDeltaDistance
|
||||
end
|
||||
|
||||
function _M.clearJoypad()
|
||||
for b = 1,#config.ButtonNames do
|
||||
input.set(0, b - 1, 0)
|
||||
end
|
||||
end
|
||||
|
||||
return _M
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
--Notes here
|
||||
|
||||
local _M = {}
|
||||
|
||||
function _M.sigmoid(x)
|
||||
return 2/(1+math.exp(-4.9*x))-1
|
||||
end
|
||||
|
||||
function _M.squashDistance(x)
|
||||
local window = 0.20
|
||||
local delta = 0.25
|
||||
|
||||
local dist = (x-8)
|
||||
local newDist = 1
|
||||
|
||||
while dist > 0 do
|
||||
newDist = newDist - (window*delta)
|
||||
dist = dist - 1
|
||||
end
|
||||
|
||||
if newDist < 0.80 then
|
||||
newDist = 0.80
|
||||
end
|
||||
|
||||
return newDist
|
||||
end
|
||||
|
||||
|
||||
--Notes here
|
||||
|
||||
local _M = {}
|
||||
|
||||
function _M.sigmoid(x)
|
||||
return 2/(1+math.exp(-4.9*x))-1
|
||||
end
|
||||
|
||||
function _M.squashDistance(x)
|
||||
local window = 0.20
|
||||
local delta = 0.25
|
||||
|
||||
local dist = (x-8)
|
||||
local newDist = 1
|
||||
|
||||
while dist > 0 do
|
||||
newDist = newDist - (window*delta)
|
||||
dist = dist - 1
|
||||
end
|
||||
|
||||
if newDist < 0.80 then
|
||||
newDist = 0.80
|
||||
end
|
||||
|
||||
return newDist
|
||||
end
|
||||
|
||||
|
||||
return _M
|
2328
neat-donk.lua
2328
neat-donk.lua
File diff suppressed because it is too large
Load diff
BIN
pool/PiratePanic.lsmv
Normal file
BIN
pool/PiratePanic.lsmv
Normal file
Binary file not shown.
44
util.lua
Normal file
44
util.lua
Normal file
|
@ -0,0 +1,44 @@
|
|||
local _M = {}
|
||||
|
||||
function _M.table_to_string(tbl)
|
||||
local result = "{"
|
||||
local keys = {}
|
||||
for k in pairs(tbl) do
|
||||
table.insert(keys, k)
|
||||
end
|
||||
table.sort(keys)
|
||||
for _, k in ipairs(keys) do
|
||||
local v = tbl[k]
|
||||
if type(v) == "number" and v == 0 then
|
||||
goto continue
|
||||
end
|
||||
|
||||
-- Check the key type (ignore any numerical keys - assume its an array)
|
||||
if type(k) == "string" then
|
||||
result = result.."[\""..k.."\"]".."="
|
||||
end
|
||||
|
||||
-- Check the value type
|
||||
if type(v) == "table" then
|
||||
result = result..table_to_string(v)
|
||||
elseif type(v) == "boolean" then
|
||||
result = result..tostring(v)
|
||||
else
|
||||
result = result.."\""..v.."\""
|
||||
end
|
||||
result = result..",\n"
|
||||
::continue::
|
||||
end
|
||||
-- Remove leading commas from the result
|
||||
if result ~= "" then
|
||||
result = result:sub(1, result:len()-1)
|
||||
end
|
||||
return result.."}"
|
||||
end
|
||||
|
||||
function _M.file_exists(name)
|
||||
local f=io.open(name,"r")
|
||||
if f~=nil then io.close(f) return true else return false end
|
||||
end
|
||||
|
||||
return _M
|
Loading…
Add table
Reference in a new issue