Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Wire a hotbar for combat

One-click attacks, stances, and spell prep — on buttons that dim, recolor, and count down as the fight changes.

What you’ll build

A row of combat buttons that isn’t just a row of buttons. Attack dims itself while roundtime is running and shows the seconds left. Hide goes green and reads “Hidden” once you’re in the shadows. Your 909 dims the moment you can’t afford it, and swaps to a different command while a cast is in flight. Every button also takes a hotkey, so the bar doubles as a set of bindings you can read.

📷 screenshot pending
The combat bar mid-fight: Attack dimmed with "3s" counting down, Hide green and reading "Hidden", 909 dimmed for lack of mana.

Before you start

  • Condition states are authored in the Desktop GUI. The TUI hotbar editor builds bars, buttons, hotkeys, and countdowns, but shows states as a count and leaves them untouched — it renders them faithfully, it just doesn’t edit them. The Mobile tab explains what the phone offers instead.
  • Know the bar-to-window rule before you start: a hotkeybar window displays the bar with the same name as the window. Name them to match or nothing appears.

Steps

1 — Place the bar’s window. Type .addwindow combat hotkeybar 0 0 40 3 in the command input. This creates a hotkeybar window named combat, which will display the bar named combat.

2 — Create the bar. Open the Editors hub in the toolbar and click Hotbars (or type .hotbars). Add a bar named combat and set Title: to Combat. Leave Global (all characters) ticked, or untick it to give this character its own bar. The bar list tags each bar [G] for global and [C] for character so you always know which you’re editing.

3 — Add an attack button that dims during roundtime. Click Add button and set Label to Attack, Command to attack, and Hotkey to f1 — or click Capture, which reads “Press a key…” while it waits, and press the key itself. If the key is already spoken for you’ll see “Key is already bound by … - it wins over this button.”; pick another.

Set Countdown overlay to Roundtime so the button shows the seconds left.

Now scroll to States, note the reminder beside it — (first matching state styles the button) — and click Add state. A new state arrives already set to Roundtime active with dim ticked, which is exactly this rule. Click Save bar.

4 — Add a Hide button that reports being hidden. Click Add button: Label Hide, Command hide, Hotkey alt+h, Tooltip Attempt to hide. Add a state, and on its condition row open the kind combo and choose Indicator; set the id to hidden and leave active ticked. Under Style while active:, set Label to Hidden and the foreground to #80ff80. A state’s style can replace the button’s text, so the button tells you your own state rather than offering an action you’re already in.

Add a second state below it for Roundtime active with dim ticked. Order matters: hidden sits above roundtime, so being hidden wins over being in roundtime. Click Save bar.

5 — Add a spell button that knows what you can afford. Click Add button: Label 909, Command incant 909. Set Countdown overlay to Casttime.

Add a state and choose Vital on its condition row: vital mana, comparison <, value 9, unit combo set to abs — absolute points, not percent, because a spell’s cost is a number of mana and not a fraction of your pool. Tick dim under Style while active:.

6 — Give that button a different command while casting. On a state’s card, fill in Command while active: — the field hinting (button command). Whatever you type there is sent instead of the button’s own command while that state matches. This is literal text; anything dynamic belongs inside the command, such as a ;eq … line that Lich evaluates. Click Save bar.

7 — Watch it before you commit. The Preview: row above the button list renders the bar live against your current game state, using the same resolution the real widget uses. Step into roundtime and watch the preview change. If the preview is wrong, the bar will be wrong.

Expected result: a Combat bar on screen. F1 attacks and the Attack button dims with a countdown while roundtime runs. Alt+H hides, and the button turns green reading Hidden once you are. The 909 button dims whenever you’re under 9 mana.

What the states look like on disk

You never need this file — the editor writes it — but three lines of it explain the ordering rule better than a paragraph can. Here is the Hide button from step 4:

[[bars.buttons.states]]                            # checked FIRST
[bars.buttons.states.when]
type = "indicator"
id = "hidden"
active = true
[bars.buttons.states.style]
label = "Hidden"
fg = "#80ff80"

[[bars.buttons.states]]                            # checked only if the above missed
[bars.buttons.states.when]
type = "rt_active"
[bars.buttons.states.style]
dim = true

States are checked top to bottom and the first match wins — the second block never runs while you’re hidden. Swap the two blocks and a hidden character in roundtime shows a dim “Hide” instead of a green “Hidden”. In the editor the ^ and v buttons on each state card are this same ordering; the file just makes it visible. Editors build one level of all of / any of nesting; deeper trees are file-authored, render as (nested group - edit in hotbars.toml), and still evaluate correctly.

Make it yours

A melee bar that reads your hands. Choose Hand holds on a condition row and set the hand to Right with item type weapon to light your attack button only when you’re actually armed. Pair it with a Hand empty state carrying a Command while active: of get my weapon, and one button both draws and swings depending on what you’re holding.

A caster bar that grays out what you can’t cast. Instead of writing a mana threshold per spell, use Spell affordable with the spell’s number. It reads the bundled spell table’s static costs against your current mana and fails closed — unknown numbers and formula-cost spells evaluate false — so a button grays out rather than lying to you.

A stance bar built from indicators. Give each stance button an Indicator state on standing, kneeling, sitting, or prone, styled bright, so the bar always shows your current posture as the one lit button. The same eleven ids — standing, kneeling, sitting, prone, stunned, bleeding, hidden, invisible, webbed, joined, dead — are available in every condition builder in the product.

When it doesn’t work

The window is there but empty. The window name and the bar name must match exactly — a hotkeybar window displays the bar of the same name, and there is no bar-picker in the window’s right-click menu (only Edit hotbars…, which opens this editor). Rename one to match the other.

The wrong state keeps winning. The first matching state wins, so a broad condition placed above a narrow one swallows it. Put “hidden” above “roundtime”, and “health < 25%” above “health < 50%”. Reorder with each card’s ^ and v, then Save bar.

The hotkey does nothing. Existing keybinds.toml bindings beat hotbar buttons. The editor warns you at the time — “Key is already bound by … - it wins over this button.” — and the button list marks the row (key conflict). Pick a free key, or rebind the keybind.

A duplicated button’s hotkey is gone. That’s deliberate: duplicating a key would guarantee a conflict, so Dup clears the copy’s hotkey. Give the copy its own.

The button shows text where you wanted art. Icons are GUI-only — the TUI always renders the label. In the GUI, check Face is set to Icon or Icon + label and that the bar’s Icon px is large enough to see; the default is 24, and barbar-style art reads best between 32 and 64.

Your global bar stopped responding to edits. A per-character bar with the same name replaces the global bar wholesale — it does not merge button by button. The bar list’s [G] / [C] badges tell you which copy exists; edit the [C] one, or delete it to fall back to global.

The state’s command override isn’t doing anything clever. Command while active: is literal text, not an expression. Put the logic in the command itself — a ;eq … line, which Lich intercepts and evaluates — rather than expecting the field to compute anything.

Nothing saved. Save bar is disabled until there are changes and shows “unsaved changes” beside it while there are. If it’s grayed out, your edit didn’t register; click into the field and change it again.

See also