Release v0.1.3 2026-07-11

This commit is contained in:
Warren H
2026-07-11 23:23:02 -04:00
parent 076f6cf97c
commit b48b3a4f8f
103 changed files with 6708 additions and 454 deletions
+54 -63
View File
@@ -1,7 +1,15 @@
import type { BossCollection, GameModeId, GameSettings, HunterSave, SaveSlotId } from "./types";
import { BOSS_ORDER } from "../game/bossCatalog";
import { BOSS_DEFINITIONS, BOSS_ORDER } from "../game/bossCatalog";
import { createClassInventory } from "../game/healers";
import type { BossId } from "../game/types";
import { createDefaultGearProgress } from "../game/progression/gear";
import {
BOSS_DROP_TABLES,
createEmptyCollectionLog,
type CollectionLog,
type LootRarity,
type MaterialStack,
} from "../game/progression/loot";
export const DEFAULT_SETTINGS: GameSettings = {
masterVolume: 80,
@@ -10,52 +18,39 @@ export const DEFAULT_SETTINGS: GameSettings = {
largeText: false,
};
export const DEFAULT_COLLECTIONS: BossCollection[] = [
{
bossId: "bulldrome",
bossName: "Bulldrome",
defeated: true,
drops: [
{ id: "bull-horn", name: "Cinder Horn", icon: "♜", rarity: "Common", count: 7 },
{ id: "bull-hide", name: "Ember Hide", icon: "▧", rarity: "Uncommon", count: 3 },
{ id: "bull-idol", name: "Vault Idol", icon: "◇", rarity: "Rare", count: 1 },
{ id: "bull-heart", name: "Furnace Heart", icon: "✦", rarity: "Mythic", count: 0 },
],
},
{
bossId: "vexa",
bossName: "Vexa",
defeated: false,
drops: [
{ id: "vexa-silk", name: "Living Silk", icon: "⌁", rarity: "Common", count: 0 },
{ id: "vexa-venom", name: "Widow Venom", icon: "✣", rarity: "Uncommon", count: 0 },
{ id: "vexa-eye", name: "Loom Eye", icon: "◉", rarity: "Rare", count: 0 },
{ id: "vexa-heart", name: "Webmother Heart", icon: "✦", rarity: "Mythic", count: 0 },
],
},
{
bossId: "cindermaw",
bossName: "Cindermaw",
defeated: true,
drops: [
{ id: "maw-scale", name: "Soot Scale", icon: "◈", rarity: "Common", count: 4 },
{ id: "maw-gland", name: "Mending Gland", icon: "+", rarity: "Uncommon", count: 2 },
{ id: "maw-crest", name: "Ashen Crest", icon: "⌁", rarity: "Rare", count: 0 },
{ id: "maw-breath", name: "Bottled Breath", icon: "☀", rarity: "Mythic", count: 0 },
],
},
{
bossId: "ember-mantis-duelist",
bossName: "Ember Mantis Duelist",
defeated: false,
drops: [
{ id: "mantis-chitin", name: "Ember Chitin", icon: "◇", rarity: "Common", count: 0 },
{ id: "mantis-edge", name: "Cinderblade Edge", icon: "⚔", rarity: "Uncommon", count: 0 },
{ id: "mantis-antenna", name: "Duelist Antenna", icon: "⌁", rarity: "Rare", count: 0 },
{ id: "mantis-core", name: "Molten Mantis Core", icon: "✦", rarity: "Mythic", count: 0 },
],
},
];
const RARITY_LABELS: Record<LootRarity, BossCollection["drops"][number]["rarity"]> = {
common: "Common",
uncommon: "Uncommon",
rare: "Rare",
epic: "Epic",
legendary: "Legendary",
};
export function buildCollections(collectionLog: CollectionLog, bossKills: Record<string, number>): BossCollection[] {
return BOSS_ORDER.map((bossId) => {
const table = BOSS_DROP_TABLES[bossId];
return {
bossId,
bossName: BOSS_DEFINITIONS[bossId].name,
defeated: (bossKills[bossId] ?? 0) > 0,
drops: table.entries.map((drop) => ({
id: drop.id,
name: drop.name,
icon: drop.glyph,
rarity: RARITY_LABELS[drop.rarity],
count: drop.kind === "coin"
? collectionLog.dropsFound[drop.id] ?? 0
: collectionLog.petsFound[drop.id] ?? 0,
chance: drop.chanceLabel,
itemLevel: drop.kind === "coin" ? drop.itemLevel : undefined,
kind: drop.kind,
})),
};
});
}
export const DEFAULT_COLLECTION_LOG: CollectionLog = createEmptyCollectionLog();
export const DEFAULT_COLLECTIONS: BossCollection[] = buildCollections(DEFAULT_COLLECTION_LOG, {});
export const MODE_COPY: Record<GameModeId, { eyebrow: string; title: string; description: string; detail: string; status: string }> = {
"roguelike-pve": {
@@ -69,7 +64,7 @@ export const MODE_COPY: Record<GameModeId, { eyebrow: string; title: string; des
eyebrow: "14 hunters · chosen encounter",
title: "Dungeons",
description: "Choose a guardian, review its mechanics, and bring a prepared healing loadout into a focused encounter.",
detail: "Bulldrome · Vexa · Cindermaw · Ember Mantis",
detail: "Ten prototype guardians available",
status: "Playable now",
},
"roguelike-pvp": {
@@ -92,12 +87,6 @@ export function selectRandomBoss(random: () => number = Math.random): BossId {
return BOSS_ORDER[Math.floor(random() * BOSS_ORDER.length)] ?? BOSS_ORDER[0];
}
export function selectRandomBossPair(random: () => number = Math.random): readonly [BossId, BossId] {
const firstIndex = Math.floor(random() * BOSS_ORDER.length) % BOSS_ORDER.length;
const secondOffset = 1 + Math.floor(random() * (BOSS_ORDER.length - 1));
return [BOSS_ORDER[firstIndex], BOSS_ORDER[(firstIndex + secondOffset) % BOSS_ORDER.length]];
}
export const MAX_HUNTER_NAME_LENGTH = 20;
export function normalizeHunterName(value: string): string {
@@ -112,25 +101,27 @@ export function createHunterSave(slotId: SaveSlotId, now: string, hunterName: st
const normalizedName = normalizeHunterName(hunterName);
if (!normalizedName) throw new Error("Hunter name is required.");
return {
schemaVersion: 2,
schemaVersion: 4,
slotId,
hunterName: normalizedName,
activeClassId: "priest",
healers: {
priest: { level: 12, inventory: createClassInventory("priest") },
priest: { level: 1, inventory: createClassInventory("priest") },
druid: { level: 1, inventory: createClassInventory("druid") },
shaman: { level: 1, inventory: createClassInventory("shaman") },
},
location: "Ember Vault Approach",
playSeconds: 8 * 60 * 60 + 42 * 60,
playSeconds: 0,
updatedAt: now,
stats: {
totalBossKills: 16,
flawlessClears: 5,
alliesSaved: 143,
healingDone: 284_650,
bossKills: { Bulldrome: 12, Vexa: 0, Cindermaw: 4, "Ember Mantis Duelist": 0 },
totalBossKills: 0,
flawlessClears: 0,
alliesSaved: 0,
healingDone: 0,
bossKills: {},
},
collections: structuredClone(DEFAULT_COLLECTIONS),
materials: [] as MaterialStack[],
collectionLog: createEmptyCollectionLog(),
gearProgress: createDefaultGearProgress(),
};
}