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.
- package/LICENSE +21 -0
- package/README.md +60 -0
- package/dist/adventure/adventureUI.d.ts +24 -0
- package/dist/adventure/adventureUI.js +290 -0
- package/dist/adventure/adventures.d.ts +4 -0
- package/dist/adventure/adventures.js +206 -0
- package/dist/adventure/biomes.d.ts +30 -0
- package/dist/adventure/biomes.js +80 -0
- package/dist/adventure/combat/combat.d.ts +14 -0
- package/dist/adventure/combat/combat.js +638 -0
- package/dist/adventure/combat/combatUI.d.ts +5 -0
- package/dist/adventure/combat/combatUI.js +116 -0
- package/dist/adventure/combat/conditions.d.ts +20 -0
- package/dist/adventure/combat/conditions.js +111 -0
- package/dist/adventure/combat/enemies.d.ts +4 -0
- package/dist/adventure/combat/enemies.js +430 -0
- package/dist/adventure/combat/gear.d.ts +3 -0
- package/dist/adventure/combat/gear.js +199 -0
- package/dist/adventure/combat/skills.d.ts +6 -0
- package/dist/adventure/combat/skills.js +197 -0
- package/dist/adventure/combat.d.ts +31 -0
- package/dist/adventure/combat.js +732 -0
- package/dist/adventure/combatUI.d.ts +5 -0
- package/dist/adventure/combatUI.js +116 -0
- package/dist/adventure/endless.d.ts +18 -0
- package/dist/adventure/endless.js +154 -0
- package/dist/adventure/enemies.d.ts +4 -0
- package/dist/adventure/enemies.js +320 -0
- package/dist/adventure/engine.d.ts +20 -0
- package/dist/adventure/engine.js +137 -0
- package/dist/adventure/gear.d.ts +3 -0
- package/dist/adventure/gear.js +149 -0
- package/dist/adventure/generation/biomes.d.ts +30 -0
- package/dist/adventure/generation/biomes.js +102 -0
- package/dist/adventure/generation/endless.d.ts +18 -0
- package/dist/adventure/generation/endless.js +154 -0
- package/dist/adventure/generation/generator.d.ts +9 -0
- package/dist/adventure/generation/generator.js +245 -0
- package/dist/adventure/generation/templates.d.ts +25 -0
- package/dist/adventure/generation/templates.js +228 -0
- package/dist/adventure/generator.d.ts +9 -0
- package/dist/adventure/generator.js +245 -0
- package/dist/adventure/skills.d.ts +6 -0
- package/dist/adventure/skills.js +197 -0
- package/dist/adventure/templates.d.ts +25 -0
- package/dist/adventure/templates.js +228 -0
- package/dist/adventure/types.d.ts +236 -0
- package/dist/adventure/types.js +97 -0
- package/dist/app/state.d.ts +49 -0
- package/dist/app/state.js +51 -0
- package/dist/buddy/activities.d.ts +16 -0
- package/dist/buddy/activities.js +90 -0
- package/dist/buddy/decay.d.ts +3 -0
- package/dist/buddy/decay.js +45 -0
- package/dist/buddy/leveling.d.ts +11 -0
- package/dist/buddy/leveling.js +25 -0
- package/dist/buddy/roll.d.ts +4 -0
- package/dist/buddy/roll.js +61 -0
- package/dist/buddy/species.d.ts +4 -0
- package/dist/buddy/species.js +592 -0
- package/dist/buddy/titles.d.ts +17 -0
- package/dist/buddy/titles.js +89 -0
- package/dist/buddy/types.d.ts +92 -0
- package/dist/buddy/types.js +21 -0
- package/dist/commands/actions.d.ts +2 -0
- package/dist/commands/actions.js +141 -0
- package/dist/commands/admin.d.ts +2 -0
- package/dist/commands/admin.js +202 -0
- package/dist/commands/registry.d.ts +25 -0
- package/dist/commands/registry.js +31 -0
- package/dist/commands/social.d.ts +2 -0
- package/dist/commands/social.js +92 -0
- package/dist/dialogue/engine.d.ts +7 -0
- package/dist/dialogue/engine.js +68 -0
- package/dist/dialogue/lines.d.ts +26 -0
- package/dist/dialogue/lines.js +294 -0
- package/dist/events/engine.d.ts +20 -0
- package/dist/events/engine.js +51 -0
- package/dist/events/events.d.ts +13 -0
- package/dist/events/events.js +149 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +1665 -0
- package/dist/inventory/finding.d.ts +11 -0
- package/dist/inventory/finding.js +99 -0
- package/dist/inventory/items.d.ts +31 -0
- package/dist/inventory/items.js +63 -0
- package/dist/minigames/copycat.d.ts +2 -0
- package/dist/minigames/copycat.js +153 -0
- package/dist/minigames/fetch.d.ts +2 -0
- package/dist/minigames/fetch.js +179 -0
- package/dist/minigames/moodmatch.d.ts +2 -0
- package/dist/minigames/moodmatch.js +144 -0
- package/dist/minigames/quickpaws.d.ts +2 -0
- package/dist/minigames/quickpaws.js +142 -0
- package/dist/minigames/registry.d.ts +5 -0
- package/dist/minigames/registry.js +16 -0
- package/dist/minigames/rpsplus.d.ts +2 -0
- package/dist/minigames/rpsplus.js +168 -0
- package/dist/minigames/treasurehunt.d.ts +2 -0
- package/dist/minigames/treasurehunt.js +146 -0
- package/dist/minigames/types.d.ts +30 -0
- package/dist/minigames/types.js +69 -0
- package/dist/rendering/commandPalette.d.ts +16 -0
- package/dist/rendering/commandPalette.js +77 -0
- package/dist/rendering/display.d.ts +9 -0
- package/dist/rendering/display.js +231 -0
- package/dist/rendering/inventoryUI.d.ts +14 -0
- package/dist/rendering/inventoryUI.js +99 -0
- package/dist/rendering/items.d.ts +7 -0
- package/dist/rendering/items.js +34 -0
- package/dist/rendering/listUtils.d.ts +3 -0
- package/dist/rendering/listUtils.js +24 -0
- package/dist/rendering/minigameUI.d.ts +11 -0
- package/dist/rendering/minigameUI.js +37 -0
- package/dist/rendering/overlayUI.d.ts +24 -0
- package/dist/rendering/overlayUI.js +184 -0
- package/dist/rendering/scene.d.ts +8 -0
- package/dist/rendering/scene.js +87 -0
- package/dist/rendering/screen.d.ts +43 -0
- package/dist/rendering/screen.js +97 -0
- package/dist/sound/sound.d.ts +11 -0
- package/dist/sound/sound.js +55 -0
- package/dist/state/save.d.ts +5 -0
- package/dist/state/save.js +100 -0
- package/dist/state/settings.d.ts +7 -0
- package/dist/state/settings.js +81 -0
- package/dist/story/mainStory.d.ts +4 -0
- package/dist/story/mainStory.js +3111 -0
- package/dist/story/npcs.d.ts +17 -0
- package/dist/story/npcs.js +137 -0
- package/dist/story/progress.d.ts +26 -0
- package/dist/story/progress.js +168 -0
- package/dist/story/seasonal.d.ts +6 -0
- package/dist/story/seasonal.js +96 -0
- package/dist/story/shop.d.ts +7 -0
- package/dist/story/shop.js +26 -0
- package/dist/story/sideQuests.d.ts +4 -0
- package/dist/story/sideQuests.js +151 -0
- package/dist/story/types.d.ts +61 -0
- package/dist/story/types.js +36 -0
- package/dist/updates.d.ts +23 -0
- package/dist/updates.js +142 -0
- package/package.json +53 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.beginAdventure = beginAdventure;
|
|
4
|
+
exports.canStartAdventure = canStartAdventure;
|
|
5
|
+
exports.makeChoice = makeChoice;
|
|
6
|
+
exports.advanceToRoom = advanceToRoom;
|
|
7
|
+
exports.advanceToNextRoom = advanceToNextRoom;
|
|
8
|
+
exports.rollTreasureLoot = rollTreasureLoot;
|
|
9
|
+
exports.adjustMorale = adjustMorale;
|
|
10
|
+
const types_1 = require("./types");
|
|
11
|
+
/** Start a new adventure */
|
|
12
|
+
function beginAdventure(state, adventure) {
|
|
13
|
+
const stats = {
|
|
14
|
+
...state.stats,
|
|
15
|
+
energy: adventure.isScene ? state.stats.energy : Math.max(0, state.stats.energy - adventure.energyCost),
|
|
16
|
+
hunger: adventure.isScene ? state.stats.hunger : Math.max(0, state.stats.hunger - adventure.hungerCost),
|
|
17
|
+
};
|
|
18
|
+
const startRoom = (0, types_1.getRoom)(adventure, adventure.startRoomId);
|
|
19
|
+
return {
|
|
20
|
+
state: { ...state, stats },
|
|
21
|
+
adventure: {
|
|
22
|
+
active: true,
|
|
23
|
+
adventureId: adventure.id,
|
|
24
|
+
currentRoomId: adventure.startRoomId,
|
|
25
|
+
roomsVisited: [adventure.startRoomId],
|
|
26
|
+
phase: "room",
|
|
27
|
+
morale: Math.max(0, Math.min(100, Math.round(state.stats.happiness))),
|
|
28
|
+
textPage: 0,
|
|
29
|
+
textFullyShown: (startRoom?.text.length ?? 0) <= 3,
|
|
30
|
+
lootCollected: [],
|
|
31
|
+
xpEarned: 0,
|
|
32
|
+
battlesWon: 0,
|
|
33
|
+
battlesLost: 0,
|
|
34
|
+
battlesFled: 0,
|
|
35
|
+
damageTaken: 0,
|
|
36
|
+
buddyReaction: startRoom?.buddyLine ?? "",
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/** Check if buddy can start this adventure */
|
|
41
|
+
function canStartAdventure(state, adventure) {
|
|
42
|
+
if (!state.alive)
|
|
43
|
+
return "Your buddy needs to be alive!";
|
|
44
|
+
if (state.level < adventure.levelRequired)
|
|
45
|
+
return `Requires level ${adventure.levelRequired} (you're level ${state.level})`;
|
|
46
|
+
if (!adventure.isScene) {
|
|
47
|
+
if (state.stats.energy < adventure.energyCost)
|
|
48
|
+
return `Not enough energy (need ${adventure.energyCost}, have ${Math.round(state.stats.energy)})`;
|
|
49
|
+
if (state.stats.hunger < adventure.hungerCost)
|
|
50
|
+
return `Too hungry to adventure (need ${adventure.hungerCost} hunger)`;
|
|
51
|
+
}
|
|
52
|
+
if (state.activity)
|
|
53
|
+
return "Your buddy is busy right now!";
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
/** Handle a narrative/event choice */
|
|
57
|
+
function makeChoice(advState, adventure, choiceIndex) {
|
|
58
|
+
const room = (0, types_1.getRoom)(adventure, advState.currentRoomId);
|
|
59
|
+
if (!room)
|
|
60
|
+
return advState;
|
|
61
|
+
if (room.type === "narrative" && room.choices) {
|
|
62
|
+
const choice = room.choices[choiceIndex];
|
|
63
|
+
if (!choice)
|
|
64
|
+
return advState;
|
|
65
|
+
return advanceToRoom(advState, adventure, choice.nextRoomId);
|
|
66
|
+
}
|
|
67
|
+
if (room.type === "event" && room.eventChoices) {
|
|
68
|
+
const choice = room.eventChoices[choiceIndex];
|
|
69
|
+
if (!choice)
|
|
70
|
+
return advState;
|
|
71
|
+
// If event choice has a specific next room, go there; otherwise use room's default
|
|
72
|
+
const nextId = choice.nextRoomId ?? room.nextRoomId;
|
|
73
|
+
return {
|
|
74
|
+
...advState,
|
|
75
|
+
buddyReaction: choice.outcome,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return advState;
|
|
79
|
+
}
|
|
80
|
+
/** Move to a specific room by ID */
|
|
81
|
+
function advanceToRoom(advState, adventure, roomId) {
|
|
82
|
+
if (!roomId) {
|
|
83
|
+
return {
|
|
84
|
+
...advState,
|
|
85
|
+
currentRoomId: "",
|
|
86
|
+
phase: "result",
|
|
87
|
+
xpEarned: advState.xpEarned + adventure.completionXp,
|
|
88
|
+
buddyReaction: "That was an amazing adventure!",
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const room = (0, types_1.getRoom)(adventure, roomId);
|
|
92
|
+
if (!room) {
|
|
93
|
+
return { ...advState, phase: "result", xpEarned: advState.xpEarned + adventure.completionXp, buddyReaction: "That was an amazing adventure!" };
|
|
94
|
+
}
|
|
95
|
+
const visited = advState.roomsVisited.includes(roomId)
|
|
96
|
+
? advState.roomsVisited
|
|
97
|
+
: [...advState.roomsVisited, roomId];
|
|
98
|
+
// Reset text paging for new room — if ≤3 lines, show all immediately
|
|
99
|
+
const LINES_PER_PAGE = 3;
|
|
100
|
+
const textFullyShown = room.text.length <= LINES_PER_PAGE;
|
|
101
|
+
const textReset = { textPage: 0, textFullyShown };
|
|
102
|
+
// If combat room, set phase to combat (caller initializes CombatState)
|
|
103
|
+
if ((room.type === "combat" || room.type === "boss") && room.enemyId) {
|
|
104
|
+
return {
|
|
105
|
+
...advState,
|
|
106
|
+
...textReset,
|
|
107
|
+
currentRoomId: roomId,
|
|
108
|
+
roomsVisited: visited,
|
|
109
|
+
phase: "combat",
|
|
110
|
+
buddyReaction: room.buddyLine,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
...advState,
|
|
115
|
+
...textReset,
|
|
116
|
+
currentRoomId: roomId,
|
|
117
|
+
roomsVisited: visited,
|
|
118
|
+
phase: "room",
|
|
119
|
+
buddyReaction: room.buddyLine,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/** Advance to the current room's default next room */
|
|
123
|
+
function advanceToNextRoom(advState, adventure) {
|
|
124
|
+
const room = (0, types_1.getRoom)(adventure, advState.currentRoomId);
|
|
125
|
+
return advanceToRoom(advState, adventure, room?.nextRoomId);
|
|
126
|
+
}
|
|
127
|
+
/** Roll loot from a treasure room */
|
|
128
|
+
function rollTreasureLoot(room) {
|
|
129
|
+
if (!room.lootPool || room.lootPool.length === 0)
|
|
130
|
+
return null;
|
|
131
|
+
return room.lootPool[Math.floor(Math.random() * room.lootPool.length)];
|
|
132
|
+
}
|
|
133
|
+
/** Adjust morale */
|
|
134
|
+
function adjustMorale(advState, delta) {
|
|
135
|
+
return { ...advState, morale: Math.max(0, Math.min(100, advState.morale + delta)) };
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GEAR_ITEMS = void 0;
|
|
4
|
+
exports.GEAR_ITEMS = [
|
|
5
|
+
// ─── Weapons ───────────────────────────────────────
|
|
6
|
+
{
|
|
7
|
+
id: "wooden_stick", name: "Wooden Stick", description: "+2 ATK",
|
|
8
|
+
rarity: "common", type: "weapon", statEffect: {}, xpBonus: 0, combatATK: 2,
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: "iron_sword", name: "Iron Sword", description: "+5 ATK",
|
|
12
|
+
rarity: "uncommon", type: "weapon", statEffect: {}, xpBonus: 0, combatATK: 5,
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: "crystal_blade", name: "Crystal Blade", description: "+8 ATK, +5% crit",
|
|
16
|
+
rarity: "rare", type: "weapon", statEffect: {}, xpBonus: 0, combatATK: 8, critBonus: 0.05,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: "flame_scepter", name: "Flame Scepter", description: "+10 ATK, Fire, 15% burn on hit",
|
|
20
|
+
rarity: "epic", type: "weapon", statEffect: {}, xpBonus: 0, combatATK: 10,
|
|
21
|
+
gearElement: "fire", onHitEffect: "burn", onHitChance: 0.15, onHitPower: 3,
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: "frost_edge", name: "Frost Edge", description: "+10 ATK, Water, 10% freeze on hit",
|
|
25
|
+
rarity: "epic", type: "weapon", statEffect: {}, xpBonus: 0, combatATK: 10,
|
|
26
|
+
gearElement: "water", onHitEffect: "freeze", onHitChance: 0.10, onHitPower: 1,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: "dragon_fang", name: "Dragon Fang", description: "+14 ATK, Fire, +10% crit, 20% burn",
|
|
30
|
+
rarity: "legendary", type: "weapon", statEffect: {}, xpBonus: 0, combatATK: 14,
|
|
31
|
+
gearElement: "fire", critBonus: 0.10, onHitEffect: "burn", onHitChance: 0.20, onHitPower: 5,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "shadow_dagger", name: "Shadow Dagger", description: "+12 ATK, Shadow, +15% dodge, 15% charm",
|
|
35
|
+
rarity: "legendary", type: "weapon", statEffect: {}, xpBonus: 0, combatATK: 12,
|
|
36
|
+
gearElement: "shadow", dodgeBonus: 0.15, onHitEffect: "charm", onHitChance: 0.15, onHitPower: 1,
|
|
37
|
+
},
|
|
38
|
+
// ─── Armor ─────────────────────────────────────────
|
|
39
|
+
{
|
|
40
|
+
id: "leaf_cloak", name: "Leaf Cloak", description: "+2 DEF",
|
|
41
|
+
rarity: "common", type: "armor", statEffect: {}, xpBonus: 0, combatDEF: 2,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: "chain_mail", name: "Chain Mail", description: "+4 DEF",
|
|
45
|
+
rarity: "uncommon", type: "armor", statEffect: {}, xpBonus: 0, combatDEF: 4,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: "crystal_armor", name: "Crystal Armor", description: "+7 DEF, +10 HP",
|
|
49
|
+
rarity: "rare", type: "armor", statEffect: {}, xpBonus: 0, combatDEF: 7, combatHP: 10,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "phoenix_robe", name: "Phoenix Feather Robe", description: "+8 DEF, regen 3hp/t",
|
|
53
|
+
rarity: "epic", type: "armor", statEffect: {}, xpBonus: 0, combatDEF: 8,
|
|
54
|
+
// Regen applied at combat start as a condition
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: "thornmail", name: "Thornmail", description: "+6 DEF, reflect 3 dmg to attackers",
|
|
58
|
+
rarity: "epic", type: "armor", statEffect: {}, xpBonus: 0, combatDEF: 6,
|
|
59
|
+
// Reflect handled in applyDamageToPlayer
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "dragon_scale_armor", name: "Dragon Scale Armor", description: "+12 DEF, +20 HP, -2 flat dmg",
|
|
63
|
+
rarity: "legendary", type: "armor", statEffect: {}, xpBonus: 0, combatDEF: 12, combatHP: 20, damageReduction: 2,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: "shadow_cloak", name: "Shadow Cloak", description: "+8 DEF, +15% dodge",
|
|
67
|
+
rarity: "legendary", type: "armor", statEffect: {}, xpBonus: 0, combatDEF: 8, dodgeBonus: 0.15,
|
|
68
|
+
},
|
|
69
|
+
// ─── Accessories ───────────────────────────────────
|
|
70
|
+
{
|
|
71
|
+
id: "lucky_charm", name: "Lucky Charm", description: "+10% crit",
|
|
72
|
+
rarity: "uncommon", type: "accessory", statEffect: {}, xpBonus: 0, critBonus: 0.10,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: "swift_boots", name: "Swift Boots", description: "+3 SPD",
|
|
76
|
+
rarity: "uncommon", type: "accessory", statEffect: {}, xpBonus: 0, combatSPD: 3,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: "mana_crystal", name: "Mana Crystal", description: "+2 starting energy",
|
|
80
|
+
rarity: "rare", type: "accessory", statEffect: {}, xpBonus: 0, energyBonus: 2,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: "life_pendant", name: "Life Pendant", description: "+15 HP",
|
|
84
|
+
rarity: "rare", type: "accessory", statEffect: {}, xpBonus: 0, combatHP: 15,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: "berserker_ring", name: "Berserker Ring", description: "+20% ATK when HP < 30%",
|
|
88
|
+
rarity: "epic", type: "accessory", statEffect: {}, xpBonus: 0,
|
|
89
|
+
// Berserker effect handled in combat damage calc
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: "guardian_shield", name: "Guardian Shield", description: "Start with 15hp shield",
|
|
93
|
+
rarity: "epic", type: "accessory", statEffect: {}, xpBonus: 0,
|
|
94
|
+
},
|
|
95
|
+
// ─── New Weapons (element coverage) ────────────────
|
|
96
|
+
{
|
|
97
|
+
id: "thorn_whip", name: "Thorn Whip", description: "+7 ATK, Nature, 15% poison",
|
|
98
|
+
rarity: "rare", type: "weapon", statEffect: {}, xpBonus: 0, combatATK: 7,
|
|
99
|
+
gearElement: "nature", onHitEffect: "poison", onHitChance: 0.15, onHitPower: 3,
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: "sunblade", name: "Sunblade", description: "+10 ATK, Light, 10% blind",
|
|
103
|
+
rarity: "epic", type: "weapon", statEffect: {}, xpBonus: 0, combatATK: 10,
|
|
104
|
+
gearElement: "light", onHitEffect: "blind", onHitChance: 0.10, onHitPower: 1,
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
id: "midnight_bow", name: "Midnight Bow", description: "+7 ATK, Shadow, +10% dodge",
|
|
108
|
+
rarity: "rare", type: "weapon", statEffect: {}, xpBonus: 0, combatATK: 7,
|
|
109
|
+
gearElement: "shadow", dodgeBonus: 0.10,
|
|
110
|
+
},
|
|
111
|
+
// ─── New Armor (element coverage) ──────────────────
|
|
112
|
+
{
|
|
113
|
+
id: "bark_shield", name: "Bark Shield", description: "+6 DEF, +10 HP",
|
|
114
|
+
rarity: "rare", type: "armor", statEffect: {}, xpBonus: 0, combatDEF: 6, combatHP: 10,
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
id: "coral_plate", name: "Coral Plate", description: "+9 DEF, Water",
|
|
118
|
+
rarity: "epic", type: "armor", statEffect: {}, xpBonus: 0, combatDEF: 9,
|
|
119
|
+
},
|
|
120
|
+
// ─── New Accessories ───────────────────────────────
|
|
121
|
+
{
|
|
122
|
+
id: "nature_ring", name: "Nature Ring", description: "+5% dodge",
|
|
123
|
+
rarity: "uncommon", type: "accessory", statEffect: {}, xpBonus: 0, dodgeBonus: 0.05,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
id: "fire_amulet", name: "Fire Amulet", description: "+5% crit, Fire",
|
|
127
|
+
rarity: "rare", type: "accessory", statEffect: {}, xpBonus: 0, critBonus: 0.05, gearElement: "fire",
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
id: "dodge_cloak", name: "Dodge Cloak", description: "+12% dodge",
|
|
131
|
+
rarity: "rare", type: "accessory", statEffect: {}, xpBonus: 0, dodgeBonus: 0.12,
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
id: "vampiric_fang", name: "Vampiric Fang", description: "Heal 3 HP per attack",
|
|
135
|
+
rarity: "epic", type: "accessory", statEffect: {}, xpBonus: 0,
|
|
136
|
+
// Heal on hit handled in combat
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
id: "elementalist_orb", name: "Elementalist Orb", description: "+3 energy, +5% crit, +10 HP",
|
|
140
|
+
rarity: "legendary", type: "accessory", statEffect: {}, xpBonus: 0,
|
|
141
|
+
energyBonus: 3, critBonus: 0.05, combatHP: 10,
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
id: "thunder_bracelet", name: "Thunder Bracelet", description: "+5 SPD, 10% stun",
|
|
145
|
+
rarity: "legendary", type: "accessory", statEffect: {}, xpBonus: 0,
|
|
146
|
+
combatSPD: 5, onHitEffect: "stun", onHitChance: 0.10, onHitPower: 1,
|
|
147
|
+
},
|
|
148
|
+
];
|
|
149
|
+
//# sourceMappingURL=gear.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface Biome {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
/** Enemy IDs available in this biome, by tier */
|
|
5
|
+
enemies: {
|
|
6
|
+
easy: string[];
|
|
7
|
+
medium: string[];
|
|
8
|
+
hard: string[];
|
|
9
|
+
boss: string[];
|
|
10
|
+
};
|
|
11
|
+
/** Loot pools by rarity tier */
|
|
12
|
+
loot: {
|
|
13
|
+
common: string[];
|
|
14
|
+
uncommon: string[];
|
|
15
|
+
rare: string[];
|
|
16
|
+
epic: string[];
|
|
17
|
+
};
|
|
18
|
+
/** Flavor text pools */
|
|
19
|
+
nouns: string[];
|
|
20
|
+
adjectives: string[];
|
|
21
|
+
landmarks: string[];
|
|
22
|
+
hidingSpots: string[];
|
|
23
|
+
directions: string[];
|
|
24
|
+
/** Buddy species comfort lines — species that feel at home here */
|
|
25
|
+
comfortSpecies: string[];
|
|
26
|
+
}
|
|
27
|
+
export declare const BIOMES: Record<string, Biome>;
|
|
28
|
+
export declare function getBiome(id: string): Biome | undefined;
|
|
29
|
+
export declare function getAllBiomeIds(): string[];
|
|
30
|
+
//# sourceMappingURL=biomes.d.ts.map
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BIOMES = void 0;
|
|
4
|
+
exports.getBiome = getBiome;
|
|
5
|
+
exports.getAllBiomeIds = getAllBiomeIds;
|
|
6
|
+
exports.BIOMES = {
|
|
7
|
+
forest: {
|
|
8
|
+
id: "forest", name: "Forest",
|
|
9
|
+
enemies: { easy: ["squirrel", "mushroom"], medium: ["shadowfox", "crow", "vinecreeper"], hard: ["stormwolf"], boss: ["marshking"] },
|
|
10
|
+
loot: { common: ["berry", "herb", "stick", "wooden_stick", "leather_cap", "sandals"], uncommon: ["fish", "ball", "iron_sword", "leaf_cloak", "iron_helm", "leather_boots"], rare: ["cake", "crystal_blade", "chain_mail", "thorn_whip", "crystal_crown", "wind_runners"], epic: ["flame_scepter", "phoenix_robe", "sunblade", "shadow_steps"] },
|
|
11
|
+
nouns: ["forest", "woods", "grove", "thicket", "glade", "canopy", "clearing", "dell", "copse", "woodland"],
|
|
12
|
+
adjectives: ["sun-dappled", "misty", "ancient", "overgrown", "quiet", "verdant", "whispering", "wild", "fragrant", "twilit"],
|
|
13
|
+
landmarks: ["old oak tree", "mossy stone", "babbling brook", "fallen log", "ring of mushrooms", "fox den", "berry bush", "tree stump", "vine curtain"],
|
|
14
|
+
hidingSpots: ["the bushes", "behind a tree", "the undergrowth", "a hollow log", "thick ferns", "a bird's nest", "tangled roots", "a flower patch"],
|
|
15
|
+
directions: ["a shady path", "a sun-lit trail", "a narrow deer path", "a moss-covered passage", "through the ferns", "along the stream", "under low branches", "past the berry thicket"],
|
|
16
|
+
comfortSpecies: ["rabbit", "fox"],
|
|
17
|
+
},
|
|
18
|
+
caves: {
|
|
19
|
+
id: "caves", name: "Crystal Caves",
|
|
20
|
+
enemies: { easy: ["mushroom", "snail"], medium: ["golem", "crow", "rustknight"], hard: ["golem", "lavabeetle", "crystalbasilisk"], boss: ["crystalguardian"] },
|
|
21
|
+
loot: { common: ["herb", "wooden_stick"], uncommon: ["potion", "iron_sword", "chain_mail"], rare: ["crystal_blade", "crystal_armor", "midnight_bow"], epic: ["flame_scepter", "dragon_fang", "sunblade"] },
|
|
22
|
+
nouns: ["cavern", "tunnel", "grotto", "chamber", "crevice", "mine shaft", "chasm", "alcove", "passage", "vault"],
|
|
23
|
+
adjectives: ["glowing", "dark", "crystalline", "echoing", "damp", "deep", "narrow", "sparkling", "cold", "silent"],
|
|
24
|
+
landmarks: ["crystal cluster", "underground pool", "stalactite formation", "glowing vein", "ancient carving", "mineral deposit", "dripping ceiling", "crystal arch", "phosphorescent moss"],
|
|
25
|
+
hidingSpots: ["the shadows", "behind a stalagmite", "a dark alcove", "a crack in the wall", "under a ledge", "in a shallow pool", "behind crystal pillars", "a narrow fissure"],
|
|
26
|
+
directions: ["a narrow crystal tunnel", "a wide cavern", "a descending slope", "a flooded passage", "through a crystal archway", "down a spiral path", "along an underground river", "past glowing mushrooms"],
|
|
27
|
+
comfortSpecies: ["frog", "dragon"],
|
|
28
|
+
},
|
|
29
|
+
mountains: {
|
|
30
|
+
id: "mountains", name: "Windy Peaks",
|
|
31
|
+
enemies: { easy: ["squirrel", "flamesprite"], medium: ["crow", "shadowfox", "emberfox"], hard: ["stormwolf", "lavabeetle", "crystalbasilisk"], boss: ["crystalguardian"] },
|
|
32
|
+
loot: { common: ["berry", "herb"], uncommon: ["potion", "chain_mail", "swift_boots"], rare: ["crystal_armor", "elixir", "dodge_cloak"], epic: ["dragon_fang", "dragon_scale_armor"] },
|
|
33
|
+
nouns: ["peak", "ridge", "cliff", "plateau", "pass", "summit", "crag", "ledge", "slope", "mountain"],
|
|
34
|
+
adjectives: ["windswept", "frozen", "steep", "treacherous", "snow-covered", "jagged", "towering", "icy", "barren", "majestic"],
|
|
35
|
+
landmarks: ["cairn of stones", "frozen waterfall", "eagle's nest", "mountain shrine", "wind-carved rock", "ice cave mouth", "abandoned camp", "prayer flags", "lookout point"],
|
|
36
|
+
hidingSpots: ["the mist", "behind a boulder", "a snow drift", "a rocky overhang", "a crevasse", "swirling clouds", "an ice formation", "behind a cairn"],
|
|
37
|
+
directions: ["a steep climb", "a rocky path", "a sheltered ravine", "a windy ridge", "across a rope bridge", "up a narrow ledge", "through a snow field", "along a goat trail"],
|
|
38
|
+
comfortSpecies: ["owl", "phoenix"],
|
|
39
|
+
},
|
|
40
|
+
swamp: {
|
|
41
|
+
id: "swamp", name: "Shadow Marsh",
|
|
42
|
+
enemies: { easy: ["snail", "mushroom", "puddleslime"], medium: ["shadowfox", "vinecreeper"], hard: ["stormwolf", "bogwitch"], boss: ["marshking"] },
|
|
43
|
+
loot: { common: ["herb", "stick"], uncommon: ["potion", "fish"], rare: ["elixir", "crystal_blade", "thorn_whip"], epic: ["phoenix_robe", "flame_scepter", "coral_plate"] },
|
|
44
|
+
nouns: ["marsh", "bog", "swamp", "fen", "wetland", "mire", "bayou", "quagmire", "morass", "lagoon"],
|
|
45
|
+
adjectives: ["murky", "foggy", "dank", "eerie", "bubbling", "stagnant", "slimy", "haunted", "oppressive", "dark"],
|
|
46
|
+
landmarks: ["dead tree", "lily pad cluster", "gas vent", "sunken ruins", "rotting dock", "will-o-wisp", "hanging moss", "frog choir spot", "ancient bridge"],
|
|
47
|
+
hidingSpots: ["the fog", "under the water", "behind reeds", "the murk", "beneath lily pads", "in the mud", "behind a dead tree", "thick marsh grass"],
|
|
48
|
+
directions: ["a rickety boardwalk", "through shallow muck", "along the bank", "over mossy stones", "past bubbling mud", "through cattails", "across stepping stones", "under drooping willows"],
|
|
49
|
+
comfortSpecies: ["frog"],
|
|
50
|
+
},
|
|
51
|
+
ruins: {
|
|
52
|
+
id: "ruins", name: "Ancient Ruins",
|
|
53
|
+
enemies: { easy: ["mushroom", "flamesprite"], medium: ["golem", "crow", "rustknight"], hard: ["golem", "stormwolf", "crystalbasilisk"], boss: ["crystalguardian"] },
|
|
54
|
+
loot: { common: ["herb", "wooden_stick"], uncommon: ["iron_sword", "chain_mail", "potion"], rare: ["crystal_blade", "crystal_armor", "midnight_bow"], epic: ["dragon_fang", "dragon_scale_armor", "sunblade"] },
|
|
55
|
+
nouns: ["ruins", "temple", "hall", "corridor", "chamber", "sanctum", "crypt", "gallery", "courtyard", "archive"],
|
|
56
|
+
adjectives: ["crumbling", "ancient", "vine-covered", "mysterious", "silent", "forgotten", "sacred", "dusty", "ornate", "eerie"],
|
|
57
|
+
landmarks: ["broken statue", "faded mural", "altar", "collapsed pillar", "sealed door", "mosaic floor", "empty fountain", "stone throne", "inscription wall"],
|
|
58
|
+
hidingSpots: ["the rubble", "behind a pillar", "in the shadows", "a collapsed archway", "an empty alcove", "behind a statue", "under debris", "a dark doorway"],
|
|
59
|
+
directions: ["a dusty corridor", "through a cracked door", "down worn steps", "past fallen columns", "through an archway", "along a mosaic path", "into a side chamber", "up a spiral staircase"],
|
|
60
|
+
comfortSpecies: ["owl", "cat"],
|
|
61
|
+
},
|
|
62
|
+
volcano: {
|
|
63
|
+
id: "volcano", name: "Molten Core",
|
|
64
|
+
enemies: { easy: ["mushroom", "flamesprite"], medium: ["golem", "emberfox"], hard: ["lavabeetle", "stormwolf"], boss: ["crystalguardian", "infernodrake"] },
|
|
65
|
+
loot: { common: ["herb", "sandals"], uncommon: ["potion", "iron_sword", "fire_amulet", "iron_helm"], rare: ["flame_scepter", "elixir", "shadow_hood"], epic: ["dragon_fang", "dragon_scale_armor", "phoenix_crest", "flame_treads", "dragon_helm", "dragon_greaves"] },
|
|
66
|
+
nouns: ["volcano", "caldera", "lava tube", "vent", "magma chamber", "crater", "furnace", "forge", "inferno", "core"],
|
|
67
|
+
adjectives: ["scorching", "glowing", "smoldering", "blazing", "sulfurous", "molten", "blistering", "incandescent", "ashen", "fiery"],
|
|
68
|
+
landmarks: ["lava flow", "obsidian formation", "fire geyser", "molten pool", "charred skeleton", "cooled lava bridge", "fire crystal", "volcanic vent", "magma spring"],
|
|
69
|
+
hidingSpots: ["the heat haze", "behind cooled lava", "an obsidian wall", "a vent plume", "ash clouds", "a lava tube", "behind a fire crystal", "a smoldering crater"],
|
|
70
|
+
directions: ["across a lava bridge", "through a cooled tunnel", "along the crater rim", "past a fire geyser", "over hardened magma", "through an ash field", "along the caldera edge", "into the furnace depths"],
|
|
71
|
+
comfortSpecies: ["phoenix", "dragon"],
|
|
72
|
+
},
|
|
73
|
+
shadowrealm: {
|
|
74
|
+
id: "shadowrealm", name: "Shadow Realm",
|
|
75
|
+
enemies: { easy: ["shadowfox", "crow"], medium: ["shadowfox", "crow", "rustknight"], hard: ["crystalbasilisk", "bogwitch", "stormwolf"], boss: ["thestranger"] },
|
|
76
|
+
loot: { common: ["herb", "stick"], uncommon: ["potion", "midnight_bow"], rare: ["shadow_hood", "shadow_steps", "elixir"], epic: ["shadow_dagger", "shadow_cloak"] },
|
|
77
|
+
nouns: ["void", "rift", "abyss", "expanse", "fracture", "echo", "mirage", "hollow", "emptiness", "chasm"],
|
|
78
|
+
adjectives: ["twisted", "inverted", "dark", "warped", "shifting", "hollow", "silent", "wrong", "familiar yet alien", "dreamlike"],
|
|
79
|
+
landmarks: ["shadow tree", "mirrored stone", "dark fountain", "twisted archway", "fading memory", "corrupted crystal", "echo of a bridge", "phantom campfire"],
|
|
80
|
+
hidingSpots: ["the darkness", "a ripple in reality", "behind your own shadow", "inside a memory", "the void between spaces", "a crack in the world"],
|
|
81
|
+
directions: ["into the shifting dark", "toward a familiar echo", "through a warped doorway", "along a path that wasn't there before", "following a faint light"],
|
|
82
|
+
comfortSpecies: ["cat"],
|
|
83
|
+
},
|
|
84
|
+
thecore: {
|
|
85
|
+
id: "thecore", name: "The Core",
|
|
86
|
+
enemies: { easy: ["flamesprite", "puddleslime"], medium: ["emberfox", "golem", "vinecreeper"], hard: ["lavabeetle", "crystalbasilisk", "stormwolf"], boss: ["shadowbeast"] },
|
|
87
|
+
loot: { common: ["herb", "berry"], uncommon: ["potion", "iron_sword"], rare: ["elixir", "crystal_blade"], epic: ["dragon_fang", "dragon_scale_armor", "elementalist_orb"] },
|
|
88
|
+
nouns: ["core", "nexus", "convergence", "heart", "origin", "source", "wellspring", "singularity", "foundation", "center"],
|
|
89
|
+
adjectives: ["primordial", "blinding", "pulsing", "overwhelming", "raw", "elemental", "ancient", "pure", "infinite", "resonating"],
|
|
90
|
+
landmarks: ["elemental vortex", "stone circle", "pillar of light", "pool of all colors", "the original seal", "six stone fragments", "throne of the guardian"],
|
|
91
|
+
hidingSpots: ["swirling energy", "behind a pillar of light", "within the elements", "between the Stones", "the eye of the storm"],
|
|
92
|
+
directions: ["toward the light", "through the elemental storm", "past the broken seal", "into the heart of everything", "following all six elements"],
|
|
93
|
+
comfortSpecies: [],
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
function getBiome(id) {
|
|
97
|
+
return exports.BIOMES[id];
|
|
98
|
+
}
|
|
99
|
+
function getAllBiomeIds() {
|
|
100
|
+
return Object.keys(exports.BIOMES);
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=biomes.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("../combat/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,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
|