Difference between revisions of "Oblivion XML Reference/Traits"

16,469 bytes added ,  23:54, 17 June 2018
→‎Behavior: full spec
imported>DavidJCobb
imported>DavidJCobb
(→‎Behavior: full spec)
Line 20: Line 20:


== Behavior ==
== Behavior ==
This category includes any behavior-related traits, but it also includes keyboard navigation traits. A keyboard navigation trait tells Oblivion how to respond to a specific keypress when a tile or its menu has focus. The process for handling a keyboard navigation trait is as follows:
#The tile that had mouseover focus at the time of the navigation keypress shall be referred to as the trigger tile. The trait for the navigation keypress (e.g. xup for the up arrow key) shall be referred to as the navigation trait.
#Identify a basis tile.
#*If the trigger tile has the navigation trait, then it is the basis tile.
#*Otherwise, search upward through the trigger tile’s ancestors, stopping at the first found tile that has the navigation trait. That found tile will be the basis tile.
#If there is no basis tile, abort.
#If the navigation trait uses any ''ref'' operator, then modify the specified trait on the specified other tile only if that tile is suitable. Regardless of whether the tile is targetable, stop here.
#*For the purposes of this task, we use the first ''ref'' operator in the trait, ignoring hierarchy and treating all operators as a flat list.
#*The exact definition of suitable is yet to be determined. However, a tile can be used if it itself is ''target''able and has an ''xdefault'' greater than -99, or if its ''xlist'' trait is set to &xlist; and it contains any ''target''able tiles with ''xdefault'' traits.
#*If the trait being modified is clicked, but the target tile has an xdefault trait, then give it mouseover focus as well.
#If the navigation trait uses the &first;, &last;, &prev;, or &next; entities, then search the basis tile’s siblings (in order, from first to last) for a ''visible'' and ''target''able tile with an ''xdefault'' trait (set to any value) and a suitable ''listindex'':
#*For &first;, choose the sibling tile with the lowest ''listindex''.
#*For &last;, choose the sibling tile with the highest ''listindex''.
#*For &prev;, pick from among the sibling tiles whose ''listindex'' values are less than that of the basis tile: choose the highest ''listindex'' among those.
#*For &next;, pick from among the sibling tiles whose ''listindex'' values are greater than that of the basis tile: choose the smallest ''listindex'' among those.
#If no matching tile is found, then return to Step 2, treating the current basis tile as the trigger tile for that step.
#If a matching tile was found, scroll it into view using the ''xscroll'' trait: assume that it is a list item tile and its parent is a list container tile.
#Give the matching tile ''mouseover'' focus as appropriate.
Code analysis suggests that keyboard navigation cannot be “chained:” if one tile points xup at another tile, and that other tile points xup at a third, moving up from the first tile will not bring you directly to the third.
In at least some cases, using keyboard navigation to forward clicks will not also forward mouseover focus, unless ''xdefault'' is &true; or greater. This may be limited to the ''listindex''-related XML entities.
Bethesda’s code comments indicate that keyboard navigation in a menu may break if no tile in the menu has initial focus. Be sure that you set an ''xdefault'' trait on any ''target''able tile.
Those interested in reviewing the engine-level functionality involved can refer to subroutine <code>Tile* Tile::ResolveTraitReference(UInt32 keynavTraitID, UInt32* outTargetTraitID)</code>, located at <code>0x0058E3B0</code> in the latest version of Oblivion. That function handles Steps 1 through 7 in the above outline; Steps 4 (modifying the trait) and 8 are handled by some (all?) callers. The return value is the tile pointed to by the ref operator in Step 4, or the tile identified in Step 5; <code>*outTargetTraitID</code> is set to the trait identified by the ref operator in Step 4.
To investigate the meaning of “suitable” in Step 4, examine <code>InterfaceManager::HandleNavigationKeypress</code> (located at <code>0x00580BA0</code> in the latest version of Oblivion), which calls <code>Tile::ResolveTraitReference</code> multiple times.
----
;clickcountafter
;clickcountbefore
:Found in the executable. Purpose unknown.
;clicked
:If the tile’s ''target'' trait is true and the tile has an ''id'', then clicking on the tile will set this property to 1 for a single frame.
;clicksound
:If the tile’s ''target'' trait is true and the tile has an ''id'', then clicking on the tile will play the specified sound. Values are numbers which correspond to the hardcoded editor IDs of sounds. (The sounds themselves are defined in Oblivion.esm.) The default value is zero.
:{| class="wikitable"
!Sound index !! Sound editor ID !! Description
|-
|1 || UIMenuOK || A clicking sound overtop a low drumbeat.
|-
|2 || UIMenuCancel || A clicking sound.
|-
|3 || UIMenuPrevNext || A slightly higher-pitched clicking sound.
|-
|4 || UIMenuFocus || Silent.
|-
|5 || UIMenuTabs || Silent.
|-
|6 || ITMBookPageTurn ||
|-
|7 || UISpeechRollover || A quick, high-pitched clink.
|-
|8 || UISpeechRotate || Something rotating into place, with several quick metallic clicks as it goes. A longer sound. Used for the Persuade minigame.
|-
|9 || UIQuestNew || Quick cymbals and a drumbeat. Used when a quest starts.
|-
|10 || UIQuestUpdate || The same as UIQuestNew, but with some chiming at the end. Used when a quest updates.
|-
|11 || UIMessage || A low drumbeat.
|-
|12 || MenuEnd ||
|-
|13 || MenuStart ||
|-
|14 || UIMenuBracket || A metallic object sliding into place, with a high-pitched clink at the end.
|-
|15 || UIMessageFade || Two high-pitched chimes.
|-
|16 || UIInventoryOpen || Silent.
|-
|17 || UIInventoryClose || Silent.
|-
|18 || UIPotionCreate || A glass clink, followed by a low beat and the sound of bubbling. Used when you brew a poison or potion.
|-
|19 || DRSLocked ||
|-
|20 || UIMessage ||
|-
|21 || UIMenuCancel ||
|-
|22 || UIStatsSkillUp || Drums. Used when a skill increases.
|-
|23 || SPLEquip || A quick shuffling of papers over a low drumbeat.
|-
|24 || ITMWelkyndStoneUse ||
|-
|25 || ITMScrollOpen ||
|-
|26 || ITMScrollClose ||
|-
|27 || ITMBookOpen ||
|-
|28 || ITMBookClose ||
|-
|29 || ITMTakeAll ||
|-
|30 || ITMIngredientNothing ||
|-
|31 || ITMIngredientDown ||
|-
|32 || ITMSoulTrap ||
|-
|33 || UIArmorWeaponRepairBreak || The sound of a Repair Hammer breaking after being used up.
|-
|34 || ITMBoundDisappear ||
|-
|35 || ITMGoldUp || The sound of coins clinking together. Good for spending or receiving gold.
|-
|36 || UIItemEnchant || A long, louder magical sound effect.
|}
;focusinset
:The game uses this to offset the position of a focus box, shrinking it inward by the value; the trait must be manually read and used by each menu with a focus box. See the description for ''target'' for further information on focus boxes.
;listindex
:When a tile is generated as part of a list, the executable typically sets its ''listindex'' trait to its index within the list. Note that you’re perfectly free to use ''listindex'' in “preplaced” content; in fact, this can be incredibly convenient for setting up keyboard navigation!
:If a keyboard navigation trait (e.g. xup) is set to &amp;prev; or &amp;next;, then pressing that button while a tile has focus will transfer ''mouseover'' focus to the previous or next list item – that is, the tile whose ''listindex'' is the "closest" to the current tile in either direction. When searching for the previous or next list item, the game starts by scanning all of the current tile’s siblings (in order from first to last), before recursing outward (i.e. scanning the parent tile’s siblings and so on) if nothing is found. For the purposes of this entire feature, the ''listindex'' values are truncated to integers. Gaps between ''listindex'' values won’t interfere with &amp;prev; or &amp;next;; for example, if the only two children in a tile have ''listindex'' values 1 and 3, you can still use ''listindex'' for keyboard navigation.
:Refer to the keyboard navigation explanation at the top of this section for complete information.
;mouseover
:If the tile’s ''target'' property is true, then this trait will be set to 1 when the mouse is over the tile, and 0 at all other times. Note that this trait will not update if the tile is moved under the player’s cursor, or if the tile is moved out from under the player’s cursor (both are common when working with tiles in scrollable panes: the user can use the scroll wheel to move tiles within these panes under and out from the cursor without actually moving the cursor over them first).
:Keep in mind that Oblivion XML doesn’t use standard Boolean values: 1 converts to false in Oblivion. It’s generally better to use ''mult'' instead of ''onlyif'' to handle this trait. For example, to make a trait use the value 140 normally and 255 when the tile is under the mouse, try <code>&lt;copy&gt;140&lt;/copy&gt;&lt;max&gt;&lt;copy&gt;255&lt;/copy&gt;&lt;mult src="me()" trait="mouseover" /&gt;&lt;/max&gt;</code>.
:Testing suggests that elements cannot receive ''mouseover'' focus from the mouse if they do not have an ''id'' trait, even though they can still receive ''mouseover'' focus from keyboard navigation. Further investigation is required. Remember that you can usually set a tile’s id to &amp;generic; to ensure that it doesn’t trigger any special menu-related behaviors.
;shiftclicked
:If the tile’s ''target'' trait is true and the tile has an ''id'', then clicking on the tile while holding the Shift key will set this trait to 1 for a single frame.
;target
:If this trait is set to true, the tile will be able to receive mouse and keyboard focus. Moreover, if the tile has an ''id'', the game engine will also apply the ''clicked'' and ''clicksound'' properties and forward click events to the menu’s engine-level code to be handled (or not) by that menu.
:In (some?) vanilla menus that have scrollbars, using the mouse wheel while the cursor is over any ''target''able tile (or one of its descendants) will cause the scrollbar to scroll. It is not known whether this behavior is linked to the ''xlist'' trait.
:Some menus will show “focus boxes” under targetable elements with specific IDs, when those elements have keyboard and mouse focus. The focus boxes are themselves elements with special IDs, whose sizes and positions are altered by the executable.
;xbuttona
;xbuttonb
;xbuttonlb
;xbuttonlt
;xbuttonrb
;xbuttonrt
;xbuttonstart
;xbuttonx
;xbuttony
:These keyboard navigation traits indicate how the tile should respond to various Xbox buttons when the tile has ''mouseover'' state. For example, if you want a button to act as Shift+Click, then you might use the value <code>&lt;ref src="me()" trait="shiftclicked" /&gt;</code>.
:It’s not clear whether ''ref'' operators work inside of prefabs, but a tile defined in a prefab can be targeted by a ''ref'' operator outside of the prefab.
:The ''xbuttonlt'' and ''xbuttonrt'' traits also trigger when the player presses the left or right arrow keys while holding the Shift key.
;xdefault
:This trait has something to do with specifying which tile will take keyboard navigation focus, if the user presses a keyboard navigation key when no tile has focus. However, the exact meaning of its value is not known at this time. Bethesda specifies it as both a Boolean and an integer – sometimes mixing formats even within the same menu. Analysis of the executable has not yet revealed the value’s meaning, but certain details (described below) suggest that it may be a way of prioritizing input focus: it may be that the tile with the highest ''xdefault'' value is the one that gets initial focus.
:If ''xdefault'' is set to -1, then the tile can be used in keyboard navigation, but its ''xdefault'' trait will not be increased. For tiles that are visible and ''target''able, ''xdefault'' values below -99 skip some sort of processing apparently related to the ''xlist'' trait, and in testing seem to prevent keyboard navigation to the tiles in question as well.
:The value can be modified by the executable. Testing indicates that the executable maintains a running counter of some kind, which persists past the closure of a menu and may persist across all menus. Every time a tile gains or loses ''mouseover'' focus from keyboard navigation (but not mouse movement), the counter is incremented by a value between 1 and 3 (inclusive), and the tile’s ''xdefault'' trait is set to that value. Modifications to a tile’s ''xdefault'' trait do not persist across the closure and later reopening of the tile’s containing menu, but (as stated before) the counter’s value does persist. This may be how the game remembers focus when navigating between two different list panes (see description for ''xlist'').
;xlist
:This trait has something to do with indicating whether a tile is a list container, a list item, or (by default) neither. Vanilla code comments wrongly describe this as a Boolean even when the values supplied are not Booleans (or numerically equivalent to Booleans under the hood). The trait should be set to &amp;xlist; for a list’s immediate container and &amp;xitem; for generated list items.
:This trait influences how keyboard navigation works: if a keyboard navigation trait is processed and “leads” to a tile whose ''xlist'' trait is set to &amp;xlist;, then Oblivion will instead attempt to focus a list item inside of the tile. The precise operational definition of “list item” with respect to the previous sentence is not known at this time, but testing and disassembly indicate that “list items” work for this purpose if they have an ''xdefault'' trait (set to any value), are visible and ''target''able (a requirement for receiving keyboard focus), and if their xlist trait is set to &amp;xitem;. The result of this functionality is that you can place keyboard navigation traits (e.g. ''xleft'' and ''xright'') on two list containers, with each container’s trait pointing at the other, to allow keyboard navigation between the two lists; Oblivion will remember which list item previously had focus in each list, and will return focus to that list item if the user navigates back to its containing list.
;All of this is necessary because for a number of reasons, it is impossible to target generated list items by name for keyboard navigation. The biggest obstacle is that if the list items are not renamed after being generated from a template, then they will all have the same name; if they are renamed, they will be renamed to an executable-defined string that will likely vary based on the generated content (e.g. for an inventory item in the RepairMenu, a sanitized version of the item name with certain characters replaced). Aside from this, ''src'' attributes and selectors seem to only be processed at final parse time (templates are kept “half-parsed” and parsing finishes each time tiles are generated from them), so attempting to reference any generated list item from outside of its list will fail (because the list item does not exist at parse time).
;xdown
;xleft
;xright
;xup
These keyboard navigation traits indicate how the tile should respond to the arrow keys (and presumably the Xbox D-Pad and joysticks) when the tile has ''mouseover'' state. For example, if you want one tile to transfer ''mouseover'' status to another tile named SomeElement, you might use the value <code>&lt;ref src="SomeElement" trait="mouseover" /&gt;</code>.
:Disassembly of the executable suggests that the trait you specify here is ignored; these always influence a target tile’s ''mouseover'' trait. This hasn’t been tested yet.
;xscroll
:This trait is used when scrolling a tile into view, when that tile receives ''mouseover'' focus from keyboard navigation rather than from a mouse movement.
:For list items, this trait should be set to the value that the scrollbar should be scrolled to. For list containers (always the direct parents of list items), this value should be a ref operator indicating the scrollbar whose state needs to be modified. The trait specified in the ''ref'' operator will be ignored: the executable will perform a special-case modification to the scrollbar’s ''user5'' trait in order to forcibly set the scroll position.
:It is not yet clear how the game determines that a tile is a list item that should receive the above behavior.
== Box model ==
== Box model ==
;clips
;clips
Anonymous user