General
Adds new traits, operators, selectors, and menus. See the relevant article.
Fixes a bug that affects all vanilla textboxes, where pressing the up or down arrow keys inserts invisible garbage characters into the text that you’re entering. These characters are retained when saving any text, may be visible in modded fonts, and may affect alphabetical sorting. Text already affected by this bug cannot retroactively have garbage text characters stripped out.
Disables texture filtering for the menu cursor. This addresses an unknown bug that severely breaks texture filtering for all other menu assets whenever the cursor receives texture filtering. The effect of this is that all assets look cleaner, particularly high-resolution assets that are downscaled and displayed at different sizes, though the cursor will look rougher.
Prevents menus from receiving Tab keypresses generated when Alt+Tabbing out of the game.
Prevents the player from entering tab characters into their name when editing it in the RaceSexMenu. If a character name contains tabs, all attempts at saving the game fail silently unless you use the SaveGame console command with a custom filename.
Save files are now sent to the Recycle Bin when deleted, instead of obliterated forever. OBSE co-saves are also accounted for.
The game’s XML parser no longer uses “lazy” number recognition. Trait values will no longer be recognized as numbers if they: consist solely of decimal points and/or minus signs; or have more than one decimal point or more than one minus sign. This means that strings like “127.0.0.1”, “.” and “...” are no longer recognized the number zero. Whitespace-only strings are still recognized as zero.
Like MenuQue, NorthernUI patches the game's XML parser to add parse-time XML entities: amp, apos, gt, lt, nbsp, newline, quot. NorthernUI also adds entities that MenuQue does not add: minus. The NBSP entity isn't a proper non-breaking space, but it allows you to have a whitespace-only value without that value being parsed as a numeric zero. NorthernUI also adds support for numeric XML entities, e.g. #x2E or #46 for a period.
In Oblivion, activating a horse counts as activating its rider. However, the vanilla game still processes the horse, not the rider, when deciding what reticle icon to show. NorthernUI addresses this.
The local map now renders at a user-configurable resolution. The default for NorthernUI is 1024px per cell. The original resolution was a grainy 256px.
The keyboard navigation system for menus has been patched slightly. When writing menu XML, you can use REF operators to tell the game that a certain keyboard navigation keypress (including gamepad buttons) should count as mousing-over, clicking, or shift-clicking a certain tile, by using certain traits with a REF operator. The vanilla game processes only the first REF operator it encounters. NorthernUI patches the game to run through all of the REF operators on the tile, preferring the earliest one with a "valid" result. This allows you to define fallback cases (e.g. "keynav to this list if it isn't empty, or to this other list otherwise").
Patches the game to account for non-mipmapped textures that were improperly saved by the GIMP-DDS exporter. The patch ensures that these textures render properly (instead of displaying garbage data) when the player uses a lower texture quality. Technically, this fixes a GIMP problem, not an Oblivion problem: GIMP identifies these textures as having one mipmap (it should identify them as having zero), so Oblivion can end up reading past the end of the file and displaying whatever nonsense it finds there.
Patches the game so that you can use forward slashes in XML prefab paths even when specifying files within a BSA. (BSA files exclusively use backslashes, so forward slashes actually count as different paths and yield missing-file errors.)
Patches the game so that run-time changes to an image tile's "zoom" trait count as changing its size. In vanilla, if an image's zoom changed after the image has been rendered (due to operators using data that changes while a menu is open), the tile would not be redrawn and the change would not take effect.
The in-game debug console has been patched. Entered lines that begin with "!xxn " will be handled differently, allowing me to create convenient debugging commands for use at run-time.
The game's camera inertia has been patched. In vanilla Oblivion, entering or exiting a building can sometimes cause the camera to swerve wildly, almost as if it's trying to show off the area you're walking into (and doing a very bad job of it). This is in fact a bug in the camera inertia: interior spaces are essentially pocket dimensions and can use their own coordinate systems, and load doors are teleporters. If the "outside" door has a very different alignment from the "inside" door, then the camera inertia system interprets your walking through the doors as your rotating a significant distance in a single frame, and in the vanilla game, it tries to animate the camera accordingly. NorthernUI's fix (which can be turned off if desired) forces the camera inertia to reset when you change spaces (from a worldspace to an interior, or vice versa, or from one interior to another).
Though this has no effect on the game’s actual functioning, several MenuQue patch sites are detected and “cleaned up” if MenuQue has patched them, making them easier to view in a disassembler. Specifically, vanilla opcodes that are “split in half” by MenuQue patches and skipped during execution will have the skipped, broken halves overwritten with NOPs. (NorthernUI generally also does this for its own patches.)
XInput
XInput is loaded from the user's system and used as the API for gamepad controls.
Gamepad input is sent to the menus by virtue of the existing traits for that purpose, e.g. xbuttonlb.
The xbuttonstart trait is not enabled. Code analysis and testing both indicate that even if a menu has an xbuttonstart handler, firing that handler won’t stop the game from opening the PauseMenu. No vanilla content ever used xbuttonstart, so there’s no reason to believe this would’ve been different in the Xbox version of the game; accordingly, the trait was considered an acceptable loss when addressing an input bug.
Supports LockPickMenu by allowing the joystick to control the menu cursor while that menu is open. This is a notably imperfect solution with poor responsiveness.
Re-enables the gamepad-specific cursor on the MapMenu. This is conditional on a trait on the root tile.
Supports PersuadeMenu by teleporting the cursor to the right minigame quadrant when the joystick or D-Pad are used. This is conditional on a trait on the root tile.
Camera and movement code is patched extensively both to enable gamepad controls, and to enable 360-degree movement and multiple third-person camera modes.
Menus
AlchemyMenu
The root tile can use traits user16 through user20 to receive data from the RepairMenu and MagicPopupMenu when an item is being selected. Traits are updated on every frame.
- The user16 trait indicates that the DLL’s frame hook is running.
- The user17 trait indicates that the RepairMenu is open.
- The user18 trait is copied from the RepairMenu if it’s open, or set to zero otherwise.
- The user19 trait indicates that the RepairMenu is open and the MagicPopupMenu is visible.
- The user20 trait is copied from the MagicPopupMenu if user19 is &true;, or set to zero otherwise.
AudioMenu
Clicking the “Reset Defaults” button now pops a confirmation box before proceeding. The confirmation box’s text is determined by NorthernUI’s L10n file.
ContainerMenu
List items’ user24 trait is set to the item’s raw form type.
NorthernUI can skip showing the confirmation prompt on bartering based on a user's settings, stored in NorthernUI.ini.
DialogMenu
Tile ID 9001 forwards any clicks it receives to Tile ID 8 (the "barter" button).
The user24 trait is the width of the widest dialogue topic in the menu, including topics that are scrolled out of view. This is checked every time the topic list is rebuilt.
EffectSettingMenu
The user22 trait indicates whether the SkillsMenu is open.
The user23 trait is the current magicka/soul cost for the spell or enchantment under construction.
The user24 trait is the maximum possible magicka/soul cost for the spell or enchantment under construction. If there is no limit, then the trait is never changed from the XML-specified value. The user23 and user24 traits together express the same ratio that the vanilla game stringifies into user1, but the patched traits are numbers and can be compared, among other things.
EnchantmentMenu
The user24 trait indicates whether the RepairMenu is open.
GameplayMenu
Fixed a bug wherein the menu would tamper with the alpha trait on its exit button for no reason.
Clicking the “Reset Defaults” button now pops a confirmation box before proceeding. The confirmation box’s text is determined by NorthernUI’s L10n file.
HUDInfoMenu
Root tile's user15 trait is set to &true; if the player is holding Block while aiming at something hostile to the player.
Root tile's user16 trait is set to &true; if the player is aiming at something that cannot be interacted with (e.g. an NPC in combat with someone other than the player).
Root tile's user17 trait is set to the DXScanCode of the keyboard/mouse key mapped to Activate.
Root tile's user18 trait is set to the DXScanCode of the gamepad button mapped to Activate.
Root tile’s user19 trait receives the numeric form type of the reference the player is aiming at.
Root tile’s user20 trait is set to &true; if activating that reference would be a crime, or &false; otherwise.
Root tile’s user21 trait is set to the same value as HUDReticle’s Tile ID 1 user5. Note that the HUDInfoMenu traits are only modified when the player aims at a reference that can be activated; when the player first loads into the game, all traits have their XML-specified values.
Root tile’s user22 trait is set to the result of a GetOpenState query on the reference the player is aiming at.
Root tile’s user23 trait is a bitmask. Flag 1 indicates that the reference is an empty container and is not a living actor. Flag 2 indicates that the reference is a dead Actor.
HUDMainMenu
Tile ID #5 (the weapon icon) now receives the weapon’s remaining enchantment charge (as a percentage) and uses in user20 and user21. This can be used to show a charge meter. Authors are recommended to force such a meter’s value to zero if the number of uses is zero; it’s possible for a weapon to have a non-zero charge value that isn’t large enough to actually use the enchantment.
HUDReticle
If the tile with ID #1 sets its user20 trait to &false;, then the reticle will not be hidden in third-person view.
The sneak meter (tile ID #3) now has finer-grained information on detection stats:
- The vanilla game animates the sneak meter between four different alpha values, one per distinct detection state. The values for all four detection states (lost, unseen, noticed, and seen) can be controlled with the user22 through user25 traits.
- The user20 trait is a Boolean indicating whether the player is in sneak mode.
- The user19 trait estimates the animation percentage for the vanilla user8 trait.
- The user21 trait is the value toward which the vanilla user8 trait is animating.
InventoryMenu
List items’ user24 trait is set to the item’s raw form type.
LockPickMenu
When this menu is open, NorthernUI hardcodes directional keyboard navigation (up, down, left, and right) to operation of the lockpicking minigame. This allows the user to move the lockpick using the gamepad or arrow keys.
NorthernUI patches this menu to disable vanilla hardcoded gamepad button mappings (which in some cases were improperly coded anyway).
NorthernUI patches this menu so that clicks to any tile with ID 9001 count as clicks in the lockpicking minigame. This can be used to map a gamepad button to the "try to fix a tumbler in place" action.
MagicPopupMenu
The value in trait user20 will be copied to the AlchemyMenu on every frame while the RepairMenu is open and the MagicPopupMenu is visible, contingent on the settings AlchemyMenu specifies in its patched traits.
MapMenu
Render resolution for the local map is increased from 256px per cell to 1024px. The resolution is determined by an INI setting.
Root tile’s user20 trait can be used to alter quest selection behavior so that selecting a new active quest does not punt the user into the Active Quest tab. As of this writing, this is the trait’s only functionality; it is not useful, it may break the viewing of a completed quest’s stages, and it is subject to change or be removed later on.
Tile ID 13 is the list pane for quests and quest objectives. NorthernUI sets its user20 trait to the Y-coordinate of the last list item plus that list item’s height. This makes it possible to add spacing between list items, if desired, and still have proper scrollbar behavior: just supply user20 to the scrollbar’s user2 trait, instead of the list pane’s height.
Tile ID 47’s user24 trait can be set to &false; to disable the local map’s background image even if the bLocalMapShader INI setting is enabled.
Tile ID 47’s user25 trait can be set to the file path of a background image that should be used instead of the normal local map background image.
If the root tile’s user21 trait is set to true, then gamepad input is sent to the maps. The user can move a second cursor and pan the maps using the left stick, and activate map markers using the A button.
Tile ID 9001 forcibly redraws the currently-displayed map. Run-time changes to the world map's "zoom" trait will be accounted for.
MessageMenu
On every frame, a patch will check whether the message's text has changed. If so, a few functions will be called under the hood to force updates to certain UI controls. This addresses issues with OBSE improperly updating message text during the OpenTextInput command, with this improper update only causing problems in a (NorthernUI-critical) edge case.
NegotiateMenu
Tile ID 9001 forwards any clicks it receives to the "OK" button.
OptionsMenu
Clicking a tile with ID 9001 opens the new XXNOptionsMenu.
Clicking a tile with ID 9002 opens the new XXNControlsMenu.
PersuadeMenu
If the root tile’s user24 trait is stet to true, then directional keyboard navigation inputs (xup, etc.) are intercepted during the minigame and used to teleport the cursor to the relevant quadrant, allowing minigame play with the gamepad.
RaceSexMenu
Instances of the race_template_button template now receive a user24 bool indicating whether their vanilla user2 values are not whitespace.
RepairMenu
The value in trait user18 will be copied to the AlchemyMenu on every frame while the RepairMenu is open and visible, contingent on the settings AlchemyMenu specifies in its patched traits.
SigilStoneMenu
The user24 trait indicates whether the RepairMenu is open.
StatsMenu
The root tile's user24 trait is the listindex of the last misc-stat tile to be generated. This is intended to fix issues with the misc stats scrollbar: scrollbars normally work by checking a list pane's childcount, but the misc-stat pane adds empty space between lines by offsetting them downward (not by adding actual blank line tiles), so a scrollbar relying on childcount would render the last few rows inaccessible.
VideoMenu
Clicking the “Reset Defaults” button now pops a confirmation box before proceeding. The confirmation box’s text is determined by NorthernUI’s L10n file.