RCPOLSKI Posted November 9, 2020 Posted November 9, 2020 Hello there! Once again, its me, RCPOLSKI... I had a good time with GG for these past 4 years. Helped with the PT-BR translation (Holdin' up to 92% of its total progress) and i had some topics on the spotlight too, the best one was in the same matter of this topic, a simple [ON] and [OFF] switch. So for today, I'll teach and explain 3 points to make your Menu more user friendly ON and OFF status SubMenus Multi Status For easy understanding, please consider reading the GG LUA Scripting Documentation 1. [ON] and [OFF] I'll take a reproach on this matter. In fact, a lot of people came to use my method of letting the user know if the function is running or not. And this is a good point in a Menu... It makes the menu compact, without the needing of 2 instances in gg.choice (one to activate and another to deactivate). It prevents codeloop or crashes if your code can't handle a second call in case of the user pressing ON or OFF 2 times in a row. Let's go then. First you'll need to declare a global variable, doesnt matter if it is a integer or string value. I recommend doing it as a table, cuz you can short your code and prevent double stack. -- The use of '[' is tottaly optional. But if you're willing to use it, do it in these global variables to prevent a concat writting isOn = '[ON] ' -- Consider adding a blank space in front if your status will be at the end or in the back if it'll be at the beggining isOff = '[OFF] ' chStatus = {isOn, isOff, isOff} -- The table name doesn't matter, just remember to add isOn/isOff for every cheat You took the fact that I said global variables? It means that it is outside a scope like a function and so, it can be used globabally and carry information from a scope to another. My last tutorial on this, didnt stated that before. And some people without a thinking of it, came to write that same variables throughout the entire script for every single cheat. But now, we're using a table, so we can define the status of each cheat from a single call without affecting any of already running cheats by calling or writing it like this: function Main() gg.choice({ chStatus[1] .. 'CheatOne', -- The number inside [x] represents the position of your cheat storage inside the chStatus table. chStatus[2] .. 'CheatTwo', -- If at any case you use the same number in two or more cheats, they'll share the same status chStatus[3] .. 'CheatThree' -- the ".." is a concat statement, it means that you're trying to glue the argument content with anything inside this -> ' ' }, nil) end Ok then, now we have a way of reading the initial status of every cheat, but what does it matters if we don't know how to overwrite it... Actually it is more simple than you think! We just need a new function to compare and overwrite this. function Status(cheat) -- I set 'cheat' as an indefined parameter, it's not a string neither a number. So u can share any data with it if chStatus[cheat] == isOn then -- We'll just compare if the chStatus[value provided by the parameter cheat] is ON or OFF chStatus[cheat] = isOff -- The value provided by the parameter is going to point to a position inside the chStatus table else chStatus[cheat] = isOn -- And so we can overwrite values end end But how can we provide the parameter a value? Easy thing there, just call the function Status and inside ( ) you set your parameter to the position of its cheat. Something like Status(2) is equals Status(cheatTwo) Here we go, the entire code: -- Variables isOn = '[ON] ' isOff = '[OFF] ' chStatus = {isOn, isOff, isOff} -- Function overwritting status function Status(cheat) if chStatus[cheat] == isOn then chStatus[cheat] = isOff else chStatus[cheat] = isOn end end -- Main function function Main() menu = gg.choice({ chStatus[1] .. 'CheatOne', chStatus[2] .. 'CheatTwo', chStatus[3] .. 'CheatThree' },nil) if menu == 1 then Status(1) -- Calling the Status function and setting its 'cheat' parameter as position 1 doCheatOne() end if menu == 2 then Status(2) -- Position 2 = chStatus[2] doCheatTwo() end if menu == 3 then Status(3) -- Same here doCheatThree() end if menu == nil then os.exit() end end Hope you enjoyed the new method! 2. Sub menu (aka a menu inside a menu) One of the main differences noticiable between computer and mobile scripting, is the complexity of computers scripts. I've been in this scene for 7 years now. I work with C++ better than any other language, but Lua is a light and easy languange to use for scripting... Still, it lacks in statements like CASE or SWITCH. I never saw a single script in this entire forum with sub menus in these 4 years. I think I know why... GG forms are persistents, it means that only one function (2020, Usually Main) can carry the forms drawing, if you try to add a second function drawing, it'll overlap behind the first function and be forgoten by the loop that open your script. So people tried to separate cheats into categories and made them a function for each. Which proved to do nothing cuz as I said, only one function can carry the forms drawing and receive enough attention from the loop. So considering that only one function has the power, we aint prohibited to do everything we want inside that same function! function Main() menu = gg.choice({ -- This is a normal menu, which contains the categories to select 'Player', 'Weapons', 'Cheese' }, nil) if menu == 1 then pMenu = gg.choice({ -- Here it comes, the sub menu categorized as "Player" 'Godmode', 'Speedhack', '\n\nRETURN' -- I always recommend to add a return/back choice to prevent conflicts between menus, like pressing "cancel" and ending the script }, nil, 'Player') if oMenu == 1 then godMode() end if oMenu == 2 then speedHack() end if oMenu == 3 then Main() -- Just recall the function Main() to re-open the first menu end end if menu == 2 then wMenu = gg.choice({ -- If you look closer, every menu has its own const name. Menu > pMenu > wMenu > cMenu. Don't try using the same 'Infinite ammo', 'Rapid Fire', '\n\nRETURN' -- The two breaklines (\n\n) are there trying to create a space between the cheats and the RETURN action }, nil, 'Weapons') -- You know how it continues, wont be writting all of this! end if menu == 3 then cMenu = gg.choice({ 'Good cheese', -- As example, I'm only using 2 options, but u're free to include as many you want! 'Bad Cheese', '\n\nRETURN' }, nil, 'Cheese') -- You know how it continues, wont be writting all of this! end end And here we've a Menu inside a Menu. Don't forget the RETURN/BACK option, cuz trusting in the "cancel" button will only give the user a bye bye from the script. Keep in mind to use it only with gg.choice and never use it with gg.multiChoice (the results are crashes)... While using gg.prompt doesnt show too much diference since it is an extra form by default! 3. Multi Status Now that we know how to create and store an ON and OFF status and how to make Sub Menus, we're open to new possibilities. Like showing the cheats activated in the submenu right on the main menu... Confused? Take a look Of course you'd say that as you already know the two methods above, it's just storing it inside a table and calling them... And thats right, but we're working with a lot of cheats options and as many combinations possible. Player A could go with Godmode, Speedhack and Rapid Fire while Player B full on. So you're saying that you'll code every single possible arrangement of cheats activated? No, we don't do that here! As we don't spam emojis inside a menu (If you do, I pity you, please stop it!). So then, lets proceed We can aproach this with inumerous ways, but I'll teach you the way that i use. I give every cheat a unique number/position isOn = ' [ON > ' -- This variables are totally optional... You could only point the cheats that are running by adding their names to the category isOff = ' [OFF]' -- This one too chStatus = {isOff, isOff, isOff, isOff} -- As i said, every cheat has its unique number or position, which means that chStatus[2] corresponds to allCheats[2] allCheats = {'Godmode', 'Speedhack', 'Infinite Ammo', 'Rapid Fire'} -- Adding this table will help you understand each position and short your code in the future! -- Now I'm creating tables for each category, again inumerous ways, but this is easier to manage playerCtg = {'', ''} -- IMPORTANT: You need to define its values as blank strings. As we've 2 cheats available for Player Category, there are 2 values! weaponsCtg = {'', ''} -- Leaving it blank {} or nil is going to result in crashes, since values pre-alocated conserves their position We'll do the same thing as the ON and OFF method, but now adding a new parameter to the Status(cheats). function Status(cheat, pos, category) -- Notice that now we've another 2 parameters... -- Cheat still refers to the cheat position inside the allCheats table -- Pos refers to the position of the cheat inside the submenu: Player > Godmode or Speedhack, etc... -- Category refers to the category of the cheat: Player, Weapons, etc... if (category == 1) then -- With the category parameter, we can set the modifier to a scope if chStatus[cheat] == isOff then -- Checking if OFF using cheat parameter | Eg: chStatus[2] == isOff chStatus[cheat] = isOn -- If yes, set it to ON playerCtg[pos] = allCheats[cheat] -- Now with the pos parameter, it changes the string inside playerCtg table using allCheats position else -- As we're working inside a category with only 2 possibilities (ON/OFF) a simple 'else' after each if is enough chStatus[cheat] = isOff playerCtg[pos] = '' -- This is why pre-set the tables, conserve their position! end elseif (category == 2) then if chStatus[cheat] == isOff then chStatus[cheat] = isOn weaponsCtg[pos] = allCheats[cheat] else chStatus[cheat] = isOff weaponsCtg[pos] = '' end end end Now, every time that an user activate a cheat, it'll be added to its own Category Table and to read it, this code makes sure that it is already pointed with the value in relation with the string... Some of you could say that it'd be easier if I used table.insert( ) and table.remove( ) to do it. But have you tried? LUA can't conserve table positions when using table.remove( )... If you know somehow do it, feel free to post! By now we have variables into tables and a compare/overwrite function. Let's move to the real fun! function Main() -- If Player or Weapons categories are empty, it'll present a default string... It could be anything from "Player" to "Player [OFF]" and whatever if (playerCtg[1] == '') and (playerCtg[2] == '') then playerMenu = 'Player [OFF]' elseif (playerCtg[1] ~= '') and (playerCtg[2] ~= '') then -- Show only if all the strings inside the table aren't blank playerMenu = 'Player [' .. table.concat(playerCtg, ', ') .. ']' elseif (playerCtg[1] == '') or (playerCtg[2] == '') then -- Show only if one or more strings inside the table aren't blank playerMenu = 'Player [' .. table.concat(playerCtg) .. ']' end -- Same thing, but for weaponsCtg table... Yes, you need to do it for every single category/option if (weaponsCtg[1] == '') and (weaponsCtg[2] == '') then weaponsMenu = 'Player [OFF]' elseif (weaponsCtg[1] ~= '') and (weaponsCtg[2] ~= '') then weaponsMenu = 'Player [' .. table.concat(weaponsCtg, ', ') .. ']' elseif (weaponsCtg[1] == '') or (weaponsCtg[2] == '') then weaponsMenu = 'Player [' .. table.concat(weaponsCtg) .. ']' end menu = gg.choice({ playerMenu, -- As you can see, it's a variable instead of a direct string... The variable is written above (Eg. default: Player [OFF]) weaponsMenu, 'Cheese' }, nil) if menu == 1 then oMenu = gg.choice({ 'Godmode', 'Speedhack', '\n\nRETURN' }, nil) if oMenu == 1 then Status(1, 1, 1) -- Calling Status(cheat, pos, category) godMode() end if oMenu == 2 then Status(2, 2, 1) -- Same thing, category stil the same, but cheat and pos are diferent speedHack() end if oMenu == 3 then Main() end end if menu == 2 then tMenu = gg.choice({ 'Infinite ammo', 'Rapid Fire', '\n\nRETURN' }, nil) if tMenu == 1 then Status(3, 1, 2) -- Category changed, cheat still going up and pos is back to 1, cuz its position is 1 of 2 into category 2 godMode() end if tMenu == 2 then Status(4, 2, 2) -- Again, cheat up, pos up and category is the same speedHack() end if tMenu == 3 then Main() end end -- 3rd menu and whatever... end end And this ends our 3rd point in this topic! Thank you! I'd like to ty for reading till here... I hope this help you in your journey. If this post have a somehow an impact in our community, I'd be glad in sharing how to optimize your script. I've been working as developer for more than 1 decade, 7 of them as third-party software for games... Computer and android have a lot of diferences, but they speak the same language inside running apps. Instead of brute search as numbers, we can go for byte/opcodes with wildcards and find the address in less than 1 second... Making your script more reliable. Well, thats all. Feel free to use and improve all the code here. No need to put my name as contribuitor... Knowledge should be shared for free! If you really enjoyed the content provided here and wanna contribute somehow, feel free to donate, any amount is appreciated!
animehack Posted November 10, 2020 Posted November 10, 2020 thx for sharing the info your implementation of of sub menus is much more efficient then the one i have been using for about 5 months and your post about on off status was great thx for sharing the info
MonkeySAN Posted November 10, 2020 Posted November 10, 2020 in SUB MENU How can we return to sub menu (pMenu or any sub menu) after we execute any hack in it? for example if.. after i run 'Godmode' then it return to Player menu so i can run 'Speedhack' next.. instead to Main menu. sorry for my nooby nature.
RCPOLSKI Posted November 11, 2020 Author Posted November 11, 2020 7 hours ago, MonkeySAN said: sorry for my nooby nature. Don't worry buddy, curiosity leads to knowledge 7 hours ago, MonkeySAN said: How can we return to sub menu (pMenu or any sub menu) after we execute any hack in it? That is simple... Instead of setting your sub menu inside 'menu' calls like this menu = gg.choice({ "Player", "Weapons", "Cheese" }, nil) if menu == 1 then -- Sub Menu 'Player' here else if menu == 2 then -- Sub Menu 'Weapons' here else if menu == 3 then -- Sub Menu 'Cheese' here end You first set a parameter at Main(menu) function and make a direct menu call... You've 2 ways of doing it, first is when a player get into a submenu and select an option. The menu//GG UI CLOSES but when re-opened, it shows the submenu instead the main menu rMenu = 0 -- First create an int variable that set the menu. 0 = Main menu | The name is optional function Main(rMenu) -- Now you have a parameter at Main function if rMenu == 0 then -- As var rMenu is set 0 by default, it will call the menu below when initialized menu = gg.choice({ "Player", "Weapon", "Cheese" }, nil) if menu == 1 then Main(1) end -- Calls function Main again, but its parameter is 1, so it will call any code that is at rMenu instance if menu == 2 then Main(2) end -- Same here if menu == 3 then Main(3) end -- Same here elseif rMenu == 1 then -- As you called Main(1) at menu == 1, it will go right here pMenu = gg.choice({ "Godmode", "Speehack", "\n\nReturn" }, nil) rMenu = 1 -- If you set it here, you will have to set rMenu = 0 before Main(0) at option 3 that is RETURN if pMenu == 1 then rMenu = 1 -- If you set it here and every option below, it will only set rMenu to 1 if a function was selected godMode() elseif pMenu == 2 then speedHack() elseif pMenu == 3 then rMenu = 0 -- Set rMenu to 0 here ONLY IF you set rMenu outside the pMenu instance Main(0) -- As pMenu 3 is RETURN, just call Main(0) to return to the Main Menu end elseif rMenu == 2 then -- Weapons menu elseif rMenu == 3 then -- Cheese menu end end The second way is when a player select an option, but the menu do not closes... Allowing multiple choices function Main(rMenu) -- The parameter still there, but rMenu variable is out! if rMenu == 0 then -- It'll be called here because down there, at your gg.setVisible loop, instead of just doing Main(), you'll call Main(0) menu = gg.choice({ "Player", "Weapon", "Cheese" }, nil) if menu == 1 then Main(1) end -- Still the same if menu == 2 then Main(2) end -- Same here if menu == 3 then Main(3) end -- Same here elseif rMenu == 1 then -- Here you'll always call Main(1) pMenu = gg.choice({ "Godmode", "Speehack", "\n\nReturn" }, nil) if pMenu == 1 then godMode() Main(1) -- Now you'll call the submenu again cuz Main(1) = pMenu elseif pMenu == 2 then speedHack() Main(1) -- Remember to always call it at the end, if you call it first, your cheat won't be played elseif pMenu == 3 then Main(0) -- No need to do nothing more than calling this RETURN as Main(0) end elseif rMenu == 2 then -- Here you'll always call Main(2) -- Weapons menu elseif rMenu == 3 then -- Here you'll always call Main(3) -- Cheese menu end end REMEMBER TO CHANGE YOUR LOOP! gg.setVisible(true) while true do if gg.isVisible() then gg.setVisible(false) Main(0) -- or Main(rMenu) if you went with the first way and declared the variable end gg.sleep(100) end
MonkeySAN Posted November 11, 2020 Posted November 11, 2020 wow...thats great im not sure i understand it all but do please comment on this...sir. function Main(rMenu) if rMenu == 0 then menu = gg.choice({ '\n➣ Player', '\n➣ Weapons', '\n➣ Cheese', '\n\n EXIT', }, nil) if menu == nil then gg.toast("minimize") end if menu == 1 then Main(1) end if menu == 2 then Main(2) end if menu == 3 then Main(3) end if menu == 4 then gg.toast("Canceled") os.exit() end elseif rMenu == 1 then pMenu = gg.choice({ '\n• Godmode', '\n• Speedhack', '\n\n RETURN' }, nil, 'Player Menu') if pMenu == 1 then gg.alert("God Mode ON") Main(1) elseif pMenu == 2 then gg.alert("Speed Hack ON") Main(1) elseif pMenu == 3 then gg.toast('return to main') Main(0) end elseif rMenu == 2 then wMenu = gg.choice({ '\n• Infinite ammo', '\n• Rapid Fire', '\n\n RETURN' }, nil, 'Weapons Menu') if wMenu == 1 then gg.alert("Infinite Ammo ON") Main(2) elseif wMenu == 2 then gg.alert("Rapid Fire ON") Main(2) elseif pMenu == 3 then gg.toast('return to main') Main(0) end elseif rMenu == 3 then cMenu = gg.choice({ '\n• Good cheese', '\n• Bad Cheese', '\n\nRETURN' }, nil, 'Cheese On Menu') if cMenu == 1 then gg.alert("Yummy....") Main(3) elseif cMenu == 2 then gg.alert("Gross....") Main(3) elseif cMenu == 3 then gg.toast('return to main') Main(0) end end end while true do if gg.isVisible() then gg.setVisible(false) Main(0) end gg.sleep(100) end
RCPOLSKI Posted November 11, 2020 Author Posted November 11, 2020 Yeah, that's it... You're free to set as many options you want since you follow the count But in your toasts, if you set it like gg.alert("Rapid Fire ON") or whatever without something like the ON & OFF method (doesn't need to have the whole thing, just a comparer) even if the player turn off the hack, it still shows that same toast. So consider adding the chStatus and allCheats tables and the function Status(cheat) in collaboration with simple function to return the right toast... Easy to do it would be -- Considering ON & OFF method, chStatus and allCheats tables and function Status(cheat) added function myToast(cheat) -- You can put it anywhere, but I would put it below function Status(cheat) standardToast = allCheats[cheat] .. ' is ' .. chStatus[cheat] -- The function pick the string insided allCheats and its status (ON or OFF) based at the parameter pointed when calling myToast(x) return standardToast -- Remember to return it! end if pMenu == 1 then gg.toast(myToast(1)) -- Will return a toast pointing at cheat 1 status and string... So it can return 'Godmode is ON' or 'Godmode is OFF' without needing to write it twice godMode() Main(1) end And I was high when I wrote the tutorial... So I did a mistake saying that you can't use anything instead of a "RETURN" option... You can simple go back from a sub menu to the main menu doing this if pMenu == nil then Main(0) end There are a lot of ways to customize your script
MonkeySAN Posted November 11, 2020 Posted November 11, 2020 i did ON/OFF before so im going with this.. on = '[ON]' off = '[OFF]' A = off F = off G = off S = off function Main(rMenu) if rMenu == 0 then menu = gg.choice({ '\n➣ Player', '\n➣ Weapons', '\n➣ Cheese', '\n\n EXIT', }, nil) if menu == nil then gg.toast("minimize") end if menu == 1 then Main(1) end if menu == 2 then Main(2) end if menu == 3 then Main(3) end if menu == 4 then gg.toast("Canceled") os.exit() end elseif rMenu == 1 then pMenu = gg.choice({ '\n• Godmode '..G, '\n• Speedhack '..S, '\n\n RETURN' }, nil, 'Player Menu') if pMenu == 1 then if G == off then gg.alert("God Mode ON") G = on Main(1) elseif G == on then gg.alert("God Mode OFF") G = off Main(1) end end if pMenu == 2 then if S == off then gg.alert("Speed Hack ON") S = on Main(1) elseif S == on then gg.alert("Speed Hack OFF") S = off Main(1) end end if pMenu == 3 then gg.toast('return to main') Main(0) end elseif rMenu == 2 then wMenu = gg.choice({ '\n• Infinite Ammo '..A, '\n• Rapid Fire '..F, '\n\n RETURN' }, nil, 'Weapons Menu') if wMenu == 1 then if A == off then gg.alert("Infinite Ammo ON") A = on Main(2) elseif A == on then gg.alert("Infinite Ammo OFF") A = off Main(2) end end if wMenu == 2 then if F == off then gg.alert("Rapid Fire ON") F = on Main(2) elseif F == on then gg.alert("Rapid Fire OFF") F = off Main(2) end end if pMenu == 3 then gg.toast('return to main') Main(0) end elseif rMenu == 3 then cMenu = gg.choice({ '\n• Good cheese', '\n• Bad Cheese', '\n\nRETURN' }, nil, 'Cheese On Menu') if cMenu == 1 then gg.alert("Yummy....") Main(3) elseif cMenu == 2 then gg.alert("Gross....") Main(3) elseif cMenu == 3 then gg.toast('return to main') Main(0) end end end while true do if gg.isVisible() then gg.setVisible(false) Main(0) end gg.sleep(100) end thats the way of how i understand it and work just fine for noob like me.
Recommended Posts
Archived
This topic is now archived and is closed to further replies.