Post subject: Buttons lua script.
Editor, Skilled player (1202)
Joined: 9/27/2008
Posts: 1085
A general-purpose script for producing buttons. I hope the helpful help text I added helps helpfully. Silly bit of code, but it's yet another way of allowing the user to interact with a lua script. I hope it feels convenient. ... Maybe I should create sample scripts that uses this... Download YummyButton.lua
Language: lua

--[[ Welcome to my Buttons script! To start, put in the following lines: require("thisScript") NewBtn{x= 1, y= 1, fn= function() ((Various code here)) end} And all of a sudden, you have this bluish button on the top left corner of the emulator window, once you run the script. Use the mouse to click the button. The code you put in will happen. Now, there are ways to configure these buttons to your desires. For one thing, make as many NewBtn objects as you like. This script will keep track of 'em. For another, change that x and y up there if you don't like the NewBtn being stuck in the top-left corner. Finally, there's various options you can use to tweak your NewBtn desires. REQUIRED: x - X position. Where is the button horizontally? y - Y position. Where do we put it vertically? fn - Function. The button had better do something!! Optional: text - Cute text to display on button. May size button automatically. x1 - Identical to the otherwise required x. If both present, x has priority x2 - The right side of the button y1 - Identical to y. y1 can take y's place, but if you make both, y is used y2 - The bottom side of the button width - Width of button. Would interfere with x2, but x2 takes priority. height- Height of button. Use if you don't feel like using y2. color - General color scheme of the button. This affects all aspects of color. MBC - Main Border Color. "Main" is when your mouse isn't over the button. MFC - Main Fill Color. ... I use "Main" for lack of better words... SBC - Sub Border Color. "Sub" is used when you're mousing over the button. SFC - Sub Fill Color. Anyone have better words for me? tag - Spare variable. Included functions: draw - Draws the button. Don't bother using it, it's automatically called. recolor- Modifies the color scheme. Takes in one value depicting base color. move - Moves the button so that the top-left corner matches the x,y input. While it is packaged for simple use as is, the more savvy programmers may want to read on. I pass the button object to the clicked button function as the only parameter. I can't think of any real way of passing variables you want for it, but I added the "tag" variable for this purpose. Technically, after the button is constructed, you can add new parameters to the button object itself, but the "tag" variable seemed like a convenient thing to add to the constructor. In addition, I put the HandleBtns function in gui.register by default, but go ahead and call it in another function and replace the gui.register callback. This function will return whatever the button function returns, so if it is in your interest to have the button function return something, it will do so through _FRK_Btn.HandleBtns. The NewBtn constructor returns the button object it created as a table for you to mess around with, should you have a reason to. Maybe you want to move it around or change its colors, who knows. Finally, _FRK_Btn.MB holds all my buttons. You can, in the middle of creating new buttons, set another variable (MB2, perhaps?), set _FRK_Btn.MB = {}, then create more buttons. You'll have two different sets of buttons which you can switch between, but you'll have to make your own functions to do the switch. But if you're not experienced in lua programming, none of the previous four paragraphs are of any interest to you. The simple use of these buttons are good enough for many uses. ]]-- _FRK_Btn= {} local EMUCHWID= 6 local EMUCHHGT= 8 if stylus then EMUCHWID= 6; EMUCHHGT= 8 elseif snes9x then EMUCHWID= 4; EMUCHHGT= 6 elseif VBA then EMUCHWID= 4; EMUCHHGT= 6 end _FRK_Btn.ClickType= "leftclick" _FRK_Btn.MB= {} keys, lastkeys= {}, {} function UpdateKeys() lastkeys= keys; keys= input.get() end function Press(k) return keys[k] and not lastkeys[k] end --***************************************************************************** function _FRK_Btn.FindBtn() --***************************************************************************** if (keys.xmouse == lastkeys.xmouse) and (keys.ymouse == lastkeys.ymouse) then return end local X,Y= keys.xmouse, keys.ymouse for i= 1, #_FRK_Btn.MB do -- linear scan, darn it! local n= _FRK_Btn.MB[i] if (Y >= n.y1) and (Y <= n.y2) and (X >= n.x1) and (X <= n.x2) then return i end end return -1 end --***************************************************************************** function _FRK_Btn.ClickBtn(id) --***************************************************************************** if id and _FRK_Btn.MB[id] then return _FRK_Btn.MB[id]:fn() end end --***************************************************************************** function _FRK_Btn.DrawUnsel(B) --***************************************************************************** gui.box(B.x1, B.y1, B.x2, B.y2, B.MFC, B.MBC) gui.text(B.xt, B.yt, B.text) end --***************************************************************************** function _FRK_Btn.DrawSel(B) --***************************************************************************** gui.box(B.x1, B.y1, B.x2, B.y2, B.SFC, B.SBC) gui.text(B.xt, B.yt, B.text) end --***************************************************************************** function _FRK_Btn.ShowBtns() --***************************************************************************** B= _FRK_Btn.MB for i= 1, #B do B[i]:draw() end end --***************************************************************************** function _FRK_Btn.Recolor(B,color) --***************************************************************************** -- Does not like strings. Still will accept them, however. local t= type(color) if t == "string" then -- Uh, no. No tricky color stuff. Sorry. B.MBC= Cns.color B.SBC= Cns.color B.MFC= 0x00000040 B.SFC= 0xC0C0C0C0 --Oh, not a string! Better be table or number, please. else if t == "table" then color= 0 local q= color.r or color[1] if q then color= bit.lshift(q,24) end q= color.g or color[2] if q then color= bit.bor(color,bit.lshift(q,16)) end q= color.b or color[3] if q then color= bit.bor(color,bit.lshift(q, 8)) end q= color.a or color[4] if q then color= bit.bor(color,q) else color= bit.bor(color,0xFF) end end B.MBC= color B.MFC= bit.rshift(bit.band(color,0xFEFEFEFE),1) B.SBC= bit.bor(color+bit.band(0xFFFFFFFF-color,0xFEFEFEFE)/2,0xFF) B.SFC= color end end --***************************************************************************** function _FRK_Btn.Move(B, x,y) --***************************************************************************** -- Moves the whole button for you! if x then local XDiff= x - B.x1 B.x1= x B.x2= B.x2 + XDiff B.xt= B.xt + XDiff end if y then local YDiff= y - B.y1 B.y1= y B.y2= B.y2 + YDiff B.yt= B.yt + YDiff end end --***************************************************************************** function _FRK_Btn.NewBtn(Cns) --***************************************************************************** -- the button constructor! --Insert universal function pointers while creating a new table. local NewTbl= { draw= _FRK_Btn.DrawUnsel, recolor= _FRK_Btn.Recolor, move= _FRK_Btn.Move } --Insert presumed information. NewTbl.fn= Cns.fn NewTbl.x1= Cns.x or Cns.x1 NewTbl.y1= Cns.y or Cns.y1 NewTbl.tag= Cns.tag --Check if user defined the right side. if Cns.x2 then NewTbl.x2= math.max(NewTbl.x1,Cns.x2) NewTbl.x1= math.min(NewTbl.x1,Cns.x2) elseif Cns.width then NewTbl.x2= NewTbl.x1 + Cns.width end --Check if user defined the bottom side. if Cns.y2 then NewTbl.y2= math.max(NewTbl.y1,Cns.y2) NewTbl.y1= math.min(NewTbl.y1,Cns.y2) elseif Cns.height then NewTbl.y2= NewTbl.y1 + Cns.height end --Look for text. Do tricky stuff based on where to put the darn text or --how to resize the button. if Cns.text then NewTbl.text= tostring(Cns.text) local len= #NewTbl.text * EMUCHWID if NewTbl.x2 then NewTbl.xt= math.floor((NewTbl.x1 + NewTbl.x2 - len)/2) else NewTbl.x2= NewTbl.x1 + len + 3 NewTbl.xt= NewTbl.x1 + 2 end if NewTbl.y2 then NewTbl.yt= math.floor((NewTbl.y1 + NewTbl.y2 - 8)/2) else NewTbl.y2= NewTbl.y1 + EMUCHHGT + 4 NewTbl.yt= NewTbl.y1 + 2 end else NewTbl.text= "" NewTbl.xt= NewTbl.x1 NewTbl.yt= NewTbl.y1 if not NewTbl.x2 then NewTbl.x2= NewTbl.x1 + 8 end if not NewTbl.y2 then NewTbl.y2= NewTbl.y1 + 8 end end --Mess with colors! if Cns.color then NewTbl:recolor(Cns.color) else NewTbl.MBC= Cns.MBC or 0x0020FFC0 NewTbl.MFC= Cns.MFC or 0x00000040 NewTbl.SBC= Cns.SBC or 0x0080FFFF NewTbl.SFC= Cns.SFC or 0x2000C0C0 end --Finally add the button to our MB array. local index= #(_FRK_Btn.MB)+1 _FRK_Btn.MB[index]= NewTbl --Here's the button object in case you want to handle it yourself. return NewTbl end local ID= -1 --***************************************************************************** function _FRK_Btn.HandleBtns() --***************************************************************************** UpdateKeys() local id= _FRK_Btn.FindBtn() if id then if ID ~= -1 then _FRK_Btn.MB[ID].draw= _FRK_Btn.DrawUnsel end if id ~= -1 then _FRK_Btn.MB[id].draw= _FRK_Btn.DrawSel end ID= id end _FRK_Btn.ShowBtns() if Press(_FRK_Btn.ClickType) and (ID ~= -1) then return _FRK_Btn.ClickBtn(ID) end end --============================================================================= if not FRK_NoAuto then --============================================================================= gui.register(_FRK_Btn.HandleBtns) NewBtn= _FRK_Btn.NewBtn end
Post subject: Super Mario World -- Powerup buttons script
Editor, Skilled player (1202)
Joined: 9/27/2008
Posts: 1085
Something small. Use with Snes9x while playing Super Mario World. The purpose is to let you click one of four buttons using the mouse to change powerups at will. I hope it's a nice example on how to make use of these buttons. Download SMWPowerupButtons.lua
Language: lua

require("YummyButton") local PowerUpAddr= 0x7E0019 local function SetPowerUp(B) memory.writebyte(PowerUpAddr, B.tag) end local T= { [0]= NewBtn{x= 1, y= 3, fn= SetPowerUp, text= "s", tag= 0, color= 0x00FF00C0}, NewBtn{x= 17, y= 3, fn= SetPowerUp, text= "B", tag= 1, color= 0xFF0000C0}, NewBtn{x= 33, y= 3, fn= SetPowerUp, text= "C", tag= 2, color= 0xFF0000C0}, NewBtn{x= 49, y= 3, fn= SetPowerUp, text= "F", tag= 3, color= 0xFF0000C0} } local LastScan= 0 local function CheckPower() local Scan= memory.readbyte(PowerUpAddr) if Scan ~= LastScan then T[LastScan]:recolor(0xFF0000C0) T[Scan]:recolor(0x00FF00C0) LastScan= Scan end end emu.registerafter(CheckPower)
Skilled player (1652)
Joined: 11/15/2004
Posts: 2202
Location: Killjoy
I've been meaning to try this, I just haven't thought of an application for it yet.
Sage advice from a friend of Jim: So put your tinfoil hat back in the closet, open your eyes to the truth, and realize that the government is in fact causing austismal cancer with it's 9/11 fluoride vaccinations of your water supply.
Joined: 1/26/2009
Posts: 558
Location: Canada - Québec
I can draw the button but somehow when I leftlick on it, my function won't trigguer at all on pcsxrr. I might test with fceu later. While been there, I was curious if there could be a way to redraw/update the screen while the emulator is paused. I know that gens is more featured on this side, but if there could be a way as similar as gui.register can track hotkey down, that would be very appreciated and useful :)
Editor, Skilled player (1202)
Joined: 9/27/2008
Posts: 1085
Emulator? Does the button get highlighted at all when you mouse over it? That is to say, does it have any visible difference in color when you're moving the mouse on and off the button? Was the emulator paused at the time? I recall there being some sort of emu.wait and gui.redraw somewhere. I don't have the lua documentation handy for Gens, and I'm completely unfamiliar with the emulator. I recall there being something like gui.redraw and emu.wait functions for Gens, but it would take several lines to have them implemented. I haven't seen similar functions for Snes9x or VBA, however. In particular, the example script I have for Super Mario World will not react to the mouse if you have the emulator paused. Its magical transformation can only happen when the emulator is running, thanks to the fact gui.register is never called more than once per frame, and Snes9x 1.43 and 1.51 is missing the critical components to call lua code while paused. Again, I'm asking for what emulator you're using. I'm going to guess Gens. Edit: This is a stab into the dark, but if you're using Gens, and my wild guessing is any good, this piece of code might actually do something:
Language: lua

local lk= input.get() --***************************************************************************** local function BoundaryKeyScan() --***************************************************************************** local k= input.get() if k.A and not lk.A then --Pseudo frameadvance NoAdvance= false LuaPause= true end if k.B and not lk.B then --Pseudo pause/unpause NoAdvance= false LuaPause= not LuaPause end lk= k end while true do NoAdvance= true while NoAdvance do gui.redraw() gens.wait() BoundaryKeyScan() end repeat BoundaryKeyScan() gens.frameadvance() until LuaPause end
Gens? Stick this at the bottom of your code, getting rid of any while true do gens.frameadvance() end you might already have in there. I found the documentation. I just haven't gone far enough to actually find a ROM someplace and run the emulator yet. All this, currently, is a wild guess. First, it hinges on the fact you're using Gens. Second, it also hinges on the functions doing what I think they do. Lastly, the fact I can't even test this stuff myself at this hour means there's no way for me to find out on my own if what I typed even works. But here's something to try anyway. The chances it works are low, but I'll be sure to reward myself with a pat if it works out anyway.
Post subject: Emulator: PCSXrr
Joined: 1/26/2009
Posts: 558
Location: Canada - Québec
I'm using pcsxrr and I tried both paused/unpaused. There no difference when I'm overing the button... maybe I did something wrong?
Language: lua

require("YummyButton") local X = 151; local Y = 230; local Z = 0; function test() --print(Z) --button2:recolor(0x00FF00C0); button2:recolor(Z); Z = Z +0x20; end button2 = NewBtn{x= 50, y= 90, fn=test, text= "Hello", tag= 0, color= 0xFF0000C0} button2:draw(); --emu.registerafter(test) while true do emu.frameadvance() end
I talked about gens, because I prefer to work frame by frame, rather than unpaused and that's why a homemade redraw feature would be handy for working. Thought now thinking about it, I suppose that it could be easier to simply make a savestate/loadstate for redrawing the current frame, might need some testing...
Editor, Skilled player (1202)
Joined: 9/27/2008
Posts: 1085
pcsxrr... Another one I can't say I'm familiar with. The button2:draw(); line is optional. My script already handles drawing stuff. A line in my file says Don't bother using it, it's automatically called. But that doesn't solve your problem... Give me some time to think of something... But to start with, uncomment the print(Z) line. I'm running your code pretty well from DeSmuME here. (Although I may want to double-check my recolor routine) You might want to throw in gui.text(1,1,keys.xmouse) in _FRK_Btn.HandleBtns(). Should at least show the X position of the mouse. This will take further thought...