feat: implement non-combat room gameplay (Library, Recovery, Treasure, Puzzle)
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 1m4s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 1m4s
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
// Spire-specific utility functions for room generation, enemy stat scaling, etc.
|
||||
|
||||
import type { RoomType, FloorState, EnemyState } from '../types';
|
||||
import type { LootDrop } from '../types/game';
|
||||
import { PUZZLE_ROOMS } from '../constants';
|
||||
import { getAvailableDrops, rollLootDrops } from '../data/loot-drops';
|
||||
import { getFloorMaxHP, getFloorElement } from './floor-utils';
|
||||
import { getEnemyName } from './enemy-utils';
|
||||
import { getGuardianForFloor, isGuardianFloor } from '../data/guardian-encounters';
|
||||
@@ -159,11 +161,17 @@ export function generateSpireFloorState(floor: number, roomIndex: number, totalR
|
||||
libraryRequired: 1,
|
||||
};
|
||||
|
||||
case 'treasure':
|
||||
case 'treasure': {
|
||||
const loot = generateTreasureLoot(floor);
|
||||
return {
|
||||
roomType: 'treasure',
|
||||
enemies: [],
|
||||
treasureProgress: 0,
|
||||
treasureRequired: 1,
|
||||
treasureLoot: loot,
|
||||
treasureLootClaimed: [],
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
return generateCombatRoom(floor, element, baseHP);
|
||||
@@ -267,6 +275,52 @@ export function calcInsight(floor: number, isGuardian: boolean): number {
|
||||
|
||||
// ─── Room Type Display ────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Generate treasure loot for a treasure room based on floor.
|
||||
* Returns pre-generated loot drops that are progressively revealed.
|
||||
*/
|
||||
export function generateTreasureLoot(floor: number): LootDrop[] {
|
||||
const available = getAvailableDrops(floor, false);
|
||||
const drops: LootDrop[] = [];
|
||||
|
||||
// Determine item count based on floor
|
||||
let itemCount: number;
|
||||
if (floor <= 10) {
|
||||
itemCount = 2 + Math.floor(Math.random() * 2); // 2-3
|
||||
} else if (floor <= 50) {
|
||||
itemCount = 4 + Math.floor(Math.random() * 4); // 4-7
|
||||
} else {
|
||||
itemCount = 8 + Math.floor(Math.random() * 8); // 8-15
|
||||
}
|
||||
|
||||
// Roll for each item
|
||||
for (let i = 0; i < itemCount; i++) {
|
||||
const rolled = rollLootDrops(floor, false, 0);
|
||||
for (const { drop, amount } of rolled) {
|
||||
// For materials, add amount; for others, just add the drop
|
||||
const existing = drops.find(d => d.id === drop.id);
|
||||
if (existing && existing.amount) {
|
||||
existing.amount = {
|
||||
min: existing.amount.min + (drop.amount?.min ?? 1),
|
||||
max: existing.amount.max + (drop.amount?.max ?? amount),
|
||||
};
|
||||
} else {
|
||||
drops.push({ ...drop, amount: drop.amount || { min: amount, max: amount } });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure at least one item
|
||||
if (drops.length === 0) {
|
||||
const fallback = available.find(d => d.type === 'material' && d.rarity === 'common');
|
||||
if (fallback) {
|
||||
drops.push({ ...fallback, amount: { min: 1, max: 3 } });
|
||||
}
|
||||
}
|
||||
|
||||
return drops;
|
||||
}
|
||||
|
||||
export function getSpireRoomTypeDisplay(roomType: SpireRoomType): { label: string; icon: string; color: string } {
|
||||
const displays: Record<string, { label: string; icon: string; color: string }> = {
|
||||
combat: { label: 'Combat', icon: '⚔️', color: '#EF4444' },
|
||||
|
||||
Reference in New Issue
Block a user