User File #23965765941835859

Upload All User Files

#23965765941835859 - NES Salamander (JPN version of Life Force) - Interesting lua script

SalamanderStuff2.lua
935 downloads
Uploaded 7/7/2015 6:53 AM by FatRatKnight (see all 245)
Third exhibit. Can't confirm whether it works right now. Dear, ye... This thing is ancient! This is before I started attaching local to most of my functions. Time to dust off some cobwebs.
Apparently I was working out wall detection, and even an attempt at an automatic way of keeping the player safer versus walls when playing normally. I'm not sure how much this is TASing and how much is casual enhancement, but hey. There are some good memories for me to find here. I recommend lua knowledge before testing the script, since again, I can't confirm it works right now.
--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