Difference between revisions of "Adding an Options Menu"

17,367 bytes added ,  09:03, 17 January 2009
→‎Creating An Options Menu: Decided to work on the Menu section this time
imported>Cipscis
(Re-wrote introduction and "Utilising Your Variables" sections to clarify categorisations)
imported>Cipscis
(→‎Creating An Options Menu: Decided to work on the Menu section this time)
Line 1: Line 1:
<p>This tutorial is a Work in Progress.  If you have any feedback or suggestions, please leave a comment in the discussion page.</p>
<!--Start WIP -->
 
{| style="width:650px;height:50px;background:lavender;border:1px solid royalblue;margin: 1em auto 1em auto"
<p>I'm assuming that anybody reading this is familiar enough with the GECK that I can ignore things like how to make a new quest, and can instead concentrate on the scripting side of things.</p>
| align="center" | '''This article is a Work in Progress.''' <br /><small>If you have any feedback or suggestions, please leave a comment in the discussion page.</small>
|-
|}
<!-- End WIP -->


<h1>Setting Up Your Plugin To Use An Options Menu</h1>
<h1>Setting Up Your Plugin To Use An Options Menu</h1>
<h2>Introduction</h2>


<p>Creating an Options Menu is a good way to keep your plugin modular without having to make multiple plugin files available.  It allows the user to change settings in-game.</p>
<p>Creating an Options Menu is a good way to keep your plugin modular without having to make multiple plugin files available.  It allows the user to change settings in-game.</p>
Line 152: Line 153:
<p>In the above code, ExampleVRQuest.sItem1OS1 controls how many of Item1 is added to the player.  If sItem1OS1 is set to 0, none will be given to the player, effectively switching the feature off.</p>
<p>In the above code, ExampleVRQuest.sItem1OS1 controls how many of Item1 is added to the player.  If sItem1OS1 is set to 0, none will be given to the player, effectively switching the feature off.</p>


<h2>Still to Come</h2>
<h1>Creating An Options Menu</h1>
 
<p>Now that your plugin is set up for using an options menu, you can finally add the menu to your plugin.  To do this, you'll need to do two things:</p>
 
<ul>
<li>Give the player access to the menu</li>
<li>Create the menu</li>
</ul>
 
<h2>Giving the player access to the menu</h2>
 
<p>Before we create the actual menu, we'll have to set up the plugin so that the player is able to access the menu.  By doing this before we start working with the menu code, it'll make testing a whole lot easier.</p>
 
<p>The method I'm going to describe here is not the only method, although it is the method that I prefer.  It consists of two stages:</p>
 
<ol>
<li>Give the player a "Menu Key" - A piece of equipment which the player can equip in order to open the menu.</li>
<li>When the player equips the Key, a token will be added to them.  A token is a piece of unplayable (invisible to the player) equipment, and in this case will contain the script that controls the options menu.</li>
</ol>
 
<p>Before we can use the Menu Key, we're going to have to make it.  It's going to be a piece of armour with no Biped Objects (slots) so that equipping it won't force anything else to be unequipped.  It's also going to be a quest item, so the player can't lose it anywhere (this also has the side effect of preventing the player from attaching it to a hotkey).</p>
 
<p>Remember when we initialised all our variables by using a [[SetStage]] command to run a result script?  Now we're going to go back to that result script now and add three more lines:</p>
 
<pre>if player.GetItemCount ExampleMenuKey == 0
player.AddItem ExampleMenuKey 1
endif
</pre>
 
<p>Now, when our variables are first initialised, the Menu Key that we just made will be automatically added to the player.</p>
 
<p>When the Menu Key is equipped, we want it to run some code that adds a token to the player, but before we can do this we have to make the token.  It's also going to be a piece of armour, but unlike the Menu Key it's going to have the "playable" flag unchecked.  This ensures that the player can't see it in their inventory.</p>
 
<p>Now that we've created the token, we can write a script for the Menu Key that adds the token to the player's inventory.  Because the Menu Key is a quest item, it can't be given a hotkey - meaning that the player has to equip it manually from their inventory.  If you want the menu to open right then and there, this script will suffice:</p>
 
<pre>ScriptName ExampleMenuKeySCRIPT
 
short sDoOnce
 
Begin OnEquip
 
set sDoOnce to 1
AddItem ExampleMenuToken 1 1
 
End
</pre>
 
<p>However, I personally prefer to have the menu open after the player has put away their Pip-Boy.  To do this, a timer will need to be used so that the menu doesn't appear as soon as the player starts to put away their Pip-Boy (that's when the game returns to GameMode).  It takes about half a second for the player to put the Pip-Boy away, so let's use a script like this:</p>
 
<pre>ScriptName ExampleMenuKeySCRIPT
 
short sDoOnce
 
float fTimer
 
Begin OnEquip
 
; Don't need to check MenuMode here, as Quest Items can't be attached to hotkeys
set fTimer to 0.5 ; It takes about 0.5 seconds to put the Pip-Boy away
set sDoOnce to 1
 
End
 
Begin GameMode
 
if sDoOnce == 1
if fTimer > 0
set fTimer to fTimer - GetSecondsPassed ; Count down to 0
else
; Once the Pip-Boy has been put away, open the Options Menu
player.AddItem ExampleMenuToken 1 1
set sDoOnce to 0
endif
endif
 
End
</pre>
 
<p>That's looking very nice now, but because the menu is being opened in GameMode you may also want to prevent the player from opening the menu while they're in combat.  To do this, you'll need to check whether or not the player is in combat when they equip the Menu Key, and unequip the Key without adding the token if this is the case.</p>
 
<pre>ScriptName ExampleMenuKeySCRIPT
 
short sDoOnce
 
float fTimer
 
Begin OnEquip
 
; Don't need to check MenuMode here, as Quest Items can't be attached to hotkeys
if player.IsInCombat == 1
ShowMessage ExampleNoMenuCombatMsg ; Prevent the player from opening the menu
; during combat
player.UnequipItem ExampleMenuKey 0 1
else
set fTimer to 0.5 ; It takes about 0.5 seconds to put the Pip-Boy away
set sDoOnce to 1
endif
 
End
 
Begin GameMode
 
if sDoOnce == 1
if fTimer > 0
set fTimer to fTimer - GetSecondsPassed ; Count down to 0
else
; Once the Pip-Boy has been put away, open the Options Menu
player.AddItem ExampleMenuToken 1 1
set sDoOnce to 0
endif
endif
 
End
</pre>
 
<p>Now that that's set up, all that's left is the actual Menu script, which will be attached to the token.</p>
 
<h2>Creating the Options Menu</h2>
 
<p>The main difference between a single-level menu and a multi-level menu is that the latter requires navigation - the script needs to remember the path that the player took to get to where they are.  Our script will achieve this by having a "sMenuLevel" variable to store the current level of navigation, and giving each level of navigation its own "sButton" variable.  That way, the script can remember which buttons the player pressed on each level of navigation.</p>
 
<p>The example menu that I'm going to use for this tutorial will have four levels, each with their own sButton variables:</p>
 
<ul>
<li>Level 0 - Initialisation->Introduction Message</li>
<li>Level 1 - Introduction Message->Main Menu</li>
<li>Level 2 - Main Menu->Sub Menu</li>
<li>Level 3 - Sub menu->Change Settings</li>
</ul>
 
<p>The basic structure of the script consists of one big GameMode block filled with a list of "if" statements checking the values of sMenuLevel and the various sButton variables.  At the highest level, it only checks sMenuLevel:</p>
 
<pre>ScriptName ExampleMenuSCRIPT
 
short sMenuLevel ; Records the current depth of the ShowMessage framework
; 0 - Initialisation -> Introduction Message
; 1 - Introduction Message -> Main Menu
; 2 - Main Menu -> Sub Menu
; 3 - Sub Menu -> Change Settings
 
; This GameMode block contains all of the ShowMessage framework
Begin GameMode
 
; =================================================
; INITIALISATION --> INTRODUCTION MESSAGE
; =================================================
if sMenuLevel == 0 ; Show Introduction Message
endif
; =================================================
; /INITIALISATION --> INTRODUCTION MESSAGE
; =================================================
 
 
; =================================================
; INTRODUCTION MESSAGE --> MAIN MENU
; =================================================
if sMenuLevel == 1
endif
; =================================================
; /INTRODUCTION MESSAGE --> MAIN MENU
; =================================================
 
 
; =================================================
; MAIN MENU --> SUB MENU
; =================================================
if sMenuLevel == 2
endif
; =================================================
; /MAIN MENU --> SUB MENU
; =================================================
 
 
; =================================================
; SUB MENU --> CHANGE SETTING
; =================================================
if sMenuLevel == 3
endif
; =================================================
; /SUB MENU --> CHANGE SETTING
; =================================================
 
End
</pre>
 
<p>As you can see, the GameMode block is now divided up into four different segments.  Which one runs will depend on the menu's current level of navigation.</p>
 
<p>The first section of the script runs when sMenuLevel == 0.  Because variables are initialised to 0, this section will run when the script first runs.  This section is also the simplest - all that happens in it is the introduction message is called, sMenuLevel is incremented, and sButton1 is intialised:</p>
 
<pre> ; =================================================
; INITIALISATION --> INTRODUCTION MESSAGE
; =================================================
if sMenuLevel == 0 ; Show Introduction Message
ShowMessage introMessage
set sMenuLevel to 1
set sButton1 to -1
endif
; =================================================
; /INITIALISATION --> INTRODUCTION MESSAGE
; =================================================
</pre>
 
<p>If you're wondering why I've included an Introduction message before the Main Message, it's useful if you have conditions for the buttons in the Main Menu that have to be initialised before each time it's opened.  Usually, you'll use an OnAdd block in this script to do this.</p>
 
<p>Now, because we've set sMenuLevel to 1, the next section of the script is running.  In this section, we need to check when the player clicks the button to continue from the Introduction message into the Main Menu.  When this does happen, the script will call the Main Menu, increment sMenuLevel again, and initialise the next sButton variable - sButton2:</p>
 
<pre> ; =================================================
; INTRODUCTION MESSAGE --> MAIN MENU
; =================================================
if sMenuLevel == 1
 
if sButton1 == -1
set sButton1 to GetButtonPressed
endif
 
if sButton1 == -1 ; None of the buttons have been pressed yet
 
Return
 
else ; Show the Main Menu
 
; mainMenu contains buttons corresponding to Sub Menus
ShowMessage mainMenu
set sMenuLevel to 2
set sButton2 to -1
 
endif
 
endif
; =================================================
; /INTRODUCTION MESSAGE --> MAIN MENU
; =================================================
</pre>
 
<p>You may already have guessed what the next section consists of - it's a step up again in complexity.  Unlike the Introduction Message, the Main Menu contains multiple buttons.  That means that, in this section of the script, we need to check which button the player presses and update the Menu accordingly.</p>
 
<p>If the player presses a button that takes them deeper into the menu, we'll need to call the appropriate message.  If, instead, the player presses the "Done" button, we'll need to remove the Menu Token in order to stop the script and therefore close the menu.  We'll also need to increment sMenuLevel, and initialise the next sButton variable - sButton3:</p>
 
<pre> ; =================================================
; MAIN MENU --> SUB MENU
; =================================================
if sMenuLevel == 2
 
if sButton2 == -1
set sButton2 to GetButtonPressed
endif
 
if sButton2 == -1 ; None of the buttons have been pressed yet
 
Return
 
elseif sButton2 == 0 ; Show the 1st Sub Menu
 
ShowMessage subMenu1
 
elseif sButton2 == 1 ; Show the 2nd Sub Menu
 
ShowMessage subMenu2
 
else ; "Done" button - close Options Menu
 
player.UnequipItem OptionsMenuEquipKey 0 1
RemoveMe
 
endif
 
set sMenuLevel to 3
 
set sButton3 to -1
 
endif
; =================================================
; /MAIN MENU --> SUB MENU
; =================================================
</pre>
 
<p>As you can see, this section is practically identical to the previous section.  The only differences are that there is a "Done" button and, depending on which button the player pressed, a different menu is shown.  We still use GetButtonPressed to check if a button has been pressed, and when one has we increment sMenuLevel and initialise the next sButton variable.</p>
 
<p>The next section is the final section for this example script - it's where the actual settings are changed.  It differs from the previous level in that, when a button is pressed, we change a quest variable (remember them?) instead of showing a menu, and it has a "Back" button instead of a "Done" button.</p>
 
<p>There are two ways this can be sorted - by which setting was selected and by which sub-menu the player came through.  In this example, the script is sorted by which setting was selected.</p>
 
<pre> ; =================================================
; SUB MENU --> CHANGE SETTING
; =================================================
if sMenuLevel == 3
 
if sButton3 == -1
set sButton3 to GetButtonPressed
endif
 
if sButton3 == -1
 
Return ; None of the buttons have been pressed yet
 
elseif sButton3 == 0 ; The 1st setting was selected
 
if sButton2 == 0 ; The player came through the 1st Sub Menu
 
set VariablesQuest.Variable1 to (VariablesQuest.Variable1 == 0)
 
elseif sButton2 == 1 ; The player came through the 2nd Sub Menu
 
set VariablesQuest.Variable2 to (VariablesQuest.Variable2 == 0)
 
endif
 
elseif sButton3 == 1 ; The 2nd setting was selected
 
if sButton2 == 0 ; The player came through the 1st Sub Menu
 
set VariablesQuest.Variable3 to (VariablesQuest.Variable3 == 0)
 
elseif sButton2 == 1 ; The player came through the 2nd Sub Menu
 
set VariablesQuest.Variable4 to (VariablesQuest.Variable4 == 0)
 
endif
 
else ; "Back" button was pressed
 
set sMenuLevel to 1
Return
 
endif
 
set sMenuLevel to 2
 
endif
; =================================================
; /SUB MENU --> CHANGE SETTING
; =================================================
</pre>
 
<p>As you can see, the highest level of "if" statements in this example checks which setting has been selected, and the next level of "if" statements checks which sub-menu the player has come through.  It would be perfectly acceptable to swap these two around if you'd like.</p>
 
<p>This method of making multi-level menus can be used to make menus with any number of levels that you'd like, although obviously the script will become more complicated at higher levels.  You should also remember that the structure that I've used in these examples is not set in stone by any means - you can, for example, change some variables straight from the main menu.</p>
 
<p>Now that the script is finished, let's look at the whole thing in one piece!</p>
 
<pre>ScriptName ExampleMenuSCRIPT
 
short sMenuLevel ; Records the current depth of the ShowMessage framework
; 0 - Initialisation -> Introduction Message
; 1 - Introduction Message -> Main Menu
; 2 - Main Menu -> Sub Menu
; 3 - Sub Menu -> Change Settings
 
short sButton1 ; sButton variable for the Introduction Message level
short sButton2 ; sButton variable for the Main Menu level
short sButton3 ; sButton variable for the Sub Menu level
 
; This GameMode block contains all of the ShowMessage framework
Begin GameMode
 
; =================================================
; INITIALISATION --> INTRODUCTION MESSAGE
; =================================================
if sMenuLevel == 0 ; Show Introduction Message
ShowMessage introMessage
set sMenuLevel to 1
set sButton1 to -1
endif
; =================================================
; /INITIALISATION --> INTRODUCTION MESSAGE
; =================================================
 
 
; =================================================
; INTRODUCTION MESSAGE --> MAIN MENU
; =================================================
if sMenuLevel == 1
 
if sButton1 == -1
set sButton1 to GetButtonPressed
endif
 
if sButton1 == -1 ; None of the buttons have been pressed yet
 
Return
 
else ; Show the Main Menu
 
; mainMenu contains buttons corresponding to Sub Menus
ShowMessage mainMenu
set sMenuLevel to 2
set sButton2 to -1
 
endif
 
endif
; =================================================
; /INTRODUCTION MESSAGE --> MAIN MENU
; =================================================
 
 
; =================================================
; MAIN MENU --> SUB MENU
; =================================================
if sMenuLevel == 2
 
if sButton2 == -1
set sButton2 to GetButtonPressed
endif
 
if sButton2 == -1 ; None of the buttons have been pressed yet
 
Return
 
elseif sButton2 == 0 ; Show the 1st Sub Menu
 
ShowMessage subMenu1
 
elseif sButton2 == 1 ; Show the 2nd Sub Menu
 
ShowMessage subMenu2
 
else ; "Done" button - close Options Menu
 
player.UnequipItem OptionsMenuEquipKey 0 1
RemoveMe
 
endif
 
set sMenuLevel to 3
 
set sButton3 to -1
 
endif
; =================================================
; /MAIN MENU --> SUB MENU
; =================================================
 
 
; =================================================
; SUB MENU --> CHANGE SETTING
; =================================================
if sMenuLevel == 3
 
if sButton3 == -1
set sButton3 to GetButtonPressed
endif
 
if sButton3 == -1
 
Return ; None of the buttons have been pressed yet
 
elseif sButton3 == 0 ; The 1st setting was selected
 
if sButton2 == 0 ; The player came through the 1st Sub Menu
 
set VariablesQuest.Variable1 to (VariablesQuest.Variable1 == 0)
 
elseif sButton2 == 1 ; The player came through the 2nd Sub Menu
 
set VariablesQuest.Variable2 to (VariablesQuest.Variable2 == 0)
 
endif
 
elseif sButton3 == 1 ; The 2nd setting was selected
 
if sButton2 == 0 ; The player came through the 1st Sub Menu
 
set VariablesQuest.Variable3 to (VariablesQuest.Variable3 == 0)
 
elseif sButton2 == 1 ; The player came through the 2nd Sub Menu
 
set VariablesQuest.Variable4 to (VariablesQuest.Variable4 == 0)
 
endif
 
else ; "Back" button was pressed
 
set sMenuLevel to 1
Return
 
endif
 
set sMenuLevel to 2
 
endif
; =================================================
; /SUB MENU --> CHANGE SETTING
; =================================================
 
End
</pre>
 
<h2>See Also</h2>


<ul>
<ul>
<li>
<li>
Navigating The Options Menu
[[SetStage]]
</li>
</li>
<li>
<li>
Allowing User Access
[[ShowMessage]]
</li>
<li>
[[GetButtonPressed]]
</li>
<li>
[[RemoveMe]]
</li>
</li>
<li>
<li>
Anything else that I think of
[[AddItem]]
</li>
</li>
</ul>
<h2>See Also</h2>
<ul>
<li>
<li>
[[ShowMessage]]
[[UnequipItem]]
</li>
</li>
<li>
<li>
[[SetStage]]
[[IsInCombat]]
</li>
</li>
</ul>
</ul>
Anonymous user