Options Menu

From the CreationKit Wiki
Revision as of 22:42, 3 July 2012 by imported>Threedee (→‎Examples)
Jump to navigation Jump to search

Overview

Using Show - Message, it is possible to make an options menu with any number of buttons and/or levels. This is enabling as one can maintain but a single plugin with an options menu offering multiple configuration setting rather than necessitating multiple versions. In these examples, we'll use apparel items and a book, but a menu can be prompted and managed in a number of ways. First, create a message(s) form(s) and add/fill the buttons with the options you'd like to offer. Note that no more than ten buttons can be in a message box and that the button indices are offset by one such that the first option's index is 0 and not 1. If offering a lot of options, it's best to think ahead regarding how you want to organize your options, making the message forms first, then plugging them into the script. Also note that if you use many buttons and if the button names are long, your menu might be too wide to fit on the screen, so keep the layout as compact as possible.

Examples

  • For the first example, we'll have only three options: "Mage", "Thief", and "Warrior". When the token is added to the player, the menu will be prompted and will exit as soon as a button is selected, executing the appropriate code right after the token is silently removed.
ScriptName OptionsMenuScript extends ObjectReference

Armor Property MenuARMO Auto ; The token that holds the menu script
Message Property OptionsMESG Auto ; The Message form that configures the menu buttons

Event OnContainerChanged(ObjectReference akNewContainer, ObjectReference akOldContainer)
	If akNewContainer == Game.GetPlayer(); Only the player
		Int iButton = OptionsMESG.Show() ; Shows your menu.
		akNewContainer.RemoveItem(MenuARMO, 1, True) ; Silently remove token
		If iButton == 0  ; Mage
			Debug.Notification("Mage selected")
		ElseIf iButton == 1 ; Thief
			Debug.Notification("Thief selected")
		ElseIf iButton == 2 ; Warrior
			Debug.Notification("Warrior selected")
		EndIf
	EndIf
EndEvent
  • For the next example, we'll offer sub-options for each main selection. For a multilevel menu, functions can be used to keep the menu well organized. Keep in mind that you can assign conditions to each button in the Message forms, so you could hide "Lunch" and "Dinner" if it's time for breakfast, or hide "Lobster" if it's not currently available. In this case, to make it repeatable, we'll use a book so the menu will show each time it is read. A book cannot be favorited or hotkeyed, unlike an apparel item. A potion can be hotkeyed, but it will be consumed when used and not remain hotkeyed even if immediately replaced. This example will let the user choose breakfast, lunch, or dinner, then close after one meal is selected.
ScriptName OptionsMenuScript extends ObjectReference
;===================================================
 
ObjectReference Property MenuBook Auto
Message Property MainMenuMESG Auto
Message Property BreakfastMESG Auto
Message Property LunchMESG Auto
Message Property DinnerMESG Auto
 
;===================================================

Event OnRead()
	Game.DisablePlayerControls(False, False, False, False, False, True) ; Temporarily disable other menus
	Menu()
	Game.EnablePlayerControls(False, False, False, False, False, True) ; Re-enable Player controls
EndEvent 
 
;===================================================

Function Menu()
	int aiButton = MainMenuMESG.Show() ; Main Menu
	If aiButton == 0 ; Breakfast
		BreakfastMenu()
	ElseIf aiButton == 1 ; Lunch
		LunchMenu()
	ElseIf aiButton == 2 ; Dinner
		DinnerMenu()
	ElseIf aiButton == 3 ; Quit the menu
		Return
	EndIf
EndFunction

;===================================================

Function BreakfastMenu()
	int aiButton = BreakfastMESG.Show()
	If aiButton == 0
		Debug.Notification("Choice = Sweet Roll & Coffee")
	ElseIf aiButton == 1
		Debug.Notification("Choice = Pancakes, Bacon & Eggs")
	ElseIf aiButton == 2
		Debug.Notification("Choice = Chicken Fried Pony Steak")
	ElseIf aiButton == 3 ; Return to the main menu
		Return
	EndIf
EndFunction

;===================================================

Function LunchMenu()
	int aiButton = LunchMESG.Show()
	If aiButton == 0
		Debug.Notification("Choice = Glazed Turkey Sandwich")
	ElseIf aiButton == 1
		Debug.Notification("Choice = Grilled Ham Sandwich")
	ElseIf aiButton == 2
		Debug.Notification("Choice = Shredded Pony Sandwich")
	ElseIf aiButton == 3 ; Return to the main menu
		Return
	EndIf
EndFunction

;===================================================

Function DinnerMenu()
	aiButton = DinnerMESG.Show()
	If aiButton == 0
		Debug.Notification("Choice = Filet Mignon")
	ElseIf aiButton == 1
		Debug.Notification("Choice = Pony Fajitas")
	ElseIf aiButton == 2
		Debug.Notification("Choice = Lobster")
	ElseIf aiButton == 3 ; Return to the main menu
		Return
	EndIf
EndFunction

;===================================================
  • To make a multilevel, looping menu with thirty buttons that will not close until a "Done" button is pressed, use the above method but with an altered Menu() function. Note that you can jump to a given message by specifying the aiMessage argument when calling the function. Sub-options as described in the previous example can be added to the below in the same manner. Theoretically, any number of options can be added with the below structure.
ScriptName OptionsMenuScript extends ObjectReference

Actor Property PlayerREF Auto
Armor Property MenuARMO Auto ; Playable apparel item
Message Property OptionsMenu00MESG Auto
Message Property OptionsMenu01MESG Auto
Message Property OptionsMenu02MESG Auto

Event OnEquipped(Actor akActor)
	If akActor == PlayerREF
		Game.DisablePlayerControls(False, False, False, False, False, True) ; Momentarily disable other menus
		PlayerREF.EquipItem(MenuARMO, True, True) ; Prevent unequip/reequip in favorites until the current menu is resolved
		Utility.Wait(0.01) ; This ensures equipping the token from the favorites menu works
		PlayerREF.UnequipItem(MenuARMO, False, True) ; Silently unequip item
		Game.EnablePlayerControls(False, False, False, False, False, True) ; Undo DisablePlayerControls
		Menu()
	EndIf
EndEvent

Function Menu(Int aiMessage = 0, Int aiButton = 0, Bool abMenu = True)
	While abMenu
		If aiButton == -1 ; Wait for input
		ElseIf aiMessage == 0
			aiButton = OptionsMenu00MESG.Show()
			If aiButton == 0
			ElseIf aiButton == 1
			ElseIf aiButton == 2
			ElseIf aiButton == 3
			ElseIf aiButton == 4
			ElseIf aiButton == 5
			ElseIf aiButton == 6
			ElseIf aiButton == 7
			ElseIf aiButton == 8 ; More
				aiMessage = 1
			ElseIf aiButton == 9 ; Done
				abMenu = False
			EndIf
		ElseIf aiMessage == 1
			aiButton = OptionsMenu01MESG.Show()
			If aiButton == 0
			ElseIf aiButton == 1
			ElseIf aiButton == 2
			ElseIf aiButton == 3
			ElseIf aiButton == 4
			ElseIf aiButton == 5
			ElseIf aiButton == 6
			ElseIf aiButton == 7 ; Back
				aiMessage = 0
			ElseIf aiButton == 8 ; More
				aiMessage = 2
			ElseIf aiButton == 9 ; Done
				abMenu = False
			EndIf
		ElseIf aiMessage == 2
			aiButton = OptionsMenu02MESG.Show()
			If aiButton == 0
			ElseIf aiButton == 1
			ElseIf aiButton == 2
			ElseIf aiButton == 3
			ElseIf aiButton == 4
			ElseIf aiButton == 5
			ElseIf aiButton == 6
			ElseIf aiButton == 7
			ElseIf aiButton == 8 ; Back
				aiMessage = 1
			ElseIf aiButton == 9 ; Done
				abMenu = False
			EndIf
		EndIf
	EndWhile
EndFunction

Notes

  • Given the buttons in Skyrim are listed from side to side, it is easy to spill over the edges of the user's monitor, particularly if it's a 4:3, in the event either the options are too verbose or there are too many options presented by a single message form. Currently, there's no way to list them from top to bottom as they were in previous Bethesda games. To mitigate this, keep the button text to a minimum and/or make sure to always set up conditions on mutually exclusive buttons to ensure only applicable options are presented.
  • To conditionalize buttons upon script/quest variables, use GetVMScriptVariable and GetVMQuestVariable.
  • To hide buttons you wish to fill in later, add an impossible condition like 'IsXBox == -1'.
  • Conditionalizing MessageBox buttons will not change their indices such that, for instance, button 9 will still execute the "Done" code in the last example even if buttons 0-8 are hidden.
  • To learn how to assign user-created messageboxes as values to the message box properties defined in the above scripts, see the Papyrus tutorial's page on Properties and Functions
  • If the Message property isn't filled in the CK the Show() will always return a 0.
  • If the Message is a Notification (without buttons) instead of a Message Box the Show() will return a -1.

See Also

Show - Message