Post subject: Port attempt of Multitrack Script to Snes9x.
Editor, Skilled player (1158)
Joined: 9/27/2008
Posts: 1084
This Pastey link contains my attempt. I have something working, but I can't really recommend it as a means for controlling more than 1 player. It's rather clunky, and I don't see any way around it. There are several problems I can not overcome. This is nothing like what I've made for FCEUX. The two major problems are as follows: Snes9x does not run lua through any register while paused. FCEUX will continuously run a function placed in gui.register even while paused. Intentional or not, this provided significant control. This feature allowed me to precisely tune the input list with script-defined keys. The same can't be said for Snes9x, by my experience, so far. Snes9x uses joypad.set in an ALL OR NOTHING basis. To put it simply, if I call this function, all 12 of the specified controller's buttons will ignore the user input, regardless of what buttons I actually want to handle. If there are both "passthrough" and "invert" options I can pick, this will allow me to mesh the user and script controls together, granting a rather fluid control. If just one of these problems are taken care of, I can make a script with far greater functionality. If both are taken care of, one can probably just copy the FCEUX script over, and with a little adjustment to accommodate the 12 buttons, expect it to work without problem. As it stands, there isn't much I can do from the lua side. There might be something more I can do, such as showing a bit more information and adding instructions, but it will not be anything close to what I made for FCEUX. In any case, pastey link up there. Play around with the script, though I sort of forgot to write up instructions for it.
HHS
Active player (282)
Joined: 10/8/2006
Posts: 356
Just use joypad.set with the table returned from joypad.read, with your changes to it.
Editor, Skilled player (1158)
Joined: 9/27/2008
Posts: 1084
HHS wrote:
Just use joypad.set with the table returned from joypad.read, with your changes to it.
If it only were that simple. Just how- ... Uh, okay. I put stuff in the main loop and things just magically work. Why, then, am I bothering with registers like emu.registerbefore and gui.register? I think I'd still have the problem with the display on stateload, but the fact the main loop does something I didn't expect is enough to work with. Okay, everything is changed. Everything. I'm working on a new script now! EDIT: It seems to show promise, indeed. Here's the message I had previously written before my further attempts: Suggest how I can make these changes. On any given frame, I can either read from the joypad to figure out what the user is doing, or write to it using what is stored in the script, but not both in the same frame. If I read up what the user is doing, I can't modify it and write to the joypad in the same frame, as far as what I have seen. I have made attempts using emu.registerbefore, and had no luck. Yeah, shrunk because I don't feel so... Eh, forget the word. Keywords in there being that I was using emu.registerbefore. I didn't try to, ya know, not use emu.registerbefore.
Editor, Skilled player (1158)
Joined: 9/27/2008
Posts: 1084
I had received a PM asking about this script. I have salvaged some scripts from my TASing computer. As I haven't managed to get my usual TASing stuff on this new computer, I didn't test out whether these scripts work as is. It will take a while before I can get things working well again. I recall MtEdit was basically a somewhat simplified version of Multitrack2, so that I can make changes to it better, or something. Regardless, here are two different scripts: The first one is Multitrack2 The second one is MtEdit Whether they work is currently unknown. So are their settings. I am copying these files here as is, as the pastey link certainly isn't working now, and any access is better than nothing. Download Multitrack2.lua
Language: lua

-- XOR Multitrack for Snes9x by FatRatKnight -- It simply records all input and XORs it with the user's button presses. -- Still a few problems, but things are definitely much smoother. --*************** local players= 1 -- You may tweak the number of players here. --*************** --Display local PlayerSwitch= "home" -- For viewing other players local ListSwitch= "end" -- Should the script use or ignore its own list? local JoypadSwitch= "delete" -- Should we allow or deny your input? local btn={"left","up","right","down","A","B","Y","X","L","R","start","select"} --Try to avoid changing btn. You may reorder btn's stuff if you don't --like the default order, however. local solid= "pageup" -- Make the display less local clear= "pagedown" -- or more transparant. local DispN= "numpad8" local DispS= "numpad2" -- For moving the local DispE= "numpad6" -- display around. local DispW= "numpad4" local MoreFutr= "numpad3" local LessFutr= "numpad1" -- These will determine local MorePast= "numpad7" -- how many frames you local LessPast= "numpad9" -- want to display. local ResetFP= "numpad5" --Various colors I'm using. If you wish to bother, go ahead. local shade= 0x00000080 local white= 0xFFFFFFFF local red= 0xFF0000FF local green= 0x00FF00FF local blue= 0x0040FFFF local orange=0xFFC000FF --***************************************************************************** --Please do not change the following, unless you plan to change the code: local plmin , plmax= 1 , 1 local fc= movie.framecount() local InputList= {} local OptionUseList= {} local OptionUseJoypad= {} local keys, lastkeys= {}, {} for pl= 1, players do InputList[pl]= {} OptionUseList[pl]= true OptionUseJoypad[pl]= true end --***************************************************************************** print("Running Multitrack Script made by FatRatKnight.", "\r\nIts primary use is to preserve input after a loadstate.", "\r\nNot as functional as what I have in FCEUX, but this works.", "\r\nThis assumes you're using frame advance, so unpaused playerswitching", "will toggle through the players at a rapid pace.\r\n") print(PlayerSwitch,"- Display another player's input") print(ListSwitch, "- Toggle whether the script uses its list") print(JoypadSwitch,"- Toggle whether the joypad input is used\r\n") print(solid,"- Make display more opaque.") print(clear,"- Fade the display a bit.") print(DispN,DispS,DispE,DispW,"- Move the display.") print(MoreFutr,LessFutr,MorePast,LessPast,"- Adjust how much the display shows") print(ResetFP,"- Reset display around current frame\r\n") print("When running this script, you'll see a bunch of symbols appear.", "This basically says what the script has recorded so far.", "As I can't accept input while paused, you'll need to hold the", "option key down and hit frame advance.\r\n") print("But the script has basic, useful functionality. It works as well as", "well as I hoped. And remember, edit the script if you don't like some", "of the controls. The options are near the top.\r\n") print("Players:",players) --***************************************************************************** function FBoxOld(x1, y1, x2, y2, color) --***************************************************************************** -- Gets around Snes9x's problem of double-painting the corners. -- The double-paint is visible with non-opaque drawing. -- It acts like the old-style border-only box. -- Slightly messes up when x2 or y2 are less than their counterparts. if (x1 == x2) and (y1 == y2) then gui.pixel(x1,y1,color) elseif (x1 == x2) or (y1 == y2) then gui.line(x1,y1,x2,y2,color) else --(x1 ~= x2) and (y1 ~= y2) gui.line(x1 ,y1 ,x2-1,y1 ,color) -- top gui.line(x2 ,y1 ,x2 ,y2-1,color) -- right gui.line(x1+1,y2 ,x2 ,y2 ,color) -- bottom gui.line(x1 ,y1+1,x1 ,y2 ,color) -- left end end --***************************************************************************** function FakeBox(x1, y1, x2, y2, Fill, Border) --***************************************************************************** -- Gets around Snes9x's problem of double-painting the corners. -- It acts like the new-style fill-and-border box. if not Border then Border= Fill end gui.box(x1,y1,x2,y2,Fill,0) FBoxOld(x1,y1,x2,y2,Border) end --***************************************************************************** local Draw= {} --Draw[button]( Left , Top , color ) --***************************************************************************** function Draw.right(x,y,color) -- ## gui.line(x ,y ,x+1,y ,color) -- # gui.line(x ,y+2,x+1,y+2,color) -- ## gui.pixel(x+2,y+1,color) end function Draw.left(x,y,color) -- ## gui.line(x+1,y ,x+2,y ,color) -- # gui.line(x+1,y+2,x+2,y+2,color) -- ## gui.pixel(x ,y+1,color) end function Draw.up(x,y,color) -- # gui.line(x ,y+1,x ,y+2,color) -- # # gui.line(x+2,y+1,x+2,y+2,color) -- # # gui.pixel(x+1,y ,color) end function Draw.down(x,y,color) -- # # gui.line(x ,y ,x ,y+1,color) -- # # gui.line(x+2,y ,x+2,y+1,color) -- # gui.pixel(x+1,y+2,color) end function Draw.start(x,y,color) -- # gui.line(x+1,y ,x+1,y+2,color) -- ### gui.pixel(x ,y+1,color) -- # gui.pixel(x+2,y+1,color) end function Draw.select(x,y,color) -- ### FBoxOld(x ,y ,x+2,y+2,color) -- # # end -- ### function Draw.A(x,y,color) -- ### FBoxOld(x ,y ,x+2,y+1,color) -- ### gui.pixel(x ,y+2,color) -- # # gui.pixel(x+2,y+2,color) end function Draw.B(x,y,color) -- # # gui.line(x ,y ,x ,y+2,color) -- ## gui.line(x+1,y+1,x+2,y+2,color) -- # # gui.pixel(x+2,y ,color) end function Draw.X(x,y,color) gui.line(x ,y ,x+2,y+2,color) -- # # gui.pixel(x ,y+2,color) -- # gui.pixel(x+2,y ,color) -- # # end function Draw.Y(x,y,color) gui.line(x+1,y+1,x+1,y+2,color) -- # # gui.pixel(x ,y ,color) -- # gui.pixel(x+2,y ,color) -- # end function Draw.L(x,y,color) -- # gui.line(x ,y+2,x+2,y+2,color) -- # gui.line(x ,y ,x ,y+1,color) -- ### end function Draw.R(x,y,color) gui.line(x ,y ,x ,y+2,color) -- ## gui.line(x+1,y ,x+1,y+1,color) -- ## gui.pixel(x+2,y+2,color) -- # # end function Draw.D0(left, top, color) gui.line(left ,top ,left ,top+4,color) gui.line(left+2,top ,left+2,top+4,color) gui.pixel(left+1,top ,color) gui.pixel(left+1,top+4,color) end function Draw.D1(left, top, color) gui.line(left ,top+4,left+2,top+4,color) gui.line(left+1,top ,left+1,top+3,color) gui.pixel(left ,top+1,color) end function Draw.D2(left, top, color) gui.line(left ,top ,left+2,top ,color) gui.line(left ,top+3,left+2,top+1,color) gui.line(left ,top+4,left+2,top+4,color) gui.pixel(left ,top+2,color) gui.pixel(left+2,top+2,color) end function Draw.D3(left, top, color) gui.line(left ,top ,left+1,top ,color) gui.line(left ,top+2,left+1,top+2,color) gui.line(left ,top+4,left+1,top+4,color) gui.line(left+2,top ,left+2,top+4,color) end function Draw.D4(left, top, color) gui.line(left ,top ,left ,top+2,color) gui.line(left+2,top ,left+2,top+4,color) gui.pixel(left+1,top+2,color) end function Draw.D5(left, top, color) gui.line(left ,top ,left+2,top ,color) gui.line(left ,top+1,left+2,top+3,color) gui.line(left ,top+4,left+2,top+4,color) gui.pixel(left ,top+2,color) gui.pixel(left+2,top+2,color) end function Draw.D6(left, top, color) gui.line(left ,top ,left+2,top ,color) gui.line(left ,top+1,left ,top+4,color) gui.line(left+2,top+2,left+2,top+4,color) gui.pixel(left+1,top+2,color) gui.pixel(left+1,top+4,color) end function Draw.D7(left, top, color) gui.line(left ,top ,left+1,top ,color) gui.line(left+2,top ,left+1,top+4,color) end function Draw.D8(left, top, color) gui.line(left ,top ,left ,top+4,color) gui.line(left+2,top ,left+2,top+4,color) gui.pixel(left+1,top ,color) gui.pixel(left+1,top+2,color) gui.pixel(left+1,top+4,color) end function Draw.D9(left, top, color) gui.line(left ,top ,left ,top+2,color) gui.line(left+2,top ,left+2,top+3,color) gui.line(left ,top+4,left+2,top+4,color) gui.pixel(left+1,top ,color) gui.pixel(left+1,top+2,color) gui.pixel(left+2,top+3,color) end Draw[0],Draw[1],Draw[2],Draw[3],Draw[4]=Draw.D0,Draw.D1,Draw.D2,Draw.D3,Draw.D4 Draw[5],Draw[6],Draw[7],Draw[8],Draw[9]=Draw.D5,Draw.D6,Draw.D7,Draw.D8,Draw.D9 --***************************************************************************** function DrawNum(right, top, Number, color, bkgnd) --***************************************************************************** -- Paints the input number as right-aligned. -- Returns the x position where it would paint another digit. -- It only works with integers. Rounds fractions toward zero. local Digit= {} local Negative= false if Number < 0 then Number= -Number Negative= true end Number= math.floor(Number) if not color then color= "white" end if not bkgnd then bkgnd= "clear" end local i= 0 if Number < 1 then Digit[1]= 0 i= 1 end while (Number >= 1) do i= i+1 Digit[i]= Number % 10 Number= math.floor(Number/10) end if Negative then i= i+1 end local left= right - i*4 FakeBox(left+1, top-1, right+1, top+5,bkgnd,bkgnd) i= 1 while Draw[Digit[i]] do Draw[Digit[i]](right-2,top,color) right= right-4 i=i+1 end if Negative then gui.line(right, top+2,right-2,top+2,color) right= right-4 end return right end --***************************************************************************** function limits( value , low , high ) -- Expects numbers --***************************************************************************** -- Returns value, low, or high. high is returned if value exceeds high, -- and low is returned if value is beneath low. return math.max(math.min(value,high),low) end --***************************************************************************** function within( value , low , high ) -- Expects numbers --***************************************************************************** -- Returns true if value is between low and high. False otherwise. return ( value >= low ) and ( value <= high ) end --***************************************************************************** function JoyToNum(Joys) -- Expects a table containing joypad buttons --***************************************************************************** -- Returns a number from 0 to 4095, representing button presses. -- These numbers are the primary storage for this version of this script. local joynum= 0 for i= 1, 12 do if Joys[btn[i]] then joynum= bit.bor(joynum, bit.rshift(0x1000,i)) end end return joynum end --***************************************************************************** function ReadJoynum(input, button) -- Expects... Certain numbers! --***************************************************************************** -- Returns true or false. True if the indicated button is pressed -- according to the input. False otherwise. return ( bit.band(input , bit.rshift( 0x1000,button )) ~= 0 ) end --***************************************************************************** function ShowOnePlayer(x,y,color,button,pl) --***************************************************************************** -- Displays an individual button. -- Helper function for DisplayInput. Called as HighlightButton x= x + 4*button - 3 Draw[btn[button]](x,y,color) end --***************************************************************************** function ShowManyPlayers(x,y,color,button,pl) --***************************************************************************** -- Displays an individual button. Uses 2x3 boxes instead of button graphics. -- Helper function for DisplayInput. Called as HighlightButton x= x + (players + 1)*(button - 1) + pl gui.line(x,y,x,y+2,color) end local DispX, DispY= 160, 70 local Past, Future= -12, 20 local Opaque= 1 --***************************************************************************** function DisplayOptions(width) -- Expects width calculated by DisplayInput --***************************************************************************** -- Returns true if Opaque is 0, as a signal to don't bother painting. -- Separated from DisplayInput to make it clear which half is doing what. -- Change opacity? if keys[solid] then Opaque= Opaque + 1/8 end if keys[clear] then Opaque= Opaque - 1/8 end Opaque= limits(Opaque,0,1) gui.opacity(Opaque) if Opaque == 0 then return true end -- Don't bother processing display if there's none to see. -- How many frames to show? if keys[LessFutr] then Future= Future-1 if Future < Past then Past= Future end end if keys[MoreFutr] then Future= Future+1 if Future > Past+53 then Past= Future-53 end end if keys[MorePast] then Past= Past-1 if Past < Future-53 then Future= Past+53 end end if keys[LessPast] then Past= Past+1 if Past > Future then Future= Past end end if keys[ResetFP] then Past= -12; Future= 12 end -- Move the display around? if keys[DispS] then DispY= DispY+1 end if keys[DispW] then DispX= DispX-1 end if keys[DispE] then DispX= DispX+1 end if keys[DispN] then DispY= DispY-1 end if keys["leftclick"] and lastkeys["leftclick"] then DispX= DispX + keys.xmouse - lastkeys.xmouse DispY= DispY + keys.ymouse - lastkeys.ymouse end DispX= limits(DispX,1,254-width) DispY= limits(DispY,3-4*Past,218-4*Future) return nil -- Signal to display the input end --***************************************************************************** function DisplayInput() --***************************************************************************** -- Paints on the screen the current input stored within the script's list. -- Rather a shoddy job at loadstate, however. --Are we showing all players or just one? local HighlightButton= ShowOnePlayer local width= 48 if plmin ~= plmax then HighlightButton= ShowManyPlayers width= 12*players + 12 end --For both setting options and asking if we should bother displaying ourselves if DisplayOptions(width) then return end --Display frame offsets we're looking at. local RtDigit= DispX + width + 22 if RtDigit > 254 then RtDigit= DispX - 4 end local TpDigit= DispY + 4*Past - 2 DrawNum(RtDigit,TpDigit,Past,white,shade) if Future > Past+1 then TpDigit= DispY + 4*Future DrawNum(RtDigit,TpDigit,Future,white,shade) end --Show cute little box around current frame if Past <= 0 and Future >= 0 then local color= green local temp= 0 for pl= plmin, plmax do if OptionUseJoypad[pl] then temp= temp+1 end end if temp == 0 then color= red elseif (plmin ~= plmax) and (temp ~= players) then color= orange end FBoxOld(DispX-1,DispY-2,DispX+width+1,DispY+4,color) end --Finally, we get to show the actual buttons! for i= Past, Future do local Y= DispY + 4*i if i < 0 then Y=Y-2 elseif i > 0 then Y=Y+2 end gui.box(DispX,Y-1,DispX+width,Y+3,shade,shade) for pl= plmin, plmax do local scanz= InputList[pl][fc+i] for button= 1, 12 do local color if not scanz then color= white elseif ReadJoynum(scanz,button) then color= green else color= red end if (not OptionUseList[pl]) and i >= 0 then color= bit.bor(color, 0xC080C000) end HighlightButton(DispX,Y,color,button,pl) end end end end --***************************************************************************** function SetInput() --***************************************************************************** -- Sets the joypads. It's smart, at long last! for pl= 1, players do local temp= InputList[pl][fc-1] if temp and OptionUseList[pl] then local ThisInput= {} if OptionUseJoypad[pl] then ThisInput= joypad.get(pl) end for i= 1, 12 do if ReadJoynum(temp,i) then ThisInput[btn[i]]= not ThisInput[btn[i]] end end joypad.set(pl, ThisInput) end end end --***************************************************************************** function CatchInput() --***************************************************************************** -- For use with registerbefore. It will get the input and paste it into -- the input list. fc= movie.framecount() for pl= 1, players do InputList[pl][fc-1]= JoyToNum(joypad.get(pl)) end end emu.registerbefore(CatchInput) --***************************************************************************** function ItIsYourTurn() --***************************************************************************** -- Rather stripped down from FCEUX version. Only has basic functionality. -- Mainly just there to set options and controls now. --Ensure things are nice, shall we? fc= movie.framecount() lastkeys= keys keys= input.get() --Switch players on keypress if keys[PlayerSwitch] then if plmin ~= plmax then plmax= 1 elseif plmin == players then plmin= 1 else plmin= plmin+1 plmax= plmax+1 end end --Sets controller to pick either this script or the player. if keys[ListSwitch] then for pl= plmin, plmax do OptionUseList[pl]= not OptionUseList[pl] end end if keys[JoypadSwitch] then for pl= plmin, plmax do OptionUseJoypad[pl]= not OptionUseJoypad[pl] end end --Display which player we're selecting. Upperleft corner seems good. if plmin == plmax then gui.text(1,2,plmin) else gui.text(1,2,"A") end SetInput() collectgarbage("collect") end gui.register(DisplayInput) emu.pause() while true do ItIsYourTurn() emu.frameadvance() end
Download MtEdit.lua
Language: lua

local PLAYERS = 1 local btn={"left","up","right","down","A","B","Y","X","L","R","start","select"} --############################################################################# -- Keyboard Control mapping local PlayerSwitch= "home" local solid= "pageup" -- Make the display less local clear= "pagedown" -- or more transparant. local mp= "numpad7" --More past. Tweak display to see further back! local lp= "numpad1" --Less past. You'll see less of the input stream. local mf= "numpad3" --More future. local lf= "numpad9" --Less future. local rs= "numpad5" --Reset display local AutoList= true local Insert= "insert" local Delete= "delete" local AutoSwitch= "end" local Pl1Switch= "numpad+" --############################################################################# -- Default values local Opq= 1 local DispX, DispY= 50, 80 local Past, Future= -12, 12 local WatermarkInterval= 12 local Pl1Control= true --Colors local White =-0x00000001 --0xFFFFFFFF local Red =-0x00DFFF01 --0xFF2000FF local Green = 0x00FF00FF local Orange=-0x007FFF01 --0xFF8000FF --############################################################################# local PlSel= 1 local ThisJoypad= {} local JoypadList= {} local UserControl= {} local ListControl= {} for pl= 1, PLAYERS do ThisJoypad[pl]= {} JoypadList[pl]= {} UserControl[pl]= "inv" ListControl[pl]= true end local fc , Lastfc= 0 , 0 --***************************************************************************** local function UpdateFC() Lastfc= fc; fc= movie.framecount() end --***************************************************************************** --***************************************************************************** local function Within(V,l,h) return (V >= l) and (V <= h) end local function Limits(V,l,h) return math.max(math.min(V,h),l) end local function NullFN() return end --***************************************************************************** --############################################################################# --############################################################################# --Joypad --***************************************************************************** local function JoyToNum(Joys) -- Expects a table containing joypad buttons --***************************************************************************** -- Returns a number representing button presses. -- These numbers are the primary storage for this version of this script. local joynum= 0 for i= 1, #btn do if Joys[btn[i]] then joynum= bit.bor(joynum, bit.lshift(1,i)) end end return joynum end --***************************************************************************** local function ReadJoynum(Jn, button) -- Expects... Certain numbers! --***************************************************************************** -- Returns true or false. True if the indicated button is pressed -- according to the input. False otherwise. return ( bit.band(Jn , bit.lshift( 1, button )) ~= 0 ) end --***************************************************************************** local function LoadJoypad(pl) --***************************************************************************** -- Sets up the joypad to inject into the emulation. local joys= JoypadList[pl][fc] if ListControl[pl] then for b= 1, #btn do if joys and ReadJoynum(joys, b) then ThisJoypad[pl][btn[b]]= (UserControl[pl] or true) else ThisJoypad[pl][btn[b]]= (UserControl[pl] and nil) end end else for b= 1, #btn do ThisJoypad[pl][btn[b]]= (UserControl[pl] and nil) end end --UserControl is "inv" or false. I abuse the shortcutting of or & and. end --***************************************************************************** local function JoypadGetAlternate(player) --***************************************************************************** if Pl1Control then return joypad.get(1) end return joypad.get(player) end --***************************************************************************** local function JoypadSetFCEUXStyle(player,inputs) --***************************************************************************** -- Snes9x has two values: Force on, force off. -- FCEUX has four: Force on, force off, user passthrough, and user invert. -- I need the four, but I can at least emulate the four from lua. -- This is only possible because Snes9x can read+modify on the immediate frame. local TempInput= JoypadGetAlternate(player) for btn,val in pairs(inputs) do -- This skips nil; User passthrough if not val then -- Lua-side false; Force off TempInput[btn]= false elseif type(val) == "string" then -- A string, eh? User invert TempInput[btn]= not TempInput[btn] else -- Assume what's left is true; Force on TempInput[btn]= true end end joypad.set(player, TempInput) end --***************************************************************************** local function RegBoundaryHandleJoypad() --***************************************************************************** for pl= 1, PLAYERS do JoypadSetFCEUXStyle(pl, ThisJoypad[pl]) end end --***************************************************************************** local function RegAfterHandleJoypad() --***************************************************************************** for pl= 1, PLAYERS do JoypadList[pl][Lastfc]= JoyToNum(joypad.get(pl)) LoadJoypad(pl) end end --############################################################################# --############################################################################# --Display (Joypad) --***************************************************************************** local Draw= {} --***************************************************************************** function Draw.left(x,y,color) -- ## gui.line(x+1,y ,x+2,y ,color) -- # gui.line(x+1,y+2,x+2,y+2,color) -- ## gui.pixel(x ,y+1,color) end function Draw.up(x,y,color) -- # gui.line(x ,y+1,x ,y+2,color) -- # # gui.line(x+2,y+1,x+2,y+2,color) -- # # gui.pixel(x+1,y ,color) end function Draw.right(x,y,color) -- ## gui.line(x ,y ,x+1,y ,color) -- # gui.line(x ,y+2,x+1,y+2,color) -- ## gui.pixel(x+2,y+1,color) end function Draw.down(x,y,color) -- # # gui.line(x ,y ,x ,y+1,color) -- # # gui.line(x+2,y ,x+2,y+1,color) -- # gui.pixel(x+1,y+2,color) end function Draw.A(x,y,color) -- ### gui.line(x ,y ,x ,y+2,color) -- ### gui.line(x+1,y ,x+1,y+1,color) -- # # gui.line(x+2,y ,x+2,y+2,color) end function Draw.B(x,y,color) -- # # gui.line(x ,y ,x ,y+2,color) -- ## gui.line(x+1,y+1,x+2,y+2,color) -- # # gui.pixel(x+2,y ,color) end function Draw.start(x,y,color) -- # gui.line(x+1,y ,x+1,y+2,color) -- ### gui.pixel(x ,y+1,color) -- # gui.pixel(x+2,y+1,color) end function Draw.select(x,y,color) -- ### gui.line(x ,y ,x+2,y ,color) -- # # gui.line(x ,y+2,x+2,y+2,color) -- ### gui.pixel(x ,y+1,color) gui.pixel(x+2,y+1,color) end function Draw.X(x,y,color) gui.line(x ,y ,x+2,y+2,color) -- # # gui.pixel(x ,y+2,color) -- # gui.pixel(x+2,y ,color) -- # # end function Draw.Y(x,y,color) gui.line(x+1,y+1,x+1,y+2,color) -- # # gui.pixel(x ,y ,color) -- # gui.pixel(x+2,y ,color) -- # end function Draw.L(x,y,color) -- # gui.line(x ,y+2,x+2,y+2,color) -- # gui.line(x ,y ,x ,y+1,color) -- ### end function Draw.R(x,y,color) gui.line(x ,y ,x ,y+2,color) -- ## gui.line(x+1,y ,x+1,y+1,color) -- ## gui.pixel(x+2,y+2,color) -- # # end Draw[0]= function(left, top, color) -- ### gui.line(left ,top ,left ,top+4,color)-- # # gui.line(left+2,top ,left+2,top+4,color)-- # # gui.pixel(left+1,top ,color) -- # # gui.pixel(left+1,top+4,color) -- ### end Draw[1]= function(left, top, color) -- # gui.line(left ,top+4,left+2,top+4,color)-- ## gui.line(left+1,top ,left+1,top+3,color)-- # gui.pixel(left ,top+1,color) -- # end -- ### Draw[2]= function(left, top, color) -- ### gui.line(left ,top ,left+2,top ,color)-- # gui.line(left ,top+3,left+2,top+1,color)-- ### gui.line(left ,top+4,left+2,top+4,color)-- # gui.pixel(left ,top+2,color) -- ### gui.pixel(left+2,top+2,color) end Draw[3]= function(left, top, color) -- ### gui.line(left ,top ,left+1,top ,color)-- # gui.line(left ,top+2,left+1,top+2,color)-- ### gui.line(left ,top+4,left+1,top+4,color)-- # gui.line(left+2,top ,left+2,top+4,color)-- ### end Draw[4]= function(left, top, color) -- # # gui.line(left ,top ,left ,top+2,color)-- # # gui.line(left+2,top ,left+2,top+4,color)-- ### gui.pixel(left+1,top+2,color) -- # end -- # Draw[5]= function(left, top, color) -- ### gui.line(left ,top ,left+2,top ,color)-- # gui.line(left ,top+1,left+2,top+3,color)-- ### gui.line(left ,top+4,left+2,top+4,color)-- # gui.pixel(left ,top+2,color) -- ### gui.pixel(left+2,top+2,color) end Draw[6]= function(left, top, color) -- ### gui.line(left ,top ,left+2,top ,color)-- # gui.line(left ,top+1,left ,top+4,color)-- ### gui.line(left+2,top+2,left+2,top+4,color)-- # # gui.pixel(left+1,top+2,color) -- ### gui.pixel(left+1,top+4,color) end -- ### Draw[7]= function(left, top, color) -- # gui.line(left ,top ,left+1,top ,color)-- ## gui.line(left+2,top ,left+1,top+4,color)-- # end -- # Draw[8]= function(left, top, color) -- ### gui.line(left ,top ,left ,top+4,color)-- # # gui.line(left+2,top ,left+2,top+4,color)-- ### gui.pixel(left+1,top ,color) -- # # gui.pixel(left+1,top+2,color) -- ### gui.pixel(left+1,top+4,color) end Draw[9]= function(left, top, color) -- ### gui.line(left ,top ,left ,top+2,color)-- # # gui.line(left+2,top ,left+2,top+3,color)-- ### gui.line(left ,top+4,left+2,top+4,color)-- # gui.pixel(left+1,top ,color) -- ### gui.pixel(left+1,top+2,color) end local function Neg(n) if n >= 0x80000000 then n= n - 0xFFFFFFFF - 1 end return n end local function Pos(n) if n < 0 then n= n + 0xFFFFFFFF + 1 end return n end --***************************************************************************** local function GetColorBasic(Jn,b) --***************************************************************************** if not Jn then return White end --Does not exist if not ReadJoynum(Jn,b) then return Red end --Not pressed return Green --Button pressed end --***************************************************************************** local function GetColor(Frame,b) --***************************************************************************** local c= GetColorBasic(JoypadList[PlSel][Frame],b) if Frame%WatermarkInterval == 0 then c= bit.bor(Neg(Pos(bit.band(c, -0x03030400))*0.75),0xFF) end return c end --***************************************************************************** local function PaintFrame(x,y,Frame) --***************************************************************************** for b= 1, #btn do Draw[btn[b]](x+4*b,y,GetColor(Frame,b)) end end --***************************************************************************** local function PaintBorder(x,y) --***************************************************************************** local color= Green if not AutoList then color= Orange end gui.line(x, y,x, y+4,color) gui.line(x+2+4*#btn,y,x+2+4*#btn,y+4,color) gui.pixel(x+1 ,y ,color) gui.pixel(x+1 ,y+4,color) gui.pixel(x+1+4*#btn,y ,color) gui.pixel(x+1+4*#btn,y+4,color) if PLAYERS > 1 then Draw[PlSel](x-4,y,color) end end --***************************************************************************** local function PaintJoypadList(x,y) --***************************************************************************** gui.box(x+3,y+4*Past-1,x+4*#btn+3,y+4*Future+3,0x00000080) for i= Past, Future do PaintFrame(x,y+4*i, fc+i) end if Past <= 0 and Future >= 0 then PaintBorder(x+2,y-1) end end --############################################################################# --############################################################################# --User local lastkeys, keys= input.get(), input.get() --***************************************************************************** local function UpdateKeys() lastkeys= keys; keys= input.get() end local function Press(k) return keys[k] and (not lastkeys[k]) end --***************************************************************************** local KF= {} --***************************************************************************** local function KeyReader() --***************************************************************************** -- No "run while paused" code version. for k,v in pairs(keys) do if KF[k] then KF[k]() end end end local HandleMouse --***************************************************************************** local function HandleMouse_Main() --***************************************************************************** if keys.leftclick and lastkeys.leftclick then DispX= DispX + keys.xmouse - lastkeys.xmouse DispY= DispY + keys.ymouse - lastkeys.ymouse end end --***************************************************************************** local function HandleMouse_Option() --***************************************************************************** end HandleMouse= HandleMouse_Main local MaxRange= 54 ------------------------------------------------------------------------------- KF[solid]= function() Opq= math.min(Opq+0.125 , 1); gui.opacity(Opq) end KF[clear]= function() Opq= math.max(Opq-0.125 , 0); gui.opacity(Opq) end ------------------------------------------------------------------------------- KF[mp]=function() Past = Past -1; Future= math.min(Future,Past+MaxRange) end KF[lp]=function() Past = Past +1; Future= math.max(Future,Past) end KF[mf]=function() Future= Future+1; Past= math.max(Past,Future-MaxRange) end KF[lf]=function() Future= Future-1; Past= math.min(Past,Future) end KF[rs]=function() Past, Future= -12, 12 end ------------------------------------------------------------------------------- KF[Pl1Switch]= function() Pl1Control= not Pl1Control end local PlSwitch --***************************************************************************** local function PlSw() --***************************************************************************** for pl= 1, PLAYERS do UserControl[pl]= false ListControl[pl]= true end UserControl[PlSel]= "inv" ListControl[PlSel]= AutoList for pl= 1, PLAYERS do LoadJoypad(pl) end end PlSwitch= PlSw PlSw() ------------------------------------------------------------------------------- KF[PlayerSwitch]= function() ------------------------------------------------------------------------------- PlSel= (PlSel%PLAYERS)+1 PlSwitch() end ------------------------------------------------------------------------------- KF[Insert]= function() ------------------------------------------------------------------------------- local frame= fc while JoypadList[PlSel][frame] do frame=frame+1 end for i= frame, (fc+1), -1 do JoypadList[PlSel][i]= JoypadList[PlSel][i-1] end JoypadList[PlSel][fc]= 0 LoadJoypad(PlSel) end ------------------------------------------------------------------------------- KF[Delete]= function() ------------------------------------------------------------------------------- local i= fc while JoypadList[PlSel][i] do JoypadList[PlSel][i]= JoypadList[PlSel][i+1] i=i+1 end LoadJoypad(PlSel) end ------------------------------------------------------------------------------- KF[AutoSwitch]= function() ------------------------------------------------------------------------------- AutoList= not AutoList ListControl[PlSel]= AutoList end --############################################################################# --############################################################################# --Registry --***************************************************************************** local function RegisterAfter() --***************************************************************************** UpdateFC() RegAfterHandleJoypad() end emu.registerafter(RegisterAfter) --***************************************************************************** local function RegisterGui() --***************************************************************************** UpdateKeys() KeyReader() HandleMouse() DispX= Limits(DispX,-2,251-#btn*4) DispY= Limits(DispY,1+-4*Past,220-4*Future) PaintJoypadList(DispX, DispY) gui.pixel(0,0,0) end gui.register(RegisterGui) --***************************************************************************** local function RegisterLoad() --***************************************************************************** UpdateFC(); fc= fc-1 --Snes9x acts a tad off for the UpdateFC routine. for pl= 1, PLAYERS do LoadJoypad(pl) end end savestate.registerload(RegisterLoad) --***************************************************************************** while true do --Register boundary --***************************************************************************** RegBoundaryHandleJoypad() emu.frameadvance() end