Client project

Turn-Based Combat

Tactics combat you can replay from a seed.

Combat rules for a client's isometric tactics game. Click a unit, pick Bolt or Stunbolt, and the rules object resolves hit, crit, armor shields, and daze. Every roll goes through a seeded RNG, so the same fight can be replayed. Between battles, health sticks. Dead units stay off the roster. Art, map, and unit sprites are the client's.

01

See it running

Pick an ability: Bolt, Stunbolt, Skip Turn. Tooltips show range, strength %, and status chance. Grid tile highlights the target.
Wait-for-action: SELECT ABILITY, selected-unit panel, overhead HP and silver shield icons.
02

The short version

  • Made for a client. I built the combat rules the battle uses: hit, crit, armor, morale, turn order.
  • One rules object owns the numbers. Units and abilities do not hide magic values in their scripts.
  • Seeded random rolls: same seed, same fight. That is what makes the tests possible.
  • On screen: isometric grid, ability bar, selected-unit card, overhead HP and shield icons.
  • Campaign layer: health persists, death is permanent until an explicit heal point.
  • Tests cover RNG, turn order, morale, campaign save, and a check that combat never auto-heals.
03

What it does

  • Isometric grid battle: click a unit, pick an ability, resolve the attack
  • Abilities the client authored (Bolt, Stunbolt, Stab, Axeblade) run through the same rules object
  • Ability panel shows range, strength %, status, and chance (Stunbolt: 50% daze at range 4)
  • Overhead HP plus silver shield icons for remaining armor. Selected-unit card shows class and current / max health
  • Accuracy 1–10 sets hit and crit. A physical hit spends one armor shield, then health
  • Faster units act first. Speed above 10 always goes before everyone else
  • End of a real turn: morale check. Fail: -2 speed next round. Morale 10 cannot fail
  • Between battles, health carries over. Dead units cannot be deployed again
  • Unit tests prove the same seed produces the same rolls. Combat is not allowed to auto-heal
04

Built for a client

Made for a client from a written spec: the combat rules layer inside their tactics game. I owned hit/crit/armor/morale math, seeded RNG, the battle state machine, and the tests. Art, units, and the isometric map are theirs.

Client briefMazen — implementation
05

The thought

The client needed combat a designer can tune without opening unit scripts, and that I can re-run in tests. Hit chance, crits, armor, and morale sit in one rules object. Random rolls go through a seeded RNG. Campaign health is attrition: wounded stays wounded, dead stays dead. Their isometric battle is the skin. The rules file is the job.

06

Mechanics

Click a unit. The selected-unit panel shows class and health (Tank 14/20, Squire Crossbow 7/11). The ability bar offers that unit's attacks plus Skip Turn. Hovering Stunbolt shows range 4, 50% strength, 50% chance to daze. A pink tile marks the target. An attack rolls to hit from Accuracy, then rolls to crit. A physical hit spends one armor shield before it touches health. That is the silver icon next to the HP bar. Optional penetration lets a fraction through. Crits double damage after armor. Miss and crit show as on-screen indicators. Magic bypasses armor in this version. Turn order is speed, including morale buffs. Ties break at random. Speed above 10 always acts before anyone at 10 or below. At the end of a real turn (skipped units do not roll), morale is checked against a table. Fail: -2 speed until the next round. Morale 10 cannot fail, and grants +2 speed.

07

Systems

A unit has a definition (class, faction, stats, abilities) and live combat state (current health, armor, morale, buffs, effective speed). Health ranges are clamped by class. Strength scales melee. Arcane Might scales mage damage. Accuracy is the only crit stat. A corpse cannot be killed twice. Speed buffs apply after the queue rebuilds, so a morale fail shows up next round, not mid-turn. Between battles a campaign object stores health by unit id, a dead list, and the last seed. Heal only happens at points the campaign chooses. Dead units cannot be deployed.

08

Under the hood

Three globals: events, random rolls, and the combat tables. A state machine runs the fight: setup, start turn, wait for action, resolve attack, check victory, end turn. Wait-for-action is the SELECT ABILITY panel. Resolve builds an attack, asks the rules object for the result, then plays hit or die. Unit tests cover roll sequences, the accuracy table, turn-order distribution, morale fail rates, campaign save/load, and a lint that combat must not heal on its own. Design can change numbers without touching resolution.

09

Controls

Select unit / tileLeft Mouse
Choose abilityBolt / Stunbolt / Stab / Axeblade
Skip turnSkip Turn
10

How it came together

2026 · Jul

Rules spec

Six stats, armor shields, accuracy table, morale table, seeded RNG. One autoload owns every threshold.

2026 · Jul

Battle loop

State machine: setup, start turn, wait for action, resolve attack, check victory, end turn + morale.

2026 · Jul

Campaign attrition

Health persists between fights. Dead units leave the roster. Heal only at explicit campaign points.

2026 · Aug

Client battle

Wired into the client's isometric map: ability bar, selected-unit panel, HP and shield icons, wait-for-action state.

11

What I would do differently

One rules file beats magic numbers in unit scripts. Seeded rolls are what made the test suite possible. The client's map and sprites made the systems readable; the job was keeping every threshold out of those sprites. Next is freeze the tables so design can tune without rewriting resolution.

Need something like this built?

Tell me what the system has to do and where it sits. I'll tell you what that takes, or say straight away if it isn't a fit.