Jump to content

Ultimate guide for a good MENU/INTERFACE


RCPOLSKI

Recommended Posts

Posted

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]

2pOLOQd.png

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.

gmDPIcC.png

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

YVhgDyn.png

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!

Posted

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

Posted

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.

Posted
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

 

Posted

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\n↩️RETURN' 
      }, 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

 

Posted

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

Posted

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\n↩️RETURN' 
      }, 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.

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.