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,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createOverlay = createOverlay;
|
|
4
|
+
exports.openOverlay = openOverlay;
|
|
5
|
+
exports.scrollOverlay = scrollOverlay;
|
|
6
|
+
exports.renderTitlesOverlay = renderTitlesOverlay;
|
|
7
|
+
exports.renderNotificationsOverlay = renderNotificationsOverlay;
|
|
8
|
+
exports.getSettingEntries = getSettingEntries;
|
|
9
|
+
exports.renderSettingsOverlay = renderSettingsOverlay;
|
|
10
|
+
exports.renderGearOverlay = renderGearOverlay;
|
|
11
|
+
exports.renderCombatInfoOverlay = renderCombatInfoOverlay;
|
|
12
|
+
exports.renderShopOverlay = renderShopOverlay;
|
|
13
|
+
const titles_1 = require("../buddy/titles");
|
|
14
|
+
const combat_1 = require("../adventure/combat/combat");
|
|
15
|
+
const items_1 = require("../inventory/items");
|
|
16
|
+
const shop_1 = require("../story/shop");
|
|
17
|
+
const listUtils_1 = require("./listUtils");
|
|
18
|
+
const screen_1 = require("./screen");
|
|
19
|
+
function createOverlay() {
|
|
20
|
+
return { type: null, scrollIndex: 0 };
|
|
21
|
+
}
|
|
22
|
+
function openOverlay(type) {
|
|
23
|
+
return { type, scrollIndex: 0 };
|
|
24
|
+
}
|
|
25
|
+
function scrollOverlay(overlay, delta, maxItems) {
|
|
26
|
+
return { ...overlay, scrollIndex: (0, listUtils_1.moveListIndex)(overlay.scrollIndex, delta, maxItems, false) };
|
|
27
|
+
}
|
|
28
|
+
function formatTimeAgo(timestamp) {
|
|
29
|
+
const seconds = Math.floor((Date.now() - timestamp) / 1000);
|
|
30
|
+
if (seconds < 60)
|
|
31
|
+
return "just now";
|
|
32
|
+
const minutes = Math.floor(seconds / 60);
|
|
33
|
+
if (minutes < 60)
|
|
34
|
+
return `${minutes}m ago`;
|
|
35
|
+
const hours = Math.floor(minutes / 60);
|
|
36
|
+
if (hours < 24)
|
|
37
|
+
return `${hours}h ago`;
|
|
38
|
+
const days = Math.floor(hours / 24);
|
|
39
|
+
return `${days}d ago`;
|
|
40
|
+
}
|
|
41
|
+
function renderTitlesOverlay(state, overlay) {
|
|
42
|
+
const lines = [];
|
|
43
|
+
lines.push(` ${screen_1.ansi.dim}${"─".repeat(48)}${screen_1.ansi.reset}`);
|
|
44
|
+
lines.push(` ${screen_1.ansi.bold}Titles${screen_1.ansi.reset} ${screen_1.ansi.dim}(${state.titles.length}/${titles_1.TITLE_RULES.length} earned) Esc to close${screen_1.ansi.reset}`);
|
|
45
|
+
lines.push(` ${screen_1.ansi.dim}${"─".repeat(48)}${screen_1.ansi.reset}`);
|
|
46
|
+
for (let i = 0; i < titles_1.TITLE_RULES.length; i++) {
|
|
47
|
+
const rule = titles_1.TITLE_RULES[i];
|
|
48
|
+
const earned = state.titles.includes(rule.id);
|
|
49
|
+
const active = state.activeTitle === rule.id;
|
|
50
|
+
const selected = i === overlay.scrollIndex;
|
|
51
|
+
const pointer = selected ? `${screen_1.ansi.colors.cyan}▸${screen_1.ansi.reset}` : " ";
|
|
52
|
+
if (earned) {
|
|
53
|
+
const tag = active ? ` ${screen_1.ansi.colors.cyan}[equipped]${screen_1.ansi.reset}` : "";
|
|
54
|
+
lines.push(` ${pointer} ${screen_1.ansi.colors.green}✓${screen_1.ansi.reset} ${screen_1.ansi.bold}${rule.label}${screen_1.ansi.reset}${tag}`);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
lines.push(` ${pointer} ${screen_1.ansi.dim}✗ ??? — ${rule.hint}${screen_1.ansi.reset}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
lines.push(` ${screen_1.ansi.dim}${"─".repeat(48)}${screen_1.ansi.reset}`);
|
|
61
|
+
lines.push(` ${screen_1.ansi.dim}Enter to equip selected title${screen_1.ansi.reset}`);
|
|
62
|
+
return lines;
|
|
63
|
+
}
|
|
64
|
+
function renderNotificationsOverlay(notifications, overlay) {
|
|
65
|
+
const lines = [];
|
|
66
|
+
lines.push(` ${screen_1.ansi.dim}${"─".repeat(48)}${screen_1.ansi.reset}`);
|
|
67
|
+
lines.push(` ${screen_1.ansi.bold}Notifications${screen_1.ansi.reset} ${screen_1.ansi.dim}(${notifications.length}) Esc to close${screen_1.ansi.reset}`);
|
|
68
|
+
lines.push(` ${screen_1.ansi.dim}${"─".repeat(48)}${screen_1.ansi.reset}`);
|
|
69
|
+
if (notifications.length === 0) {
|
|
70
|
+
lines.push(` ${screen_1.ansi.dim} No notifications.${screen_1.ansi.reset}`);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// Show newest first
|
|
74
|
+
const reversed = [...notifications].reverse();
|
|
75
|
+
for (let i = 0; i < reversed.length; i++) {
|
|
76
|
+
const notif = reversed[i];
|
|
77
|
+
const selected = i === overlay.scrollIndex;
|
|
78
|
+
const pointer = selected ? `${screen_1.ansi.colors.cyan}▸${screen_1.ansi.reset}` : " ";
|
|
79
|
+
const timeAgo = formatTimeAgo(notif.timestamp);
|
|
80
|
+
lines.push(` ${pointer} ${notif.message}`);
|
|
81
|
+
lines.push(` ${screen_1.ansi.dim}${timeAgo}${screen_1.ansi.reset}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
lines.push(` ${screen_1.ansi.dim}${"─".repeat(48)}${screen_1.ansi.reset}`);
|
|
85
|
+
lines.push(` ${screen_1.ansi.dim}Enter to clear all${screen_1.ansi.reset}`);
|
|
86
|
+
return lines;
|
|
87
|
+
}
|
|
88
|
+
const SETTING_ENTRIES = [
|
|
89
|
+
{ key: "sound", name: "Sound", description: "Terminal bell on events" },
|
|
90
|
+
];
|
|
91
|
+
function getSettingEntries() {
|
|
92
|
+
return SETTING_ENTRIES;
|
|
93
|
+
}
|
|
94
|
+
function renderSettingsOverlay(settings, overlay) {
|
|
95
|
+
const lines = [];
|
|
96
|
+
lines.push(` ${screen_1.ansi.dim}${"─".repeat(48)}${screen_1.ansi.reset}`);
|
|
97
|
+
lines.push(` ${screen_1.ansi.bold}Settings${screen_1.ansi.reset} ${screen_1.ansi.dim}Enter to toggle, Esc to close${screen_1.ansi.reset}`);
|
|
98
|
+
lines.push(` ${screen_1.ansi.dim}${"─".repeat(48)}${screen_1.ansi.reset}`);
|
|
99
|
+
for (let i = 0; i < SETTING_ENTRIES.length; i++) {
|
|
100
|
+
const entry = SETTING_ENTRIES[i];
|
|
101
|
+
const value = settings[entry.key];
|
|
102
|
+
const selected = i === overlay.scrollIndex;
|
|
103
|
+
const pointer = selected ? `${screen_1.ansi.colors.cyan}▸${screen_1.ansi.reset}` : " ";
|
|
104
|
+
const toggle = value
|
|
105
|
+
? `${screen_1.ansi.colors.green}[ON] ${screen_1.ansi.reset}`
|
|
106
|
+
: `${screen_1.ansi.colors.red}[OFF]${screen_1.ansi.reset}`;
|
|
107
|
+
lines.push(` ${pointer} ${toggle} ${screen_1.ansi.bold}${entry.name}${screen_1.ansi.reset} ${screen_1.ansi.dim}${entry.description}${screen_1.ansi.reset}`);
|
|
108
|
+
}
|
|
109
|
+
lines.push(` ${screen_1.ansi.dim}${"─".repeat(48)}${screen_1.ansi.reset}`);
|
|
110
|
+
return lines;
|
|
111
|
+
}
|
|
112
|
+
function renderGearOverlay(state) {
|
|
113
|
+
const s = state.adventureStats;
|
|
114
|
+
const weapon = s.equippedWeapon ? (0, items_1.getItem)(s.equippedWeapon) : null;
|
|
115
|
+
const armor = s.equippedArmor ? (0, items_1.getItem)(s.equippedArmor) : null;
|
|
116
|
+
const helmet = s.equippedHelmet ? (0, items_1.getItem)(s.equippedHelmet) : null;
|
|
117
|
+
const boots = s.equippedBoots ? (0, items_1.getItem)(s.equippedBoots) : null;
|
|
118
|
+
const accessory = s.equippedAccessory ? (0, items_1.getItem)(s.equippedAccessory) : null;
|
|
119
|
+
const lines = [];
|
|
120
|
+
lines.push(` ${screen_1.ansi.dim}${"─".repeat(48)}${screen_1.ansi.reset}`);
|
|
121
|
+
lines.push(` ${screen_1.ansi.bold}Equipped Gear${screen_1.ansi.reset} ${screen_1.ansi.dim}Esc to close${screen_1.ansi.reset}`);
|
|
122
|
+
lines.push(` ${screen_1.ansi.dim}${"─".repeat(48)}${screen_1.ansi.reset}`);
|
|
123
|
+
lines.push(` ⚔ Weapon: ${weapon ? `${weapon.name} (+${weapon.combatATK} ATK)${weapon.gearElement ? ` [${weapon.gearElement}]` : ""}` : `${screen_1.ansi.dim}None${screen_1.ansi.reset}`}`);
|
|
124
|
+
if (weapon?.onHitEffect)
|
|
125
|
+
lines.push(` ${screen_1.ansi.dim}${Math.round((weapon.onHitChance ?? 0) * 100)}% ${weapon.onHitEffect} on hit${screen_1.ansi.reset}`);
|
|
126
|
+
lines.push(` 🛡 Armor: ${armor ? `${armor.name} (+${armor.combatDEF} DEF)` : `${screen_1.ansi.dim}None${screen_1.ansi.reset}`}`);
|
|
127
|
+
if (armor?.combatHP)
|
|
128
|
+
lines.push(` ${screen_1.ansi.dim}+${armor.combatHP} HP${screen_1.ansi.reset}`);
|
|
129
|
+
lines.push(` 🪖 Helmet: ${helmet ? `${helmet.name} (${helmet.description})` : `${screen_1.ansi.dim}None${screen_1.ansi.reset}`}`);
|
|
130
|
+
lines.push(` 👢 Boots: ${boots ? `${boots.name} (${boots.description})` : `${screen_1.ansi.dim}None${screen_1.ansi.reset}`}`);
|
|
131
|
+
lines.push(` 💍 Acc: ${accessory ? `${accessory.name} (${accessory.description})` : `${screen_1.ansi.dim}None${screen_1.ansi.reset}`}`);
|
|
132
|
+
lines.push(` ${screen_1.ansi.dim}${"─".repeat(48)}${screen_1.ansi.reset}`);
|
|
133
|
+
lines.push(` ${screen_1.ansi.dim}Equip gear from /inventory${screen_1.ansi.reset}`);
|
|
134
|
+
return lines;
|
|
135
|
+
}
|
|
136
|
+
function renderCombatInfoOverlay(state) {
|
|
137
|
+
const stats = (0, combat_1.deriveCombatStats)(state);
|
|
138
|
+
const { equippedWeapon, equippedArmor } = state.adventureStats;
|
|
139
|
+
const weapon = equippedWeapon ? (0, items_1.getItem)(equippedWeapon) : null;
|
|
140
|
+
const armor = equippedArmor ? (0, items_1.getItem)(equippedArmor) : null;
|
|
141
|
+
const lines = [];
|
|
142
|
+
lines.push(` ${screen_1.ansi.dim}${"─".repeat(48)}${screen_1.ansi.reset}`);
|
|
143
|
+
lines.push(` ${screen_1.ansi.bold}Combat Stats${screen_1.ansi.reset} ${screen_1.ansi.dim}Esc to close${screen_1.ansi.reset}`);
|
|
144
|
+
lines.push(` ${screen_1.ansi.dim}${"─".repeat(48)}${screen_1.ansi.reset}`);
|
|
145
|
+
lines.push(` HP: ${screen_1.ansi.colors.green}${stats.maxHp}${screen_1.ansi.reset}`);
|
|
146
|
+
lines.push(` ATK: ${screen_1.ansi.colors.red}${stats.atk}${screen_1.ansi.reset}${weapon ? ` (base + ${weapon.combatATK} from ${weapon.name})` : ""}`);
|
|
147
|
+
lines.push(` DEF: ${screen_1.ansi.colors.blue}${stats.def}${screen_1.ansi.reset}${armor ? ` (base + ${armor.combatDEF} from ${armor.name})` : ""}`);
|
|
148
|
+
lines.push(` SPD: ${stats.spd}`);
|
|
149
|
+
lines.push(` Dodge: ${Math.round(stats.dodgeChance * 100)}%`);
|
|
150
|
+
lines.push("");
|
|
151
|
+
lines.push(` ${screen_1.ansi.dim}Adventures: ${state.adventureStats.adventuresCompleted} | Battles won: ${state.adventureStats.battlesWon}${screen_1.ansi.reset}`);
|
|
152
|
+
lines.push(` ${screen_1.ansi.dim}Bosses defeated: ${state.adventureStats.bossesDefeated} | Perfect runs: ${state.adventureStats.perfectAdventures}${screen_1.ansi.reset}`);
|
|
153
|
+
lines.push(` ${screen_1.ansi.dim}${"─".repeat(48)}${screen_1.ansi.reset}`);
|
|
154
|
+
return lines;
|
|
155
|
+
}
|
|
156
|
+
function renderShopOverlay(state, overlay) {
|
|
157
|
+
const lines = [];
|
|
158
|
+
const gold = state.questProgress.gold;
|
|
159
|
+
lines.push(` ${screen_1.ansi.dim}${"─".repeat(48)}${screen_1.ansi.reset}`);
|
|
160
|
+
lines.push(` ${screen_1.ansi.bold}Pip's Shop${screen_1.ansi.reset} ${screen_1.ansi.colors.yellow}Gold: ${gold}${screen_1.ansi.reset} ${screen_1.ansi.dim}Esc to close${screen_1.ansi.reset}`);
|
|
161
|
+
lines.push(` ${screen_1.ansi.dim}${"─".repeat(48)}${screen_1.ansi.reset}`);
|
|
162
|
+
for (let i = 0; i < shop_1.SHOP_ITEMS.length; i++) {
|
|
163
|
+
const shopItem = shop_1.SHOP_ITEMS[i];
|
|
164
|
+
const item = (0, items_1.getItem)(shopItem.itemId);
|
|
165
|
+
if (!item)
|
|
166
|
+
continue;
|
|
167
|
+
const selected = i === overlay.scrollIndex;
|
|
168
|
+
const pointer = selected ? `${screen_1.ansi.colors.cyan}▸${screen_1.ansi.reset}` : " ";
|
|
169
|
+
const canAfford = gold >= shopItem.price;
|
|
170
|
+
const priceColor = canAfford ? screen_1.ansi.colors.yellow : screen_1.ansi.colors.red;
|
|
171
|
+
const rarityColor = items_1.ITEM_RARITY_COLORS[item.rarity] ?? "";
|
|
172
|
+
if (selected) {
|
|
173
|
+
lines.push(` ${pointer} ${rarityColor}${item.name}${screen_1.ansi.reset} ${priceColor}${shopItem.price}g${screen_1.ansi.reset}`);
|
|
174
|
+
lines.push(` ${screen_1.ansi.dim}${item.description}${screen_1.ansi.reset}`);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
lines.push(` ${pointer} ${screen_1.ansi.dim}${item.name} ${shopItem.price}g${screen_1.ansi.reset}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
lines.push(` ${screen_1.ansi.dim}${"─".repeat(48)}${screen_1.ansi.reset}`);
|
|
181
|
+
lines.push(` ${screen_1.ansi.dim}Enter to buy${screen_1.ansi.reset}`);
|
|
182
|
+
return lines;
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=overlayUI.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SceneItem } from "./items";
|
|
2
|
+
/**
|
|
3
|
+
* Compose a scene by placing buddy art and an optional item
|
|
4
|
+
* into a fixed-width character buffer.
|
|
5
|
+
* Returns an array of lines ready to render.
|
|
6
|
+
*/
|
|
7
|
+
export declare function composeScene(buddyArt: string[], item: SceneItem | null, groundLine?: boolean): string[];
|
|
8
|
+
//# sourceMappingURL=scene.d.ts.map
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.composeScene = composeScene;
|
|
4
|
+
const SCENE_WIDTH = 50;
|
|
5
|
+
/**
|
|
6
|
+
* Compose a scene by placing buddy art and an optional item
|
|
7
|
+
* into a fixed-width character buffer.
|
|
8
|
+
* Returns an array of lines ready to render.
|
|
9
|
+
*/
|
|
10
|
+
function composeScene(buddyArt, item, groundLine = true) {
|
|
11
|
+
if (!item) {
|
|
12
|
+
// No item — just center the buddy with optional ground line
|
|
13
|
+
const lines = buddyArt.map((line) => centerPad(line, SCENE_WIDTH));
|
|
14
|
+
if (groundLine) {
|
|
15
|
+
lines.push(centerPad("─".repeat(Math.max(...buddyArt.map(visibleLength)) + 4), SCENE_WIDTH));
|
|
16
|
+
}
|
|
17
|
+
return lines;
|
|
18
|
+
}
|
|
19
|
+
if (item.position === "below") {
|
|
20
|
+
return composeBuddyAboveItem(buddyArt, item);
|
|
21
|
+
}
|
|
22
|
+
// "right" or "left" — side by side
|
|
23
|
+
return composeSideBySide(buddyArt, item);
|
|
24
|
+
}
|
|
25
|
+
function composeBuddyAboveItem(buddyArt, item) {
|
|
26
|
+
const lines = [];
|
|
27
|
+
// Center buddy above the item
|
|
28
|
+
for (const line of buddyArt) {
|
|
29
|
+
lines.push(centerPad(line, SCENE_WIDTH));
|
|
30
|
+
}
|
|
31
|
+
// Item below
|
|
32
|
+
for (const line of item.art) {
|
|
33
|
+
lines.push(centerPad(line, SCENE_WIDTH));
|
|
34
|
+
}
|
|
35
|
+
return lines;
|
|
36
|
+
}
|
|
37
|
+
function composeSideBySide(buddyArt, item) {
|
|
38
|
+
const itemArt = item.art;
|
|
39
|
+
const gap = " ";
|
|
40
|
+
// Determine heights and vertical alignment (bottom-align)
|
|
41
|
+
const maxHeight = Math.max(buddyArt.length, itemArt.length);
|
|
42
|
+
// Pad shorter array from the top
|
|
43
|
+
const paddedBuddy = topPad(buddyArt, maxHeight);
|
|
44
|
+
const paddedItem = topPad(itemArt, maxHeight);
|
|
45
|
+
const buddyWidth = Math.max(...buddyArt.map(visibleLength));
|
|
46
|
+
const lines = [];
|
|
47
|
+
for (let i = 0; i < maxHeight; i++) {
|
|
48
|
+
const bLine = rightPad(paddedBuddy[i], buddyWidth);
|
|
49
|
+
const iLine = paddedItem[i];
|
|
50
|
+
if (item.position === "right") {
|
|
51
|
+
lines.push(centerPad(bLine + gap + iLine, SCENE_WIDTH));
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
lines.push(centerPad(iLine + gap + bLine, SCENE_WIDTH));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Ground line
|
|
58
|
+
const totalWidth = buddyWidth + gap.length + Math.max(...itemArt.map(visibleLength));
|
|
59
|
+
lines.push(centerPad("─".repeat(totalWidth + 2), SCENE_WIDTH));
|
|
60
|
+
return lines;
|
|
61
|
+
}
|
|
62
|
+
/** Pad array from top with empty strings to reach target length */
|
|
63
|
+
function topPad(arr, targetLen) {
|
|
64
|
+
const padding = targetLen - arr.length;
|
|
65
|
+
if (padding <= 0)
|
|
66
|
+
return arr;
|
|
67
|
+
return [...Array(padding).fill(""), ...arr];
|
|
68
|
+
}
|
|
69
|
+
/** Visible length of a string (excluding ANSI escape codes) */
|
|
70
|
+
function visibleLength(str) {
|
|
71
|
+
// Strip ANSI codes
|
|
72
|
+
return str.replace(/\x1b\[[0-9;]*m/g, "").length;
|
|
73
|
+
}
|
|
74
|
+
/** Right-pad a string with spaces to target visible width */
|
|
75
|
+
function rightPad(str, targetWidth) {
|
|
76
|
+
const pad = targetWidth - visibleLength(str);
|
|
77
|
+
return pad > 0 ? str + " ".repeat(pad) : str;
|
|
78
|
+
}
|
|
79
|
+
/** Center a string within target width */
|
|
80
|
+
function centerPad(str, targetWidth) {
|
|
81
|
+
const len = visibleLength(str);
|
|
82
|
+
if (len >= targetWidth)
|
|
83
|
+
return str;
|
|
84
|
+
const leftPad = Math.floor((targetWidth - len) / 2);
|
|
85
|
+
return " ".repeat(leftPad) + str;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=scene.js.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Full-screen terminal renderer.
|
|
3
|
+
* Owns the entire terminal — clears and redraws each frame.
|
|
4
|
+
* No scrolling, no message spam.
|
|
5
|
+
*/
|
|
6
|
+
export declare const ansi: {
|
|
7
|
+
clearScreen: string;
|
|
8
|
+
hideCursor: string;
|
|
9
|
+
showCursor: string;
|
|
10
|
+
moveTo: (row: number, col: number) => string;
|
|
11
|
+
eraseDown: string;
|
|
12
|
+
bold: string;
|
|
13
|
+
dim: string;
|
|
14
|
+
reset: string;
|
|
15
|
+
colors: {
|
|
16
|
+
red: string;
|
|
17
|
+
green: string;
|
|
18
|
+
yellow: string;
|
|
19
|
+
blue: string;
|
|
20
|
+
magenta: string;
|
|
21
|
+
cyan: string;
|
|
22
|
+
white: string;
|
|
23
|
+
gray: string;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export declare class Screen {
|
|
27
|
+
private regions;
|
|
28
|
+
private footer;
|
|
29
|
+
private inputLine;
|
|
30
|
+
private width;
|
|
31
|
+
private height;
|
|
32
|
+
constructor();
|
|
33
|
+
/** Replace all content and redraw */
|
|
34
|
+
draw(content: string, footer?: string): void;
|
|
35
|
+
/** Update just the input line at the bottom without full redraw */
|
|
36
|
+
drawInputLine(input: string): void;
|
|
37
|
+
/** Draw an overlay (command palette) over the bottom portion of the screen */
|
|
38
|
+
drawOverlay(lines: string[], inputLine: string): void;
|
|
39
|
+
getWidth(): number;
|
|
40
|
+
getHeight(): number;
|
|
41
|
+
cleanup(): void;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=screen.d.ts.map
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Full-screen terminal renderer.
|
|
4
|
+
* Owns the entire terminal — clears and redraws each frame.
|
|
5
|
+
* No scrolling, no message spam.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.Screen = exports.ansi = void 0;
|
|
9
|
+
const ESC = "\x1b";
|
|
10
|
+
exports.ansi = {
|
|
11
|
+
clearScreen: `${ESC}[2J${ESC}[H`,
|
|
12
|
+
hideCursor: `${ESC}[?25l`,
|
|
13
|
+
showCursor: `${ESC}[?25h`,
|
|
14
|
+
moveTo: (row, col) => `${ESC}[${row};${col}H`,
|
|
15
|
+
eraseDown: `${ESC}[J`,
|
|
16
|
+
bold: `${ESC}[1m`,
|
|
17
|
+
dim: `${ESC}[2m`,
|
|
18
|
+
reset: `${ESC}[0m`,
|
|
19
|
+
colors: {
|
|
20
|
+
red: `${ESC}[31m`,
|
|
21
|
+
green: `${ESC}[32m`,
|
|
22
|
+
yellow: `${ESC}[33m`,
|
|
23
|
+
blue: `${ESC}[34m`,
|
|
24
|
+
magenta: `${ESC}[35m`,
|
|
25
|
+
cyan: `${ESC}[36m`,
|
|
26
|
+
white: `${ESC}[37m`,
|
|
27
|
+
gray: `${ESC}[90m`,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
class Screen {
|
|
31
|
+
regions = [];
|
|
32
|
+
footer = "";
|
|
33
|
+
inputLine = "";
|
|
34
|
+
width;
|
|
35
|
+
height;
|
|
36
|
+
constructor() {
|
|
37
|
+
this.width = process.stdout.columns || 80;
|
|
38
|
+
this.height = process.stdout.rows || 24;
|
|
39
|
+
process.stdout.on("resize", () => {
|
|
40
|
+
this.width = process.stdout.columns || 80;
|
|
41
|
+
this.height = process.stdout.rows || 24;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/** Replace all content and redraw */
|
|
45
|
+
draw(content, footer) {
|
|
46
|
+
const out = process.stdout;
|
|
47
|
+
out.write(exports.ansi.hideCursor);
|
|
48
|
+
out.write(exports.ansi.clearScreen);
|
|
49
|
+
out.write(content);
|
|
50
|
+
if (footer) {
|
|
51
|
+
// Draw footer at bottom
|
|
52
|
+
out.write(exports.ansi.moveTo(this.height - 1, 1));
|
|
53
|
+
out.write(footer);
|
|
54
|
+
}
|
|
55
|
+
// Position cursor at input line
|
|
56
|
+
out.write(exports.ansi.moveTo(this.height, 1));
|
|
57
|
+
out.write(exports.ansi.eraseDown);
|
|
58
|
+
out.write(this.inputLine);
|
|
59
|
+
out.write(exports.ansi.showCursor);
|
|
60
|
+
}
|
|
61
|
+
/** Update just the input line at the bottom without full redraw */
|
|
62
|
+
drawInputLine(input) {
|
|
63
|
+
this.inputLine = input;
|
|
64
|
+
const out = process.stdout;
|
|
65
|
+
out.write(exports.ansi.moveTo(this.height, 1));
|
|
66
|
+
out.write("\x1b[2K"); // erase line
|
|
67
|
+
out.write(input);
|
|
68
|
+
}
|
|
69
|
+
/** Draw an overlay (command palette) over the bottom portion of the screen */
|
|
70
|
+
drawOverlay(lines, inputLine) {
|
|
71
|
+
const out = process.stdout;
|
|
72
|
+
const startRow = this.height - lines.length - 1;
|
|
73
|
+
// Draw overlay lines
|
|
74
|
+
for (let i = 0; i < lines.length; i++) {
|
|
75
|
+
out.write(exports.ansi.moveTo(startRow + i, 1));
|
|
76
|
+
out.write("\x1b[2K"); // erase line
|
|
77
|
+
out.write(lines[i]);
|
|
78
|
+
}
|
|
79
|
+
// Draw input line at bottom
|
|
80
|
+
out.write(exports.ansi.moveTo(this.height, 1));
|
|
81
|
+
out.write("\x1b[2K");
|
|
82
|
+
out.write(inputLine);
|
|
83
|
+
out.write(exports.ansi.showCursor);
|
|
84
|
+
}
|
|
85
|
+
getWidth() {
|
|
86
|
+
return this.width;
|
|
87
|
+
}
|
|
88
|
+
getHeight() {
|
|
89
|
+
return this.height;
|
|
90
|
+
}
|
|
91
|
+
cleanup() {
|
|
92
|
+
process.stdout.write(exports.ansi.showCursor);
|
|
93
|
+
process.stdout.write(exports.ansi.clearScreen);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
exports.Screen = Screen;
|
|
97
|
+
//# sourceMappingURL=screen.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare function soundLevelUp(): void;
|
|
2
|
+
export declare function soundTitleEarned(): void;
|
|
3
|
+
export declare function soundItemFound(): void;
|
|
4
|
+
export declare function soundDeath(): void;
|
|
5
|
+
export declare function soundRareRoll(): void;
|
|
6
|
+
export declare function soundGameEnd(): void;
|
|
7
|
+
export declare function soundBattleWin(): void;
|
|
8
|
+
export declare function soundBossEncounter(): void;
|
|
9
|
+
export declare function soundAdventureComplete(): void;
|
|
10
|
+
export declare function soundCombo(): void;
|
|
11
|
+
//# sourceMappingURL=sound.d.ts.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.soundLevelUp = soundLevelUp;
|
|
4
|
+
exports.soundTitleEarned = soundTitleEarned;
|
|
5
|
+
exports.soundItemFound = soundItemFound;
|
|
6
|
+
exports.soundDeath = soundDeath;
|
|
7
|
+
exports.soundRareRoll = soundRareRoll;
|
|
8
|
+
exports.soundGameEnd = soundGameEnd;
|
|
9
|
+
exports.soundBattleWin = soundBattleWin;
|
|
10
|
+
exports.soundBossEncounter = soundBossEncounter;
|
|
11
|
+
exports.soundAdventureComplete = soundAdventureComplete;
|
|
12
|
+
exports.soundCombo = soundCombo;
|
|
13
|
+
const settings_1 = require("../state/settings");
|
|
14
|
+
function bell() {
|
|
15
|
+
if ((0, settings_1.getSettings)().sound) {
|
|
16
|
+
process.stdout.write("\x07");
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function doubleBell() {
|
|
20
|
+
if ((0, settings_1.getSettings)().sound) {
|
|
21
|
+
process.stdout.write("\x07");
|
|
22
|
+
setTimeout(() => process.stdout.write("\x07"), 200);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function soundLevelUp() {
|
|
26
|
+
bell();
|
|
27
|
+
}
|
|
28
|
+
function soundTitleEarned() {
|
|
29
|
+
bell();
|
|
30
|
+
}
|
|
31
|
+
function soundItemFound() {
|
|
32
|
+
bell();
|
|
33
|
+
}
|
|
34
|
+
function soundDeath() {
|
|
35
|
+
doubleBell();
|
|
36
|
+
}
|
|
37
|
+
function soundRareRoll() {
|
|
38
|
+
doubleBell();
|
|
39
|
+
}
|
|
40
|
+
function soundGameEnd() {
|
|
41
|
+
bell();
|
|
42
|
+
}
|
|
43
|
+
function soundBattleWin() {
|
|
44
|
+
bell();
|
|
45
|
+
}
|
|
46
|
+
function soundBossEncounter() {
|
|
47
|
+
doubleBell();
|
|
48
|
+
}
|
|
49
|
+
function soundAdventureComplete() {
|
|
50
|
+
doubleBell();
|
|
51
|
+
}
|
|
52
|
+
function soundCombo() {
|
|
53
|
+
bell();
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=sound.js.map
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.saveState = saveState;
|
|
37
|
+
exports.loadState = loadState;
|
|
38
|
+
exports.deleteState = deleteState;
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const os = __importStar(require("os"));
|
|
42
|
+
const types_1 = require("../story/types");
|
|
43
|
+
const STATE_DIR = path.join(os.homedir(), ".clibuddy");
|
|
44
|
+
const STATE_FILE = path.join(STATE_DIR, "state.json");
|
|
45
|
+
function ensureDir() {
|
|
46
|
+
if (!fs.existsSync(STATE_DIR)) {
|
|
47
|
+
fs.mkdirSync(STATE_DIR, { recursive: true });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function saveState(state) {
|
|
51
|
+
ensureDir();
|
|
52
|
+
fs.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2), "utf-8");
|
|
53
|
+
}
|
|
54
|
+
function loadState() {
|
|
55
|
+
if (!fs.existsSync(STATE_FILE))
|
|
56
|
+
return null;
|
|
57
|
+
try {
|
|
58
|
+
const raw = fs.readFileSync(STATE_FILE, "utf-8");
|
|
59
|
+
const state = JSON.parse(raw);
|
|
60
|
+
// Backfill new fields for old save files
|
|
61
|
+
if (!state.titles)
|
|
62
|
+
state.titles = [];
|
|
63
|
+
if (!state.actionCounts)
|
|
64
|
+
state.actionCounts = { feeds: 0, plays: 0, sleeps: 0, heals: 0, revives: 0, pets: 0, minigamesWon: 0, itemsFound: 0, combosTriggered: 0 };
|
|
65
|
+
// Backfill new action count fields
|
|
66
|
+
if (state.actionCounts.pets === undefined)
|
|
67
|
+
state.actionCounts.pets = 0;
|
|
68
|
+
if (state.actionCounts.minigamesWon === undefined)
|
|
69
|
+
state.actionCounts.minigamesWon = 0;
|
|
70
|
+
if (state.actionCounts.itemsFound === undefined)
|
|
71
|
+
state.actionCounts.itemsFound = 0;
|
|
72
|
+
if (state.actionCounts.combosTriggered === undefined)
|
|
73
|
+
state.actionCounts.combosTriggered = 0;
|
|
74
|
+
if (!state.inventory)
|
|
75
|
+
state.inventory = [];
|
|
76
|
+
if (!state.notifications)
|
|
77
|
+
state.notifications = [];
|
|
78
|
+
// Migrate old string[] notifications to Notification[]
|
|
79
|
+
if (state.notifications.length > 0 && typeof state.notifications[0] === "string") {
|
|
80
|
+
state.notifications = state.notifications.map((msg) => ({ message: msg, timestamp: Date.now() }));
|
|
81
|
+
}
|
|
82
|
+
if (!state.adventureStats)
|
|
83
|
+
state.adventureStats = {
|
|
84
|
+
adventuresCompleted: 0, battlesWon: 0, battlesLost: 0,
|
|
85
|
+
battlesFled: 0, bossesDefeated: 0, totalDamageDealt: 0, perfectAdventures: 0,
|
|
86
|
+
};
|
|
87
|
+
if (!state.questProgress)
|
|
88
|
+
state.questProgress = (0, types_1.createDefaultQuestProgress)();
|
|
89
|
+
return state;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function deleteState() {
|
|
96
|
+
if (fs.existsSync(STATE_FILE)) {
|
|
97
|
+
fs.unlinkSync(STATE_FILE);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=save.js.map
|