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,5 @@
1
+ import { BuddyState } from "../buddy/types";
2
+ import { CombatState } from "./types";
3
+ export declare function renderCombat(combat: CombatState, state: BuddyState, adventureName: string): string;
4
+ export declare function renderSkillMenu(combat: CombatState, state: BuddyState): string;
5
+ //# sourceMappingURL=combatUI.d.ts.map
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderCombat = renderCombat;
4
+ exports.renderSkillMenu = renderSkillMenu;
5
+ const types_1 = require("../buddy/types");
6
+ const species_1 = require("../buddy/species");
7
+ const types_2 = require("./types");
8
+ const lines_1 = require("../dialogue/lines");
9
+ const skills_1 = require("./skills");
10
+ const screen_1 = require("../rendering/screen");
11
+ const CONDITION_ICONS = {
12
+ burn: "🔥", poison: "☠", freeze: "❄", stun: "⚡", charm: "💕",
13
+ blind: "👁", regen: "💚", shield: "🛡", buff: "↑", debuff: "↓",
14
+ };
15
+ function formatConditions(conditions) {
16
+ if (conditions.length === 0)
17
+ return "";
18
+ const icons = conditions.map((c) => CONDITION_ICONS[c.type] ?? c.type).join(" ");
19
+ return ` ${icons}`;
20
+ }
21
+ function hpBar(current, max, width = 15) {
22
+ const filled = Math.max(0, Math.round((current / max) * width));
23
+ const empty = width - filled;
24
+ const pct = Math.round((current / max) * 100);
25
+ let color;
26
+ if (pct > 60)
27
+ color = screen_1.ansi.colors.green;
28
+ else if (pct > 30)
29
+ color = screen_1.ansi.colors.yellow;
30
+ else
31
+ color = screen_1.ansi.colors.red;
32
+ return `${color}${"█".repeat(filled)}${screen_1.ansi.dim}${"░".repeat(empty)}${screen_1.ansi.reset} ${color}${current}/${max}${screen_1.ansi.reset}`;
33
+ }
34
+ function renderCombat(combat, state, adventureName) {
35
+ const species = (0, species_1.getSpecies)(state.speciesId);
36
+ const lines = [];
37
+ lines.push("");
38
+ lines.push(` ${screen_1.ansi.bold}${adventureName}${screen_1.ansi.reset} ${screen_1.ansi.dim}Combat${screen_1.ansi.reset}`);
39
+ lines.push(` ${screen_1.ansi.dim}${"─".repeat(44)}${screen_1.ansi.reset}`);
40
+ lines.push("");
41
+ // Enemy
42
+ const enemyElemIcon = types_2.ELEMENT_ICONS[combat.enemyElement] ?? "";
43
+ lines.push(` ${screen_1.ansi.colors.red}${screen_1.ansi.bold}${combat.enemy.name}${screen_1.ansi.reset} ${enemyElemIcon}`);
44
+ lines.push(` HP: ${hpBar(combat.enemyStats.hp, combat.enemyStats.maxHp)} ${screen_1.ansi.dim}ATK:${combat.enemyStats.atk} DEF:${combat.enemyStats.def}${screen_1.ansi.reset}${formatConditions(combat.enemyConditions)}`);
45
+ for (const artLine of combat.enemy.art) {
46
+ lines.push(` ${screen_1.ansi.colors.red}${artLine}${screen_1.ansi.reset}`);
47
+ }
48
+ lines.push("");
49
+ lines.push(` ${screen_1.ansi.dim} vs${screen_1.ansi.reset}`);
50
+ lines.push("");
51
+ // Player buddy
52
+ const speciesColor = species ? types_1.RARITY_COLORS[species.rarity] : "";
53
+ const playerElemIcon = types_2.ELEMENT_ICONS[combat.playerElement] ?? "";
54
+ lines.push(` ${speciesColor}${screen_1.ansi.bold}${state.name}${screen_1.ansi.reset} ${playerElemIcon}`);
55
+ lines.push(` HP: ${hpBar(combat.playerStats.hp, combat.playerStats.maxHp)} ${screen_1.ansi.dim}ATK:${combat.playerStats.atk} DEF:${combat.playerStats.def}${screen_1.ansi.reset}${formatConditions(combat.playerConditions)}`);
56
+ if (species) {
57
+ const frame = species.animations.idle[0].split("\n");
58
+ for (const artLine of frame) {
59
+ lines.push(` ${speciesColor}${artLine}${screen_1.ansi.reset}`);
60
+ }
61
+ }
62
+ lines.push("");
63
+ // Combat log (last 2 messages)
64
+ const recentLog = combat.log.slice(-2);
65
+ for (const msg of recentLog) {
66
+ lines.push(` ${screen_1.ansi.dim}${msg}${screen_1.ansi.reset}`);
67
+ }
68
+ lines.push("");
69
+ // Action menu (only during player turn)
70
+ if (combat.phase === "player_turn") {
71
+ lines.push(` ${screen_1.ansi.dim}${"─".repeat(44)}${screen_1.ansi.reset}`);
72
+ lines.push(` [1] Attack [2] Skill [3] Item`);
73
+ lines.push(` [4] Defend [5] Flee`);
74
+ lines.push(` ${screen_1.ansi.dim}Energy: ${"◆".repeat(combat.combatEnergy)}${"◇".repeat(combat.maxCombatEnergy - combat.combatEnergy)}${screen_1.ansi.reset}`);
75
+ }
76
+ else if (combat.phase === "victory") {
77
+ const victoryLines = lines_1.COMBAT_VICTORY_LINES[state.speciesId];
78
+ const victoryLine = victoryLines ? victoryLines[Math.floor(Math.random() * victoryLines.length)] : "We did it!";
79
+ lines.push(` ${screen_1.ansi.colors.green}${screen_1.ansi.bold}Victory!${screen_1.ansi.reset} ${screen_1.ansi.dim}+${combat.enemy.xpReward} XP${screen_1.ansi.reset}`);
80
+ lines.push(` ${state.name}: "${victoryLine}"`);
81
+ lines.push(` ${screen_1.ansi.dim}Press Enter to continue...${screen_1.ansi.reset}`);
82
+ }
83
+ else if (combat.phase === "defeat") {
84
+ const defeatLines = lines_1.COMBAT_DEFEAT_LINES[state.speciesId];
85
+ const defeatLine = defeatLines ? defeatLines[Math.floor(Math.random() * defeatLines.length)] : "We'll get them next time...";
86
+ lines.push(` ${screen_1.ansi.colors.red}${screen_1.ansi.bold}Defeated!${screen_1.ansi.reset}`);
87
+ lines.push(` ${state.name}: "${defeatLine}"`);
88
+ lines.push(` ${screen_1.ansi.dim}Press Enter to retreat...${screen_1.ansi.reset}`);
89
+ }
90
+ else if (combat.phase === "fled") {
91
+ lines.push(` ${screen_1.ansi.colors.yellow}Escaped!${screen_1.ansi.reset}`);
92
+ lines.push(` ${screen_1.ansi.dim}Press Enter to continue...${screen_1.ansi.reset}`);
93
+ }
94
+ else {
95
+ // Animating
96
+ lines.push(` ${screen_1.ansi.dim}...${screen_1.ansi.reset}`);
97
+ }
98
+ lines.push("");
99
+ return lines.join("\n");
100
+ }
101
+ function renderSkillMenu(combat, state) {
102
+ const skills = (0, skills_1.getAvailableSkills)(state.speciesId, state.level);
103
+ const lines = [];
104
+ lines.push(` ${screen_1.ansi.dim}${"─".repeat(44)}${screen_1.ansi.reset}`);
105
+ lines.push(` ${screen_1.ansi.bold}Skills${screen_1.ansi.reset} ${screen_1.ansi.dim}Energy: ${"◆".repeat(combat.combatEnergy)}${"◇".repeat(combat.maxCombatEnergy - combat.combatEnergy)}${screen_1.ansi.reset}`);
106
+ for (let i = 0; i < skills.length; i++) {
107
+ const s = skills[i];
108
+ const canUse = combat.combatEnergy >= s.energyCost;
109
+ const color = canUse ? "" : screen_1.ansi.dim;
110
+ lines.push(` ${color}[${i + 1}] ${s.name} (${s.energyCost}◆) — ${s.description}${screen_1.ansi.reset}`);
111
+ }
112
+ lines.push(` ${screen_1.ansi.dim}[0] Back${screen_1.ansi.reset}`);
113
+ lines.push(` ${screen_1.ansi.dim}${"─".repeat(44)}${screen_1.ansi.reset}`);
114
+ return lines.join("\n");
115
+ }
116
+ //# sourceMappingURL=combatUI.js.map
@@ -0,0 +1,18 @@
1
+ import { BuddyState } from "../buddy/types";
2
+ import { AdventureDef, RoomDef } from "./types";
3
+ /** Generate a single room for the Endless Depths at a given depth */
4
+ export declare function generateEndlessRoom(depth: number, buddyState: BuddyState): RoomDef;
5
+ /** Create the initial Endless Depths adventure (just 1 room to start) */
6
+ export declare function createEndlessAdventure(buddyState: BuddyState): AdventureDef;
7
+ /** Add the next room to an Endless Depths adventure */
8
+ export declare function addEndlessRoom(adventure: AdventureDef, depth: number, buddyState: BuddyState): {
9
+ adventure: AdventureDef;
10
+ roomId: string;
11
+ };
12
+ /** Get enemy stat scaling for Endless Depths */
13
+ export declare function scaleEndlessEnemy(baseHp: number, baseAtk: number, baseDef: number, depth: number): {
14
+ hp: number;
15
+ atk: number;
16
+ def: number;
17
+ };
18
+ //# sourceMappingURL=endless.d.ts.map
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateEndlessRoom = generateEndlessRoom;
4
+ exports.createEndlessAdventure = createEndlessAdventure;
5
+ exports.addEndlessRoom = addEndlessRoom;
6
+ exports.scaleEndlessEnemy = scaleEndlessEnemy;
7
+ const types_1 = require("./types");
8
+ const biomes_1 = require("./biomes");
9
+ const enemies_1 = require("./enemies");
10
+ const templates_1 = require("./templates");
11
+ function pick(arr) {
12
+ return arr[Math.floor(Math.random() * arr.length)];
13
+ }
14
+ let endlessRoomCounter = 0;
15
+ /** Get difficulty scaling for a given depth */
16
+ function depthDifficulty(depth) {
17
+ // Starts at ~2, scales up every 3 rooms
18
+ return Math.min(15, 2 + Math.floor(depth / 3));
19
+ }
20
+ /** Pick a biome for this depth (rotates) */
21
+ function depthBiome(depth) {
22
+ const ids = (0, biomes_1.getAllBiomeIds)();
23
+ const biome = biomes_1.BIOMES[ids[depth % ids.length]];
24
+ return biome;
25
+ }
26
+ /** Get enemy tier for depth */
27
+ function depthEnemyTier(depth) {
28
+ if (depth <= 3)
29
+ return "easy";
30
+ if (depth <= 8)
31
+ return "medium";
32
+ return "hard";
33
+ }
34
+ /** Pick room type based on depth */
35
+ function pickRoomType(depth) {
36
+ // Boss every 5 rooms
37
+ if (depth > 0 && depth % 5 === 0)
38
+ return "boss";
39
+ const roll = Math.random();
40
+ if (roll < 0.55)
41
+ return "combat";
42
+ if (roll < 0.70)
43
+ return "treasure";
44
+ if (roll < 0.82)
45
+ return "event";
46
+ return "rest"; // rare rest
47
+ }
48
+ /** Generate a single room for the Endless Depths at a given depth */
49
+ function generateEndlessRoom(depth, buddyState) {
50
+ endlessRoomCounter++;
51
+ const biome = depthBiome(depth);
52
+ const diff = depthDifficulty(depth);
53
+ const roomType = pickRoomType(depth);
54
+ const roomId = `endless_${endlessRoomCounter}`;
55
+ const buddyLine = (0, templates_1.generateBuddyLine)(buddyState.speciesId, biome);
56
+ switch (roomType) {
57
+ case "combat": {
58
+ const tier = depthEnemyTier(depth);
59
+ const pool = biome.enemies[tier];
60
+ const enemyId = pool.length > 0 ? pick(pool) : "squirrel";
61
+ const enemy = enemies_1.ENEMIES[enemyId];
62
+ return {
63
+ id: roomId, type: "combat",
64
+ title: `Depth ${depth + 1} — ${(0, templates_1.generateCombatTitle)(biome)}`,
65
+ text: (0, templates_1.generateCombatText)(biome, enemy?.name ?? "creature"),
66
+ buddyLine,
67
+ enemyId,
68
+ };
69
+ }
70
+ case "boss": {
71
+ const bossPool = biome.enemies.boss;
72
+ const bossId = bossPool.length > 0 ? pick(bossPool) : "marshking";
73
+ const boss = enemies_1.ENEMIES[bossId];
74
+ return {
75
+ id: roomId, type: "boss",
76
+ title: `Depth ${depth + 1} — BOSS`,
77
+ text: (0, templates_1.generateBossText)(biome, boss?.name ?? "The Boss"),
78
+ buddyLine: "This feels like a big one... STAY STRONG!",
79
+ enemyId: bossId,
80
+ };
81
+ }
82
+ case "treasure": {
83
+ const tier = diff <= 4 ? "uncommon" : diff <= 7 ? "rare" : "epic";
84
+ return {
85
+ id: roomId, type: "treasure",
86
+ title: `Depth ${depth + 1} — Stash`,
87
+ text: (0, templates_1.generateTreasureText)(biome),
88
+ buddyLine,
89
+ lootPool: biome.loot[tier],
90
+ };
91
+ }
92
+ case "rest": {
93
+ const healAmount = 10 + Math.floor(diff * 1.5);
94
+ return {
95
+ id: roomId, type: "rest",
96
+ title: `Depth ${depth + 1} — Safe Haven`,
97
+ text: (0, templates_1.generateRestText)(biome),
98
+ buddyLine: "Quick break... don't get too comfortable.",
99
+ healAmount,
100
+ };
101
+ }
102
+ case "event": {
103
+ const event = (0, templates_1.generateEvent)(biome);
104
+ return {
105
+ id: roomId, type: "event",
106
+ title: `Depth ${depth + 1} — Encounter`,
107
+ text: event.text,
108
+ buddyLine,
109
+ eventChoices: event.choices.map((c) => ({
110
+ label: c.label,
111
+ outcome: c.outcome,
112
+ effect: c.effect,
113
+ })),
114
+ };
115
+ }
116
+ }
117
+ }
118
+ /** Create the initial Endless Depths adventure (just 1 room to start) */
119
+ function createEndlessAdventure(buddyState) {
120
+ endlessRoomCounter = 0;
121
+ const firstRoom = generateEndlessRoom(0, buddyState);
122
+ return {
123
+ id: "endless_depths",
124
+ name: "The Endless Depths",
125
+ description: "How deep can you go?",
126
+ difficulty: 99,
127
+ levelRequired: 5,
128
+ energyCost: 20,
129
+ hungerCost: 15,
130
+ rooms: [firstRoom],
131
+ roomMap: (0, types_1.buildRoomMap)([firstRoom]),
132
+ startRoomId: firstRoom.id,
133
+ completionXp: 0, // XP awarded per room, not on completion
134
+ };
135
+ }
136
+ /** Add the next room to an Endless Depths adventure */
137
+ function addEndlessRoom(adventure, depth, buddyState) {
138
+ const room = generateEndlessRoom(depth, buddyState);
139
+ const rooms = [...adventure.rooms, room];
140
+ return {
141
+ adventure: { ...adventure, rooms, roomMap: (0, types_1.buildRoomMap)(rooms) },
142
+ roomId: room.id,
143
+ };
144
+ }
145
+ /** Get enemy stat scaling for Endless Depths */
146
+ function scaleEndlessEnemy(baseHp, baseAtk, baseDef, depth) {
147
+ const mult = 1 + depth * 0.12;
148
+ return {
149
+ hp: Math.floor(baseHp * mult),
150
+ atk: Math.floor(baseAtk * mult),
151
+ def: Math.floor(baseDef * mult),
152
+ };
153
+ }
154
+ //# sourceMappingURL=endless.js.map
@@ -0,0 +1,4 @@
1
+ import { EnemyDef } from "./types";
2
+ export declare const ENEMIES: Record<string, EnemyDef>;
3
+ export declare function getEnemy(id: string): EnemyDef | undefined;
4
+ //# sourceMappingURL=enemies.d.ts.map
@@ -0,0 +1,320 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ENEMIES = void 0;
4
+ exports.getEnemy = getEnemy;
5
+ exports.ENEMIES = {
6
+ // ─── Easy ──────────────────────────────────────────
7
+ squirrel: {
8
+ id: "squirrel",
9
+ name: "Cheeky Squirrel",
10
+ element: "nature",
11
+ aiBehavior: "aggressive",
12
+ art: [" /\\ ∩ ", " (°°)// ", " ('') "],
13
+ encounterLine: "A squirrel chatters angrily at you!",
14
+ attackLine: "Squirrel throws an acorn!",
15
+ defeatLine: "Squirrel scampers up a tree!",
16
+ baseHp: 15, baseAtk: 4, baseDef: 2, baseSpd: 6,
17
+ xpReward: 10,
18
+ dropChance: 0.3,
19
+ dropPool: ["berry", "stick"],
20
+ },
21
+ mushroom: {
22
+ id: "mushroom",
23
+ name: "Mischievous Mushroom",
24
+ element: "nature",
25
+ aiBehavior: "defensive",
26
+ defendLine: "Mushroom curls up defensively!",
27
+ art: [" .--. ", " / \\ ", " | oo | ", " \\__/ "],
28
+ encounterLine: "A mushroom bounces into your path!",
29
+ attackLine: "Mushroom bonks you with its cap!",
30
+ defeatLine: "Mushroom pops and deflates!",
31
+ baseHp: 20, baseAtk: 3, baseDef: 4, baseSpd: 3,
32
+ xpReward: 12,
33
+ dropChance: 0.3,
34
+ dropPool: ["herb", "berry"],
35
+ },
36
+ snail: {
37
+ id: "snail",
38
+ name: "Grumpy Snail",
39
+ element: "water",
40
+ aiBehavior: "defensive",
41
+ defendLine: "Snail retreats into its shell!",
42
+ art: [" @@ ", " (__)\\ ", " ====== "],
43
+ encounterLine: "A snail glares at you. Slowly.",
44
+ attackLine: "Snail slimes you!",
45
+ defeatLine: "Snail retreats into its shell.",
46
+ baseHp: 25, baseAtk: 2, baseDef: 6, baseSpd: 1,
47
+ xpReward: 10,
48
+ dropChance: 0.2,
49
+ dropPool: ["herb"],
50
+ },
51
+ // ─── Medium ────────────────────────────────────────
52
+ shadowfox: {
53
+ id: "shadowfox",
54
+ name: "Shadow Fox",
55
+ element: "shadow",
56
+ aiBehavior: "evasive",
57
+ baseDodge: 0.20,
58
+ art: [" /\\ /\\ ", "( o.o ) ", " > V < "],
59
+ encounterLine: "A dark fox appears from the shadows!",
60
+ attackLine: "Shadow Fox strikes swiftly!",
61
+ defeatLine: "Shadow Fox vanishes into the dark.",
62
+ baseHp: 30, baseAtk: 7, baseDef: 3, baseSpd: 8,
63
+ xpReward: 20,
64
+ dropChance: 0.4,
65
+ dropPool: ["fish", "ball", "iron_sword"],
66
+ },
67
+ golem: {
68
+ id: "golem",
69
+ name: "Crystal Golem",
70
+ element: "light",
71
+ aiBehavior: "defensive",
72
+ defendLine: "Golem braces with crystal arms!",
73
+ art: [" [===] ", " |o o| ", " |___| ", " /| |\\ "],
74
+ encounterLine: "A crystal golem blocks the path!",
75
+ attackLine: "Golem slams the ground!",
76
+ defeatLine: "Golem crumbles into sparkling dust.",
77
+ baseHp: 40, baseAtk: 5, baseDef: 8, baseSpd: 2,
78
+ xpReward: 25,
79
+ dropChance: 0.4,
80
+ dropPool: ["crystal_blade", "potion"],
81
+ },
82
+ crow: {
83
+ id: "crow",
84
+ name: "Trickster Crow",
85
+ element: "shadow",
86
+ aiBehavior: "tactical",
87
+ art: [" \\ / ", " (oo) ", " /||\\ "],
88
+ encounterLine: "A crow swoops down, cackling!",
89
+ attackLine: "Crow pecks viciously!",
90
+ defeatLine: "Crow flaps away, grumbling.",
91
+ baseHp: 25, baseAtk: 8, baseDef: 2, baseSpd: 7,
92
+ xpReward: 18,
93
+ dropChance: 0.35,
94
+ dropPool: ["ball", "puzzle"],
95
+ },
96
+ // ─── Hard ──────────────────────────────────────────
97
+ stormwolf: {
98
+ id: "stormwolf",
99
+ name: "Storm Wolf",
100
+ element: "nature",
101
+ aiBehavior: "berserker",
102
+ art: [" /\\_/\\ ~", "( o o )~", " \\ / ", " W W "],
103
+ encounterLine: "A wolf howls amidst crackling thunder!",
104
+ attackLine: "Storm Wolf lunges!",
105
+ defeatLine: "Storm Wolf slinks away, whimpering.",
106
+ baseHp: 45, baseAtk: 10, baseDef: 5, baseSpd: 6,
107
+ xpReward: 35,
108
+ dropChance: 0.5,
109
+ dropPool: ["chain_mail", "iron_sword", "potion"],
110
+ },
111
+ lavabeetle: {
112
+ id: "lavabeetle",
113
+ name: "Lava Beetle",
114
+ element: "fire",
115
+ aiBehavior: "aggressive",
116
+ art: [" *\\ /* ", " (>.<) ", " /===\\ "],
117
+ encounterLine: "A beetle glowing with heat scuttles toward you!",
118
+ attackLine: "Lava Beetle spits fire!",
119
+ defeatLine: "Lava Beetle cools down and scurries off.",
120
+ baseHp: 35, baseAtk: 12, baseDef: 4, baseSpd: 5,
121
+ xpReward: 30,
122
+ dropChance: 0.45,
123
+ dropPool: ["flame_scepter", "potion", "elixir"],
124
+ },
125
+ // ─── Bosses ────────────────────────────────────────
126
+ marshking: {
127
+ id: "marshking",
128
+ name: "The Marsh King",
129
+ element: "water",
130
+ aiBehavior: "tactical",
131
+ art: [" .---. ", "/ o o \\ ", "| VVV | ", "\\ / ", " '---' "],
132
+ encounterLine: "The ground trembles... The Marsh King rises!",
133
+ attackLine: "Marsh King lashes with a slimy tentacle!",
134
+ defeatLine: "The Marsh King sinks back into the swamp... defeated!",
135
+ baseHp: 60, baseAtk: 8, baseDef: 6, baseSpd: 4,
136
+ xpReward: 60,
137
+ dropChance: 0.8,
138
+ dropPool: ["crystal_blade", "crystal_armor", "elixir"],
139
+ isBoss: true,
140
+ specialMove: {
141
+ name: "Swamp Surge",
142
+ line: "Marsh King summons a wave of muck!",
143
+ damageMultiplier: 1.8,
144
+ chance: 0.4,
145
+ },
146
+ phase2Move: {
147
+ name: "Poison Tide",
148
+ line: "The Marsh King unleashes a toxic flood!",
149
+ damageMultiplier: 1.4,
150
+ chance: 0.5,
151
+ },
152
+ enrageAtkBonus: 0.3,
153
+ },
154
+ crystalguardian: {
155
+ id: "crystalguardian",
156
+ name: "The Crystal Guardian",
157
+ element: "light",
158
+ aiBehavior: "defensive",
159
+ defendLine: "Crystal Guardian raises a barrier of light!",
160
+ art: [" /===\\ ", "| o o |", "| A |", "|=====|", " \\===/ "],
161
+ encounterLine: "A towering crystal construct awakens!",
162
+ attackLine: "Crystal Guardian fires a beam of light!",
163
+ defeatLine: "The Crystal Guardian shatters into a thousand sparkles!",
164
+ baseHp: 80, baseAtk: 10, baseDef: 10, baseSpd: 3,
165
+ xpReward: 80,
166
+ dropChance: 0.9,
167
+ dropPool: ["crystal_blade", "crystal_armor", "dragon_fang", "dragon_scale_armor"],
168
+ isBoss: true,
169
+ specialMove: {
170
+ name: "Crystal Heal",
171
+ line: "Crystal Guardian glows and regenerates!",
172
+ damageMultiplier: -0.2,
173
+ chance: 0.35,
174
+ },
175
+ phase2Move: {
176
+ name: "Prismatic Beam",
177
+ line: "Crystal Guardian channels a devastating beam!",
178
+ damageMultiplier: 2.0,
179
+ chance: 0.45,
180
+ },
181
+ enrageAtkBonus: 0.3,
182
+ },
183
+ // ─── New Easy ──────────────────────────────────────
184
+ flamesprite: {
185
+ id: "flamesprite",
186
+ name: "Flame Sprite",
187
+ element: "fire",
188
+ aiBehavior: "aggressive",
189
+ art: [" *\\|/* ", " (!) ", " /\\ "],
190
+ encounterLine: "A tiny flame dances angrily toward you!",
191
+ attackLine: "Flame Sprite flicks a spark!",
192
+ defeatLine: "The flame flickers out... poof!",
193
+ baseHp: 12, baseAtk: 5, baseDef: 1, baseSpd: 7,
194
+ xpReward: 10,
195
+ dropChance: 0.25,
196
+ dropPool: ["herb", "berry"],
197
+ },
198
+ puddleslime: {
199
+ id: "puddleslime",
200
+ name: "Puddle Slime",
201
+ element: "water",
202
+ aiBehavior: "defensive",
203
+ defendLine: "Puddle Slime jiggles defensively!",
204
+ art: [" ~~~ ", " (o o) ", " \\___/ "],
205
+ encounterLine: "A blob of water gurgles at you!",
206
+ attackLine: "Puddle Slime splashes you!",
207
+ defeatLine: "Puddle Slime evaporates into mist.",
208
+ baseHp: 22, baseAtk: 2, baseDef: 5, baseSpd: 2,
209
+ xpReward: 10,
210
+ dropChance: 0.25,
211
+ dropPool: ["herb", "berry"],
212
+ },
213
+ // ─── New Medium ────────────────────────────────────
214
+ emberfox: {
215
+ id: "emberfox",
216
+ name: "Ember Fox",
217
+ element: "fire",
218
+ aiBehavior: "evasive",
219
+ baseDodge: 0.15,
220
+ art: [" /\\ /\\ ", "(*.* )~", " > V < "],
221
+ encounterLine: "A fox wreathed in embers snarls at you!",
222
+ attackLine: "Ember Fox lunges with fiery claws!",
223
+ defeatLine: "Ember Fox's flames die down as it retreats.",
224
+ baseHp: 28, baseAtk: 6, baseDef: 3, baseSpd: 9,
225
+ xpReward: 20,
226
+ dropChance: 0.35,
227
+ dropPool: ["fish", "potion", "flame_scepter"],
228
+ },
229
+ vinecreeper: {
230
+ id: "vinecreeper",
231
+ name: "Vine Creeper",
232
+ element: "nature",
233
+ aiBehavior: "tactical",
234
+ art: [" }|{ ", " /|o|\\ ", " \\|_|/ "],
235
+ encounterLine: "Vines lash out from the ground!",
236
+ attackLine: "Vine Creeper whips you with thorns!",
237
+ defeatLine: "The vines wither and retreat underground.",
238
+ baseHp: 35, baseAtk: 6, baseDef: 5, baseSpd: 3,
239
+ xpReward: 22,
240
+ dropChance: 0.35,
241
+ dropPool: ["herb", "potion", "thorn_whip"],
242
+ },
243
+ rustknight: {
244
+ id: "rustknight",
245
+ name: "Rust Knight",
246
+ element: "neutral",
247
+ aiBehavior: "defensive",
248
+ defendLine: "Rust Knight raises its corroded shield!",
249
+ art: [" [+] ", " /||\\ ", " _||_ "],
250
+ encounterLine: "An ancient suit of armor clanks to life!",
251
+ attackLine: "Rust Knight swings a rusty blade!",
252
+ defeatLine: "The armor collapses into a pile of rust.",
253
+ baseHp: 38, baseAtk: 6, baseDef: 7, baseSpd: 3,
254
+ xpReward: 24,
255
+ dropChance: 0.4,
256
+ dropPool: ["iron_sword", "chain_mail", "potion"],
257
+ },
258
+ // ─── New Hard ──────────────────────────────────────
259
+ crystalbasilisk: {
260
+ id: "crystalbasilisk",
261
+ name: "Crystal Basilisk",
262
+ element: "light",
263
+ aiBehavior: "tactical",
264
+ art: [" /\\_/\\ ", " {o o} ", " /====\\ ", " ~~~~ "],
265
+ encounterLine: "A serpent of crystal light slithers toward you!",
266
+ attackLine: "Crystal Basilisk strikes with a beam of light!",
267
+ defeatLine: "The basilisk shatters into prismatic shards!",
268
+ baseHp: 42, baseAtk: 9, baseDef: 6, baseSpd: 5,
269
+ xpReward: 32,
270
+ dropChance: 0.45,
271
+ dropPool: ["crystal_blade", "crystal_armor", "sunblade"],
272
+ },
273
+ bogwitch: {
274
+ id: "bogwitch",
275
+ name: "Bog Witch",
276
+ element: "water",
277
+ aiBehavior: "tactical",
278
+ art: [" /\\ ", " {><} ", " /||\\ ", " _/\\_ "],
279
+ encounterLine: "Cackling echoes from the mist... a witch emerges!",
280
+ attackLine: "Bog Witch hurls a curse!",
281
+ defeatLine: "The witch dissolves into swamp fog.",
282
+ baseHp: 38, baseAtk: 11, baseDef: 4, baseSpd: 4,
283
+ xpReward: 30,
284
+ dropChance: 0.45,
285
+ dropPool: ["potion", "elixir", "coral_plate"],
286
+ },
287
+ // ─── New Boss ──────────────────────────────────────
288
+ infernodrake: {
289
+ id: "infernodrake",
290
+ name: "The Inferno Drake",
291
+ element: "fire",
292
+ aiBehavior: "berserker",
293
+ art: [" /\\/\\ ", " {o><o} ", " /|/\\|\\ ", " \\~~~~/ ", " |||| "],
294
+ encounterLine: "The air shimmers with heat... The Inferno Drake descends!",
295
+ attackLine: "Inferno Drake rakes with burning claws!",
296
+ defeatLine: "The drake crashes down, its flames extinguished!",
297
+ baseHp: 70, baseAtk: 12, baseDef: 5, baseSpd: 5,
298
+ xpReward: 70,
299
+ dropChance: 0.85,
300
+ dropPool: ["dragon_fang", "flame_scepter", "dragon_scale_armor", "phoenix_tears"],
301
+ isBoss: true,
302
+ specialMove: {
303
+ name: "Flame Barrage",
304
+ line: "Inferno Drake unleashes a torrent of fire!",
305
+ damageMultiplier: 1.6,
306
+ chance: 0.5,
307
+ },
308
+ phase2Move: {
309
+ name: "Molten Breath",
310
+ line: "The Drake's breath turns to liquid fire!",
311
+ damageMultiplier: 1.8,
312
+ chance: 0.5,
313
+ },
314
+ enrageAtkBonus: 0.4,
315
+ },
316
+ };
317
+ function getEnemy(id) {
318
+ return exports.ENEMIES[id];
319
+ }
320
+ //# sourceMappingURL=enemies.js.map
@@ -0,0 +1,20 @@
1
+ import { BuddyState } from "../buddy/types";
2
+ import { AdventureDef, AdventureState, RoomDef } from "./types";
3
+ /** Start a new adventure */
4
+ export declare function beginAdventure(state: BuddyState, adventure: AdventureDef): {
5
+ state: BuddyState;
6
+ adventure: AdventureState;
7
+ };
8
+ /** Check if buddy can start this adventure */
9
+ export declare function canStartAdventure(state: BuddyState, adventure: AdventureDef): string | null;
10
+ /** Handle a narrative/event choice */
11
+ export declare function makeChoice(advState: AdventureState, adventure: AdventureDef, choiceIndex: number): AdventureState;
12
+ /** Move to a specific room by ID */
13
+ export declare function advanceToRoom(advState: AdventureState, adventure: AdventureDef, roomId: string | undefined): AdventureState;
14
+ /** Advance to the current room's default next room */
15
+ export declare function advanceToNextRoom(advState: AdventureState, adventure: AdventureDef): AdventureState;
16
+ /** Roll loot from a treasure room */
17
+ export declare function rollTreasureLoot(room: RoomDef): string | null;
18
+ /** Adjust morale */
19
+ export declare function adjustMorale(advState: AdventureState, delta: number): AdventureState;
20
+ //# sourceMappingURL=engine.d.ts.map