Moonforge is a C# game engine for turn-based RPGs — the kind with parties, stat blocks, quest journals, and treasure chests.
It ships the systems every RPG re-invents: combat with status effects and damage types (including a Pokemon-style 2× / 0.5× / 0× type effectiveness chart), per-monster move PP, parties with mid-battle swap-in, capture-the-enemy into your roster, evolution on level-up, a bestiary / codex that tracks itself, an inventory and economy that survives the player buying things on a full bag, quests that track themselves from gameplay events, dialogue trees, loot tables, save/load with migrations. All deterministic, all atomic, all wired together so modules don't need to know about each other.
Unity-friendly (netstandard2.1), MIT-licensed.
- Deterministic. Seeded RNG, explicit clock — same inputs always produce the same outputs. Save resilience, replay, and lockstep multiplayer just work.
- Atomic. Every command runs inside a snapshot/rollback transaction. Failures revert state and discard buffered events — no half-applied purchases, no orphaned quest progress, no need to write your own undo path.
- Composable. Modules integrate through a typed event bus and a reactor model. Combat doesn't know about quests; quests don't know about inventory; everything still wires up.
- Pluggable. Bring your own formula evaluator, your own RNG, your own commands, reactors, and event types. The engine ships defaults you can replace one at a time.
dotnet add package Moonforge.Core
Or clone the repo and reference src/Moonforge.Core/Moonforge.Core.csproj directly.
The quest below auto-completes the moment the player picks up their third potion. No
explicit "advance the quest" call — a built-in reactor watches inventory events and
tracks Collect objectives for you.
using Moonforge.Core;
using Moonforge.Core.Data.Definitions;
using Moonforge.Core.Inventory.Commands;
using Moonforge.Core.Quests;
using Moonforge.Core.Quests.Commands;
using Moonforge.Core.Quests.Queries;
using Moonforge.Core.Runtime.Commands;
using Moonforge.Core.Runtime.Events;
using Moonforge.Core.Runtime.Formulas;
using Moonforge.Core.Runtime.Random;
using Moonforge.Core.Runtime.Time;
GameState gameState = new();
InMemoryDomainEventSink sink = new();
InMemoryGameDefinitionCatalog definitions = new InMemoryGameDefinitionCatalog()
.AddItem(new ItemDefinition("item.potion", maxStack: 10))
.AddQuest(new QuestDefinition(
id: "quest.tutorial",
objectives:
[
new QuestObjectiveDefinition(
id: "obj.collect",
objectiveType: QuestObjectiveType.Collect,
targetId: "item.potion",
requiredCount: 3,
displayName: "Collect 3 potions")
],
displayName: "Stock the larder"));
CommandContext context = new(
new Pcg32RandomSource(seed: 1234),
new SimulationClock(0),
new NoOpFormulaEvaluator(),
sink,
definitions);
CommandDispatcher dispatcher = DefaultCommandDispatcher.Create();
dispatcher.Dispatch(gameState, new ConfigureInventoryCapacityCommand(20), context);
dispatcher.Dispatch(gameState, new StartQuestCommand("quest.tutorial"), context);
dispatcher.Dispatch(gameState, new AddInventoryItemCommand("item.potion", 3), context);
QuestStatus status = new GetQuestStatusQueryHandler()
.Query(gameState, new GetQuestStatusQuery("quest.tutorial"));
System.Console.WriteLine($"Quest: {status}"); // Quest: CompletedStart with the docs index.
- Getting Started — first-time setup, the smallest working dispatch
- Architecture —
GameState, command/query/reactor pipeline, determinism contract - Cookbook — recipes for common gameplay tasks
- Troubleshooting — gotchas and common errors
Per-module deep dives: combat, stats, quests, dialogue, economy & inventory, equipment, progression, shops, loot, encounters, interactables, world variables, persistence, party, evolution, bestiary.
# Full roguelike — town, procedurally-generated dungeons, quests, dialogue, save/load,
# combat with elemental damage types and fire-immune bosses.
dotnet run --project samples/Moonforge.Sample.Console
# Monster catcher — Pokemon-style game: procedural 45-screen world, eight gym leaders,
# Champion ending, shops, items, the works.
dotnet run --project samples/Moonforge.Sample.MonsterCatcher.Console
# Minimal API demo — copy-paste starting point.
dotnet run --project samples/Moonforge.Sample.Minimalsamples/Moonforge.Sample.Console is the reference for how every engine subsystem fits
together: a stat block with derived MaxHp, a shop with multi-currency prices, locked
interactables, save migrations, weighted encounter tables, status effects, elemental
resistances. When the docs describe a pattern, this sample has the production-grade
version.
samples/Moonforge.Sample.MonsterCatcher.Console is a small Pokemon-style game built
end-to-end on the engine — procedurally-generated 45-screen world across seven biomes,
eight themed gym leaders with multi-monster rosters and badge gating, town shops with
tiered capture balls and potions, an "eight wardens" main quest tracked by the engine's
quest reactor, Pokemon-style faint-warp on party wipe, and a five-mon Champion battle.
The full monster-catcher feature stack (party + swap + type chart + capture + evolution
- bestiary + per-skill PP) is wired together with the Quests / Shops / Inventory / Economy / Loot / Dialogue / Interactables modules. See the sample walkthrough for the layout.
dotnet restore src/Moonforge.Core/Moonforge.Core.csproj
dotnet build src/Moonforge.Core/Moonforge.Core.csproj -c Release
dotnet test tests/Moonforge.Core.Tests/Moonforge.Core.Tests.csproj -c Release
dotnet test tests/Moonforge.Sample.Console.Tests/Moonforge.Sample.Console.Tests.csproj -c ReleaseRequires the .NET 8 SDK or later. To build via the solution file (Moonforge.slnx) you
need .NET 9 SDK or later; the per-project commands above work on .NET 8.
To produce a NuGet package:
dotnet pack src/Moonforge.Core/Moonforge.Core.csproj -c Release -o artifactsRelease notes are auto-categorized by .github/release.yml when
generating a GitHub release.
src/Moonforge.Core/ the engine — one folder per gameplay module
samples/Moonforge.Sample.Console/ roguelike reference sample (~3.7k lines)
samples/Moonforge.Sample.MonsterCatcher.Console/ monster-catcher Pokemon-style game (~3.3k lines)
samples/Moonforge.Sample.Minimal/ minimal API demo
tests/Moonforge.Core.Tests/ engine unit + behavior tests (xUnit)
tests/Moonforge.Sample.Console.Tests/ roguelike sample-level tests
tests/Moonforge.Sample.MonsterCatcher.Console.Tests/ monster-catcher smoke test
docs/ guides, architecture, cookbook, per-module deep dives
See CONTRIBUTING.md for development workflow, standards, and pull request expectations.
See SECURITY.md for responsible disclosure guidance.
MIT. See LICENSE.