Monster collector template (MOSSBOUND)
Net Forge, the open-source multiplayer browser game engine built for AI coding agents, is published on npm under @netforge with source at github.com/netnetdev/net-forge.
MOSSBOUND is a complete multiplayer monster collector: each player picks one of three starters at camp, walks a marsh shared with up to seven others, meets wild creatures in tall grass and battles them turn by turn with a team of three, catching the ones worth keeping. Every player in the marsh wears down the same boss, the warden, which has to fall before dusk.
npm create netforge@latest my-game -- --template collector --yes
cd my-game
npm run playWalk with WASD, the arrows or the left thumb. Open the link in a second tab and you meet the other keeper in the marsh.
What you get
| Part | What it does | Where |
|---|---|---|
| The map | Size in tiles, camp, water, blocked tiles, grass zones with encounter rates and creature pools, the warden, dusk, snares | marsh({...}) |
| Creatures | Up to 24 creatures with an element, base stats that grow 12% a level, 1 to 4 moves and a catch rate | creature(...) |
| Moves | Up to 48 moves with element, power and accuracy; effects drain, heal, guard | move(...) |
| Elements | A four-way cycle (root, tide, spark, stone); strong hits deal 1.5x, weak ones 0.67x | the engine |
| Battles | Turn order by speed, swaps, snares, flee, XP for the active and benched creatures | the engine |
| Shared boss | One health pool for the whole marsh; everyone who hurt it is credited when it falls | marsh({ warden }) |
| Netcode | 30 Hz authoritative room; walking is predicted with the room's own tile collision; battles are private to each player | the template package |
| Playtest bots | Four keepers for four minutes: battles won, catches, levels, team wipes, earn | npm test |
Measured on an Apple M2 Pro, Node 22: four bots over four minutes (7,200 ticks at 30 Hz) caught 14 creatures, raised a creature to level 6 and fired the catch rules, at 0.002 ms per server tick on average.
1. Add a creature and a move
import { creature, move } from "@netforge/engine";
move("thorn_curl", { element: "root", power: 0, effect: "guard" });
move("tide_crash", { element: "tide", power: 70, accuracy: 0.8 });
creature("thistlehog", {
model: "style.lowpoly.fox",
element: "root",
hp: 50,
atk: 52,
def: 48,
spd: 46,
moves: ["leaf_lash", "thorn_curl"],
catchRate: 0.7,
});power: 40 is a plain hit. drain heals half the damage dealt, heal (with power: 0) restores amount of max health, and guard halves the next hit taken. Then put the creature in a grass pool and add its label to src/names.json.
2. Lay out the marsh
import { marsh } from "@netforge/engine";
marsh({
size: [30, 20],
camp: [2, 10],
starters: ["mossling", "cindertail", "puddlewump"],
starterLevel: 4,
water: [[11, 0, 2, 6]],
blocked: [[19, 0, 1, 8]],
grass: [
{ at: [4, 2, 6, 5], rate: 0.22, pool: [{ creature: "thistlehog", weight: 3, level: [2, 3] }] },
{ at: [21, 4, 4, 12], rate: 0.18, pool: [{ creature: "bogling", weight: 2, level: [6, 8] }] },
],
warden: { creature: "fenwarden", at: [27, 10], level: 9, hp: 700 },
dusk: 600,
snares: 6,
});Rectangles are [x, y, width, height] in tiles of 2 m. Put weak creatures near camp and stronger ones toward the warden, and leave a walkable way from camp to every grass zone. The build checks that the camp and warden stand on open tiles and that every pool names a declared creature.
3. Add an earn rule
import { earn } from "@netforge/engine";
earn.rule("ten_wins", { when: "creature.defeated", n: 10, pay: 15, oncePer: "run" });Events are creature.caught, creature.defeated, creature.levelup, level.five and level.ten (each credits the player), warden.defeated (everyone who hurt it) and run.won (everyone in the marsh).
4. Check it with bots
npm testHow it works
The collector is a board genre: its rules are a deterministic module in @netforge/engine/rules. Every roll (encounters, accuracy, damage spread, snares and the wild creature's move) comes from the room's seeded random number, so a run replays exactly from its inputs. Walking is predicted with the same tile collision the room runs, so it never waits for the server. Battles are private: your team, your opponent and the battle log reach only you, while other players see the creature walking beside you. See Simulation and ECS.
The full guide is Build a monster collecting game with battles and a party.
Alternatives
- Godot has a tilemap editor, a scripting language and a web export. Pick it for a single-player collector with a hand-built overworld and story.
- Phaser is a 2D HTML5 framework with tilemaps. Pick it for a top-down 2D collector with pixel art.
- Net Forge fits when you want a shared world where players catch and battle side by side, with every roll made on the server and a shared boss fight.
FAQ
How do wild encounters work?
Each step into a new tile of tall grass rolls the zone's rate. A hit starts a battle with a creature from that zone's pool, at a level in its range.
How is the catch chance calculated?
A snare succeeds with chance catchRate x (0.25 + 0.75 x the opponent's missing health), so weakening a creature first makes it easier to catch.
Can players battle each other?
Not in this template. Players share the marsh and the warden fight; battles are against wild creatures and the warden.
How big can a team be?
Three creatures travel with you; more catches go into your lantern. The amount upgrade adds extra snares.
What happens if my whole team faints?
You are sent back to camp with half health. Standing at camp heals your team.