{"id":51666970,"url":"https://github.com/Paranoidgrinch/RogueDeck-Core","last_synced_at":"2026-08-03T01:01:06.998Z","repository":{"id":362936190,"uuid":"1260518733","full_name":"Paranoidgrinch/RogueDeck-Core","owner":"Paranoidgrinch","description":"Deterministic, modular C# combat engine for roguelike deckbuilders — UI-independent, event-driven and built for extensible mechanics.","archived":false,"fork":false,"pushed_at":"2026-07-15T10:51:55.000Z","size":2466,"stargazers_count":11,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-15T11:24:54.435Z","etag":null,"topics":["card-game","csharp","deckbuilder","deterministic","dotnet","event-driven","game-development","game-engine","modular-architecture","roguelike","turn-based"],"latest_commit_sha":null,"homepage":"https://moonvineforge.com","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Paranoidgrinch.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-05T15:21:01.000Z","updated_at":"2026-07-15T10:51:59.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Paranoidgrinch/RogueDeck-Core","commit_stats":null,"previous_names":["paranoidgrinch/roguedeck-core"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Paranoidgrinch/RogueDeck-Core","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Paranoidgrinch%2FRogueDeck-Core","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Paranoidgrinch%2FRogueDeck-Core/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Paranoidgrinch%2FRogueDeck-Core/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Paranoidgrinch%2FRogueDeck-Core/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Paranoidgrinch","download_url":"https://codeload.github.com/Paranoidgrinch/RogueDeck-Core/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Paranoidgrinch%2FRogueDeck-Core/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":36213603,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-08-02T02:00:06.915Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["card-game","csharp","deckbuilder","deterministic","dotnet","event-driven","game-development","game-engine","modular-architecture","roguelike","turn-based"],"created_at":"2026-07-14T21:00:41.570Z","updated_at":"2026-08-03T01:01:06.992Z","avatar_url":"https://github.com/Paranoidgrinch.png","language":"C#","funding_links":[],"categories":["C# #"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# ⚙️ RogueDeck Core\n\n### Build the mechanic. Keep the core clean.\n\nA deterministic, modular C# combat engine for roguelike deckbuilders.\n**Combat Engine v1 is complete and ready to embed** — strange mechanics compose *into* it instead of turning\nthe core into a giant switch statement.\n\n\u003cbr\u003e\n\n\u003ca href=\"https://github.com/Paranoidgrinch/RogueDeck-Core\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/STAR_THE_ENGINE-181717?style=for-the-badge\u0026logo=github\u0026logoColor=white\" alt=\"Star RogueDeck Core\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/Paranoidgrinch/RogueDeck-Core/tree/main/src/RogueDeck.Core/Combat\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/EXPLORE_THE_ENGINE-512BD4?style=for-the-badge\u0026logo=dotnet\u0026logoColor=white\" alt=\"Explore the engine\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://moonvineforge.com/card-forge.html\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/CHALLENGE_THE_ENGINE-6B7D58?style=for-the-badge\" alt=\"Challenge the engine\"\u003e\n\u003c/a\u003e\n\n\u003cbr\u003e\u003cbr\u003e\n\n[![CI](https://github.com/Paranoidgrinch/RogueDeck-Core/actions/workflows/ci.yml/badge.svg)](https://github.com/Paranoidgrinch/RogueDeck-Core/actions/workflows/ci.yml)\n![.NET](https://img.shields.io/badge/.NET-10.0-512BD4?style=flat-square\\\u0026logo=dotnet\\\u0026logoColor=white)\n![Language](https://img.shields.io/badge/language-C%23-512BD4?style=flat-square\\\u0026logo=dotnet\\\u0026logoColor=white)\n![Status](https://img.shields.io/badge/combat_engine-v1_complete-3FB950?style=flat-square)\n![Tests](https://img.shields.io/badge/tests-1%2C300%2B_green-3FB950?style=flat-square)\n![Architecture](https://img.shields.io/badge/core-UI_independent-394B59?style=flat-square)\n\n\u003c/div\u003e\n\n---\n\n## Why it exists\n\nMost combat code rots the same way: every new card, relic or status teaches the *whole* engine what it is,\nuntil the core is one enormous switch statement nobody dares to touch.\n\nRogueDeck Core takes the opposite bet. Mechanics are **composed** from a small set of primitives on a\ndeterministic queue, so the hundredth mechanic is no harder to add than the first — and the same final state\nis reproducible from the same seed, every time.\n\nIt is a finished, tested **engine you can use today**: drive it from your own game, script fights in code, or\ndesign them live in the browser sandbox. It is not a game itself — it carries no rendering, input or themes,\nonly the reusable combat language beneath a deckbuilder.\n\n---\n\n## The rule above all others\n\n\u003e **Adding a new effect must not require changing the central resolver.**\n\nEverything is built around composition rather than special cases:\n\n* no central switch over concrete effects\n* no hardcoded `PoisonStacks`, `IsStunned` or `Thorns` fields\n* no game-specific rules hidden inside turn processing\n* no effects bypassing the deterministic queue\n* no unrelated systems changing whenever a new mechanic appears\n\nA mechanic joins the engine through focused definitions, handlers, providers and packages — not by teaching\nthe entire core what that mechanic is.\n\n---\n\n## Compose mechanics instead of hardcoding them\n\nTriggered mechanics are separated into five questions:\n\n```text\nWHEN       What happened?\nIF         Which conditions must match?\nWHO        Which combatants are affected?\nHOW MUCH   How is the value calculated?\nWHAT       Which primitive effect is requested?\n```\n\nAn existing event combines with an existing effect without another event-specific engine class:\n\n```text\nWHEN damage is received          WHEN a skill card is played\nIF   the target has Thorns       IF   it is the second skill this turn\nWHO  the attacker                WHO  the player\nHOW  the current Thorns value    HOW  1\nWHAT deal damage                 WHAT draw cards\n```\n\nThe content describes the interaction. The engine resolves it.\n\n---\n\n## How resolution works\n\n```mermaid\nflowchart LR\n    A[Combat event] --\u003e B[Typed trigger]\n    B --\u003e C[Filters]\n    C --\u003e D[Target and value providers]\n    D --\u003e E[Effect program]\n    E --\u003e F[Deterministic queue]\n    F --\u003e G[Typed effect handler]\n    G --\u003e H[State change and new events]\n    H --\u003e F\n```\n\nEffects and events continue through the queue until the chain is complete or combat ends. Chain ancestry,\nre-entry rules and configurable depth limits keep reactive mechanics powerful without allowing accidental\ninfinite loops — and a snapshot can be hashed at any point, so identical inputs prove identical outcomes.\n\n---\n\n## Getting started\n\n### Prerequisites\n\n* [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0)\n* Git\n\n### Get the code and verify it\n\n```bash\ngit clone https://github.com/Paranoidgrinch/RogueDeck-Core.git\ncd RogueDeck-Core\ndotnet restore\ndotnet test          # ~1,300 tests across the solution\n```\n\nCI runs the same suite on Windows + Linux, verifies formatting with `dotnet format`, and builds the\nbenchmarks on every push and pull request to `main`.\n\n### Try it live in the browser\n\n```bash\ndotnet run --project src/RogueDeck.Sandbox\n```\n\nOpen the printed `http://localhost:\u003cport\u003e` URL to define a hero, enemies and cards, then play the fight and\nread the live log. The sandbox exposes the **whole** engine surface — every operation, value read, control\nnode, trigger, selector and interceptor — so you can author almost any mechanic without writing C#.\n\n### Author a fight in code\n\nThe scenario harness is the ergonomic way to *use* the engine: describe a fight, script the turns, run them\non the real combat loop, and read what happened.\n\n```csharp\nusing RogueDeck.Core.Combat;\nusing RogueDeck.Scenario.Authoring;\nusing RogueDeck.Scenario.Dsl;\nusing RogueDeck.Scenario.Reporting;\nusing RogueDeck.Scenario.Scripting;\n\nvar fight = new ScenarioBlueprint();\n\n// A card: deal 8 damage to the chosen target, for 1 energy.\nfight.Cards.Add(new CardBlueprint(\"strike\")\n{\n    Program = Effects.Program(Effects.DealDamage(Targets.EventTarget, 8)),\n}.Cost(StandardCombatIds.EnergyResource, 1));\n\n// An enemy action: smash the hero for 12.\nfight.EnemyActions.Add(new EnemyActionBlueprint(\"smash\", new ActionIntent(\"Smash\", IntentKind.Attack))\n{\n    Program = new EffectProgram\u003cEnemyActionContext\u003e(\n        new DealDamageNode\u003cEnemyActionContext\u003e(\n            CombatantTargetSelectors.EventTarget, new ConstantExpression\u003cEnemyActionContext\u003e(12))),\n});\n\n// The hero (with a small deck) and the enemy.\nfight.Hero = new HeroBlueprint(\"knight\")\n{\n    MaxHealth = 50,\n    Deck = { new DeckEntry(new CardDefinitionId(\"strike\"), Count: 3) },\n};\nfight.Hero.Resources.Add(new ResourceSpec(StandardCombatIds.EnergyResource, Current: 3, Max: 3));\n\nvar ogre = new EnemyBlueprint(\"ogre\") { MaxHealth = 40 };\nogre.Actions.Add(new EnemyActionDefinitionId(\"smash\"));\nfight.Enemies.Add(ogre);\n\n// Script the turns…\nvar script = new ScenarioScript()\n    .HeroPlays(\"strike\", \"ogre\")\n    .HeroEndsTurn()\n    .EnemyActs(\"ogre\", \"smash\", \"knight\")\n    .Build();\n\n// …run them on the real engine, and read the narrative log.\nvar report = new ScenarioRunner().Run(new Playthrough(fight, script, combatId: \"demo\"));\nConsole.WriteLine(new NarrativeLogRenderer().Render(report));\n```\n\nNeed lower-level control for your own game loop? Drop down to `RogueDeck.Core` directly — build a\n`CombatDefinitionRegistryBuilder`, register a `StandardCombatPackage`, and drive a `CombatState` with the\n`CombatReplayRunner` (`PlayCardCommand` / `EndTurnCommand`). `src/RogueDeck.ConsoleSandbox/Program.cs` is a\ncomplete, runnable end-to-end example of exactly that.\n\n### Embed it in your project\n\nThe engine is a plain .NET 10 library with no game dependencies. Reference `src/RogueDeck.Core` from your\nsolution, or `dotnet pack src/RogueDeck.Core` to produce a NuGet package you can consume locally. Everything\nyou author is pure C#, deterministic, and unit-testable without a UI.\n\n---\n\n## What you get\n\nThe combat core ships with:\n\n* deterministic combat state and seeded randomness (snapshot → stable hash → replay)\n* modular effect-request / handler registries and ordered effect + event queues\n* turn, round and combat-result lifecycles\n* cards, card instances and zones — draw, discard, exhaust, banish, retain\n* card costs and cost modifiers; reusable resources and resource lifecycles\n* status definitions with stacking, duration and charges\n* damage, healing, block and defensive pools\n* typed target selectors and value expressions\n* card, status, resource and lifecycle triggers, with re-entry protection\n* a modifier / interceptor pipeline (damage, block, cost, status application, death prevention)\n* package-based registration, combat logging, and architecture-guard tests\n\nMechanics are authored as **Effect Programs** — typed trees of nodes (sequence, conditional, causal, repeat,\nfor-each) over native operations, value expressions and selectors — validated by a build-time preflight and\nexecuted on the deterministic queue. Cards, enemy actions, triggered programs and runtime temporary rules all\nrun through the same runtime.\n\n### The toolchain around the core\n\n| Project | What it gives you |\n| --- | --- |\n| **`RogueDeck.Scenario`** | A fluent DSL to author a fight as blueprints + scripted turns, run it through the *real* engine, and render a readable play-by-play. |\n| **`RogueDeck.Sandbox`** | A Blazor browser editor with complete practical engine coverage — author and play any mechanic, with JSON save/load and a live log. |\n| **`RogueDeck.Sandbox/Fuzzing`** | A bot that generates random scenarios and plays them to surface crashes and determinism violations; a 20,000-seed sweep is clean. |\n\n---\n\n## Repository structure\n\n```text\nRogueDeck-Core\n├── src\n│   ├── RogueDeck.Core            # the engine library (Combat: Cards, Effects, Resources, …)\n│   ├── RogueDeck.Scenario        # scripting harness: blueprints, fluent DSL, runner, narrative log\n│   ├── RogueDeck.Sandbox         # Blazor browser editor + random-scenario fuzzer (Fuzzing/)\n│   └── RogueDeck.ConsoleSandbox  # runnable end-to-end smoke demo\n├── tests\n│   ├── RogueDeck.Core.Tests      # the main engine suite (the executable specification)\n│   ├── RogueDeck.Scenario.Tests\n│   ├── RogueDeck.Sandbox.Tests   # includes the fuzzer regression test\n│   └── RogueDeck.Core.Benchmarks # BenchmarkDotNet\n└── .github/workflows/ci.yml\n```\n\nThis README is the front door; the engine documents itself through code and tests. Start in\n**`src/RogueDeck.Core/Combat`** for the engine and **`tests/RogueDeck.Core.Tests`** for a focused test of\nevery behaviour it guarantees (including the architecture-guard tests that enforce the rules above).\n\n---\n\n## Status\n\n**Combat Engine v1: complete (strict) and green.** The full closure series shipped end to end — typed and\ncardinality preflight, the complete generic trigger-parity matrix, temporary rules and delayed programs,\ndeterministic trace identities, snapshots + hashing + replay, and the modifier / interceptor pipeline.\n~1,300 tests pass across the solution, formatting is clean, and a 20,000-seed fuzz sweep is clean.\n\nTwo behaviours are documented, stable v1 decisions rather than gaps: `CombatResultChanged` is\nobservable-but-non-triggerable (the queue stops at a terminal result), and only the `Combatant` target domain\nexists (the machinery is enforced; other domains are a later phase). The Card Composition Engine (snippet\nsystem / card generation) is intentionally **deferred** as a separate future project.\n\n---\n\n## Where it came from\n\nRogueDeck Core grew out of the first playable systems beta of:\n\n### 🧙 [Bureaucrats and Broomsticks](https://github.com/Paranoidgrinch/bureaucrats-and-broomsticks-v2)\n\nA satirical fantasy roguelike deckbuilder about magic, paperwork and deeply questionable career choices.\nBuilding a complete game revealed the cost of tightly coupled effects and event-specific action classes.\n\nRogueDeck Core is the answer:\n\n\u003e Build the next mechanic without making the previous hundred harder to understand.\n\n\u003ca href=\"https://github.com/Paranoidgrinch/bureaucrats-and-broomsticks-v2/releases/latest\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/PLAY_THE_ORIGIN_GAME-Windows_beta-70566D?style=for-the-badge\u0026logo=windows\u0026logoColor=white\" alt=\"Play Bureaucrats and Broomsticks\"\u003e\n\u003c/a\u003e\n\n---\n\n## Try to break the architecture\n\nHave a mechanic that *should* be hard to represent? Bring it. A card, relic, status, resource, curse, enemy\naction, triggered interaction or completely unreasonable combat rule — the most useful ideas are not the\nbalanced ones, they are the ones that force the engine to prove its modularity.\n\nFor a mechanic proposal, describe: **what causes it, which conditions apply, who it targets, how its value is\ncalculated, and what effect it produces.**\n\n\u003cdiv align=\"center\"\u003e\n\n\u003ca href=\"https://github.com/Paranoidgrinch/RogueDeck-Core/issues/new\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/OPEN_AN_ISSUE-Describe_the_mechanic-181717?style=for-the-badge\u0026logo=github\u0026logoColor=white\" alt=\"Open an issue\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://moonvineforge.com/card-forge.html\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/BUILD_YOUR_OWN_CARD-Enter_the_Community_Forge-6B7D58?style=for-the-badge\" alt=\"Enter the Community Card Forge\"\u003e\n\u003c/a\u003e\n\n\u003c/div\u003e\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n### New effects should extend the language — not expand the switch statement.\n\n\u003cbr\u003e\n\n\u003ca href=\"https://github.com/Paranoidgrinch/RogueDeck-Core\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/STAR_ROGUEDECK_CORE-181717?style=for-the-badge\u0026logo=github\u0026logoColor=white\" alt=\"Star RogueDeck Core\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/Paranoidgrinch\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/FOLLOW_ME_ON_GITHUB-181717?style=for-the-badge\u0026logo=github\u0026logoColor=white\" alt=\"Follow me on GitHub\"\u003e\n\u003c/a\u003e\n\n\u003cbr\u003e\u003cbr\u003e\n\n\u003ca href=\"https://moonvineforge.com\"\u003e\u003cstrong\u003eMoonvine Forge Studios\u003c/strong\u003e\u003c/a\u003e\n\n\u003cbr\u003e\n\n\u003cem\u003eSmall studio. Careful craft. Unusual worlds.\u003c/em\u003e\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FParanoidgrinch%2FRogueDeck-Core","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FParanoidgrinch%2FRogueDeck-Core","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FParanoidgrinch%2FRogueDeck-Core/lists"}