Skip to content
Felucca Online

Docs

Melee: committed blows on the timeline

Status: built (decision #145, 2026-10-25). Written from a design discussion with the user (alpha feedback: combat is dull and old-fashioned; melee needs active "strong blows"; the weapon-skill sprawl of late UO is not wanted) and then built in full. § 17 lists what the first version does and where it differs from the design below; the numbers in the tables are the code's (uo_proto::melee, uo_combat::melee).

Reads with: docs/combat.md (#68 timeline and AP, #71 cover and kegs, #93/#125 speed properties), crates/uo-combat/src/{battle,rules}.rs.


1. The problem

Melee today is UO's swing timer on a tile grid:

  • a fighter picks a target and auto-attacks; the only melee orders are Attack, Guard (4 AP of better parry), Hold, Potion;
  • hit, parry and damage are dice rolls from skills (hit_pct, parry_pct, weapon_damage);
  • the swing already has a wind-up (impact_ms = 35 % of its cost, 250–700 ms) but nothing can be done with it: it is presentation only.

A warrior makes a meaningful decision every 5–10 seconds (which target, when to drink). A viewer on a stream sees two figures trading numbers. There is no skill expression, nothing to learn, no moment to clip.

2. Goal and the line we don't cross

Goal: a melee fight is a sequence of commitments and reads. Every 1–3 seconds the player chooses: commit to a heavy blow, keep pressure with light ones, guard the enemy's telegraphed blow, step out of its arc, or punish an enemy who just over-committed. Good play is visible: parries, broken guards, executions.

What stays (the tactical identity, #68):

  • one world grid, no battle screen; positions, reach, cover, destruction;
  • AP = recovery in real time (1 AP = 250 ms), no pool, no banking, the clock never pauses;
  • the public timeline; queued orders; auto-attack as the floor;
  • click-target, no free aim: no skill-shots, no mouse-aimed swings. Targets are mobiles and tiles, as now;
  • deterministic, server-authoritative rules in uo-combat; bots use the same protocol.

What is new (the ARPG layer): readable wind-ups, active defence with timing, techniques (strong blows) that cost stamina, a break bar that opens enemies to executions, a charged state, facing, knockback into the world, and a lot of feedback.

References, for the developer's feel, not to copy: Clair Obscur: Expedition 33 (timeline plus parry/dodge windows), Octopath Traveler (break), Monster Hunter (committed heavy blows, punish windows), Albion Online (weapon defines the abilities), BG3 / DOS2 (environment as a weapon).

The rule that shapes everything: bots are players (#3)

Anything that rewards reaction speed goes to bots: a script reading Swing { impact_ms } guards perfectly every time. So:

  1. timing windows are generous (they exist for feel, not as the skill ceiling);
  2. the skill ceiling is in reads: feints, mix-ups, positioning, spending stamina and the charged state at the right moment, using the environment. LLM agents and simple scripts are weak at these, people are strong;
  3. the wire never reveals what a person couldn't see (§ 9.2: feints).

3. One melee skill

3.1 Skills

TodayProposal
Swordsmanship, Fencing, Mace Fighting, WrestlingMelee (one skill: every melee weapon and bare hands)
Tactics (damage 50–100 %)retired: folded into Melee for melee and Archery for bows
Parrying (passive parry %)Parrying: guard window, block strength, shields
Anatomy (+20 % damage)Anatomy: crits and break damage
Archeryunchanged (out of scope; must take over Tactics' damage scaling)

Why one skill is more than a simplification: today weapon identity comes from the skill, so a swordsman never touches a mace. With one Melee skill identity moves to the weapon class and its techniques, and carrying two weapons and swapping (mace for skeletons, blade for wolves) becomes a real decision. That is where Albion found its depth.

A pure fighter now needs Melee + Parrying + Anatomy (+ Healing): about 30–40 of the 70 levels (#139), leaving room for a trade. That fits "you become what you do" (#125).

3.2 Melee levels unlock techniques

Levels as in #139 (1 level = 10.0 points). Melee unlocks; Parrying and Anatomy scale.

Melee levelUnlocks
1light blow (auto), guard, dodge
2the weapon class's first technique
4the class's second technique
5Execute on broken enemies
7empowered techniques (§ 6)
10the class's mastery passive (§ 5.3)

A visible unlock every one or two levels in the first hours of play is the progression hook.

3.3 No migration (user directive)

The five old skills are removed from the catalog, not retired: "we have no backward compatibility to keep". Skill::Melee took Swordsmanship's free id 40; Mace Fighting (41), Fencing (42), Wrestling (43) and Tactics (27) are gone, so skill ids now have gaps (Skill::index() is the position in Skill::ALL, Skill::from_id searches). A saved sheet that still names an old skill loads with that skill dropped (Skills skips unknown keys): no migration, no failed load; wiping between alpha waves (#128) starts everyone clean anyway.

  • WeaponDef gains class: WeaponClass; ItemDef::weapon(class, …) sets skill to Archery for bows and Melee for everything else.
  • Creation (NewCharacter, the six callings, the client's presets) and starter kits use Melee, Parrying and Anatomy; the Melee kit is a katana and a leather tunic.

4. Anatomy of an action

Every melee action already has a wind-up, an impact and a recovery. The proposal makes the three phases explicit and gives each one rules.

 order    wind-up (telegraph)    impact   recovery                     ready
   |==========================>|  *  |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
   committed: no reactions        hit   reactions allowed with a tax
  • Wind-up: shown on the timeline, on the actor's model and, for techniques, as red tiles on the ground that fill up until the impact. A technique's wind-up is committed: no guard, no dodge, and a hit during it is a counter hit (§ 9.1). A plain swing's wind-up is not: a guard or a dodge gives the swing up (built that way because auto-attack keeps a fighter in a wind-up a third of the time, and refused reactions felt broken).
  • Impact: resolved as now (land_blow), plus the guard, facing and break checks below.
  • Recovery: the rest of the cost. Reactions (guard, dodge) may be used during it, but they push ready_at back (§ 6.3). Heavy weapons thus commit longer, and light ones stay nimble.

Today's impact_ms = 35 % of cost, clamped 250–700 stays for light blows. Techniques define their own wind-up (§ 5).


5. Weapon classes and techniques

5.1 Classes

WeaponDef gains class: WeaponClass and damage_type: Slash | Pierce | Crush. Every catalog weapon gets one:

ClassWeapons (catalog)DamageFeel
Bladelongsword, broadsword, katana, scimitarslashall-round, closes gaps
Pointdagger, kryss, short spear (reach 2: spear)piercefast, armour-piercing, feints
Bluntmace, war hammer, club, quarterstaffcrushslow, breaks guards and walls
Polearmhalberd, bardicheslashreach 2, areas, pulls
Fistsnonecrushshoves, the fallback

Off-hand shield adds its own technique (Shield Bash) and better blocks.

5.2 Techniques

Two per class (unlocked at Melee 2 and 4), on keys 1 and 2 when a melee weapon is in hand (spells move to the spellbook bar when the hands hold one; mixed builds get a bar switch, open question). All numbers are starting values for the balance tools, not tuned.

ClassTechniqueWind-upTotal APStaminaEffectTelegraph shape
BladeCleave750 ms9101.6× damage to the target and both front diagonals of it; poise 15 eacharc of 3
BladeLunge500 ms812dash up to 2 tiles to the target (needs a free path), strike 1.5×; answers kitingline
PointPuncture400 ms581.3×, ignores half the armour, bleed 3 × 4 dmg over 3 ssingle
PointFeintshown 750, real 35048telegraphs like a heavy blow, strikes early (§ 9.2) for 1.3×; a guard pressed for the shown impact missessingle
BluntCrushing Blow1000 ms10121.9×, poise 45, a block against it only halves the damage; 3 hits to an obstaclesingle
BluntConcussion750 ms8101.2×, knockback 1 tile (§ 8), interrupts a cast, poise 25single + arrow
PolearmSweep1000 ms12121.3× to every enemy within 1 tile around and the targetring
PolearmHook500 ms880.8×, pulls the target 1 tile towards you (out of cover, off a doorway), drops its guardline
FistsShove350 ms45knockback 1, 0.5×single + arrow
ShieldShield Bash250 ms48interrupts a wind-up or a cast, poise 20, 0.4×single

Rules:

  • A technique replaces one auto blow; auto-attack resumes after it.
  • Can be queued during recovery like any order (#68).
  • Out of stamina: techniques and dodge are refused ("Exhausted"), light blows keep going (slower, as today's stamina factor).
  • Later, magic items can swap a technique ("Longsword of the Lunge"): ties into #93's property loot.

5.3 Masteries (Melee 10)

One passive per class, felt not computed: Blade: Lunge refunds its stamina on a kill. Point: bleeding targets take +15 % from your blows. Blunt: Crushing Blow breaks a shield block fully. Polearm: Sweep's arc reaches 2. Fists: Shove on a broken target throws it 2 tiles.


6. Resources: stamina and momentum

6.1 Stamina is the melee resource

Stamina exists (max_stam from Dex; low stamina slows swings) but nothing spends it. It becomes the fighter's mana:

  • techniques 5–12 (stamina is Dex, as in UO, so a new colonist has 10–45), dodge 10, a block costs blocked damage / 2, a perfect guard refunds 5;
  • regeneration 6 % of max per second (at least 2) after 1.5 s without spending;
  • the bar is on the vitals ring (#130) and flashes when a technique can't be afforded.

6.2 Momentum is the charged state

0–5 pips per fighter, shown as a ring of embers around the stance in the HUD and a glint on the weapon in the world.

  • +1: perfect guard, counter hit, a technique that lands; +2: a kill; +1 per three light blows landed in a row.
  • Decays one pip per 4 s without hitting or being hit.
  • At 3+ pips the next technique is empowered and consumes 3: +50 % damage and poise, and it can't be perfect-guarded (only blocked or dodged). No extra button: the player sees the glow and decides when to spend it.

This is the pay-off loop: defend well → charge up → land a big empowered blow → break → execute.

6.3 Reactions during recovery

Guard and dodge may be used while recovering. They act at once and set

ready_at = max(ready_at, now + own cost) + REACTION_TAX (1 AP) when used during recovery.

So a halberdier who swung and missed can still dodge, but loses another quarter-second. A dagger user, recovering 1 s per blow, barely notices.


7. Defence: guard, perfect guard, dodge, facing

7.1 Guard

Guard becomes a held stance (hold E; Guard { on: bool } on the wire), not a 4-AP action:

  • while held: auto-attack pauses, each step costs 3 AP, and every blow from the front is blocked: damage × (1 − block %). Block is 40 % with a weapon, 60 % with a buckler and 75 % with a heater shield at Parrying 0; +15 percentage points at Parrying 10. Each block costs stamina;
  • a guard broken by stamina (0 left) staggers for 1 s.

7.2 Perfect guard

A press of guard (the edge, not holding) within W ms before the impact of a blow aimed at you:

  • the blow does nothing;
  • the attacker is staggered (+600 ms on its ready_at) and takes poise 30 (light blows: no stagger, poise 10);
  • you gain 1 momentum and 5 stamina; the client plays a parry spark, a bright sound and 80 ms of hitstop.

W = 200 ms + 15 ms per Parrying level (200–350 ms). Parrying makes the window forgiving: the skill grows the player's safety net, which is the right kind of progression.

Anti-mashing: a press is eligible for a perfect guard only if the previous press was ≥ 600 ms earlier. A press that catches no blow within W + 200 ms leaves the window halved for 1 s.

Passive parry (parry_pct today) drops to Parrying / 8 with a shield and 0 without: active defence is the main defence. AI fighters perfect-guard by chance (§ 10).

7.3 Dodge

Space + a direction (or towards the cursor, as held running #91): one tile, 2 AP, 10 stamina, invulnerable for 300 ms from the press, not through blocked edges. Dodging out of a telegraphed arc avoids it fully, including empowered techniques. Used during recovery: § 6.3 tax.

7.4 Facing and flanks

Fighters already have 8 facings (#6). Rule: a fighter faces its target whenever it acts or stands within 3 tiles of it, and its walking direction while it walks (a fighter running away shows its back, whatever it targets). The server publishes the rules' facing, so a rear attack reads on screen.

  • A blow from the three rear directions relative to the defender's facing deals +30 % and can't be blocked or perfect-guarded.
  • This gives groups something to do (pin from the front, hit from behind) and gives movement a purpose in a fight.

8. Poise, break, execute, knockback

8.1 Poise and break

Every fighter has a poise bar (max_poise from Str and armour; species set their own: troll high, wolf low). Shown under the health bar of the target card and overhead.

  • Filled by technique poise values, perfect guards (30), counter hits (+50 % poise), hits to a weakness (§ 8.4), knockback into something (§ 8.3), keg blasts and falling debris.
  • Drains 10 % of max per second after 2 s without taking poise.
  • Full: Broken for 2.5 s (players 1.5 s): staggered (ready_at pushed), guard dropped, no reactions, takes +50 % damage. The client shows a "BROKEN" burst over the model, a hard hitstop and a camera nudge.
  • After a break, poise can't rise for 8 s (players: diminishing returns, § 11).

8.2 Execute

On an adjacent broken enemy, key 3 (or the target card's button) plays Execute: 500 ms wind-up the target can't answer, 3× damage, its own animation per weapon class. A kill by Execute refunds 25 stamina. This is the moment players clip.

8.3 Knockback into the world

Concussion, Shove, Hook and keg blasts move fighters a tile. Where they land matters:

Lands on / againstEffect
free tilemoved, poise as listed
wall, fence, furniture, doorstops; +10 damage, +20 poise, and the obstacle takes the knockback's hits (#66): shoving someone through a fence breaks the fence
another fighterboth staggered 500 ms
waterstays there if walkable shallows, else stopped at the bank with the wall rule
a drop (z lower by ≥ 1 unit: quays #108, stairs)falls: z drop × 8 damage, broken
a lit keg's tilenothing special; the keg is your problem now

This makes destruction (#66) a melee tool, not only a backdrop.

8.4 Damage types and weaknesses

Slash / Pierce / Crush on weapons, resistances on armour and species:

  • plate takes −25 % slash and +15 % crush, leather and studded −15 % pierce (full table in tuning);
  • species rows in uo_proto::creatures gain weak / resist (skeleton weak to crush, resists pierce; wolf and spider weak to slash; troll resists crush; treant weak to slash and fire).
  • A weakness hit shows a distinct number colour and adds +50 % poise. Players learn it, the bestiary records it: knowledge as progression.

9. Counter hits and feints

9.1 Counter hits

A blow that lands while the target is in its own wind-up of a technique is a counter hit: +50 % damage and poise, and a distinct sound. It does not interrupt (fast weapons would interrupt everything); only Shield Bash, Concussion and Break interrupt.

9.2 Feints and what the wire shows

Today Swing { impact_ms } tells every client exactly when a blow lands. With perfect guards that is a free win for scripts. So:

  • A technique's start event carries what an onlooker would see: the technique, its target, its tiles and its nominal impact time. A Feint's nominal impact is the heavy one (750 ms); its real strike comes at 350 ms with its own Hit / Missed event.
  • Clients animate the nominal wind-up; when the feint strikes early the animation snaps to the blow (that snap is the "tell" a sharp player learns to see, a few frames before the hit).
  • The defender's choices: guard early (wins against the feint, loses to the real heavy blow when the window lapses), dodge (beats both, costs stamina), or trade (hit the feinter: counter hit).

That is a real mix-up, decided by reading the opponent rather than by reflexes.


10. Monsters and NPCs

Telegraphs only matter if enemies have heavy blows. Every melee archetype gets 1–2 techniques from the same table or its own (uo_combat::beasts):

Species / archetypeTechnique
orc, bandit bruteCrushing Blow (overhead, 1 s wind-up)
orc captainCleave + Shield Bash
wolf, frost wolfPounce: Lunge with knockdown (broken 1 s on hit)
trollSweep with its arms (ring), high poise
ogre, ettinGround Slam: 1.25 s, radius 1, knockback
giant spiderWeb: a ranged root, 2 s
skeletonFeint (they are "smart" duellists), low poise
bearCrushing Blow + high poise

AI rules:

  • AI uses techniques on cooldowns per species and when the target is in the shape;
  • AI defends by chance, scaled by its Parrying: perfect guard on telegraphed blows at parry / 4 %, block otherwise; dodge out of shapes at 25 % for agile species;
  • mobs never feint the player more than once in a row (fairness).

11. PvP rules

Full loot (#121) makes losing control expensive, so:

  • players break for 1.5 s, then 8 s of break immunity;
  • any hard control (stagger, knockdown, root, pull) on a player grants 3 s of immunity to the same kind (diminishing returns), shown as an icon;
  • no technique can be used on a player who is a ghost or protected (young, #131): the law check happens before the wind-up starts, so nothing is "half done";
  • target 1-vs-1 time to kill, equal gear: 10–20 s, with the decisive moment (a break, an empowered blow) in the last 3–5 s.

12. Timeline and HUD

  • Online timeline (today only the offline battle has one, #69): a strip above the vitals with you, your target and anyone targeting you; segments: wind-up (red, technique icon), recovery (grey), ready (gold). Feints show their nominal segment.
  • Ground telegraphs: red tile decals in the technique's shape, filling up to the impact (texel-aligned, dithered fill to match #40).
  • Target card (#130): health, poise, momentum pips, stance (guarding / broken / exhausted), resist and weakness icons once the player has seen them.
  • Feedback (client only; the sim never pauses): hitstop 40 ms (light), 80 ms (technique, perfect guard), 140 ms (break, execute); white flash (#144); numbers sized by the hit's share of max health, crit and weakness colours; camera nudge on big blows; sound per class and per outcome (task audio becomes a prerequisite, see § 15).
  • Keys (amends #70/#96): Z / X the weapon's two techniques, V Execute, G Shield Bash (the spells keep 1–7, C stays the character window), E guard (held; the press may parry perfectly), Space dodge (the way WASD points, else towards the cursor), Q potion, R hold, Tab next target. The bar's slots are clickable too.

13. Protocol and rules changes (for the implementer)

Appended, no version bump, per conventions.

Commands: Technique { id, target }, Guard { on, at } (at: the client's estimate of server time when pressed, § 13.1), Dodge { dir }, SwapWeapon, Execute { target }.

Events (uo_combat::Event → CombatEvent): Telegraph { id, technique, target, tiles, impact_ms } (nominal), Blocked { by, id, damage }, PerfectGuard { by, id }, Dodged { id, from, to }, CounterHit, PoiseBroken { id, ms }, Executed { by, id }, KnockedBack { id, from, to, against }, Exhausted { id }.

State (EntityState deltas): stamina of every fighter in view (the target card shows it), poise (permille), momentum (0–5), stance (normal / guarding / broken / exhausted).

uo-combat: Fighter gains poise, momentum, guard: Option<GuardState { since, last_press }>, invuln_until, facing, cc_immunity; Profile gains class, damage_type, resist, max_poise; the order list gains the new orders; land_blow grows the facing, block/perfect, poise, counter-hit and weakness steps. Integer maths and seeded RNG as today; every rule gets a test in tests.rs.

13.1 Perfect guard over the network

The server is authoritative and players have 30–150 ms of round-trip time. The proposal:

  • the sim resolves a blow at impact + PARRY_GRACE (100 ms) instead of at impact; clients still animate the hit at impact, so nothing looks late;
  • a Guard press counts for a blow if its at stamp lies in [impact − W, impact] and the command arrived before impact + PARRY_GRACE; at is clamped to [arrival − 150 ms, arrival], so a client can't claim an early press it didn't make;
  • fixed grace keeps the battle deterministic (same inputs, same result).

14. Balance targets and tools

Extend uo-loadtest combat / duel (#127) with scripted player skill levels: autopilot (auto blows only), average (techniques on cooldown, 40 % perfect guards, no feint reads), expert (techniques on openings, 80 % perfect guards, reads 60 % of feints). Targets:

MeasureTarget
Expert vs autopilot, equal gear and skillexpert wins ≥ 85 %
Autopilot damage per second vs expert55–65 %
Meaningful decisions per 10 s for an active melee player≥ 4
Time to kill a danger-1 mob, Melee 35–10 s
Time to kill a danger-3 elite, Melee 620–40 s
1-vs-1 PvP, equal10–20 s
Share of kills that end in Execute (PvE, expert)20–35 %

The last line is the dopamine check: if executions are rare, players never see the pay-off; if they are every kill, they stop being special.


15. Plan in playable steps

Each step ends in something testers can feel; no step waits for the next.

  1. Feel without rule changes (~1 week): sounds, hitstop, damage numbers by size, online timeline, ground telegraph for today's swings. Measures whether feedback alone moves the playtest numbers.
  2. One Melee skill: WeaponClass, damage types, migration, creation and kits.
  3. Stamina and defence: guard stance, perfect guard with network grace, dodge, reaction tax, facing.
  4. Techniques: two per class + Shield Bash, telegraph shapes, knockback into the world.
  5. Break and momentum: poise, Broken, Execute, empowered techniques, weaknesses.
  6. Monsters: techniques per archetype, AI defence by chance, species weaknesses.
  7. PvP pass: diminishing returns, feints on the wire, balance runs, then a playtest wave.

Steps 1 and 3 give the biggest change in feel for the least work.

16. Decisions taken

The user answered by asking to build it, so the proposals stand: the skill is Melee, Tactics is gone (its damage scaling is now the weapon's own skill), techniques are fixed per weapon class, hybrids keep two bars (spells on 1–7, techniques on Z/X/V/G), facing and rear attacks are in, and players break (1.5 s, then 8 s without poise gain).

17. Built (first version)

Rules (crates/uo-combat): melee.rs (numbers, windows, blocks, poise, facing, area tiles), battle.rs (state on Fighter: facing, poise, broken_until, momentum, windup, guard_press, dodge_at, bleed, …; Order::Technique; the reactions Battle::guard(id, up, pressed) and Battle::dodge(id, dir) act at once; every blow resolves through strike_fighter), ai.rs (technique_for: Execute on a broken enemy, then after a cooldown of 5–7 s Shield Bash / Concussion on someone winding up or casting, Lunge from 2–3 tiles, Sweep among two or more enemies, else the first technique that reaches; only while closing in or striking, never while running), beasts.rs (melee(key): each species' class, techniques, shield and resistances as in § 10, humanoids parry by chance), tests in tests_melee.rs (24). The shared vocabulary is uo_proto::melee (WeaponClass, DamageType, Technique + TECHNIQUES, available, bar, CombatStance).

Server: Command::Technique goes through every check an attack does (sanctuary, crown's protection, guards, the law); RaiseGuard { up, at } maps the client's stamp (server game ms) to battle time; Dodge { dir }. EntityState carries stam, max_stam, poise (permille), momentum, stance, and a fighter's facing is the rules' own. Melee trains on every swing, Anatomy on hits, Parrying on blocks and perfect guards (more), not on passive rolls any more.

Client: combat/melee_fx.rs (words over the struck by hit flags, hitstop by slowing Time<Virtual> for 40–140 ms, camera kicks, telegraph marks), the technique bar above the vitals ring (key, stamina, locked level, lit when Execute is possible or momentum empowers), the momentum pips, the target card's poise bar and stance, tactical.rs (the grid overlay in a fight: impassable tiles, obstacles by cover, edges, telegraphed tiles filling up to the impact; setting tactical_grid auto / always / never, in the Interface section; online "in a fight" is Mirror::in_fight: engaged, or the server stepping the player at the fight walk of 2 AP, #92). Offline (--combat-demo camp: the hero has a longsword and a heater shield at Melee 100) and online behave the same.

Agents (uo-mcp): tools technique, guard, dodge; the journal tells when a telegraphed blow aimed at you lands, perfect guards, breaks and executions.

Balance check: tests_melee::techniques_beat_plain_swings: two brute AIs with equal sheets (longsword, Melee 70), one using techniques, the other only auto-attacking: the first wins 31 of 40 (it was 23 of 40 with the first, timid damage numbers, which is why techniques now hit 1.3–1.9×). Nobody parries in that duel, so it measures the techniques alone.

Not done yet (follow-ups): weapon swap (X was taken by a technique), falls from quays and stairs (the arena has no heights), AI dodging out of telegraphed tiles, the masteries of § 5.3, armour damage types for players (only species resist), the online timeline strip (§ 12), the balance runs of § 14 with scripted player skill levels, sounds (task audio).