Skip to content
Felucca Online

Docs

The player's interface

Decision #130. Everything a player sees over the world: the HUD, the windows, the world map. All of it uses one toolkit, crates/uo-client/src/ui_kit.rs, in the #59 design system (docs/ui-concepts/README.md). That means smoked glass, brass hairlines and corner brackets, a rune box and spaced capitals in each title, dense tables with right-aligned numbers, and colour only as signal.

Code: crates/uo-client/src/player_ui/ (the HUD panels, journal, skills, map, help, context menus, layout), character_ui.rs (paperdoll, status, stats), online/econ/ (containers, market, crafting) and hud.rs (the HUD model, the journal history, the bars and names over mobiles).

The HUD

PartWhereWhat
Top bartop, full widthwhere you stand (town and realm, the sanctuary, open country), ping, how many are near, coin, load, hunger, the route (to Skartor: 812 t, 3m 23s north-west), game time and wall clock
Icon railleft edgeone rune per window: C character, I backpack, U skills, J journal, M map, K crafting, B market, V overview, O settings, ? keys. Lit when open; hovering names it and its key
Targettop centrethe hovered or selected mobile: an illuminated initial in its standing's colour, name, kind, standing, distance, hits and poise bars, its states with their timers and its crit counter (§ 16: counters are open to all), Attack, Clear. Offline in a battle it sits under the tempo timeline
Minimaptop rightthe atlas around you, turned like the camera (screen up is north-west, as UO's radar); towns, pins, the route, N; z zooms
Overviewright, under the minimapwho is within 24 tiles: name, distance, hits %, state icons. Tabs all / hostile / players / creatures; click a header to sort (again: reverse); click a row to select, double-click to attack; the row's tooltip names kind and standing
Vitals gaugebottom lefta segmented ring: hits on the left (red), mana on the right (blue), stamina inside (amber); the stance (run, fight, ghost) and speed in the middle; the numbers in its corners. Your own states, stances, charges and marks sit beside it with their timers
Action barbottom centrethe build system's keys (below)
Journaltop leftthe combat log of the concept; see below

Health bars and names over mobiles, floating combat text and the outcome banner stay as they were. The offline battle's tempo timeline sits under the top bar.

The combat HUD of the build system

Decisions #147–#150, concept docs/ui-concepts/v3-combat-hud.png (#161). One model, player_ui/buildview.rs::BuildHud, filled by the offline battle (combat/hud.rs) and online (online/hud.rs) from the rules' own state (the battle's, or the server's EntityState: cooldowns as ready times, counters, states, and LiveView with the states' end times, worn triggers' counts, stances, charges, marks and the Tome's spell); player_ui/bar.rs draws it.

  • Action bar Q W E | R D F | 7 Z X (Classic keys: 1–6): the icon sheets of #151 at x3, so the slot frames read (Q steel, W copper, E gold, R/D/F pewter). A cooling key is shaded by a clock sweep with the seconds left; its cost sits in the corner, red with a greyed icon when you can't pay it; a key the school level hasn't opened shows "Lv n" over its locked ability; an empowered key (momentum 3, from school level 7) or an Execute on a broken target glows gold. 7 is the Tome's spare spell, shown only with a Tome worn; Z the heal potion with how many are left, X hold; the old spellbook's spells follow. Click a key as you'd press it; the tooltip says what the ability does, its tags, shape, cost, AP, wind-up, cooldown and the rune in its socket.
  • Counter pips above it: CRIT and BLOCK (as many pips as hits it takes at your chance; no dice, at 100 % it happens), each worn clothing piece or jewel that fires every Nth time (its short name: STORMS, ECHO), MOMENTUM as diamonds.
  • Over the world: state icons under mobiles' hit bars, and the reaction word (SHATTER, ELECTROCUTE) over whoever a reaction struck.

The loadout window

Opens with the character window (C), or alone from the rail (L). Everything a build is made of (player_ui/loadout.rs):

  • the 20 slots grouped as docs/builds.md § 5 (weapon, off-hand, armour, clothing, jewellery), each with its icon (a weapon shows its own E) and the item's tooltip;
  • the weapon family's Q and W pools as icon cards: the picked one gold, locked ones dark with their level; a click sends SetLoadout (out of a fight only, the server checks too); then E (the item's) and R, D, F (the armour designs');
  • passives of the school (one, two from level 7; a new pick pushes out the oldest);
  • the armour profile: pieces per class as pips, set bonuses lit at 3 and 6, total weight and what it costs escapes (2 % slower per point, Light Step takes 25 % off, one tile shorter from 20);
  • runes: the weapon's sockets with their runes (x takes one out: it is destroyed) and the runes in the pack to socket;
  • the buckets with their icons and totals (class, speed, tags, crit "x1.75 every 4th hit", triggers, synergy, keystone, armour, hits, sustain, toughness);
  • five templates: save the build you wear, load it out of a fight (sets the loadout and puts on its gear that you carry). They live in the character's layout file;
  • build codes: "copy mine" puts FO1-… on the clipboard (base64url of append-only ids: Q and W, passives, every worn piece with tier, design, affixes and runes); paste one and "read" lists line by line what you have and what you'd need, "take its loadout" sets it.

Every item tooltip also speaks the build (player_ui/tips.rs): tier and material; for a weapon its family, its E and the Q/W pools, sockets and runes; for armour the class numbers per piece this tier and next, the set bonuses, the D/R/F ability or the affix; for clothing and jewels the event, how often, the ICD and this tier's and the next tier's number; keystones' gain and price; runes, off-hands, belts, cloak auras, surcoat drills and consumables.

Windows

Every window drags by its title bar, closes with its x or with Esc (newest first; Esc disarms an armed spell before anything else, and quits only when nothing is open and you are not in a fight).

Windows stack by when they were last opened or clicked: that one is drawn on top (#137). All ui_kit windows share GlobalZIndex(10); their rank in WindowPlaces' order is their ZIndex, set when a window is built and kept by ui_kit::stack_windows (PostUpdate), so a window its owner rebuilds from data (the economy rebuilds the containers, market and crafting every second) keeps its place instead of jumping above the others. The order is saved in the layout.

Text fields (ui_kit::text_input): a click gives a field the keyboard, and while it has it the game sees no keys. Cmd + V / C / X (Ctrl off macOS) paste, copy and cut with the system clipboard (a password field never copies out), Cmd + Backspace clears, Tab / Shift + Tab move to the next / previous field of the same window in reading order (a lone field lets go), Enter presses the form's ui_kit::submit_button (its gold main button, listing the fields it submits) or, without one, hands the line to the field's owner (TextInputs::take_submitted: chat, journal); Esc lets go.

  • Character (C): the paperdoll is two columns of slot boxes, UO's layers, around the figure (initial in the standing's colour, name, title, standing, weapon, armour). Drag gear from the backpack onto the window to wear it, drag a worn piece into a bag to take it off, out onto the world to drop it. Double-click takes off, right-click opens the menu, hovering shows the tooltip. The status column shows standing (with its timer), hits, mana, stamina, satiety, load, coin, task, town and work patents with their time left. The stats column shows base and effective Str/Dex/Int, the maxima and the best six skills.
  • Skills (U): every skill by category (collapsible), or by value; base, effective (green above base, red below), cap, patent mark (P held, - needed), lock. Clicking the lock cycles up, down, locked. The server command is the progression work's (#125) and goes into player_ui/skills.rs::lock_command when it lands; until then the journal says locks can't change yet.
  • Journal (J): every line of the session (2000 kept) with the local time. Tabs: all, system, combat, speech, and the chat channels (party, guild, trade, npc) once something was said there. In "all" the combat and system chips hide those channels (kept in the layout). The line at the bottom speaks (Command::Say); online, Enter in the game focuses it. Other modules write lines with GameLog::say (system), combat, speech and channel(Channel::…).
  • Map (M): see below.
  • Keys (/ or ?): every binding by group, buttons to open each window.
  • Settings (O): interface (UI scale 75–200 %, minimap on/off, tactical grid, keys: Albion or Classic) and the graphics settings of #67, now in the toolkit's style.
  • Backpack (I), bags, corpses, market (B), crafting (K): the economy's windows (#121), unchanged apart from tooltips and drops. Container windows (backpack, bags, corpses, chests) draw their gump floating above the framed list with nothing behind it (ui_kit::window_over, #137); dragging the gump's empty parts moves the window.

Items

Wherever an item shows (gump, list row, paperdoll), hovering it gives the tooltip. It shows the name and amount, weight, quality, damage with AP and reach or range, the skill, armour, slot and two-handedness, requirements, food, the tool's skill, durability (amber below a quarter, red when broken), uses left, material, maker, every magic property in words ("+10 strength", "+15% weapon damage") and the stolen taint with its time left. Market and recipe rows can carry container::ItemTip(item_id) for the catalog version.

Right-click opens the item's menu: open, eat, wield/wear, take off, move to the backpack, drop on the ground; from a corpse: take, take everything. Stolen goods say how to get rid of them instead of offering a drop.

Dropping (drag out of every window onto the world, or the menu) sends Command::Drop { uid, at }. The server puts the item, with what it holds, in a pile on the tile you let it go over when that is free ground within two tiles (#134; the menu and anything farther: at your feet), or into a pile already lying there: a runtime object with the backpack_abandoned sprite, looted like a corpse by anyone and without crime, rotting after 10 minutes, and the journal says where it went. Worn items come off with it; the backpack and stolen goods stay. A corpse window the server refused to open says why ("That is too far away.") instead of waiting.

The world map

The chart is the bake's atlas pictures: overview.png (1 px = 16 tiles) zoomed out, atlas-4.png (1 px = 4) closer. Over them it draws:

  • Towns by tier, coloured by realm (Karrak red, Aelwyn green, the March amber, the free port gold, the isles teal, the wilds grey), labelled as the zoom allows. Click one to route there.
  • The sanctuary of Aquais as a gold ring. The guarded highways are already in the picture (gold edges).
  • Realms: province names in the realm colours (realms chip), with a legend.
  • Places of interest you have found, dungeons in violet.
  • Pins: right-click the map; listed in the sidebar (click to centre, x to remove).
  • You, and the route.

Wheel zooms around the pointer, dragging pans, me centres on you, the footer names the tile under the pointer and the nearest town.

Fog of war (decision #130): the colonial company hands every colonist its survey. Coasts, terrain, roads and every town are known from the start, because a trade run needs them and a blank map would only hide the economy. Dungeons and other places of interest show once you come within 48 tiles of them. Each character keeps this in its layout. Exploring finds the dangerous and rewarding places; it never finds the road to market.

Routes follow the road network. The bake writes roads.json next to world.json: every road's node points before smoothing, so roads meeting in a macro cell share a point and the graph joins there. For an existing bake, uo-atlas --roads-only assets/world/felucca writes just that file (about 45 s, same seed and size as the bake). Without it the map routes along the guarded highways and straight legs and warns once. The route is the cheapest way: road tiles cost 1 (roads 1.05, tracks 1.15), off-road legs onto and off the network cost 3 (wild ground, water and danger make cross-country slow). It shows its length in tiles and the running time out of a fight (250 ms a tile, #92), and the time in a fight (twice that). The route is replanned when you stray from it. The top bar and the minimap follow it.

Layout per character

player_ui/layout.rs keeps one JSON file per character in ui/ next to the settings file (~/Library/Application Support/UO Remastered/ui/<name>.json on macOS). It holds where every fixed window was dragged, which windows are open (journal, overview, skills, map, character, backpack), the journal's hidden channels, the overview's sort and tab, and the map's pins, route and discovered places, and the windows' stacking order. It loads once the character's sheet names it. Windows from a bigger screen move back onto this one. It is written a second after the last change (write, then rename). Reproducible runs (--screenshot, --headless) keep no layout unless UO_UI_LAYOUT=<dir> names one.

Keys

KeyDoes
C, I, U, J, M, K, B, Ocharacter, backpack, skills, journal, map, crafting, market, settings
/keys and mouse
Escdisarm the spell, else close the newest window, else quit (never in a fight)
Enteronline: speak (the journal's say line)
Q W E R D Fthe six ability keys (Classic preset: 1–6; setting keys)
7, Z, X, G, Space, Tabthe Tome's spell, potion, hold, guard (held), dodge, next target
1–6the old spellbook's spells (Albion preset)
right mouse, arrowsrun (arrows in screen directions, in every preset); WASD too in the Classic preset; H roofs. The arrows pan the camera only in galleries and reviews, where there is no character
F7GI debug views (offline, or with UO_DEV_KEYS=1; never on I)

The development keys (T pause time, , . scrub it, N night, L cursor light, [ ] - = the sun, F7 GI views) work offline and with UO_DEV_KEYS=1, never in a player's online game.

Captures and tests

  • UO_UI_OPEN=journal,skills,map,help,character,backpack,… opens windows at start; UO_UI_HOVER=x,y shows the tooltip of the item at that point; UO_ROADS=<file> reads a road network made apart; --set ui_scale=1.25.
  • Over the live client: cargo run --release -p uo-server -- --world assets/world/felucca --listen 127.0.0.1:7788, then uo-client --server ws://127.0.0.1:7788 --name Tester --headless --screenshot out.png --seconds 25 with the variables above. The screenshots in the post were made this way.
  • Unit tests: layout files round trip, broken and newer files fall back, windows move onto smaller screens, and a running app saves a moved window and an open one and restores both in the next run (player_ui::tests::layout_persists_across_runs). There are also tests for the overview's sort and filter, journal tabs, skill locks, context menus, routing (junctions merge, short hops go straight), times, compass words and the minimap's turn.