Deep Dive: Balancing a Goose Game
The iteration that turned a text adventure into something playable—achievement systems, balance tuning, playtesting lessons, and why geese need a 1077-line manual.
Deep Dive: Balancing a Goose Game
The iteration that turned a text adventure into something playable
The first version of Canada Goose Simulator was technically complete. You could honk at NPCs, raise goslings, claim territory, and achieve five different victory conditions. It compiled. The tests passed.
It was also absolutely miserable to play.
This is the story of the second half of game development—the part where you take something that works and make it fun. Spoiler: it involves spreadsheets, a lot of playtesting, and eventually giving up and writing a 1077-line manual because the game got too complicated.
The Original Balance (A Disaster)
Here’s what the initial numbers looked like:
// The original config - DO NOT SHIP THIS
const ORIGINAL_BALANCE = {
timeUnitsPerDay: 100,
actions: {
honk: { cost: 2, maxAffected: 2 },
travel: { cost: 3 },
fly: { cost: 4 },
peck: { cost: 1 },
rest: { cost: 5, healthGain: 20 },
},
goals: {
agentOfChaos: { target: 50 }, // Disturb 50 NPCs
foodHoarder: { target: 75 }, // Collect 75 food
nestBuilder: { target: 15 }, // Gather 15 materials
goslingGuardian: { target: 3 }, // Raise 3 goslings
territorialTyrant: { target: 6 }, // Claim all zones
},
goslings: {
incubationDays: 3,
maturationDays: 7,
hungerPerDay: 10,
},
inventory: {
capacity: 5,
},
gameDays: 20,
};
On paper, this looks reasonable. In practice:
-
Food Hoarder was impossible — 75 food items in 20 days meant finding ~4 items per day while also eating, traveling, and not dying. Food spawns randomly. You’d run out of time.
-
Gosling Guardian was a death march — 3 days incubation + 7 days maturation = 10 days per gosling. With only 20 days total, you could barely raise 2 goslings, let alone 3.
-
Inventory was constantly full — 5 slots meant constant inventory management. “You can’t pick up that bread, you’re carrying too many sticks” is not fun.
-
Honking felt expensive — At 2 time units per honk, players were hoarding their honks like precious resources instead of, you know, being a goose.
The Playtesting Sessions
I played through the game myself about 30 times. Then I watched (via screen share) three friends try to play it. The feedback was… educational.
Player 1 (strategy gamer): “I’ve optimized my route to hit 4 zones per day, but the math doesn’t work for Food Hoarder unless RNG is perfect.”
Player 2 (casual player): “Why can’t I honk more? I thought this was a honking game.”
Player 3 (completionist): “I want to get all achievements but Gosling Guardian is literally impossible in 20 days. Did you test this?”
(I had not tested this specific scenario. The 79 unit tests verified the mechanics worked, not that they were achievable.)
The Balance Patch
After the feedback, I made surgical adjustments:
// The shipped config
const BALANCED_CONFIG = {
// ... same structure, new numbers:
actions: {
honk: { cost: 1 }, // Was 2 - HONK FREELY
travel: { cost: 2 }, // Was 3 - Explore more
// fly and peck unchanged
},
goals: {
foodHoarder: { target: 30 }, // Was 75 - Actually achievable
// Others unchanged - they were fine
},
goslings: {
incubationDays: 2, // Was 3 - Faster feedback
maturationDays: 5, // Was 7 - 2+5=7 days per gosling
},
inventory: {
capacity: 8, // Was 5 - Less tedium
},
};
The changes seem small, but the impact was massive:
| Metric | Before | After | Impact |
|---|---|---|---|
| Honk cost | 2 | 1 | 2x more honking |
| Travel cost | 3 | 2 | 50% more exploration |
| Food goal | 75 | 30 | Actually possible |
| Gosling cycle | 10 days | 7 days | Can raise 3 in 20 days |
| Inventory | 5 | 8 | 60% less tedium |
The philosophy behind each change:
- Honk cost 2→1: The core fantasy is being a chaotic goose. If honking feels expensive, the game fails at its premise.
- Travel cost 3→2: Players were afraid to explore because movement ate their time budget.
- Food goal 75→30: Math doesn’t lie. 75 was statistically impossible without perfect RNG.
- Gosling incubation 3→2: Faster feedback loop. Players want to see their eggs hatch.
- Gosling maturation 7→5: Combined with incubation change, exactly enough time for the 3-gosling achievement.
- Inventory 5→8: Inventory management should be occasional, not constant.
The Achievement System
Once the core balance worked, I added achievements—both as goals for completionists and as implicit tutorials for game mechanics.
// achievements.ts
export const ACHIEVEMENTS = {
// Goal completion achievements
'nested-life': {
name: 'The Nested Life',
description: 'Complete the Nest Builder goal',
trigger: (state) => state.victory === 'NEST_BUILDER',
},
'agent-chaos': {
name: 'Agent of Chaos',
description: 'Complete the Agent of Chaos goal',
trigger: (state) => state.victory === 'AGENT_OF_CHAOS',
},
'dynasty': {
name: 'Dynasty',
description: 'Complete the Gosling Guardian goal',
trigger: (state) => state.victory === 'GOSLING_GUARDIAN',
},
'hoard': {
name: 'The Hoard',
description: 'Complete the Food Hoarder goal',
trigger: (state) => state.victory === 'FOOD_HOARDER',
},
'territory': {
name: 'Territorial Tyrant',
description: 'Complete the Territorial Tyrant goal',
trigger: (state) => state.victory === 'TERRITORIAL_TYRANT',
},
// Milestone achievements (teaching moments)
'first-honk': {
name: 'First Honk',
description: 'Honk for the first time',
trigger: (state) => state.stats.totalHonks >= 1,
// Teaches: honking exists
},
'vocal-victor': {
name: 'Vocal Victor',
description: 'Honk 100 times in a single game',
trigger: (state) => state.stats.totalHonks >= 100,
// Teaches: honking is cheap, do it a lot
},
'minor-nuisance': {
name: 'Minor Nuisance',
description: 'Disturb 10 NPCs',
trigger: (state) => state.stats.npcsDisturbed >= 10,
// Teaches: working toward Agent of Chaos
},
'bread-bandit': {
name: 'Bread Bandit',
description: 'Steal food from 5 different NPCs',
trigger: (state) => state.stats.foodStolen >= 5,
// Teaches: some NPCs drop food when honked
},
// Hidden achievements
'peace-was-an-option': {
name: 'Peace Was Never an Option (But It Was)',
description: 'Complete any goal without honking',
trigger: (state) => state.victory && state.stats.totalHonks === 0,
hidden: true,
// The irony achievement
},
// Meta achievement
'golden-goose': {
name: 'Golden Goose',
description: 'Unlock all other achievements',
trigger: (state) => state.achievements.filter(a => a !== 'golden-goose').length === 11,
reward: 'golden-goose-trophy',
},
};
The milestone achievements serve a specific purpose: they’re breadcrumbs that teach game mechanics. “First Honk” ensures players try honking. “Bread Bandit” teaches that some NPCs drop food. “Vocal Victor” communicates that honking is cheap and encouraged.
The hidden “Peace Was an Option” achievement is pure irony. The game’s tagline is basically “cause chaos,” so completing it without a single honk is the ultimate challenge run.
The Golden Goose Trophy
Completionists need a carrot. The Golden Goose Trophy is that carrot.
// decorations.ts
export interface Decoration {
id: string;
name: string;
description: string;
svgPath: string;
width: number;
height: number;
}
export const GOLDEN_GOOSE_TROPHY: Decoration = {
id: 'golden-goose-trophy',
name: 'Golden Goose Trophy',
description: 'Awarded for achieving goose mastery',
svgPath: '/assets/decorations/golden-goose-trophy.svg',
width: 48,
height: 64,
};
When you unlock all achievements, the trophy appears on your virtual desk in the emulator’s internal bay. It’s a 48x64 pixel golden goose on a pedestal. Completely useless. Enormously satisfying.
The desk decorations system was built specifically for this trophy but designed to be extensible. Future games could add their own trophies—a feature that took maybe 2 hours to build and will probably never be used again. Classic yak shave.
The Achievement Tracker
Tracking achievements across game actions required threading a tracker through the game state:
// tracker.ts
export class AchievementTracker {
private stats: GameStats;
private unlocked: Set<string>;
private listeners: ((achievement: Achievement) => void)[];
constructor() {
this.stats = {
totalHonks: 0,
npcsDisturbed: 0,
foodCollected: 0,
foodStolen: 0,
materialsGathered: 0,
goslingsRaised: 0,
territoriesClaimed: 0,
daysSurvived: 0,
migrations: 0,
};
this.unlocked = new Set();
this.listeners = [];
}
recordHonk(affectedNpcs: number): void {
this.stats.totalHonks++;
this.stats.npcsDisturbed += affectedNpcs;
this.checkAchievements();
}
recordFoodSteal(): void {
this.stats.foodStolen++;
this.checkAchievements();
}
private checkAchievements(): void {
for (const [id, achievement] of Object.entries(ACHIEVEMENTS)) {
if (!this.unlocked.has(id) && achievement.trigger(this.getState())) {
this.unlocked.add(id);
this.notifyUnlock(achievement);
// Check for Golden Goose after each unlock
if (id !== 'golden-goose') {
this.checkAchievements(); // Recursive check for meta achievement
}
}
}
}
private notifyUnlock(achievement: Achievement): void {
for (const listener of this.listeners) {
listener(achievement);
}
}
}
The recursive checkAchievements() call handles the Golden Goose edge case: when you unlock your 11th achievement, it immediately checks again and unlocks the 12th.
The Manual Problem
After all the balance changes and achievements, the game had grown… complex. Six zones, five goals, twelve achievements, gosling personalities, NPC types that react differently to honking, territory claiming mechanics, day/night cycles.
Players were confused.
The solution was embarrassing but necessary: a 1077-line manual.
# CANADA GOOSE SIMULATOR
## User Manual v1.0
### Table of Contents
1. Introduction
2. Game Objectives
3. Your Goose
4. Commands Reference
5. Zones
6. NPCs and Interactions
7. Items
8. Goslings
9. Territory System
10. Achievements
11. Strategy Guide
12. Quick Reference Card
### 1. Introduction
You are a Canada Goose. Your mission, should you choose to accept it,
is to cause mild chaos across six zones over the course of 20 days.
This is not a difficult mission. You are a goose. Chaos is your nature.
### 2. Game Objectives
You may achieve victory by completing ANY ONE of the following goals:
| Goal | Target | Description |
|------|--------|-------------|
| Agent of Chaos | 50 NPCs | Disturb fifty humans or animals |
| Food Hoarder | 30 items | Collect thirty food items |
| Nest Builder | 15 items | Gather fifteen nesting materials |
| Gosling Guardian | 3 goslings | Raise three goslings to adulthood |
| Territorial Tyrant | 6 zones | Claim all six territories |
...
### 12. Quick Reference Card
MOVEMENT: travel <zone>, fly <zone>
ACTIONS: honk [target], peck <item>, steal <npc>, rest
STATUS: look, inventory, status, goals, map
GOSLINGS: feed <name>, check nest
OTHER: help, quit, save, load
Writing the manual took longer than several of the game’s features. But it worked—players who read even the quick reference card had dramatically better experiences.
Lessons Learned
-
Unit tests verify mechanics, not fun — My 79 tests proved the code worked. They said nothing about whether the game was enjoyable or even completable.
-
Watch people play — I thought I understood my game until I watched someone spend 10 minutes trying to figure out how to pick up an item. (It’s
peck <item>. Obvious in retrospect, but only in retrospect.) -
Math your goals — If a goal requires N actions and players have M time, and M < N, the goal is impossible. Do the arithmetic before shipping.
-
Reduce friction on core verbs — Honking is the core fantasy. Making it expensive was sabotaging my own game.
-
Achievements as tutorials — Hidden achievements are fun, but milestone achievements teach. Both have value.
-
Sometimes you need a manual — Modern game design says “no manuals, discoverable UI.” But text adventures are dense. The manual exists because players asked for it.
-
The trophy was worth it — Two hours to build a decoration system for one trophy. Watching someone’s face when the Golden Goose appears? Priceless.
The Current State
Canada Goose Simulator shipped with:
- 5 victory conditions (all achievable)
- 12 achievements (including 1 hidden, 1 meta)
- 79 unit tests (mechanics) + manual playtesting (fun)
- 1077-line manual (with quick reference)
- 1 golden trophy (for the dedicated)
It’s still a silly game about being a goose. But now it’s a silly game that people can actually finish.
Dial 555-4667 (555-GOOS) and cause some chaos. The manual’s in the help system if you need it.
Phone: 555-4667 (555-GOOS)
See also: Deep Dive: Building a Canada Goose Simulator — the first part, covering core mechanics and audio.