Once you understand how tables work and you feel confident using them effectively, this should be an easy task. I'll go from simple menus to what you're asking to make sure you understand all the concepts needed.
The basic idea of a menu in LUA is simple. Have a table with all your options, and a variable with your current selection to use as a key/index to the table. For example...
local menu = {"Option 1","Option 2"}
local selection = 1
This code does a few things. First, it creates a table in memory with 2 strings in it, then assigns that "menu" variable to be a reference to it (so using menu will access the table in memory). Secondly, it creates a selection variable and gives it the value 1. We can use that selection to get a part of the table.
menu[selection] -- this evaluates to "Option 1", because the value of selection is 1 and the first entry of the table is "Option 1". here, selection is referred to as the key.
menu[1] -- this also evaluates to "Option 1", because the first entry of the table is "Option 1". here, 1 is referred to as the key.
menu[2] -- this evaluates to "Option 2", because the second entry of the table is "Option 2". here, 2 is referred to as the key.
Pretty simply stuff. Now, for it to work like a menu that you can browse through, you just simply have to allow the value of selection to change according to some button presses. Below is a full example.
function MissionSetup()
-- Transition to coordinates (270, -110, 6) in area #0 (outside).
AreaTransitionXYZ(0,270,-110,6)
end
function main()
-- First, create our table, and create the 2 variables we need.
local menu = {"Model Selector","Style Selector","Menu #3","P_Striker_A evade FULL look down strafe menu"}
local selection = 1
-- Start the main loop. the code between [i]do[/i] and [i]end[/i] will keep running over and over until the value between [i]while[/i] and [i]do[/i] evalutes to false (which it never will, because we used a constant value of [i]true[/i]).
while true do
-- Print the menu (text)
TextPrintString(menu[selection],0,1) -- the 0ms means 1 frame.
-- Wait 0 ms (this suspends the script for 1 frame so the text can show and so the game has a chance to process button presses before we call any button related functions.
Wait(0)
-- See if any buttons were pressed.
if IsButtonBeingPressed(0,0) then
-- 0 was pressed on controller 0 (player 1's controller, which can also be a keyboard. whatever the player is using to control jimmy is controller 0). decrement [i]selection[/i].
selection = selection - 1
-- Make sure [i]selection[/i] is still at least 1. (since the first entry in our table is accessed using [i]1[/i].
if selection < 1 then
selection = 1
end
elseif IsButtonBeingPressed(1,0) then
selection = selection + 1
-- Make sure [i]selection[/i] is no higher than the amount of elements in our table (we can get this by using [i]table.getn[/i])
if selection > table.getn(menu) then
selection = table.getn(menu)
end
end
-- This is the end of the [i]while[/i] loop. now the script will go back to the start of the loop (where [i]do[/i] is) and continue from there again
end
end
Once you fully understand how that works, we can move onto having multiple values in one option instead of just one string. This is really quite simple. All you need to do is instead of having strings, have tables. Those tables should contain things like the name of the option and the function that the option is related to. So like...
local menu = {{"Option 1",F_PlayerSetHealth},{"Option 2",F_PlayerSetInvincible}}
Or you can even just put the function right in there, it's really the same effect since similarly to tables, functions are just stored in memory and the variables are just references to them instead of each variable having storing the entire function. So...
local menu = {{"Option 1",function() PlayerSetHealth(PedGetMaxHealth(gPlayer)) end},{"Option 2",function() --[[ whatever ]] end}}
You could even add some linebreaks so it looks neater. Notice how we set that up the name (a string) is the first part of each option's table, and the function is the second part. So...
menu[selection] -- this is the option table (using selection the same way as before)
menu[selection][1] -- this is the string in the option table (the 1st part of the option table)
menu[selection][2] -- this is the function in the option table (the 2nd part of the option table)
menu[selection][2]() -- this calls the function in the option table
So now it'd basically be like the example up above, but when printing the text just remember to specify the first part of the table (by appending that [1]) and add an if statement for a button to call the function.
So now we have a table (the menu) of tables (the options). How would we add more menus? Well simply add a 3rd thing of tables! So it'd become a table (the menu) of tables (of sub-menus) of tables (the options). Well... there is one more thing to consider. Each of the sub-menus should have their own selection variable. So how should we set this up? A good way is for each sub-menu to be a table that is composed of 3 values. A selection variable, another table (for the options), and the name of the menu. I'll use linebreaks this time to make it clearer, but this is totally optional.
local menu = {
{"Menu 1",menu1options,1}, -- first value is the name (a string), next is the options (a table, referenced by that menu1options variable), and 3rd is the selection (a number).
{"Menu 2",{--[[ options here ]]},1} -- same as above, but here we create the table right in the menu table instead of using a variable.
}
We'll also have to change the code up a bit. I'll make a bunch of comments to help you understand.
function MissionSetup()
AreaTransitionXYZ(0,270,-110,6)
end
function main()
local menu = {
{"Menu 1",{
{"Full health",function()
PlayerSetHealth(PedGetMaxHealth(gPlayer))
end},
{"Give apple",function()
PlayerSetWeapon(310,1)
end}
},1},
{"Menu 2",{
{"Set P_Striker_A",function()
if not HasAnimGroupLoaded("F_Preps") then
LoadAnimationGroup("F_Preps")
end
if not HasAnimGroupLoaded("P_Striker") then
LoadAnimationGroup("P_Striker")
end
if not HasAnimGroupLoaded("Straf_Prep") then
LoadAnimationGroup("Straf_Prep")
end
PedSetActionTree(gPlayer,"/Global/P_Striker_A","Act/Anim/P_Striker_A.act")
end}
},1}
}
local selection = 1
local currentMenu = nil -- this is where we will store the current sub-menu. when this is nil (nil means no value) then that means there is no sub-menu being used
while true do
if currentMenu == nil then -- it is nil, so browse the main menu
TextPrintString(menu[selection][1],0,1)
Wait(0)
if IsButtonBeingPressed(0,0) then
selection = selection - 1
if selection < 1 then
selection = 1
end
elseif IsButtonBeingPressed(1,0) then
selection = selection + 1
if selection > table.getn(menu) then
selection = table.getn(menu)
end
elseif IsButtonBeingPressed(3,0) then -- we'll use 3 (zoom-out) for selecting a menu
currentMenu = menu[selection] -- currentMenu now refers to the currently selected sub-menu table. currentMenu is no longer nil so next time the while loop runs, the 'else' part will run instead of this part.
end
else -- it is not nil, so browse that menu
-- currentMenu refers to a sub-menu table
-- currentMenu[1] is the name of the sub-menu
-- currentMenu[2] is the table of options
-- currentMenu[3] is the selection in that sub-menu
-- currentMenu[2][currentMenu[3]] is the currently selected part of the table of options
-- currentMenu[2][currentMenu[3]][1] is the name of the option
-- currentMenu[2][currentMenu[3]][2] is the function
TextPrintString(currentMenu[2][currentMenu[3]][1],0,1)
Wait(0)
if IsButtonBeingPressed(0,0) then
currentMenu[3] = currentMenu[3] - 1
if currentMenu[3] < 1 then
currentMenu[3] = 1
end
elseif IsButtonBeingPressed(1,0) then
currentMenu[3] = currentMenu[3] + 1
if currentMenu[3] > table.getn(currentMenu[2]) then
currentMenu[3] = table.getn(currentMenu[2])
end
elseif IsButtonBeingPressed(3,0) then
currentMenu[2][currentMenu[3]][2]()
elseif IsButtonBeingPressed(2,0) then -- we'll use 2 as a back button (zoom-in).
-- make currentMenu nil again so it doesn't refer to any table, making it so you'll be browsing through the main menu again
currentMenu = nil
end
end
end
end
And there ya go! You have my full permission to use the code given in this post any way you'd like, however I do strongly encourage you to rewrite your own version of it using what you've learned so that you can both understand how it works and make your own version better suited to your needs.
Good luck and have fun!