Difference between revisions of "MessageBox Tutorial"
imported>Haama |
imported>Haama |
||
Line 267: | Line 267: | ||
Return | Return | ||
Elseif (Choosing == -3) ;Food menu | |||
Messagebox "How much food would you like to donate?" "Options" | |||
"More Options" | |||
... | |||
"Cancel" | |||
Set Choosing to 3 | |||
Set Choice to GetButtonPressed | |||
Return | |||
Elseif (Choosing == 3) | |||
If (Choice == -1) ;No choice yet | If (Choice == -1) ;No choice yet | ||
Set Choice to GetButtonPressed | Set Choice to GetButtonPressed | ||
Elseif (Choice == 0) ;Options | Elseif (Choice == 0) ;Options | ||
... | |||
Elseif (Choice == 9) ;Cancel | Elseif (Choice == 9) ;Cancel | ||
Set Choosing to 0 | Set Choosing to 0 | ||
Line 311: | Line 311: | ||
<br>'''''Mmmm... sleep... I'll add these shortly...''''' | <br>'''''Mmmm... sleep... I'll add these shortly...''''' | ||
<br>[[Messagebox_Tutorial:_Centralizing_Your_Menu_Exits|Centralizing your menu exits]] | <br>[[Messagebox_Tutorial:_Centralizing_Your_Menu_Exits|Centralizing your menu exits]] | ||
<br>Running menus in both GameMode and MenuMode when your script is too large | <br>[[Messagebox_Tutorial:_GameMode_And_MenuMode|Running menus in both GameMode and MenuMode when your script is too large]] | ||
<br>Ensuring your menus are seen | <br>Ensuring your menus are seen | ||
<br>Allowing the player to set a variable to any number | <br>Allowing the player to set a variable to any number | ||
<br>[[User:Haama|Haama]] 02:08, 14 June 2007 (EDT) | <br>[[User:Haama|Haama]] 02:08, 14 June 2007 (EDT) | ||
[[Category: Scripting Tutorials]] | [[Category: Scripting Tutorials]] |
Revision as of 02:49, 14 June 2007
by haama
Intro
Most of your menu needs can be taken care of with a simple token script:
Begin onAdd Messagebox "Your message" "Some options" End Begin GameMode if (GetButtonPressed == -1) return else ;do stuff RemoveMe Endif End
Just add the token to the player whenever you want to run the menu, but be aware that this script is severely limited in functionality. There are many ways to do menus, so this guide will lead up from the simplest menu (Done!) to a fully featured menu (well, featured enough for me) that will be able to:
- Use multiple choices
- Run the same choice for multiple frames
- Run multiple menus from one script
- Make it very easy to cut and paste for each new menu
- As well as some extras
Basics
First, some basic information on menus:
There are two sides to every menu – the display of the menu and catching the player's decision. You display the menu with the function MessageBox and catch the player's decision with the function GetButtonPressed. You can keep these two separated by changing a variable (i.e., "Choosing")
MessageBox takes one frame to display, so you can use any block to display it. However, GetButtonPressed needs to be in a block that continuously runs (i.e., GameMode, MenuMode, ScriptEffectUpdate) and needs to be on a script that is running every frame (i.e., an activator that is in a loaded cell, a quest running every .001 seconds, etc.). The reason for this – in order to read it, make a decision, click the option, and let go of the mouse button it will take the player longer than a frame, so you need to run the script every frame until then.
Another oddity - GetButtonPressed returns somewhat odd numbers for each decision:
- -1 means no decision has been made
- 0 means the player selected the first option
- 1 for the second
- ...
- 9 for the tenth(you can have 10 options at most)
With those in mind, here's a basic menu script. (You may also notice that it doesn't quite work, that'll be explained afterwards.)
Short Choosing Begin GameMode If (Choosing == 0) Messagebox "What would you like to do?" "First Option" Set Choosing to 1 Return Else If (GetButtonPressed > -1) ;Player has made a decision If (GetButtonPressed == 0) ;First Option ;whatever you want to do Set Choosing to 0 Endif Else ;if (GetButtonPressed <= -1) - no decision Return ;Try to catch the decision in the next frame Endif Endif End
The variable "Choosing" is used to separate the display of the menu and the catching of the player's decision. Since it's in a GameMode block, the script will run every frame. GetButtonPressed will return -1 until the player makes a decision, in which case it will return 0 or 1, depending on the player's decision.
Avoiding Common Mistakes for More Complex Menus
There are 2 and a half problems with the above script:
First, GetButtonPressed only returns the player's decision once. On this section of code
If (GetButtonPressed > -1) If (GetButtonPressed == 0)
that means that, once the player has made a decision, GetButtonPressed will return 0 for the first line, but will return -1 for the second (this would be true for an if/elseif test as well). This can be fixed by setting a variable (for this tutorial it will be Choice) to GetButtonPressed with set Choice to GetButtonPressed. Place this line after displaying the menu, as such:
Short Choosing Short Choice ... Else ;if (Choosing == 1) or menu has been shown Set Choice to GetButtonPressed If (Choice > -1) ;Player has made a decision If (Choice == 0) ;First Option ;whatever you want to do Set Choosing to 0 Endif Else ;if (Choice <= -1) - no decision Return ;Try to catch the decision in the next frame Endif ...
The half problem – any of your code in the ;whatever you want to do section will only run for a single frame. This is good enough in most cases, however, if you need to run that section for more than one frame (i.e., waiting for another process to finish) you will have to set up things a bit differently. The reason, extending on the previous reason – GetButtonPressed will only return the player's decision once, and only for one frame. To fix this, set the variable only when GetButtonPressed returns -1, as such:
... else ;if (Choosing == 1) or menu has been shown If (Choice == -1) ;Player hasn't made a decision set Choice to GetButtonPressed return elseif (Choice == 0) ;Player has selected the first option ...
The second problem is a bit more drastic – every time the player makes a decision the menu will be displayed again. This problem can be fixed by changing the If (Choosing == 0) test to If (Choosing == -1), and having a clear start to the script (i.e., OnActivate, OnAdd, etc.) that will set Choosing to -1. There are a few ways to start the script off, but my preferred method is to use a persistent activator. The advantages of a persistent activator:
- There's a clear beginning to it (OnActivate)
- It's easy to start (unlike a quest)
- It's fast to start (harder for a quest)
- It can run every frame (harder for a quest)
- The variables can be global (harder for a token)
- And it's simply easier to manage than a spell (if a spell is really possible at all, I haven't seen one yet)
The only disadvantage is that you will have to remember to add a few lines to move the activator to the player when starting and away when finished. Of course, with some work, quests and tokens can be made to do the same, but I don't find them quite as easy to set up.
Creating Your New Menu
You'll need to set up some objects for the next script: an invisible activator, an XMarker, and your own cell:
Your own cell
- Scroll down the "Cell View" window
- Select "TestQuset01"
- Right-click it
- Select "Duplicate Cell"
- Rename your new cell to something you'll remember (and don't worry about the lack of floors, it'll work just fine)
XMarker
- Scroll down the "Object Window"
- Select Statics
- Scroll to the bottom
- Double-click your cell in the "Cell View" window to open it in the "Render Window"
- Drag the XMarker from the "Object Window" into the "Render Window"
- Right-click the red X (XMarker) in the "Render Window"
- Select edit.
- In the "Reference Editor ID" box, give it a name you'll remember (in these examples it will be "YourXMarker").
Activator
- Select an activator in the "Object Window"
- Edit the name
- Press enter (or select ok in the edit menu)
- Click "Yes" when it asks if you want to create a new item
- Drag your new activator into the "Render Window"
- Right-click it
- Give it a "Reference Editor ID"
- Mark it as "Persistent Reference" and "Initially Disabled"
- Place the following script on your new activator
- Make the following script
- In the "Object Window", right-click your new activator
- Select Edit
- In the "Script" pull-down box, select "YourMenuScript"
Activator Script
scn YourMenuScript Short Choosing Short Choice Begin onActivate Set Choosing to -1 If (GetInSameCell player == 0) MoveTo player Endif End Begin GameMode If (Choosing == 0) ;meaning it shouldn't be running If (GetInSameCell YourXMarker == 0) MoveTo YourXMarker Endif Elseif (Choosing == -1) ;Display your menu Messagebox "What would you like to do?" "First Option" "Second Option" Set Choosing to 1 Set Choice to GetButtonPressed Return Elseif (Choosing == 1) ;Catch the player's decision If (Choice == -1) ;No choice yet Set Choice to GetButtonPressed Return Elseif (Choice == 0) ;First Option ;run your code for the first decision Set Choosing to 0 ;to finish up Elseif (Choice == 1) ;Second Option ;run your code for the second descision Set Choosing to 0 ;to finish up Endif Endif End
Ok, no games that time. You can start your menus from any script with YourActivatorsReferenceEditorID.Activate player, 1 and this script will do the rest.
Multiple Menus in One Script
Not only will the above code work, but it makes multiple menus easy to do. Remember that each menu has two parts: the display of the menu and catching the player's decision. So, each menu can be broken into two numbers, a negative number (-1 in the example above) and a positive number (1 in the example above). Use different numbers for each menu, and whenever you want to move to a new menu, use set Choosing to -#. Here's several examples of menu switching: (also, please note that due to wiki limitations, the messageboxes below have been given line breaks, whereas in the CS they wouldn't have one)
Short Choosing Short Choice Begin onActivate Set Choosing to -1 If (GetInSameCell player == 0) MoveTo player Endif End Begin GameMode If (Choosing == 0) ;meaning it shouldn't be running If (GetInSameCell YourXMarker == 0) MoveTo YourXMarker Endif Elseif (Choosing == -1) ;Display your menu Messagebox "Would you like to donate gold or food?" "Gold" "Food" "Blood" "Cancel" Set Choosing to 1 Set Choice to GetButtonPressed Return Elseif (Choosing == 1) If (Choice == -1) ;No choice yet Set Choice to GetButtonPressed Return Elseif (Choice == 0) ;Gold Set Choosing to -2 ;to open the Gold menu Elseif (Choice == 1) ;Food Set Choosing to -3 ;to open the Food menu Elseif (Choice == 2) ;Blood Set Choosing to -4 ;to open the Blood menu Elseif (Choice == 3) ;Cancel Set Choosing to 0 ;to close the menus Endif Return Elseif (Choosing == -2) ;Gold menu Messagebox "How much Gold would you like to donate?" "25" "I've changed my mind" "I've changed my mind, I'll donate Food" "I've changed my mind, I'll donate Blood" "I've changed my mind, I won't donate anything" Set Choosing to 2 Set Choice to GetButtonPressed Return Elseif (Choosing == 2) If (Choice == -1) ;No choice yet Set Choice to GetButtonPressed Elseif (Choice == 0) ;25 If (player.GetGold > 25) Player.RemoveItem Gold001 25 Set Choosing to 0 Else Set Choosing to -99 ;a message that the player doesn't have enough Endif Elseif (Choice == 1) ; I've changed my mind Set Choosing to -1 ;to return to the opening menu Elseif (Choice == 2) ; I've changed my mind, I'll donate food Set Choosing to -3 ;to open the food menu Elseif (Choice == 3) ; I've changed my mind, I'll donate blood Set Choosing to -4 ;to open the blood menu Elseif (Choice == 4) ; I've changed my mind, I won't donate anything Set Choosing to 0 ;to close the menus Endif Return Elseif (Choosing == -3) ;Food menu Messagebox "How much food would you like to donate?" "Options" "More Options" ... "Cancel" Set Choosing to 3 Set Choice to GetButtonPressed Return Elseif (Choosing == 3) If (Choice == -1) ;No choice yet Set Choice to GetButtonPressed Elseif (Choice == 0) ;Options ... Elseif (Choice == 9) ;Cancel Set Choosing to 0 Endif Return Elseif (Choosing == -99) ;Player-doesn't-have-enough menu Messagebox "You don't have enough." Set Choosing to 99 Set Choice to GetButtonPressed Return Elseif (Choosing == 99) If (Choice == -1) ;No choice yet Set Choice to GetButtonPressed Elseif (Choice == 0) ;player pressed "Done", return to main menu Set Choosing to -1 Endif Return Endif End
I suggest using numbers instead of other variables when setting Choosing. Numbers give more meaning than words in this case, as the negative and positive numbers separate which part of the menu you're dealing with. You can also use numbers to signify which layer of the menu you are in. For instance, -1 was the first layer in the above example. For the sub-menus of the main menu (Gold, Food, Blood), you can use -11, -12, -13. And, for example, for the sub-menus of Food you can use -121, -122, -123 such that the first number signifies the menu of the first layer, the second the menu of the second layer, etc.
Extras
Need your menu to do more? Well, here's some extra snippets of code:
Mmmm... sleep... I'll add these shortly...
Centralizing your menu exits
Running menus in both GameMode and MenuMode when your script is too large
Ensuring your menus are seen
Allowing the player to set a variable to any number
Haama 02:08, 14 June 2007 (EDT)