A data-driven Unity framework for stacking-score card games.
DEAL is the engine under Aurayale, a Balatro-inspired collectible card
game. It exists because we wanted the core of that genre — play a hand, watch bonuses trigger one
by one, see Base × Multiplier explode — to be something designers assemble from data, not
something engineers re-code for every card.
- Game flow is a state machine you can see. Draw, select, score, resolve — each step is a ScriptableObject state with data-defined transitions. Changing "3 discards per round" to 2 is a field edit, not a code change.
- A card is a data asset. Effects are composed from
Condition[] + Effect[]traits pointing at status objects. Adding a card means creating a.asset— zero code, no recompile. - Scoring is one pipeline:
Base × Multiplier. Every bonus — card traits, statuses, "joker"-style persistent modifiers — is a step on that pipeline, and each step can drive UI feedback in sequence. - The core is deterministic and headless-testable. Seeded RNG, an immutable command log, and a 141-test EditMode suite that runs without a scene — same seed, same result, CI-friendly.
The shortest path to "numbers go up":
- Define cards. Create card assets (
CardSOsubclasses) and give them suit/number traits — or your own trait types; the base card has no built-in poker vocabulary. - Lay out the flow. Create a
ScriptableStateMachinewith states for deal → select → play-or-discard → score. Budget mechanics (hands/discards remaining) are integer player properties checked by transition conditions. - Score the hand. Wire a
ScoreCounterSO(the poker evaluator ships as one strategy; write your own by subclassing) and map results to base score and multiplier. - Add modifiers. Build "joker"-style effects as
ModifierTraits (condition + effect data) on cards, or as persistentStatusSOs that trigger at scoring phases. - Watch it stack. Score mutations flow through the command processor; hook the events to
animate your
A × Bdisplay per trigger.
The samples (Package Manager → DEAL → Samples) show working scenes for card dealing,
suit/number changes, and pattern evaluation, plus in-code samples (Tests/EditMode/Samples/)
demonstrating every extension seam: a custom command verb, a custom scoring strategy with no poker,
a custom property provider and status phase, and a two-client lockstep match over the in-process
loopback transport.
Every place a game needs its own rules is an open seam:
| You want to… | Use |
|---|---|
| Add a game-specific command verb | CommandHandlerRegistry.RegisterHandler(string, handler) |
| Score by your own rules (non-poker included) | subclass ScoreCounterSO |
| Add a status trigger phase beyond the built-ins | any string key; StatusPhases is just a preset |
| Feed FSM actions a custom system value | subclass SystemPropertyProviderSO |
| Add card mechanics | ModifierCondition / ModifierEffect / StatusSO subclasses |
| Swap how player input arrives (human, bot, remote) | IPlayerInput behind SeatRegistry |
| Run deterministic multiplayer logic in-process | INetTransport + LoopbackTransport |
Be aware of what's battle-tested and what's newer:
| Module | Status |
|---|---|
| FSM engine, card/trait system, status system, scoring pipeline, command system | Stable — shipping in Aurayale |
Poker evaluation (Mustaverse.DEAL.Poker) |
Stable — slated to move into its own assembly so non-poker games don't reference it |
Seats/input seam, determinism seam (IRng, BattleBarrier) |
Validated — adopted by a second internal title |
Net transport (loopback), damage pipeline (IDamageModifier) |
Preview — proven by tests and samples; not yet exercised by a shipping game. APIs may still move. |
DEAL targets turn-based card games with data-driven effects: score-stacking roguelikes
(Balatro-likes), turn-loop battlers, and classic flow games. The engine-free core assembly
(Mustaverse.DEAL.Core — no UnityEngine reference) holds the deterministic seams, so game logic is
testable headless.
It does not yet provide a priority/reaction-stack primitive (the Yu-Gi-Oh/MTG family of interaction), a remote network driver, or server-side score verification. The command log and seeded RNG are designed so a verifier could replay a match — building that verifier is on the roadmap, not in the box.
EditMode suite (Mustaverse.DEAL.Tests.EditMode): 141 tests across RNG reproducibility, command-log
integrity, scoring/damage math, status behavior, pattern evaluation, and the extension-seam samples.
Window → General → Test Runner → EditMode → Run All. No scene required.
- Score-verification service (replay a match from seed + command log)
- Remote transport driver + matchmaking companions for the net seam
- Poker module split into its own assembly (
PHEvaldependency leaves core) - Sample-content slimming: legacy casino-flow content moves fully into samples
Apache-2.0 — free for commercial use, patent grant included. See LICENSE.md. Issues and PRs welcome.