Wednesday, January 31, 2007

UIButton

UIButton is the generic, clickable object one expects to find on any PC game interface. It also acts as a 'restricted' container of sorts, as it can contain specific UI objects within it.

A button is made up of several child objects contained in a single pane. These pieces can be defined explicitly or left up to the engine to define.

The child objects that a UIButton can contain are:
Up to 1 UIText field. If a UIText object is not defined as a child object in the XML, the engine will create one automatically when creating the UIButton.

Up to 11 UIFrames. A UIFrame contained within a button must have a state attribute that only applies when specifically contained within a button. The following arguments are valid for the state attribute:
up
down
disabled
focused
hilited
hifocus
header
hiheader
downheader
base
These states can mean different things depending on the context of the button, so I'll just make some notes about a few of them. 'header', 'hiheader', and 'downheader' are the states for a button that is to be the header of a UICollapsable object, which will be explained further in a later article. 'base' is useful for when using state frames that leave some of the 'base' button visible, such as hotbar button icons.

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.

UIButton supports the following attributes:

style
This is a 'style' name from the stylesheet.xml file that this button should adopt for its default parameters. At this time there is not support for custom styles.

repeatcallback
If this attribute is set to true, the OnLeftClick callback will get executed every frame as long as the left mouse button is held down on it. On the first update the OnLeftClick will execute on the mousedown. There will then be a 0.5 second pause, then after that the OnLeftClick callback will be executed every frame until the left mouse button is released.

OnSelected
This callback is applicable to radio buttons and toggle boxes. If the button is a toggle box, this callback is executed when the toggle box is activated. If the button is a radio button, this callback is executed when the button becomes the selected radio button.

OnUnselected
This callback is applicable to radio buttons and toggle boxes. If the button is a toggle box, this callback is executed when the toggle box is de-activated. If the button is a radio button, this callback is executed if thi sbutton was the selected radio button, but now another radio button has been selected.

groupid
This is a group number for radio buttons. Group IDs are global for the entire XML file that contains the button. That is to say, there can only be one group of radio buttons with the group id of '1', or '2', etc. All buttons that share the same group id form a 'set' of radio buttons. Only one button in that set can be selected at a time, all the rest are non-selected. Selecting any one button in the set will unselect the previously selected radio button.

groupmemberid
This gives the UI Button a unique within a set of radio buttons. There should only be one button with a specific groupmemberid in a set of buttons. Ideally these IDs should start with 1 and increment from there, but that is not completely necessary.

buttontype
This attribute accepts only 'radio' or 'check' as arguments, defining the button as a radio button or checkbox style button.

color
This attribute accepts color strings. These colors will blend with any other colors found in the textures of the button. So setting this to grey, for example, will make a grey-scale style icon for the button.

disabledcolor
This attribute accepts color strings. This will be the blending color for when the button is put into a disabled state.

disabledtextcolor
This attribute accepts color strings. This color will change the color of any text contained in the button's text field if the button is put into a disabled state.

strref
This is a STRREF that represents the string that should appear in the button.

text
This is hard coded text that should appear in the button. It overrides the strref attribute if it is present.

UIPane

UIPane is the generic 'container' for other UI Objects. Panes can't be rendered, but they can contain 'child' objects which can be renderable objects.

Every scene has a 'rootpane', which is automatically defined by the engine when a new UIScene is loaded from a XML file.

Child objects within a pane will be positioned with their x,y origin relative to the origin of the UI Pane that contains the child. UIPanes can also simulate buttons with the tupple attribute, so many of the attributes for UIPane are similar to those found under UIButton.

The following attributes are supported by UI Pane:

MouseDownSFX
Sound effect to be played when the Pane is clicked on. This only means anything if the Pane is a tupple style pane.

MouseUpSFX
Similar to a button up sound effect, this only means anything if the Pane is a tupple style pane.

MouseDragSFX
Sound effect for dragging a tupple style UI Pane object.

MouseDropSFX
Sound effect when releasing a dragged tupple style UI Pane object.

tupple
Setting this attribute to true makes the entire UI Pane behave like a button rather than just a container. This makes it possible to design more complicated buttons than normal, default UIButton tag allows for such as having a defined layout or multiple icons within the same button, etc. Once a Pane becomes a tupple, it can be clicked on, gain focus, lose focus, become enabled, become disabled, etc., just like a normal button. Note that it is still possible to place buttons within a tupple style pane that should work fine. So you could have a listbox row that is a tupple style pane that also has a toggle button on every row, for example.

OnLeftClick
The callback to be executed when a tupple style UI Pane is left clicked on.

OnLeftDoubleClick
The callback to be executed when a tupple style UI Pane is double left clicked on.

OnRightClick
The callback to be executed when a tupple style UI Pane is right clicked on.

OnRightDoubleClick
The callback to be executed when a tupple style UI pane is double right clicked on.

Tuesday, January 30, 2007

UIScene

The UIScene tag at the top of the XML files defines certain global parameters about the entire GUI window being defined in the file.

A scene doesn't have anything to render by default, but rather contains items that will get rendered. So a file that defines a UIScene and nothing else will not appear as anything in the game.

Some of the attributes for UIScene overlap with those of UIObject, even though UIScene does not inherit from UIObject, so this attributes will be repeated here.

The following attriibutes are supported by the UIScene tag:

OnCreate
This callback gets executed when the scene is loaded from the XML file. This is not necessarily a one time thing, as it is possible for scenes to get unloaded from memory and then reloaded from the file the next time they are needed. Additional detail about this will be included later in this article.

priority
This determines where scenes fall in the render order, in terms of which scenes should cover up other scenes.
The valid arguments to this attribute in order of highest priority to lowest are:
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_SCRIPT - GUIs brought up by script
SCENE_NWN1_DIALOG - The NWN1 style dialog box
SCENE_INGAME_MENU - The popup player menu
SCENE_INGAME - Most of the windows in-game
SCENE_INGAME_TARGET - The target box

OnDestroy
This callback gets executed when the scene is unloaded from memory.

OnAdd
This callback gets executed any time the scene is made visible.

OnRemove
This callback gets executed any time the scene is closed. Note that scenes can be closed and yet remain in memory. This in fact the default behavior. See idleexpiretime below for more information.

OnBackout
This callback gets executed when the user hits their Esc key and this scene is going to be closed as a result. If the backoutkey attribute is not true, then this callback will do nothing.

OnUpdate
This is the callback to execute every frame.

OnUnhandledMouseClick
This callback gets executed if a user clicks on the scene, but none of the contents of the scene did anything with the user's click.

updaterate
The time between updates, in seconds. If no value is specified, the scene will get an update every frame.

draggable
This determines if the entire scene is draggable. This is different from dragging a single UI Object within a scene as it moves the entire window. The default setting is false.

dragregion_x
dragregion_y
dragregion_width
dragregion_height
These 4 attributes are used to define the space on the scene that can be used to drag the scene. The numbers are in pixels. If a drag region is defined using these 4 attributes, the user can only drag the scene by clicking and dragging in the defined location. If no drag region is defined, the user can drag the scene by clicking anywhere on the scene where the click will not be used by a child object of the scene.

dragresizable
Determines if this scene can be resized by dragging the edges of it. This is used in the chat window for resizing, for example. The default setting is false.

dragresizeborder
This attribute defines the size, in pixels, of the border of the scene that can be clicked on in order to resize the window.

capturemouseclicks
If set to false, then mouse clicks should pass right through the background of this scene. Useful for semi-transparent overlays and other situations where it is expected that the user be able to click through the UI Object. The default setting is true.

capturemousevents
This is pretty much a redundant attribute. It does the exact same thing as capturemouseclicks.

fullscreen
This attribute can be true or false. By default it is false. It controls what happens to this scene when the resolution of the game changes. Scenes that have this attribute set to 'true' will not have their origins moved but their dimenions will be adjusted to the new resolution. Scenes that have this attribute set to 'false' will not be resized when the resolution changes but their origin will change to stay roughly in the same part of the screen that the window appeared in before.

width
Width of the scene in pixels. The argument 'SCREEN_WIDTH' can also be used to make this scene always match the width of the full screen.

height
Height of the scene in pixels. The argument 'SCREEN_HEIGHT' can also be used to make this scene always match the height of the full screen.

x
The x origin for the window. The following string arguments are also valid: ALIGN_CENTER, ALIGN_LEFT, ALIGN_RIGHT. Defaults to 0.

y
The y origin for the window. The following string arguments are also valid: ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM. Defaults to 0.

expiretime
This is the amount of time in seconds a scene should be up before it is automatically removed from view and unloaded from memory. If 0 or not set, then the scene will never be automatically removed from view.

idleexpiretime
This is the amount of time in seconds a scene should not be visible before it should be unloaded from memory. This can be used to unload scenes that were shown once that will not be needed again anytime soon. The next time the scene is requested, it will be loaded from disk. This makes it possible to sometimes do quick testing of GUI changes by setting a short idleexpiretime, closing the window, then reopening it to see what it looks like with the new changes on disk.

autolayout
This attribute is only of interest in message-box style GUI screens. If enabled, the engine will attempt to automatically position the text, the 'okay', and the 'cancel' button in a classic message box layout. If left false, then the engine will not attempt to arrange any of the contents of the messagebox when the message box is requested. It is false by default.

modal
If set to true, then this UI scene will block access to the game or any underlying GUI screens until the window is closed. It is false by default. Note that scripts that bring up GUIs can override this parameter based on the parameters passed in to the script function.

fadein
The time in seconds this scene should take to fade in completely when opened.

fadeout
The time in seconds this scene should take to fade out completely when closed.

minwidth
This attribute is defunct and no longer does anything.

minheight
This attribute is defunct and no longer does anything.

scriptloadable
In order for a server script to have any control over this GUI at all, this attribute must exist in the UIScene tag and must be set to true. It is false by default. If false, than all script functions that attempt to manipulate a user's GUI will fail.

backoutkey
If this attribute is set true, then use of the backout key ('Esc' key by default) will cause this window to close. The backout key follows a defined set of logic for determining what to do when it is used. First it closes any open 'windows' in the reverse order that they were opened (Most recent window opened is closed first). If there are no windows to close, it clears the player's target. If the player has nothing targetted, it brings up the in-game options screen.

Long Posts and post summaries

On other blogs, I've seen that authors will write a summary or intro to the post and then there will be a link the reader can click to go to the full length article. Given that some of my technical posts are going to be very long, I'd like to do the same thing here. But I've read some of the guides on blogger as well as other various websites about how to do that and the instructions are real head scratchers, telling me to look for tags that don't exist to insert code.

Considering the guides tend to be really old, all I can imagine is that they are out of date and that some new approach is required to accomplish what I'm looking to do. If anyone has any advice or information about implementing that feature for this blog, I'd love to hear about it.

An example of what I'm talking can be seen on this blog here:
http://afkgamer.com

If you flip through a few pages of posts, you'll find longer posts where he sets up the post, and then there's a 'Read the rest' link or whatever to follow in order to read the rest of the lengthy post.

Monday, January 29, 2007

UIObject

This is the first of many posts to come to document the various attributes for GUI Objects. UIObject is the 'base' GUI object. You can't actually define it in XML, but it contains attributes that are common to many different UI Objects, so I'm starting here.

The following are the attributes that will be loaded for every UI Object in the XML file except for the attributes.

Some attributes will be ignored or overridden depending on the situation. Note that attributes are case sensitive.

name
String value for the name of the UI Object. This is used internally and will be necessary for scripting to interact with this object in the future.

scalewithscene
If this is set to true, then this UI Object will have its dimensions scaled to match its parent's dimensions if the parent object gets resized. Handy for things like background images.

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. :)

width
The width of the UI Object. Many things override this, for example if the object will be a box in a grid, the grid will control the width, or if the box is in a list box, the list box may override it, depending on the list box attributes, etc. This attribute can take pixel count arguments, or the following strings:
SCREEN_WIDTH - This object's width will be full screen no matter what the resolution is.
PARENT_WIDTH - This object's width will be the full width of its parent object, no matter what the size of the parent object is.

height
Same as the width attribute, except substitute height for width in all cases. Note that if no height or width attributes are set, the object will take on the height and width of its parent object.

x
The x origin of the object with respect to its parent UI object. This can take a pixel count, or the following strings as arguments:
ALIGN_CENTER - Center this Object to the screen
ALIGN_PARENT - Center this object within its parent UI Object.
ALIGN_LEFT - Keep this object oriented to the left of its parent (x = 0).
ALIGN_RIGHT - Push this object against the right side of the parent object.

y
The y origin of the object with respect to its parent UI object. This can take a pixel count, or the following strings as arguments:
ALIGN_CENTER - Center this object to the screen
ALIGN_PARENT - Center this object within its parent UI Object.
ALIGN_TOP - Keep this object at the top of its parent object (y=0)
ALIGN_BOTTOM - Push this object against the bottom of the parent object.

focusable
In general, this means that the object can't be clicked on. For example, if it is an object in a UIGrid, it means that object in the grid can't be clicked on. This will keep the object of being the target of an actiontarget as well (When the mouse cursor changes to indicate the user can click somewhere to perform an action). Default value is true.

ignoreevents
This is somewhat identical to setting focusable=false, but it also means that the UI Object will ignore objects being dragged on it, among some other UI events besides just mouse clicking. It defaults to false.

handleactiontarget
Setting this to true means that action targets can be used on this GUI object. Action targets actions that need to be targeted on something, indicated by the mouse cursor changing appearance. For example, clicking on a spell button, then having the cursor change to indicate you need to click on what target you want the spell cast. If this attribute is true, then the GUI object will be treated as a valid target for actions to be performed on. It defaults to false.

draggable
This indicates that the UI Object can be dragged and dropped, such as hotbar buttons. Defaults to false.

OnMouseDropReceived
This is the UI Callback to execute when a draggable UI object gets dropped on this UI object. This is not executed by the object being dropped, but rather the object that got something dropped ON it.

OnMouseDrop
This callback is executed on a UI Object when it gets dragged and then dropped. Upon being dropped, this callback will be executed.

OnMouseDropFailed
This callback is executed if a UI Object is dragged and then dropped but not dropped over another UI Object.

OnMouseEnter
This callback is executed when the mouse cursor is moved over this object.

OnMouseLeave
This callback is executed when the mouse cursor is moved off of the object after having been moved onto it.

OnResize
This callback is executed any time the UI Object gets resized for any reason.

OnTooltip
This callback gets executed if the mouse hovers over this object long enough based on the user's preference for the tooltip delay.

OnRadialRequest
This is the callback that gets executed if the user brings up the context sensitive menu on this UI object.

DefaultTooltip
This is a default tooltip STRREF that is used in case a custom tooltip callback is not really necessary.

hidden
Whether or not this object is visible. Defaults to true..

disabled
Whether or not this object is enabled. Applies mostly to buttons, but for the most part, no UI Object that is disabled will accept user input. Defaults to false.

capturemouseclicks
If set to false, then mouse clicks should pass right through this object. Useful for semi-transparent overlays and other situations where it is expected that the user be able to click through the UI Object. This also applies to MouseEnter and MouseLeave. If an object is set to not capture mouse clicks, then objects underneath of it cannot be moused over.

OnGainedFocus
This callback is executed when an object gains focus. This applies mostly to buttons that got clicked on or editable text fields that got clicked in.

OnLostFocus
This callback is executed when an object loses focus. This applies mostly to buttons that had been previously clicked on or editable text fields that had been previously clicked in.

update
This determines if this UI object receives calls to an OnUpdate callback. Defaults to false. If set to true, then this UIObject will have its OnUpdate callback called on every frame, or slower if an updaterate is defined.

OnUpdate
The callback to be executed when this object receives its update.

UpdateRate
This attribute can be used to tune the update rate of a UI Object. If a particular object doesn't need to be updated every frame, then set an update rate here to slow it down. The number value is in seconds and floating points are okay (0.5 for half second, for example).

hotbartype
This is an advanced attribute that is used for determining how the hotbar should treat another UI Object being dragged onto it. The currently valid values for this attribute are:
HOTBAR_NONE - The hotbar should ignore this.
HOTBAR_ITEM - This is an item icon being dragged, such as from inventory.
HOTBAR_KNOWNSPELL - This item being dragged is something from the spellbook.
HOTBAR_SPELL - This item is a spell from somewhere else, such as another hotbar slot.
HOTBAR_FEAT - This item is a feat from somewhere, such as the feat listing or another hotbar slot.
HOTBAR_BUTTON - This is an empty hotbar button.
HOTBAR_SKILL - This is an activateable skill, such as from the skills pane or another hotbar slot.
HOTBAR_TOGGLEMODE_BUTTON - This is a button used to toggle some kind of mode.
HOTBAR_BARTER - This is used to flag barter grid items as not being able to be dragged to the hotbar.
HOTBAR_DM_COMMAND - The item being dragged is a DM Client command.
HOTBAR_VM_COMMAND - The item being dragged is an emote command.
HOTBAR_DM_CREATOR - The item being dragged is an entry from the DM Client Creator.

Scale*ToParent
This was a set of attributes that was going to allow more control over how an object behaved when its parent got scaled. But in looking at the code, it looks like they've been gutted and no longer do anything.

MouseOverSFX
The sound effect to play when this UI Object gets moused over.

alpha
How transparent this object should be by default.

dontrendermousegrab
'Mouse Grab' means item being currently dragged. Normally the mouse grab is rendered last of all in order to keep it on top. There are situations where this behavior wasn't desired, though I can't remember what. When set to true, it means that this object needs to not get rendered last like normal dragged objects, but rather is rendered when it would normally be.

SetDataInt
This stores an 'int' value in the UI Object's data element at int index 0. More on data elements another time.

SetDataFloat
This stores a 'float' value in the UI Object's data element at float index 0. More on data elements another time.

SetDataString
This stores a 'string' value in the UI Object's data element at string index 0. More on data elements another time.

2DA Caching for Script Lookups

Our lead scripter, Charles Mead, informed me that we did not cache 2DAs that were being queried by script. This resulted in ridiculous seek time for looping over large 2DAs.

He indicated that Bioware had fixed that in the 1.64 code, so I referenced the 1.67 code drop that we had and saw that they had implemented a system whereby the most recent 2 2DAs that were queried were cached.

I took that a bit further and made it so that the # of 2DAs that are cached is a changeable value. The default is 10, but in nwnplayer.ini, an entry of:

2DA Cache Size=

under

[Server Options]

will allow users to modify that cache size to suit their needs. There should never be a need to go lower than 10, but someone may want to increase the cache if they are querying a ton of different 2DAs quite frequently.

In addition, the function:
Clear2DACache() can be used to purge the in-memory 2DA cache. This will force the 2DA to be loaded from disk the next time a script tries to look anything up from it.

This change is scheduled for 1.05.

Tuesday, January 23, 2007

So far for 1.05

While the 1.04 patch is about to come out for NWN2, the 1.05 patch isn't too far off either. Rather than make 1.05 a big patch like 1.04 is, we want to release a small, quick patch to try and quickly resolve some issues the custom content community for NWN2 is running into.

I recently revamped the auto-updater to allow for incremental patches. This means that if someone had 1.02, the patcher would patch them up to 1.03, then to 1.04 (once 1.04 is released). While this may seem like it doesn't offer anything to the end-user, it makes it several times faster to make patches on our end, which means the end-user will see more frequent, smaller patches, instead of the periodic large patch.

The following is a list of the items that have gone in so far for 1.05:

armorrulestats.2da will no longer be capped at 255 rows

DisplayGuiScreen() script function now has a new parameter that allows the script to define the *.xml file if the 'screen name' can't be found in the gui INI files.

Appearances.2da had the NWN2_Scale column changed to NWN2_Scale_X, NWN2_Scale_Y, NWN2_Scale_Z, allowing all 3 dimensions to be scaled seperately.

The chat boxes will no longer clear their text on area or module transitions.

NWN2_Deities.2da can now be overridden correctly, without having to stick it into the override directory.

NWN2_Deities.2da's description column can now work with hard coded strings in place of STRREFs. Simply enclose the string in " marks.

GetIsPartyTransition() script function will now correctly return TRUE or FALSE. Before it would always return TRUE, which would cause the default transition scripts to jump the party even if the trigger was flagged as not being a party transition.

A bug has been fixed that was preventing mouse clicks from going through the screen space occupied by the quickspell menus even if the quickspell menu wasn't visibly blocking that part of the screen.

There's a number of 2DAs that should be fixed in the toolset with regards to respecting the Label Column if the STRREF column is blank. I'm out of the office this week, so I'm not 100% sure that this had made it in at this time, but it is my goal for the 1.05 patch for it to be there.

Also going in is Multiselect for the DM Client and in the normal game mode. This will allow you to drag-select any party members not being actively controlled by another player and issue simple commands like move, attack, talk, and even unlock/disarm. The game will pick the character with the highest score for picking and disarming and have them do the action. This is our first pass at multi-select support, there will be more features going in with regards to this over time.

Anyway, that's all I can think of off hand and after looking over my notes from last week. I expect 1.05 to be released early Feb.

Something New

This blog is a site I intend to maintain as a location to post information about projects I'm working on, to the extent that I am able due to confidentiality.

The initial purpose of it will be as a page to post notes about the Neverwinter Nights 2 engine as it pertains to being modified and customized by the community. As such, many of the initial posts will be irrelevant if you're not interested in Neverwinter Nights 2 modding.