Added nwn-2-gui-scripting.md

This commit is contained in:
Thibaut CHARLES 2018-12-17 13:29:49 +00:00 committed by Wiki
parent f1dd6d4c0f
commit f146c3c060
1 changed files with 445 additions and 0 deletions

445
nwn-2-gui-scripting.md Normal file
View File

@ -0,0 +1,445 @@
<!-- TITLE: Nwn 2 Gui Scripting -->
<!-- SUBTITLE: A quick summary of Nwn 2 Gui Scripting -->
GUI Scripting
# Resources
- [oeiprogrammer](https://oeiprogrammer.blogspot.fr)
# Language
The GUI are written in a non standard form of XML.
- The first line must be something like `<?xml version="1.0" encoding="utf-8"?>`
- Attributes values can be delimited by `'`, `"` or can end with a space
+ This does not work: `OnLeftClick=UIObject_Misc_ExecuteServerScript("gui_myscript","Hello World")` because OnLeftClick value has no delimiter and will end after `Hello`
- Auto-closing tags are accepted `<UIText />`
- If you repeat an attribute twice, the GUI will not load
- The `UIScene` element is never closed
# Rules
## File name
The XML file name must not exceed 32 characters (TODO: with or without extension?)
## Stacking
- Elements with the same parent will be stacked from top to bottom. For example with `<A/><B/>`, A will appear over B
## Variables
The GUI file can store client-side variables that can be either local (only accessible through the current UI) or global (all UI share the same variables). They are identified by an integer index, and always store a string value.
Examples: `local:0`, `local:1337`, `global:42`, ...
## Functions
Functions are special attribute values that execute specific actions either on the client-side (setting local gui variables, changing gui appearance) or on the server-side (executing scripts).
It is better to put functions inside double quotes: `OnEvent="Callback('arg0','spaced arg',42)"`. This way it is compatible with XML standards and the function arguments values can contain spaces. Otherwise the UI won't load because the space will be treated as the end delimiter for the attribute value.
_TODO_: callback parameter parsing & delimitation (ie what happens if `UIObject_Misc_ExecuteServerScript("A,B","C",D,'E,F','G',H)`)
You can use multiple functions on a single event by appending 0, 1, ... to the event name, ie `OnEvent0="DoThis()" OnEvent1="ThenDoThat()"`. Note: if you don't number events correctly, the GUI will not load.
The most useful callback is certainly `UIObject_Misc_ExecuteServerScript` that allows you to execute nwscript for any event from any UI element: `OnEvent="UIObject_Misc_ExecuteServerScript('gui_yourscript','AnyArgumentList',local:25)"`
# Tips & Tricks
- When developing add the attribute `idleexpiretime="0.1"` to the UIScene. This allows the UI file to be reloaded every time you close it in-game.
- You can trace UI events by:
+ Executing console commands `DebugMode 1` and `Guidebug`
+ Running [Skywing's client extension](https://neverwintervault.org/project/nwn2/other/nwn2-client-extension) and executing the in-chat command `/guidebug`.
- When an attribute appears twice on the same element, the UI fails to load.
- Often NWN2 GUI files start with `<?xml version="1.0" encoding="utf-8">`. This can safely be replaced by `<?xml version="1.0" encoding="utf-8"?>`.
- Any standard-compliant XML parser will fail at parsing NWN2 UI files. You can find a custom XML parser implementation for nwn2 [here](https://github.com/CromFr/NWN2GuiViewer/blob/master/source/nwnxml.d). Warning: written in the D language.
---
# UIPane
This is the most basic UI construction block: an invisible container (similar to HTML `<div>`. Every other elements inherits its properties in a certain fashion.
Any content placed outside of the UIPane bounds will be clipped.
## Attributes
### Attributes - Positioning & Sizing
| Attribute | Usage | Possible values |
|--------------------------|-----------------------------------------------------------------------|---------------------------------------------------------------|
| `x="0"` | Horizontal offset | Positive integer, `ALIGN_LEFT`, `ALIGN_CENTER`, `ALIGN_RIGHT` |
| `y="0"` | Vertical offset | Positive integer, `ALIGN_TOP`, `ALIGN_CENTER`, `ALIGN_BOTTOM` |
| `width="0"` | Horizontal size | Positive integer, `PARENT_WIDTH`, `SCREEN_WIDTH` |
| `height="0"` | Vertical size | Positive integer, `PARENT_HEIGHT`, `SCREEN_HEIGHT` `DYNAMIC` |
| `draggable="false"` | Allows the user to drag and drop the pane _need more info_ | Boolean |
| `hidden="false"` | Pane visibility. Note: can be changed using gui functions or nwscript | Boolean |
| `hideoverride="false"` | Makes the pane visibility only controllable using nwscript | Boolean |
| `scalewithscene="false"` | Useful when making a fullscreen UI. _need more info_ | Boolean |
| `usescaler="false"` | See notes | Boolean |
- Any children elements that are out of the UIPane bounds will be clipped.
- `height=DYNAMIC` is often used for UIText elements inside a UIListbox, and does not work very well with other use cases.
- Warning: the default value for width or height is 0 and will make the UIPane and its content invisible
- Sometimes pane visibility goes wrong when using both nwscript and UI functions to change the hidden value.
- Notes on `usescaler`: _This tells the code to try and use some logic when this object gets resized in determining where its new X,Y origin should be. For example, if there is a lot of space to the right of the object, it will assume this object was left-anchored and keep the object to the left side with its new position. It's kind of a confusing attribute, all I can say is try it out and see if it does what you want, and don't use it if it doesn't. :)_
### Attributes - Event handling
| Attribute | Usage | Possible values |
|-----------------------------|--------------------------------------------------------------------------------------------------------------------------|------------------|
| `ignoreevents="false"` | If true, all events on this pane and all its children will be ignored. _need testing_ | Boolean |
| `capturemouseclicks="true"` | If false, mouse clicks will go through the node and trigger the associated event on its parents. | Boolean |
| `capturemouseevents="true"` | Not working / do the same as `capturemouseclicks` _need testing_ | Boolean |
| `focusable="true"` | Allow/forbid clicking on the pane _need more info_ | Boolean |
| `handleactiontarget=???` | Allows to drag & drop items on it, or do "cursor actions" on it _need testing & more info_ | Boolean |
| `DefaultTooltip` | Display a strref as tooltip when hovering the pane | Integer (strref) |
| `disabled="false"` | Prevents the player to interact with the pane (apply mostly to buttons) _need to check effects on child elements_ | Boolean |
| `update="false"` | Execute the `OnUpdate` function(s) when the GUI gets updated (at each client game frame, or set by `UpdateRate`) | Boolean |
| `UpdateRate` | Seconds between two executions of the `OnUpdate` event. | Float |
| `dontrendermousegrab` | _need testing_ | Boolean |
| `tupple` | Makes the pane behave like a button, ie can be clicked on, gain focus, lose focus, become enabled, become disabled, etc. | Boolean |
| | | |
### Attributes - Misc
| Attribute | Usage | Possible values |
|-------------------|-------------------------------------------------------------------------------------------------|----------------------|
| `name=""` | Name (more like an ID) of the UI Pane to retrieve it | String |
| `hotbartype` | ?? | |
| `MouseOverSFX=""` | Sound to play when the mouse goes over | Sound file name |
| `MouseDownSFX=""` | Sound | Sound file name |
| `MouseUpSFX=""` | Sound | Sound file name |
| `MouseDragSFX=""` | Sound | Sound file name |
| `MouseDropSFX=""` | Sound | Sound file name |
| `alpha="1.0"` | Opacity. 0: transparent, 1: opaque | Float between [0, 1] |
| `fadealpha=???` | _need info_ Used with `UIObject_Input_SetFadeAlpha` and `UIObject_OnUpdate_FadeAlpha` functions | Float between [0, 1] |
| | | |
### Events
- `OnLeftClick`: When the player clicks on the pane
- `OnLeftDoubleClick`: When the player double clicks on the pane
- `OnRightClick`: When the player right clicks on the pane
- `OnRightDoubleClick`: When the player right double clicks on the pane
- `OnMouseDrop`: Drag & drop related event
- `OnMouseDropReceived`: Drag & drop related event
- `OnMouseDropFailed`: Drag & drop related event
- `OnMouseEnter`: Mouse go over the pane
- `OnMouseLeave`: Mouse go out of the pane
- `OnGainedFocus`: For example when starting to edit a UIText _need testing_
- `OnLostFocus`: For example when clicking outside of the UIText you were editing _need testing_
- `OnResize`: _need info on resizing panes_
- `OnToolTip`: When the user keep the mose over the pane for a few seconds
+ `UIObject_Tooltip_DisplayTooltipString('Your custom tooltip',OBJECT_X,OBJECT_Y,SCREEN_TOOLTIP_2,ALIGN_NONE,ALIGN_NONE,0,0,ALIGN_LEFT)`
* Display a small tooltip
- `OnRadialRequestDefaultTooltip`: _need info_
---
# UIScene
Inherits from UIPane element.
This element the first in the XML file and is always open and never closed. All elements below are treated as UIScene children.
```xml
<?xml version="1.0" encoding="utf-8"?>
<UIScene name="MYSCENE" width="800" height="600">
<UIPane x=5 y=5 width=10 height=10>
<!-- any elements -->
</UIPane>
<!-- Do not close UIScene -->
```
## `priority` attribute
| Value | Usage |
|-------------------------------------|-----------------------------------------------------------------------|
| `SCENE_SCRIPT` | GUIs brought up by script |
| `SCENE_TOOLTIP` | Appears on top of any other GUI |
| `SCENE_GLOBAL` | Used for messageboxes generally. |
| `SCENE_FE_FULLSCREEN` | Pre-game full screen GUIs |
| `SCENE_INGAME_FULLSCREEN` | Full screen GUIs within the game. |
| `SCENE_INGAME_SYSTEM` | Escape menu and options screens. |
| `SCENE_NWN1_DIALOG` | NWN1 style dialog box _differences with `SCREEN_QUICKCHAT` ?_ |
| `SCENE_INGAME_MENU` | The popup player menu |
| `SCENE_INGAME` | Most of the windows in-game |
| `SCENE_INGAME_TARGET` | The target box |
| | |
| `SCREEN_FADE` | The first UIIcon object will be used as the fade background |
| `SCREEN_QUICKCHAT` | NWN1 style dialog box _differences with `SCENE_NWN1_DIALOG` ?_ |
| `SCREEN_CUTSCENE` | NWN2 style cutscenes |
| `SCREEN_CONTEXTMENU` | The rightclick menu system |
| `SCREEN_MINIMAP` | The in-game minimap GUI |
| `SCREEN_AREAMAP` | Full-sized area map |
| `SCREEN_MESSAGEBOX_SPLITSTACK` | Used for splitting stacks of items in inventory |
| `SCREEN_MESSAGEBOX_SPLITSTACKSTORE` | Used for splitting stacks of items for stores |
| `SCREEN_MESSAGEBOX` | Generic message box popups spawned using nwscript `DisplayMessageBox` |
| `SCREEN_STRINGINPUT_MESSAGEBOX` | Generic input box popups spawned using nwscript `DisplayInputBox` |
| `SCREEN_MESSAGE` | Unusable |
| `SCREEN_HOTBAR` | Hotbar system _need info_ |
| `SCREEN_HOTBAR_2` | Hotbar system _need info_ |
| `SCREEN_HOTBAR_V1` | Hotbar system _need info_ |
| `SCREEN_HOTBAR_V2` | Hotbar system _need info_ |
- `SCREEN_QUICKCHAT`: NWN2 will search the following elements names, and fill them.
+ `npclistbox` - Listbox of NPC spoken text
+ `npctext` - Text field for NPC spoken text (Contained by `npclistbox` generally)
+ `replieslistbox` - Listbox of Player Reply options
+ `skipdialogbutton` - Button for skipping through the NPC spoken nodes
+ `speakername` - Text field for containing the speaker's name
+ `portrait` - UIPortrait object
+ All but the speakername and portrait fields are necessary or the window will not be loaded.
- `SCREEN_CUTSCENE`: NWN2 will search the following elements names, and fill them.
+ `topbar`: UIFrame for the top black bar
+ `bottombar`: UIFrame for the bottom black bar
+ `FULLSCREEN_IMAGE`: UIIcon used for full screen images.
+ `toplistbox`: Listbox to contain the text shown on top
+ `toplistboxtext`: Textfield contained by toplistbox
+ `bottomlistbox`: Listbox to contain the text shown on the bottom. Spoken by NPCs
+ `bottomlistboxtext`: Text field contained by bottomlistbox
+ `replieslistbox`: Listbox to contain the replies available to a player.
+ `skipdialogbutton`: Fullscreen button for clicking through the dialog
+ Failure to locate any of the above objects will result in the screen not loading.
- `SCREEN_MESSAGEBOX`: NWN2 will search the following elements names, and fill them.
- `messagetext`: Text field that contains the message.
- `okbutton`: Button that will execute the OK callback
- `cancelbutton`: Button that will execute the Cancel callback
- `messageboxlb`: Listbox for containing the message text in case the text gets long.
- `MSGBOX_BACKGROUND`: Frame used for the background, this one is optional.
## Attributes
| Attribute | Usage | Possible values |
|--------------------------|---------------------------------------------------------------------------------------------------------------------------|-----------------|
| `fullscreen="false"` | Controls if the UI should to be resized to fit the game fullscreen resolution | Boolean |
| `dragregion_x` | Define the dragging handle region _need testing with UIPane_ | Integer |
| `dragregion_y` | Define the dragging handle region _need testing with UIPane_ | Integer |
| `dragregion_width` | Define the dragging handle region _need testing with UIPane_ | Integer |
| `dragregion_height` | Define the dragging handle region _need testing with UIPane_ | Integer |
| `dragresizable="false"` | Allows to resize the UIScene by dragging its edges | Boolean |
| `dragresizeborder` | Width of the edges used to resize the UIScene | Integer |
| `expiretime=0.0` | Delay in seconds before the UI is automatically closed. `0` means never _need testing_ | Float |
| `idleexpiretime=0.0` | Delay in seconds before the UI is unloaded from memory when it is closed. Unloaded UIs re re-loaded from disk when needed | Float |
| `fadein=0.0` | Fade time in seconds when the UI appears on screen | Float |
| `fadeout=0.0` | Fade time in seconds when the UI disappears on screen | Float |
| `modal="false"` | If true, will block player from interacting with other UI elements | Boolean |
| `scriptloadable="false"` | If false, prevent nwscript functions from interacting with the UI _need testing with `UIObject_Misc_ExecuteServerScript`_ | Boolean |
| `backoutkey="true"` | True allows the Esc key to close the UI | Boolean |
| `autolayout="false"` | Automatically place elements in the UIScene. Mostly unusable | Boolean |
| `minwidth` | Defunct | |
| `minheight` | Defunct | |
## Events
- `OnCreate`: The XML file is read & loaded
- `OnDestroy`: The scene is unloaded from memory, ie: the gui is closed and the `idleexpiretime` timer expired
- `OnAdd`: The GUI is made visible
- `OnRemove`: The GUI is closed
- `OnBackout`: The GUI is closed using the escape key (if `backoutkey="true"`)
- `OnUnhandledMouseClick`: when a mouse click has not been handled by any object GUI
- `OnInit`
---
# UIFrame
Inherits from UIPane element.
## Inheritance quirks
- By default `width=PARENT_WIDTH` and `height=PARENT_HEIGHT`
## Attributes
| Attribute | Usage | Possible values |
|-----------------------|---------------------------------------------------------------------------------------------------|---------------------------------|
| `fill=""` | Pattern to use to fill the element. The value is the resource name, with its extension. | Image file name with extension |
| `fillstyle="stretch"` | Texture filling method | `stretch`, `center`, `tile` |
| `border` | Thickness of the border in pixels | Integer |
| `top` | Texture for the UIFrame border | Image file name with extension |
| `topright` | Texture for the UIFrame border | Image file name with extension |
| `left` | Texture for the UIFrame border | Image file name with extension |
| `right` | Texture for the UIFrame border | Image file name with extension |
| `bottomleft` | Texture for the UIFrame border | Image file name with extension |
| `bottom` | Texture for the UIFrame border | Image file name with extension |
| `bottomright` | Texture for the UIFrame border | Image file name with extension |
| `color` | Color to blend with the UIFrame images (rgb multiplication? __need info__) | Hexadecimal color (ie `ff00ff`) |
| `mhtop` | Do not seem to work (see [oeiprogrammer](https://oeiprogrammer.blogspot.fr/search/label/uiframe)) | |
| `mhbottom` | Do not seem to work (see [oeiprogrammer](https://oeiprogrammer.blogspot.fr/search/label/uiframe)) | |
| `mvleft` | Do not seem to work (see [oeiprogrammer](https://oeiprogrammer.blogspot.fr/search/label/uiframe)) | |
| `mvright` | Do not seem to work (see [oeiprogrammer](https://oeiprogrammer.blogspot.fr/search/label/uiframe)) | |
| `mhside` | Do not seem to work (see [oeiprogrammer](https://oeiprogrammer.blogspot.fr/search/label/uiframe)) | |
| `mvside` | Do not seem to work (see [oeiprogrammer](https://oeiprogrammer.blogspot.fr/search/label/uiframe)) | |
| `maside` | Do not seem to work (see [oeiprogrammer](https://oeiprogrammer.blogspot.fr/search/label/uiframe)) | |
| | | |
---
# UIIcon
Very similar with the UIFrame element.
Inherits from UIPane element.
## Attributes
| Attribute | Usage | Possible values |
|-----------|-----------------|--------------------------------|
| `img=""` | 2D texture file | Image file name with extension |
---
# UIButton
## Attributes
| Attribute | Usage | Possible values |
|-------------------------|---------------------------------------------------------------------------------------------------------------------|---------------------------------|
| `strref="-1"` | STRREF to display inside the button | STRREF integer |
| `text=""` | Text to display inside the button | String |
| `repeatcallback="false` | If true, the OnLeftClick event will be triggered on every game frame | Boolean |
| `buttontype=""` | Type of a button if you want radio (only one can be activated at a time) or checkboxes (any can be activated) | `radio`, `check` or undefined |
| `groupid` | Button group ID in case of radio / check buttons | Integer |
| `groupmemberid` | ID of a button inside a group | Integer |
| `color` | Color to blend with the button | Hexadecimal color (ie `ff00ff`) |
| `disabledcolor` | Color to blend when the button is disabled | Hexadecimal color (ie `ff00ff`) |
| `disabledtextcolor` | Color to blend with the button text when the it is disabled | Hexadecimal color (ie `ff00ff`) |
| `style=""` | Name of an UIButton style defined in `stylesheet.xml`. The button will inherit all attributes values from its style | See `stylesheet.xml` |
## Children
UIButtons can contain multiple UIFrame children with the special `state` attribute, that controls when to display the UIFrame:
- `base`: Always displayed (ie: a background image)
- `disabled`: when the button is disabled (`disabled="true"`)
- `up`: When the button is not pressed/selected
- `down`: when the button is pressed/selected
- `focused`: When the player has the focus on the button
- `hilited`: _need info_
- `hifocus`: _need info_
- `header`: _need info_ related to `UICollapsable`
- `hiheader`: _need info_ related to `UICollapsable`
- `downheader`: _need info_ related to `UICollapsable`
You can find examples of this inside `stylesheet.xml`.
### Notes
The UIButton seems to be a kind of template element that automatically adds several children elements that are defined by its style attribute (or a default if none):
These children are:
- One `UIText`, which `text` and `strref` attributes can be set using the UIButton attribute
- Several `UIFrames`, that are shown/hidden depending on the button state, and which `color` attribute can be set using the UIButton attribute.
Define one of these children inside the UIButton element will override the style-defined one.
[Oeiprogrammer](https://oeiprogrammer.blogspot.fr/search/label/uibutton) also mention UIIcon children:
> An unlimited number of UIIcons that will be added to the 'overlay' list for that button. Overlays are extra icons that can be made visible by the engine that stay with the button. At this time, there is no way to manipulate these overlays via script.
## Events
- `OnSelected`: When the user activates the button only if `buttontype` is either `radio` or `check`
- `OnUnselected`: When the user deactivates the button only if `buttontype` is either `radio` or `check`
---
# UIText
# UICollapsable
# UIGrid
# UIListBox
Notes:
- Hiding the listbox scrollbar can cause issues because when you empty/re-fill it, the scrollbar position may be kept.
# UIScrollBar
# UIProgressBar
# Special files
## contextmenu.xml
### UIScene
Using the `OnAdd` event to trigger `UIObject_Misc_ExecuteServerScript` will prevent the GUI from loading.
### UIRadialNode
A collection of buttons in a context menu.
Each UIRadialNode can contains either a list of `UISubNode` or an `UIFrame` (can probably contain other types of elements)
Each `UIRadialNode` has a `name` property that is referred to in `UISubNode`
#### Events
- `OnLeftClickExpanded`
- `OnLeftClickCollapsed`
- `OnInit`: Triggering `UIObject_Misc_ExecuteServerScript` will prevent the GUI from loading (need more info).
### UISubNode
The `node` property refers to an existing `UIRadialNode`'s `name` property.
# Other XML elements
- `UIFontFamily`: Used only in `fontfamily.xml`. Adding new font families can cause weird bugs
- `UI3DScene`: Used for inventory, character portraits, character creation preview, ...
- `UIPointLight`: Used inside `UI3DScene` ti light up the 3d model.
- `UIFontBold`: Used only inside a `UIFontFamily` element
- `UIFontBoldItalic`: Used only inside a `UIFontFamily` element
- `UIFontItalic`: Used only inside a `UIFontFamily` element
- `UIFontNormal`: Used only inside a `UIFontFamily` element
- `UIHotbarButton`
- `UIPortrait`
- `UITextTree`
---
# Generic functions
- `UIObject_Misc_ExecuteServerScript(gui_script,arg0,arg1,...)`
+ Execute a server side script. The script must start with the `gui_` prefix (unless you are using [Skywing's AuroraServerNWScript nwnx4 plugin](http://www.nwnx.org/phpBB2/viewtopic.php?t=1803))
- `UIObject_Input_SetFadeAlpha(1.0)`
+ Need testing
- `UIObject_OnUpdate_FadeAlpha(0.25)`
+ Need testing
- `UIText_OnUpdate_DisplayLocalVar(local:1)`
+ Displays local var value in the text field. Does not render tags like `<i><b><color>`.
# NWScript functions
## SetGUITexture
- `void DisplayGuiScreen( object oPlayer, string sScreenName, int bModal, string sFileName = "", int bOverrideOptions = FALSE);`
- `void CloseGUIScreen( object oPlayer, string sScreenName );`
-
- `void SetLocalGUIVariable( object oPlayer, string sScreenName, int nVarIndex, string sVarValue );`
- `void SetGlobalGUIVariable( object oPlayer, int nVarIndex, string sVarValue );`
-
- `void SetGUITexture( object oPlayer, string sScreenName, string sUIObjectName, string sTexture );`
- `void SetGUIObjectHidden( object oPlayer, string sScreenName, string sUIObjectName, int bHidden );`
- `void SetGUIObjectDisabled( object oPlayer, string sScreenName, string sUIObjectName, int bDisabled );`
- `void SetGUIObjectText( object oPlayer, string sScreenName, string sUIObjectName, int nStrRef, string sText );`
- Set a `<UIText>`'s text. The text will render tags like `<i><b><color=red>` correctly
- `void SetGUIProgressBarPosition( object oPlayer, string sScreenName, string sUIObjectName, float fPosition );`
- `void SetGUITexture( object oPlayer, string sScreenName, string sUIObjectName, string sTexture );`
- `void SetScrollBarRanges( object oPlayer, string sScreenName, string sScrollBarName, int nMinSize, int nMaxSize, int nMinValue, int nMaxValue );`
- `void ClearListBox( object oPlayer, string sScreenName, string sListBox );`
- `void AddListBoxRow( object oPlayer, string sScreenName, string sListBox, string sRowName, string sTextFields, string sTextures, string sVariables, string sHideUnhide );`
- `void ModifyListBoxRow( object oPlayer, string sScreenName, string sListBox, string sRowName, string sTextFields, string sTextures, string sVariables, string sHideUnhide );`
- `void SetScrollBarValue( object oPlayer, string sScreenName, string sScrollBarName, int nValue );`
- `void DisplayMessageBox( object oPC, int nMessageStrRef, string sMessage, string sOkCB="", string sCancelCB="", int bShowCancel=FALSE, string sScreenName="", int nOkStrRef=0, string sOkString="", int nCancelStrRef=0, string sCancelString="" );`
- `void DisplayInputBox( object oPC, int nMessageStrRef, string sMessage, string sOkCB="", string sCancelCB="", int bShowCancel=FALSE, string sScreenName="", int nOkStrRef=0, string sOkString="", int nCancelStrRef=0, string sCancelString="", string sDefaultString="", string sUnusedString="" );`