--Salamander (J), various useful functions.
--FatRatKnight
local btn= {"right", "left", "down", "up", "start", "select", "B", "A"}
local MemRead= memory.readbyte
--*****************************************************************************
--*****************************************************************************
-- The following batch of functions help with reading the environment of
-- Salamander (J). Things like wall reading.
-- Though, wall reading is about all I can do, right now.
--*****************************************************************************
function PosTile(px, py) -- Expects input by pixel
--*****************************************************************************
-- Returns the tile for given screen coordinates.
-- tx range: 0 ~ 63 ty range: 0 ~ 29
-- Salamander (J);
local tx= MemRead(0x00FD) + bit.band(MemRead(0x00FF),1)*256
local ty= MemRead(0x00FC)
tx= math.floor( ( (px+tx) % 512 ) / 8)
ty= math.floor( ( (py+ty) % 240 ) / 8)
return tx, ty
end
--*****************************************************************************
function PosPixel(tx, ty) -- Expects input by tile
--*****************************************************************************
-- Returns the top-left pixel of given tile.
-- px range: -7 ~ 504 py range: -7 ~ 232
-- Salamander (J);
local px= MemRead(0x00FD) + bit.band(MemRead(0x00FF),1)*256
local py= MemRead(0x00FC)
px= (tx*8 - px +7) % 512 -7 -- The +7 and -7 exists
py= (ty*8 - py +7) % 240 -7 -- for devious reasons
return px, py
end
--*****************************************************************************
function GetWall(tx, ty) -- Expects input by tile
--*****************************************************************************
-- Returns a number from 0 to 3, identifying collision data for given tile
-- 0 = open space 1 = solid wall 2 and 3 = types of destructible
-- Salamander (J); Has knowledge of location and range of wall array
local addr= 0x6000
tx = tx%64
ty = ty%30
if tx > 31 then -- horizontal scroll uses two different arrays
tx = tx - 32
addr = addr + 0x100
end
addr = addr + math.floor( tx/4 ) + ty*8
return bit.band(bit.rshift( MemRead(addr) , (tx%4)*2) , 0x03)
end
--*****************************************************************************
--*****************************************************************************
-- Now we have a few fun functions that I can pick out for you!
--*****************************************************************************
function GrowinStuff()
--*****************************************************************************
-- Specifically for the regenerating gunk at the end of stage 1.
-- Will throw up a display of where regenerating gunk is expected.
local STATUS, TIMER = 0x05C0, 0x05D9
local TESTX , TESTY = 0x05CA, 0x05C5
--local GROWX , GROWY = 0x05CF, 0x05D4
local timer= nil
local gX= nil
local gY= nil
local stage= MemRead(0x0043)/256
for i=0, 4 do -- Loop through both players and three options
local status= MemRead(STATUS+i)
if status == 2 then
timer= MemRead(TIMER+i)
gX= MemRead(TESTX+i)-0x60+timer/2+stage
gY= MemRead(TESTY+i)
local left, top= PosPixel(PosTile(gX,gY))
local right, bottom= left+55, top +15
left= math.max(left,1)
top= math.max(top,1)
if left > 0 and left < 255 and right > 0 and right < 255 and top > 8 and bottom < 240 then
gui.box(left,top,right,bottom,0,"white")
gui.text(left+2,top-6,timer)
end
end
end
end
local PLX, PLY, PLS= 0, 0, 0 -- ClearPath needs access...
--*****************************************************************************
function ClearPath(x,y) -- Expects input by direction
--*****************************************************************************
-- Checks if the given direction is possible or has a wall.
-- nil if screen edge, false if solid wall in way, true otherwise (clear path)
-- Salamander (J); Needs FollowMouse variables and knowledge of screen limits
local Left= (PLX >= 0x10)
local Right=(PLX < 0xE8)
local Up= (PLY >= 0x1A)
local Down= (PLY < 0xC6)
if (x < 0 and not Left) or (x > 0 and not Right) then
return nil
elseif (y < 0 and not Up) or (y > 0 and not Down) then
return nil
elseif GetWall(PosTile(PLX+PLS*x,PLY+PLS*y)) ~= 0 then
return false
end
return true
end
--*****************************************************************************
function SafeWall()
--*****************************************************************************
-- Use with emu.registerbefore to work properly
-- Makes the player less likely to crash into walls.
-- Moving walls are still deadly.
local DF= {} ; DF[-1]= {} ; DF[ 0]= {} ; DF[ 1]= {}
DF[-1][-1]= 1; DF[ 0][-1]= 2; DF[ 1][-1]= 3
DF[-1][ 0]= 0; DF[ 0][ 0]= 8; DF[ 1][ 0]= 4
DF[-1][ 1]= 7; DF[ 0][ 1]= 6; DF[ 1][ 1]= 5
-- |<^| ^|>^|> |>v| v|<v|..|
local UD= {-1,-1,-1, 0, 1, 1, 1, 0}
local LR= {-1, 0, 1, 1, 1, 0,-1, 0}
UD[0], LR[0]= 0,-1 -- |< | Thanks to modulo, zero is too convenient
for P= 1, 2 do
local INV= MemRead(0x0073+P)
local STATE= MemRead(0x005F+P)
if (INV < 2) and (STATE == 3) then
PLX= MemRead(0x035B+P)
PLY= MemRead(0x0336+P)
PLS= MemRead(0x006F+P)
local pl= joypad.get(P)
local STATE=MemRead(0x005F+P)
local ud , lr= 0 , 0
if pl.left == true then lr= -1 end -- In case L+R or U+D is
if pl.right== true then lr= 1 end -- pressed, the game itself
if pl.up == true then ud= -1 end -- puts priority in right
if pl.down == true then ud= 1 end -- and down.
local dir= DF[lr][ud]
-- Ugh... All that just so I have all the data I need...
if dir ~= 8 then
if not ClearPath(LR[dir], UD[dir]) then
dir= (dir-1)%8 -- Left turn
end
if not ClearPath(LR[dir], UD[dir]) then
dir= (dir+2)%8 -- Right turn
end
if not ClearPath(LR[dir], UD[dir]) then
dir= 8 -- Hold still
end
end
if not ClearPath(LR[dir], UD[dir]) then
for i= 0, 8 do -- Panic! Check everything!
dir= i
if ClearPath(LR[dir], UD[dir]) then
break
end
end -- If the loop fails to break, you're doomed anyway...
end
lr , ud= LR[dir] , UD[dir]
pl.left , pl.right , pl.up , pl.down= true , true , true , true
if lr ~= -1 then pl.left = false end
if lr ~= 1 then pl.right= false end
if ud ~= -1 then pl.up = false end
if ud ~= 1 then pl.down = false end
joypad.set(P,pl)
end
end
end
--*****************************************************************************
function FollowMouse(P) -- Expects either 1 or 2
--*****************************************************************************
-- Guides the selected player to the mouse.
-- It will merely insert input, not "teleport" the player to the position.
-- Salamander (J); Has knowledge of player positions, speed, and status.
local STATE= MemRead(0x005F+P)
if (STATE < 2) or (STATE > 3) then return end -- Is player unavailable?
local PLX= MemRead(0x035B+P) + MemRead(0x0063+P)/256
local PLY= MemRead(0x0336+P) + MemRead(0x0061+P)/256
local PLS= MemRead(0x006F+P)/4 + 1.25
local keys= input.get()
local MouseIn= {}
-- Set desired direction
if keys.xmouse >= math.floor(PLX + PLS) then
MouseIn.right= true
elseif keys.xmouse <= math.floor(PLX - PLS) then
MouseIn.left= true
end
if keys.ymouse >= math.floor(PLY + PLS) then
MouseIn.down= true
elseif keys.ymouse <= math.floor(PLY - PLS) then
MouseIn.up= true
end
joypad.set(P,MouseIn)
end
--*****************************************************************************
function Within(Target,low,high)
--*****************************************************************************
return (Target >= low) and (Target <= high)
end
--*****************************************************************************
function WallBlocks()
--*****************************************************************************
for tx= 0, 63 do
for ty= 0, 29 do
if GetWall(tx, ty) ~= 0 then
local px, py= PosPixel(tx, ty)
py= py
if Within(px,0,248) and Within(py,0,184) then
gui.box(px,py,px+7,py+7,0x00FF0020,0x00FF0040)
end
end
end
end
for P= 0, 1 do
local PX, PY= MemRead(0x035C+P),MemRead(0x0337+P)
if MemRead(0x0060+P) == 3 then
gui.pixel(PX,PY,"red")
gui.box(PX-1,PY-1,PX+1,PY+1,0,"green")
end
end
end
--*****************************************************************************
function WallRadar()
--*****************************************************************************
-- Use with emu.registerafter or gui.register to work well
for pl=0, 1 do
local plX = MemRead(0x035C+pl) + MemRead(0x0064+pl)/256
local plY = MemRead(0x0337+pl) + MemRead(0x0062+pl)/256
local plS = MemRead(0x0070+pl)/4 + 1.25
for x=-2, 2 do
for y=-2, 2 do
if GetWall(PosTile(plX+x*plS , plY+y*plS)) == 0 then
color="green"
else
color="red"
end
gui.box(187+x*4+pl*28, 207+y*4, 189+x*4+pl*28, 209+y*4,0, color)
end
end
end
--WallBlocks()
end
--*****************************************************************************
function awesome()
--*****************************************************************************
for i=0, 0x24 do
eh= MemRead(0x0300+i) -- If non-zero, it's visible.
if eh ~= 0 then
ey=MemRead(0x0325+i)
ex=MemRead(0x034A+i)
ez=MemRead(0x036F+i)
if ex >= 8 and ex < 248 and ey >= 16 and ey < 223 then
gui.box(ex-8,ey-8,ex+7,ey+7,0,"green")
gui.text(ex,ey,ez)
end
end
end
-- if MemRead(0x0060) == 4 then
-- gui.text(10,40,"1P go boom")
-- end
-- if MemRead(0x0061) == 4 then
-- gui.text(10,80,"2P BANG!")
-- end
-- gui.text(10,56,MemRead(0x0072))
-- gui.text(10,96,MemRead(0x0073))
GrowinStuff()
end
--*****************************************************************************
--gui.register(awesome)
--emu.registerbefore(SafeWall)
--emu.registerafter(WallRadar)
--emu.pause()
while true do
--FollowMouse(1)
WallBlocks()
--awesome()
gui.text(1,1,"z")
FCEU.frameadvance()
end