clibuddy 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +60 -0
  3. package/dist/adventure/adventureUI.d.ts +24 -0
  4. package/dist/adventure/adventureUI.js +290 -0
  5. package/dist/adventure/adventures.d.ts +4 -0
  6. package/dist/adventure/adventures.js +206 -0
  7. package/dist/adventure/biomes.d.ts +30 -0
  8. package/dist/adventure/biomes.js +80 -0
  9. package/dist/adventure/combat/combat.d.ts +14 -0
  10. package/dist/adventure/combat/combat.js +638 -0
  11. package/dist/adventure/combat/combatUI.d.ts +5 -0
  12. package/dist/adventure/combat/combatUI.js +116 -0
  13. package/dist/adventure/combat/conditions.d.ts +20 -0
  14. package/dist/adventure/combat/conditions.js +111 -0
  15. package/dist/adventure/combat/enemies.d.ts +4 -0
  16. package/dist/adventure/combat/enemies.js +430 -0
  17. package/dist/adventure/combat/gear.d.ts +3 -0
  18. package/dist/adventure/combat/gear.js +199 -0
  19. package/dist/adventure/combat/skills.d.ts +6 -0
  20. package/dist/adventure/combat/skills.js +197 -0
  21. package/dist/adventure/combat.d.ts +31 -0
  22. package/dist/adventure/combat.js +732 -0
  23. package/dist/adventure/combatUI.d.ts +5 -0
  24. package/dist/adventure/combatUI.js +116 -0
  25. package/dist/adventure/endless.d.ts +18 -0
  26. package/dist/adventure/endless.js +154 -0
  27. package/dist/adventure/enemies.d.ts +4 -0
  28. package/dist/adventure/enemies.js +320 -0
  29. package/dist/adventure/engine.d.ts +20 -0
  30. package/dist/adventure/engine.js +137 -0
  31. package/dist/adventure/gear.d.ts +3 -0
  32. package/dist/adventure/gear.js +149 -0
  33. package/dist/adventure/generation/biomes.d.ts +30 -0
  34. package/dist/adventure/generation/biomes.js +102 -0
  35. package/dist/adventure/generation/endless.d.ts +18 -0
  36. package/dist/adventure/generation/endless.js +154 -0
  37. package/dist/adventure/generation/generator.d.ts +9 -0
  38. package/dist/adventure/generation/generator.js +245 -0
  39. package/dist/adventure/generation/templates.d.ts +25 -0
  40. package/dist/adventure/generation/templates.js +228 -0
  41. package/dist/adventure/generator.d.ts +9 -0
  42. package/dist/adventure/generator.js +245 -0
  43. package/dist/adventure/skills.d.ts +6 -0
  44. package/dist/adventure/skills.js +197 -0
  45. package/dist/adventure/templates.d.ts +25 -0
  46. package/dist/adventure/templates.js +228 -0
  47. package/dist/adventure/types.d.ts +236 -0
  48. package/dist/adventure/types.js +97 -0
  49. package/dist/app/state.d.ts +49 -0
  50. package/dist/app/state.js +51 -0
  51. package/dist/buddy/activities.d.ts +16 -0
  52. package/dist/buddy/activities.js +90 -0
  53. package/dist/buddy/decay.d.ts +3 -0
  54. package/dist/buddy/decay.js +45 -0
  55. package/dist/buddy/leveling.d.ts +11 -0
  56. package/dist/buddy/leveling.js +25 -0
  57. package/dist/buddy/roll.d.ts +4 -0
  58. package/dist/buddy/roll.js +61 -0
  59. package/dist/buddy/species.d.ts +4 -0
  60. package/dist/buddy/species.js +592 -0
  61. package/dist/buddy/titles.d.ts +17 -0
  62. package/dist/buddy/titles.js +89 -0
  63. package/dist/buddy/types.d.ts +92 -0
  64. package/dist/buddy/types.js +21 -0
  65. package/dist/commands/actions.d.ts +2 -0
  66. package/dist/commands/actions.js +141 -0
  67. package/dist/commands/admin.d.ts +2 -0
  68. package/dist/commands/admin.js +202 -0
  69. package/dist/commands/registry.d.ts +25 -0
  70. package/dist/commands/registry.js +31 -0
  71. package/dist/commands/social.d.ts +2 -0
  72. package/dist/commands/social.js +92 -0
  73. package/dist/dialogue/engine.d.ts +7 -0
  74. package/dist/dialogue/engine.js +68 -0
  75. package/dist/dialogue/lines.d.ts +26 -0
  76. package/dist/dialogue/lines.js +294 -0
  77. package/dist/events/engine.d.ts +20 -0
  78. package/dist/events/engine.js +51 -0
  79. package/dist/events/events.d.ts +13 -0
  80. package/dist/events/events.js +149 -0
  81. package/dist/index.d.ts +10 -0
  82. package/dist/index.js +1665 -0
  83. package/dist/inventory/finding.d.ts +11 -0
  84. package/dist/inventory/finding.js +99 -0
  85. package/dist/inventory/items.d.ts +31 -0
  86. package/dist/inventory/items.js +63 -0
  87. package/dist/minigames/copycat.d.ts +2 -0
  88. package/dist/minigames/copycat.js +153 -0
  89. package/dist/minigames/fetch.d.ts +2 -0
  90. package/dist/minigames/fetch.js +179 -0
  91. package/dist/minigames/moodmatch.d.ts +2 -0
  92. package/dist/minigames/moodmatch.js +144 -0
  93. package/dist/minigames/quickpaws.d.ts +2 -0
  94. package/dist/minigames/quickpaws.js +142 -0
  95. package/dist/minigames/registry.d.ts +5 -0
  96. package/dist/minigames/registry.js +16 -0
  97. package/dist/minigames/rpsplus.d.ts +2 -0
  98. package/dist/minigames/rpsplus.js +168 -0
  99. package/dist/minigames/treasurehunt.d.ts +2 -0
  100. package/dist/minigames/treasurehunt.js +146 -0
  101. package/dist/minigames/types.d.ts +30 -0
  102. package/dist/minigames/types.js +69 -0
  103. package/dist/rendering/commandPalette.d.ts +16 -0
  104. package/dist/rendering/commandPalette.js +77 -0
  105. package/dist/rendering/display.d.ts +9 -0
  106. package/dist/rendering/display.js +231 -0
  107. package/dist/rendering/inventoryUI.d.ts +14 -0
  108. package/dist/rendering/inventoryUI.js +99 -0
  109. package/dist/rendering/items.d.ts +7 -0
  110. package/dist/rendering/items.js +34 -0
  111. package/dist/rendering/listUtils.d.ts +3 -0
  112. package/dist/rendering/listUtils.js +24 -0
  113. package/dist/rendering/minigameUI.d.ts +11 -0
  114. package/dist/rendering/minigameUI.js +37 -0
  115. package/dist/rendering/overlayUI.d.ts +24 -0
  116. package/dist/rendering/overlayUI.js +184 -0
  117. package/dist/rendering/scene.d.ts +8 -0
  118. package/dist/rendering/scene.js +87 -0
  119. package/dist/rendering/screen.d.ts +43 -0
  120. package/dist/rendering/screen.js +97 -0
  121. package/dist/sound/sound.d.ts +11 -0
  122. package/dist/sound/sound.js +55 -0
  123. package/dist/state/save.d.ts +5 -0
  124. package/dist/state/save.js +100 -0
  125. package/dist/state/settings.d.ts +7 -0
  126. package/dist/state/settings.js +81 -0
  127. package/dist/story/mainStory.d.ts +4 -0
  128. package/dist/story/mainStory.js +3111 -0
  129. package/dist/story/npcs.d.ts +17 -0
  130. package/dist/story/npcs.js +137 -0
  131. package/dist/story/progress.d.ts +26 -0
  132. package/dist/story/progress.js +168 -0
  133. package/dist/story/seasonal.d.ts +6 -0
  134. package/dist/story/seasonal.js +96 -0
  135. package/dist/story/shop.d.ts +7 -0
  136. package/dist/story/shop.js +26 -0
  137. package/dist/story/sideQuests.d.ts +4 -0
  138. package/dist/story/sideQuests.js +151 -0
  139. package/dist/story/types.d.ts +61 -0
  140. package/dist/story/types.js +36 -0
  141. package/dist/updates.d.ts +23 -0
  142. package/dist/updates.js +142 -0
  143. package/package.json +53 -0
@@ -0,0 +1,245 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateExpedition = generateExpedition;
4
+ const types_1 = require("../types");
5
+ const biomes_1 = require("./biomes");
6
+ const enemies_1 = require("../combat/enemies");
7
+ const templates_1 = require("./templates");
8
+ function pick(arr) {
9
+ return arr[Math.floor(Math.random() * arr.length)];
10
+ }
11
+ let idCounter = 0;
12
+ function nextId(prefix) {
13
+ return `${prefix}_${++idCounter}`;
14
+ }
15
+ // ─── Difficulty Scaling ──────────────────────────────────────
16
+ function getRoomCount(difficulty) {
17
+ if (difficulty <= 2)
18
+ return 3 + Math.floor(Math.random() * 2); // 3-4
19
+ if (difficulty <= 4)
20
+ return 4 + Math.floor(Math.random() * 2); // 4-5
21
+ if (difficulty <= 6)
22
+ return 5 + Math.floor(Math.random() * 2); // 5-6
23
+ if (difficulty <= 8)
24
+ return 6 + Math.floor(Math.random() * 2); // 6-7
25
+ return 7 + Math.floor(Math.random() * 2); // 7-8
26
+ }
27
+ function getEnemyTier(difficulty) {
28
+ if (difficulty <= 2)
29
+ return "easy";
30
+ if (difficulty <= 5)
31
+ return "medium";
32
+ return "hard";
33
+ }
34
+ function hasBoss(difficulty) {
35
+ return difficulty >= 5;
36
+ }
37
+ function getStatMultiplier(difficulty) {
38
+ return 1 + difficulty * 0.15;
39
+ }
40
+ function getLootTier(difficulty) {
41
+ if (difficulty <= 2)
42
+ return pick(["common", "uncommon"]);
43
+ if (difficulty <= 5)
44
+ return pick(["uncommon", "rare"]);
45
+ if (difficulty <= 8)
46
+ return pick(["rare", "epic"]);
47
+ return "epic";
48
+ }
49
+ function getEnergyCost(difficulty) {
50
+ return 10 + difficulty * 3;
51
+ }
52
+ function getHungerCost(difficulty) {
53
+ return 5 + difficulty * 2;
54
+ }
55
+ function getLevelRequired(difficulty) {
56
+ return Math.max(1, (difficulty - 1) * 2);
57
+ }
58
+ // ─── Scaled Enemy Creation ───────────────────────────────────
59
+ function pickScaledEnemy(biome, difficulty) {
60
+ const tier = getEnemyTier(difficulty);
61
+ const pool = biome.enemies[tier];
62
+ if (pool.length === 0)
63
+ return biome.enemies.easy[0]; // fallback
64
+ return pick(pool);
65
+ }
66
+ function pickBoss(biome) {
67
+ return pick(biome.enemies.boss);
68
+ }
69
+ // ─── Room Type Distribution ──────────────────────────────────
70
+ function pickRoomTypes(count, hasBossRoom) {
71
+ // First room is always narrative, last is boss (if applicable) or combat
72
+ const types = ["narrative"];
73
+ const middleCount = count - (hasBossRoom ? 2 : 1); // subtract entry + boss
74
+ const pool = [];
75
+ // Ensure at least one combat
76
+ pool.push("combat");
77
+ // Fill rest with weighted random
78
+ for (let i = 1; i < middleCount; i++) {
79
+ const roll = Math.random();
80
+ if (roll < 0.35)
81
+ pool.push("combat");
82
+ else if (roll < 0.55)
83
+ pool.push("narrative");
84
+ else if (roll < 0.70)
85
+ pool.push("treasure");
86
+ else if (roll < 0.85)
87
+ pool.push("event");
88
+ else
89
+ pool.push("rest");
90
+ }
91
+ // Shuffle middle rooms
92
+ for (let i = pool.length - 1; i > 0; i--) {
93
+ const j = Math.floor(Math.random() * (i + 1));
94
+ [pool[i], pool[j]] = [pool[j], pool[i]];
95
+ }
96
+ types.push(...pool);
97
+ if (hasBossRoom) {
98
+ types.push("boss");
99
+ }
100
+ return types;
101
+ }
102
+ // ─── Main Generator ──────────────────────────────────────────
103
+ function generateExpedition(config) {
104
+ idCounter = 0;
105
+ const biome = (0, biomes_1.getBiome)(config.biomeId);
106
+ const { difficulty, buddyState } = config;
107
+ const roomCount = getRoomCount(difficulty);
108
+ const bossRoom = hasBoss(difficulty);
109
+ const roomTypes = pickRoomTypes(roomCount, bossRoom);
110
+ const rooms = [];
111
+ // Build rooms
112
+ for (let i = 0; i < roomTypes.length; i++) {
113
+ const type = roomTypes[i];
114
+ const roomId = nextId(type);
115
+ const isLast = i === roomTypes.length - 1;
116
+ // Next room ID (linear chain for now, narrative rooms get branching)
117
+ const nextRoomId = isLast ? undefined : undefined; // will be wired below
118
+ const room = buildRoom(type, roomId, biome, difficulty, buddyState);
119
+ rooms.push(room);
120
+ }
121
+ // Wire linear next-room chain
122
+ for (let i = 0; i < rooms.length - 1; i++) {
123
+ if (rooms[i].type === "narrative" && !rooms[i].choices) {
124
+ rooms[i].nextRoomId = rooms[i + 1].id;
125
+ }
126
+ else if (rooms[i].type !== "narrative") {
127
+ rooms[i].nextRoomId = rooms[i + 1].id;
128
+ }
129
+ }
130
+ // First room (narrative) gets branching choices
131
+ if (rooms.length >= 3 && rooms[0].type === "narrative") {
132
+ // Entry branches to rooms[1] and rooms[2], both converge later
133
+ const entryRoom = rooms[0];
134
+ const pathA = rooms[1];
135
+ const pathB = rooms.length > 2 ? rooms[2] : rooms[1];
136
+ const labels = (0, templates_1.generateChoiceLabels)(biome);
137
+ entryRoom.choices = [
138
+ { label: labels[0], nextRoomId: pathA.id },
139
+ { label: labels[1], nextRoomId: pathB.id },
140
+ ];
141
+ entryRoom.nextRoomId = undefined; // choices handle navigation
142
+ // Both paths converge at room[3] (or the next available room after the two paths)
143
+ if (rooms.length > 3) {
144
+ pathA.nextRoomId = rooms[3].id;
145
+ pathB.nextRoomId = rooms[3].id;
146
+ }
147
+ }
148
+ // Optionally add hidden room for matching species
149
+ if (Math.random() < 0.4 && biome.comfortSpecies.includes(buddyState.speciesId)) {
150
+ const hiddenId = nextId("hidden");
151
+ const convergeTo = rooms.length > 3 ? rooms[rooms.length - 2].id : rooms[rooms.length - 1].id;
152
+ const hiddenRoom = {
153
+ id: hiddenId,
154
+ type: "treasure",
155
+ title: "Secret Chamber",
156
+ text: (0, templates_1.generateHiddenRoomText)(biome, buddyState.speciesId),
157
+ buddyLine: "I knew I sensed something special here!",
158
+ nextRoomId: convergeTo,
159
+ lootPool: biome.loot.rare.concat(biome.loot.epic),
160
+ condition: { type: "species", value: buddyState.speciesId },
161
+ };
162
+ rooms.push(hiddenRoom);
163
+ // Add hidden room as a third choice on entry
164
+ if (rooms[0].choices) {
165
+ const speciesName = buddyState.speciesId.charAt(0).toUpperCase() + buddyState.speciesId.slice(1);
166
+ rooms[0].choices.push({
167
+ label: `[${speciesName}] Sniff out a hidden path`,
168
+ nextRoomId: hiddenId,
169
+ });
170
+ }
171
+ }
172
+ const completionXp = Math.round(15 * difficulty * roomCount * 0.3);
173
+ return {
174
+ id: `expedition_${Date.now()}`,
175
+ name: `${biome.name} Expedition`,
176
+ description: `Difficulty ${difficulty} — ${roomCount} rooms`,
177
+ difficulty,
178
+ levelRequired: getLevelRequired(difficulty),
179
+ energyCost: getEnergyCost(difficulty),
180
+ hungerCost: getHungerCost(difficulty),
181
+ rooms,
182
+ roomMap: (0, types_1.buildRoomMap)(rooms),
183
+ startRoomId: rooms[0].id,
184
+ completionXp,
185
+ };
186
+ }
187
+ // ─── Room Builder ────────────────────────────────────────────
188
+ function buildRoom(type, id, biome, difficulty, buddyState) {
189
+ const buddyLine = (0, templates_1.generateBuddyLine)(buddyState.speciesId, biome);
190
+ switch (type) {
191
+ case "narrative":
192
+ return {
193
+ id, type, title: (0, templates_1.generateNarrativeTitle)(biome),
194
+ text: (0, templates_1.generateNarrativeText)(biome), buddyLine,
195
+ // choices wired later
196
+ };
197
+ case "combat": {
198
+ const enemyId = pickScaledEnemy(biome, difficulty);
199
+ const enemy = enemies_1.ENEMIES[enemyId];
200
+ return {
201
+ id, type, title: (0, templates_1.generateCombatTitle)(biome),
202
+ text: (0, templates_1.generateCombatText)(biome, enemy?.name ?? "creature"), buddyLine,
203
+ enemyId,
204
+ };
205
+ }
206
+ case "boss": {
207
+ const bossId = pickBoss(biome);
208
+ const boss = enemies_1.ENEMIES[bossId];
209
+ return {
210
+ id, type, title: `${boss?.name ?? "Boss"}'s Lair`,
211
+ text: (0, templates_1.generateBossText)(biome, boss?.name ?? "The Boss"), buddyLine: "Here it comes... STAY STRONG!",
212
+ enemyId: bossId,
213
+ };
214
+ }
215
+ case "treasure": {
216
+ const tier = getLootTier(difficulty);
217
+ return {
218
+ id, type, title: "Hidden Stash",
219
+ text: (0, templates_1.generateTreasureText)(biome), buddyLine,
220
+ lootPool: biome.loot[tier],
221
+ };
222
+ }
223
+ case "rest":
224
+ return {
225
+ id, type, title: "Safe Haven",
226
+ text: (0, templates_1.generateRestText)(biome), buddyLine: "Can we rest here? Just for a moment?",
227
+ healAmount: 15 + difficulty * 2,
228
+ };
229
+ case "event": {
230
+ const event = (0, templates_1.generateEvent)(biome);
231
+ return {
232
+ id, type, title: "Unexpected Encounter",
233
+ text: event.text, buddyLine,
234
+ eventChoices: event.choices.map((c) => ({
235
+ label: c.label,
236
+ outcome: c.outcome,
237
+ effect: c.effect ? { itemGain: c.effect.itemGain, hp: c.effect.hp, happiness: c.effect.happiness } : undefined,
238
+ })),
239
+ };
240
+ }
241
+ default:
242
+ return { id, type: "narrative", title: "???", text: ["Something went wrong."], buddyLine: "Uh oh." };
243
+ }
244
+ }
245
+ //# sourceMappingURL=generator.js.map
@@ -0,0 +1,25 @@
1
+ import { Biome } from "./biomes";
2
+ export declare function generateNarrativeText(biome: Biome): string[];
3
+ export declare function generateNarrativeTitle(biome: Biome): string;
4
+ export declare function generateChoiceLabels(biome: Biome): string[];
5
+ export declare function generateCombatText(biome: Biome, enemyName: string): string[];
6
+ export declare function generateCombatTitle(biome: Biome): string;
7
+ export declare function generateTreasureText(biome: Biome): string[];
8
+ export declare function generateRestText(biome: Biome): string[];
9
+ export interface EventTemplate {
10
+ text: string[];
11
+ choices: {
12
+ label: string;
13
+ outcome: string;
14
+ effect?: {
15
+ itemGain?: string;
16
+ hp?: number;
17
+ happiness?: number;
18
+ };
19
+ }[];
20
+ }
21
+ export declare function generateEvent(biome: Biome): EventTemplate;
22
+ export declare function generateBuddyLine(speciesId: string, biome: Biome): string;
23
+ export declare function generateBossText(biome: Biome, bossName: string): string[];
24
+ export declare function generateHiddenRoomText(biome: Biome, speciesId: string): string[];
25
+ //# sourceMappingURL=templates.d.ts.map
@@ -0,0 +1,228 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateNarrativeText = generateNarrativeText;
4
+ exports.generateNarrativeTitle = generateNarrativeTitle;
5
+ exports.generateChoiceLabels = generateChoiceLabels;
6
+ exports.generateCombatText = generateCombatText;
7
+ exports.generateCombatTitle = generateCombatTitle;
8
+ exports.generateTreasureText = generateTreasureText;
9
+ exports.generateRestText = generateRestText;
10
+ exports.generateEvent = generateEvent;
11
+ exports.generateBuddyLine = generateBuddyLine;
12
+ exports.generateBossText = generateBossText;
13
+ exports.generateHiddenRoomText = generateHiddenRoomText;
14
+ function pick(arr) {
15
+ return arr[Math.floor(Math.random() * arr.length)];
16
+ }
17
+ // ─── Narrative Room Templates ────────────────────────────────
18
+ function generateNarrativeText(biome) {
19
+ const templates = [
20
+ [`The ${pick(biome.adjectives)} ${pick(biome.nouns)} stretches before you.`, `Two paths diverge ahead — ${pick(biome.directions)} and ${pick(biome.directions)}.`],
21
+ [`You reach a ${pick(biome.landmarks)}. The air feels ${pick(biome.adjectives)}.`, `Something rustles in ${pick(biome.hidingSpots)}.`],
22
+ [`The path narrows as you enter a ${pick(biome.adjectives)} ${pick(biome.nouns)}.`, `You can go ${pick(biome.directions)} or ${pick(biome.directions)}.`],
23
+ [`A ${pick(biome.landmarks)} marks a crossroads.`, `The ${pick(biome.nouns)} feels ${pick(biome.adjectives)} here.`],
24
+ [`Your footsteps echo in the ${pick(biome.adjectives)} ${pick(biome.nouns)}.`, `Ahead, the path splits around a ${pick(biome.landmarks)}.`],
25
+ [`The ${pick(biome.nouns)} opens up to reveal a ${pick(biome.landmarks)}.`, `The air is ${pick(biome.adjectives)}. Which way?`],
26
+ [`Deeper into the ${pick(biome.nouns)}, you hear sounds from ${pick(biome.hidingSpots)}.`, `The path branches — ${pick(biome.directions)} looks safe, ${pick(biome.directions)} looks... interesting.`],
27
+ [`You stand at the edge of a ${pick(biome.adjectives)} ${pick(biome.nouns)}.`, `A ${pick(biome.landmarks)} marks two possible routes.`],
28
+ [`Shadows dance across a ${pick(biome.landmarks)}.`, `The ${pick(biome.nouns)} seems to whisper. Two paths await.`],
29
+ ];
30
+ return pick(templates);
31
+ }
32
+ function generateNarrativeTitle(biome) {
33
+ const titles = [
34
+ `The ${capitalize(pick(biome.adjectives))} ${capitalize(pick(biome.nouns))}`,
35
+ `${capitalize(pick(biome.landmarks))}`,
36
+ `A Fork in the ${capitalize(pick(biome.nouns))}`,
37
+ `The ${capitalize(pick(biome.adjectives))} Path`,
38
+ ];
39
+ return pick(titles);
40
+ }
41
+ function generateChoiceLabels(biome) {
42
+ return [
43
+ `Go ${pick(biome.directions)}`,
44
+ `Head ${pick(biome.directions)}`,
45
+ ];
46
+ }
47
+ // ─── Combat Room Templates ───────────────────────────────────
48
+ function generateCombatText(biome, enemyName) {
49
+ const templates = [
50
+ [`A ${enemyName} leaps out from ${pick(biome.hidingSpots)}!`],
51
+ [`You stumble into a ${pick(biome.adjectives)} clearing. A ${enemyName} blocks the way!`],
52
+ [`Something moves in ${pick(biome.hidingSpots)}... it's a ${enemyName}!`],
53
+ [`The ${pick(biome.nouns)} grows ${pick(biome.adjectives)}. A ${enemyName} appears!`],
54
+ ];
55
+ return pick(templates);
56
+ }
57
+ function generateCombatTitle(biome) {
58
+ return `${capitalize(pick(biome.adjectives))} Encounter`;
59
+ }
60
+ // ─── Treasure Room Templates ─────────────────────────────────
61
+ function generateTreasureText(biome) {
62
+ const templates = [
63
+ [`Behind a ${pick(biome.landmarks)}, something glints...`],
64
+ [`Your buddy digs near ${pick(biome.hidingSpots)} and finds something!`],
65
+ [`Hidden in the ${pick(biome.adjectives)} ${pick(biome.nouns)}, a stash awaits!`],
66
+ [`A ${pick(biome.landmarks)} conceals a small cache of treasure.`],
67
+ ];
68
+ return pick(templates);
69
+ }
70
+ // ─── Rest Room Templates ─────────────────────────────────────
71
+ function generateRestText(biome) {
72
+ const templates = [
73
+ [`A peaceful spot near a ${pick(biome.landmarks)}. The ${pick(biome.nouns)} is quiet here.`],
74
+ [`A sheltered ${pick(biome.nouns)} offers respite. You could rest here...`],
75
+ [`The ${pick(biome.adjectives)} atmosphere fades. This feels safe.`],
76
+ ];
77
+ return pick(templates);
78
+ }
79
+ function generateEvent(biome) {
80
+ const events = [
81
+ {
82
+ text: [`A small creature peeks out from ${pick(biome.hidingSpots)}.`, `It seems to want to trade...`],
83
+ choices: [
84
+ { label: "Offer a Berry", outcome: "It hands you something shiny in return!", effect: { itemGain: pick(biome.loot.uncommon) } },
85
+ { label: "Wave and move on", outcome: "The creature waves goodbye." },
86
+ ],
87
+ },
88
+ {
89
+ text: [`You find a strange ${pick(biome.adjectives)} chest near a ${pick(biome.landmarks)}.`, `It could be a trap... or treasure.`],
90
+ choices: [
91
+ { label: "Open it carefully", outcome: "Inside — a useful item!", effect: { itemGain: pick(biome.loot.rare) } },
92
+ { label: "Leave it alone", outcome: "Better safe than sorry. You move on." },
93
+ { label: "Kick it open", outcome: "A puff of gas! You feel woozy.", effect: { hp: -10 } },
94
+ ],
95
+ },
96
+ {
97
+ text: [`A warm glow emanates from a ${pick(biome.landmarks)}.`, `It feels... magical.`],
98
+ choices: [
99
+ { label: "Touch the glow", outcome: "A warm feeling washes over you!", effect: { hp: 15, happiness: 5 } },
100
+ { label: "Back away cautiously", outcome: "The glow fades. Nothing happens." },
101
+ ],
102
+ },
103
+ {
104
+ text: [`A weary traveler rests by the path.`, `"Care to share some food? I'll make it worth your while."`],
105
+ choices: [
106
+ { label: "Share some food", outcome: "\"Thank you! Take this.\"", effect: { itemGain: pick(biome.loot.uncommon) } },
107
+ { label: "Apologize and decline", outcome: "The traveler nods and rests." },
108
+ ],
109
+ },
110
+ {
111
+ text: [`A wise-looking creature sits near a ${pick(biome.landmarks)}.`, `"Answer my riddle and I'll reward you!"`],
112
+ choices: [
113
+ { label: "Accept the riddle", outcome: "You answer wisely! A reward appears.", effect: { itemGain: pick(biome.loot.rare) } },
114
+ { label: "Politely refuse", outcome: "The creature nods knowingly." },
115
+ ],
116
+ },
117
+ {
118
+ text: [`A small animal is trapped under a ${pick(biome.adjectives)} rock near ${pick(biome.hidingSpots)}.`, `It whimpers for help...`],
119
+ choices: [
120
+ { label: "Help free it", outcome: "It scurries free! It drops something as thanks.", effect: { itemGain: pick(biome.loot.uncommon), happiness: 5 } },
121
+ { label: "It might be a trap...", outcome: "You move on cautiously." },
122
+ ],
123
+ },
124
+ {
125
+ text: [`A glowing rune is etched into a ${pick(biome.landmarks)}.`, `It pulses with ${pick(biome.adjectives)} energy.`],
126
+ choices: [
127
+ { label: "Touch the rune", outcome: "Power surges through you!", effect: { hp: 20 } },
128
+ { label: "Study it from afar", outcome: "You learn something, but feel nothing change." },
129
+ { label: "Smash it", outcome: "The rune explodes! Ow!", effect: { hp: -15 } },
130
+ ],
131
+ },
132
+ {
133
+ text: [`Someone left a campfire burning near ${pick(biome.hidingSpots)}.`, `There's a pack nearby...`],
134
+ choices: [
135
+ { label: "Warm up and rest", outcome: "The warmth is soothing.", effect: { hp: 10, happiness: 5 } },
136
+ { label: "Search the pack", outcome: "You find something useful!", effect: { itemGain: pick(biome.loot.uncommon) } },
137
+ { label: "Leave it — not yours", outcome: "You move on with a clear conscience." },
138
+ ],
139
+ },
140
+ ];
141
+ return pick(events);
142
+ }
143
+ // ─── Buddy Dialogue Templates ────────────────────────────────
144
+ const SPECIES_ADVENTURE_LINES = {
145
+ rabbit: [
146
+ "My ears are twitching... something's nearby!", "I can hop right over this!",
147
+ "This place smells like carrots... no wait, danger.", "Want me to scout ahead? I'm fast!",
148
+ "*nose wiggles* I sense trouble...", "I could dig us an escape route!",
149
+ "My lucky foot says... this way!",
150
+ ],
151
+ cat: [
152
+ "I sense prey ahead.", "*sniffs the air* Interesting...", "I'll lead. Stay behind me.",
153
+ "*tail flicks* Something moved.", "I've hunted worse than this.",
154
+ "Do NOT touch me right now. I'm focused.", "This reminds me of my afternoon prowl.",
155
+ ],
156
+ frog: [
157
+ "Ribbit! I mean... let's go!", "The moisture here is nice.", "*tongue flick* Just checking.",
158
+ "I can sense vibrations... something big!", "Hop hop hop! Keep up!",
159
+ "If it gets wet, that's MY territory.", "My skin is tingling... that's either danger or humidity.",
160
+ ],
161
+ owl: [
162
+ "I can see far ahead from here.", "Hoo goes there?", "Knowledge awaits in every corner.",
163
+ "I've read about places like this...", "*head rotates* Scanning for threats.",
164
+ "Logically, the left path is safer.", "My wisdom says proceed with caution.",
165
+ ],
166
+ fox: [
167
+ "I smell adventure!", "My instincts say... this way!", "Stay sharp, I'll sniff out danger.",
168
+ "There's a shortcut here, I can feel it!", "Trust the nose!",
169
+ "*tail swish* I've got a plan.", "Foxes always find the best paths.",
170
+ ],
171
+ phoenix: [
172
+ "My flames light the way!", "*feathers glow* I feel strong here.", "Even if we fall, we rise again!",
173
+ "The fire within me burns brighter here!", "Nothing can stop eternal flame!",
174
+ "I sense ancient power nearby...", "*sparks fly from wings* Let's GO!",
175
+ ],
176
+ dragon: [
177
+ "I smell treasure nearby!", "*tiny roar* I'm not scared!", "My scales will protect us!",
178
+ "Is that gold? I think I smell gold!", "*puffs smoke confidently*",
179
+ "I'm basically a fortress. With legs.", "Anything that glows is mine. That's the rule.",
180
+ ],
181
+ };
182
+ const GENERIC_BUDDY_LINES = [
183
+ "Which way should we go?",
184
+ "This looks interesting...",
185
+ "Stay close!",
186
+ "I've got a good feeling about this!",
187
+ "Let's be careful here...",
188
+ "Ooh, what's over there?",
189
+ "I wonder what we'll find!",
190
+ "This is exciting!",
191
+ "I trust your instincts!",
192
+ "Lead the way, I've got your back!",
193
+ "Something tells me this will be worth it.",
194
+ ];
195
+ function generateBuddyLine(speciesId, biome) {
196
+ // 50% species-specific, 50% generic
197
+ if (Math.random() < 0.5) {
198
+ const speciesLines = SPECIES_ADVENTURE_LINES[speciesId];
199
+ if (speciesLines)
200
+ return pick(speciesLines);
201
+ }
202
+ // Comfort bonus line
203
+ if (biome.comfortSpecies.includes(speciesId) && Math.random() < 0.3) {
204
+ return "I feel right at home here!";
205
+ }
206
+ return pick(GENERIC_BUDDY_LINES);
207
+ }
208
+ // ─── Boss Room Templates ─────────────────────────────────────
209
+ function generateBossText(biome, bossName) {
210
+ const templates = [
211
+ [`The ${pick(biome.nouns)} trembles. Something massive approaches...`, `${bossName} emerges!`],
212
+ [`A deafening sound echoes through the ${pick(biome.nouns)}.`, `${bossName} blocks your path — there's no going back!`],
213
+ [`The air grows heavy. ${bossName} rises from ${pick(biome.hidingSpots)}!`],
214
+ ];
215
+ return pick(templates);
216
+ }
217
+ // ─── Hidden Room Templates ───────────────────────────────────
218
+ function generateHiddenRoomText(biome, speciesId) {
219
+ const speciesName = speciesId.charAt(0).toUpperCase() + speciesId.slice(1);
220
+ return [
221
+ `Your ${speciesName} senses notice something others would miss...`,
222
+ `A hidden passage reveals itself in the ${pick(biome.adjectives)} ${pick(biome.nouns)}!`,
223
+ ];
224
+ }
225
+ function capitalize(s) {
226
+ return s.charAt(0).toUpperCase() + s.slice(1);
227
+ }
228
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1,9 @@
1
+ import { BuddyState } from "../buddy/types";
2
+ import { AdventureDef } from "./types";
3
+ export interface ExpeditionConfig {
4
+ difficulty: number;
5
+ biomeId: string;
6
+ buddyState: BuddyState;
7
+ }
8
+ export declare function generateExpedition(config: ExpeditionConfig): AdventureDef;
9
+ //# sourceMappingURL=generator.d.ts.map