v0.5.11-dev · 2026-07-19
Now You Can Miss
A two-player playtest pass. One of these is the worst combat bug the project has shipped, and it had been live the entire time.
Fixed — Front and Back were swapped on every attack in the game (1e11909)
Reported as "Iron Fist walked right up to White Seraph and it said from BEHIND ×1.5 — but it was FRONT."
get_facing computed its direction as where the blow travels in the top
half and read that same value as where the attacker stands in the bottom
half. The two halves disagreed, so Front and Back were transposed on every
single hit. Both armies spawn facing each other and walk forward, so the
common case — a head-on approach — collected the ×1.5 backstab bonus, while
an actual flank round the back got ×1.0. Every damage number in every match
to date was computed against an inverted facing.
It survived because every facing test in the tree hands FacingResult in
ready-made; the geometry that produces one had no test at all. It does now,
covering all four headings, range independence and the diagonal tie-break.
Added — attacks can miss (d95835d)
Reported as "all attacks, magic AND physical, seem to hit 100% of the time. in FFT there is a miss&evade calculation."
Correct, and worse than it looked: UnitStats.evade existed, shields granted
it, the Codex rendered it, and AbilityForecast even carried a hit_pct
field — and nothing read any of it. Class evade was 0 on every unit
because JobDef had no evade at all. Third instance of this project's
signature failure: registry data shipped ahead of the code that reads it,
with the UI rendering it as though it worked.
hit% = base accuracy − (target evade × facing factor)
- All 18 jobs get class evade, physical and magic separately. Light fast classes dodge steel (ninja 30 / thief 25 / dancer 22); robes dodge spells (mystic and chronomancer 20). Plate is the reverse — the knight is the hardest class in the game to miss.
- Weapon classes get base accuracy. Guns 100: a weapon that ignores its wielder's stats ignores their aim too. Axe/flail/bag 80 — the same "wild" group whose damage already swings 0.35–1.65×.
- Facing decides how much evade applies: full from the front, HALF from the side, ZERO from behind. Flanking beats dodging. This is also why the facing inversion above had to be fixed first, or the whole accuracy system would have shipped backwards on day one.
- Concentrate now makes its wielder unmissable — finally a reason to spend the Support slot on it.
- Misses say so, with the number: "Life Leech MISSES Bard (55% to hit)."
- The hover forecast fills in its real hit% from the same functions the resolver rolls against, so the box and the outcome cannot disagree.
Measured face-on hit rates now run 55% (thief) to 84% (squire). Two things measurement caught that guessing would not have: gear evade was doubling the class spread it was meant to decorate (a default-kit thief sat at 57 total, missed two swings in three), and those item numbers had been authored while the stat was inert — balance-tested against a tooltip and nothing else.
Changed — Life Leech is a gamble now, not a certainty
It was the highest power in the instant tier and a full self-heal and zero charge time, where every comparable nuke pays 2–3 CT. A mystic finished a logged match at 95/95 having deleted a bard with it. Rather than shave the numbers, it keeps the whole payoff and lands ~60% of the time.
Fixed — Confuse breaks on damage from any source
Joe's rule. The flag covers every ability, counter and drain hit for free — but the poison DOT writes HP by hand and never ran the break check, so it was also the one hit in the game that could never wake a sleeper.
Fixed — Chakra, and the reason it looked broken
Chakra restored HP only, so at full HP it visibly did nothing. It now restores MP as well, scaled off max MP rather than MA (the monk's dump stat).
But the actual cause of "chakra has no effect" was worse: abilities that hit nothing still charged full MP, silently. An earth_slash into empty ground and a Revive aimed at an enemy corpse ate 22 of the monk's 35 MP — after which Chakra was refused for insufficient MP and emitted no events at all, which is indistinguishable from a broken ability. Whiffs now refund. Charged casts still pay up front: committing a charge is the commitment.
Fixed — tiles that lit up and then refused the click
The move-range highlight never stripped body-blocked tiles the way the engine does, so ally-occupied and corpse-occupied squares were painted as reachable and then silently rejected. Lava also cost 2 in the engine and 1 in the client.
Added — the Dragoon actually jumps (ff7048d)
UnitTookFlight / UnitLanded had only ever been narrated. The dragoon now
leaves the screen on takeoff and comes down on the landing tile with weight
behind it — driven off the engine's landing coordinate, not the aimed one,
since the engine diverts to a free neighbour when the target square is taken.
Added — gear on the post-battle board
Each unit's rolled equipment on its own line under the rolled skills, same rarity tinting, through both the game-over screen and Match History.
Fixed — online matches would have had no evade at all
match_server.rs holds a fourth inline unit-stat builder — the
authoritative online factory — hardcoding evade: 0. Making the new field
required turned that into a compile error. Had it defaulted, online and
offline would have been two different games, silently.