← Shadows results

Shadows

thinkingcap qwen3.6 27b · typescript

Initial view of Shadows

Reviews & generation details

Reviews

No human review yet. Unreviewed does not mean unsuccessful.

Generation context

Imported historical artifact. Its exact original instructions and lineage are not known.

Generation prompt · exact text unavailable

See the current prompt for reference. It may differ from the instructions used to generate this artifact.

Inspect original source 97,307 bytes · SHA-256 4d3f1355bb3c
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Shadows of the Abyss</title>
<style>
/* ── css: layout ── */
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: #0a0a0f; color: #d4c5a9; font-family: 'Georgia', serif; overflow: hidden; user-select: none; }
#game-container { width: 100vw; height: 100vh; position: relative; }
.screen { position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; transition: opacity 0.3s; }
.hidden { display: none !important; }

/* Scrollbar styling */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: #1a1a2e; }
::-webkit-scrollbar-thumb { background: #4a3f6b; border-radius: 3px; }

/* Buttons */
.btn { padding: 10px 24px; border: 2px solid #5c4a8a; background: linear-gradient(180deg, #2d1f4e, #1a1030); color: #d4c5a9; font-family: 'Georgia', serif; font-size: 16px; cursor: pointer; border-radius: 4px; transition: all 0.2s; min-width: 120px; text-align: center; }
.btn:hover { background: linear-gradient(180deg, #3d2f5e, #2a2040); border-color: #7c6aaa; transform: scale(1.05); box-shadow: 0 0 15px rgba(92, 74, 138, 0.5); }
.btn:active { transform: scale(0.98); }
.btn-danger { border-color: #8a2a2a; background: linear-gradient(180deg, #4e1f1f, #301010); }
.btn-danger:hover { border-color: #aa4a4a; box-shadow: 0 0 15px rgba(138, 42, 42, 0.5); }
.btn-gold { border-color: #8a7a2a; background: linear-gradient(180deg, #4e4f1f, #303010); }

/* Class select */
.class-cards { display: flex; gap: 30px; margin-top: 30px; }
.class-card { width: 220px; padding: 25px; border: 2px solid #3a2f5e; background: linear-gradient(180deg, #1a1030, #0d0a1a); border-radius: 8px; cursor: pointer; transition: all 0.3s; text-align: center; }
.class-card:hover { transform: translateY(-5px); box-shadow: 0 10px 30px rgba(92, 74, 138, 0.4); border-color: #6c5aaa; }
.class-card h2 { font-size: 22px; margin-bottom: 10px; color: #e8d5b5; }
.class-card p { font-size: 13px; line-height: 1.5; color: #a89878; }

/* Combat screen */
#combat-area { width: 100%; height: 100%; display: flex; flex-direction: column; position: relative; }
#enemy-zone { flex: 0 0 35%; display: flex; justify-content: center; align-items: center; gap: 20px; padding: 20px; background: linear-gradient(180deg, #0d0a1a, transparent); }
#player-zone { flex: 0 0 40%; display: flex; flex-direction: column; justify-content: flex-end; padding: 15px; position: relative; }
#hand-area { display: flex; justify-content: center; gap: 8px; min-height: 160px; align-items: flex-end; flex-wrap: wrap; padding-bottom: 10px; }

/* Cards */
.card { width: 120px; height: 170px; border-radius: 8px; padding: 8px; cursor: pointer; transition: all 0.2s; position: relative; display: flex; flex-direction: column; font-size: 11px; overflow: hidden; }
.card:hover { transform: translateY(-20px); z-index: 10; box-shadow: 0 5px 20px rgba(0,0,0,0.8); }
.card-attack { border: 2px solid #c44; background: linear-gradient(180deg, #3a1515, #1a0a0a); }
.card-skill { border: 2px solid #44c; background: linear-gradient(180deg, #15153a, #0a0a1a); }
.card-power { border: 2px solid #cc4; background: linear-gradient(180deg, #3a3a15, #1a1a0a); }
.card-curse { border: 2px solid #666; background: linear-gradient(180deg, #2a2a2a, #151515); opacity: 0.7; cursor: not-allowed; }
.card-status { border: 2px solid #494; background: linear-gradient(180deg, #153a15, #0a1a0a); opacity: 0.7; cursor: not-allowed; }
.card-cost { position: absolute; top: 4px; right: 4px; width: 24px; height: 24px; border-radius: 50%; background: #3a2f6e; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 14px; color: #fff; }
.card-name { font-weight: bold; font-size: 12px; margin-bottom: 4px; text-align: center; color: #e8d5b5; }
.card-desc { flex: 1; line-height: 1.3; color: #a89878; overflow-y: auto; }

/* Enemy display */
.enemy-display { width: 140px; text-align: center; padding: 15px; border-radius: 8px; background: rgba(26, 16, 48, 0.8); border: 1px solid #3a2f5e; }
.enemy-display.dead { opacity: 0.3; filter: grayscale(1); }
.enemy-name { font-size: 14px; font-weight: bold; color: #c97; margin-bottom: 5px; }
.enemy-hp-bar { width: 100%; height: 8px; background: #2a1a1a; border-radius: 4px; overflow: hidden; margin: 5px 0; }
.enemy-hp-fill { height: 100%; background: linear-gradient(90deg, #c44, #a33); transition: width 0.3s; }
.enemy-intent { font-size: 12px; color: #e87; margin-top: 5px; padding: 4px; border-radius: 3px; background: rgba(200, 60, 60, 0.1); }

/* HUD */
#hud { position: absolute; top: 10px; left: 10px; right: 10px; display: flex; justify-content: space-between; align-items: center; padding: 8px 15px; background: rgba(10, 10, 20, 0.9); border-radius: 6px; z-index: 100; }
.hud-stat { display: flex; align-items: center; gap: 6px; font-size: 14px; }
.hud-hp { color: #e55; }
.hud-block { color: #5af; }
.hud-energy { color: #ee5; }
.hud-gold { color: #da3; }

/* Map */
#map-area { width: 100%; height: 100%; overflow-y: auto; display: flex; justify-content: center; padding: 60px 20px 20px; }
.map-grid { position: relative; min-height: 700px; width: 400px; }
.map-node { position: absolute; width: 50px; height: 50px; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all 0.3s; font-size: 20px; z-index: 1; }
.map-node:hover { transform: scale(1.2); }
.map-node.available { animation: pulse 2s infinite; border: 2px solid #fff; }
.map-node.visited { opacity: 0.4; cursor: default; }
@keyframes pulse { 0%, 100% { box-shadow: 0 0 5px rgba(255,255,255,0.3); } 50% { box-shadow: 0 0 20px rgba(255,255,255,0.6); } }
.node-enemy { background: #8a3a3a; }
.node-elite { background: #aa4a1a; }
.node-boss { background: #cc2222; width: 60px; height: 60px; font-size: 24px; }
.node-rest { background: #3a8a3a; }
.node-shop { background: #8a7a2a; }
.node-event { background: #5a3a8a; }

/* Rewards */
.reward-cards { display: flex; gap: 15px; margin: 20px 0; }
.reward-card { width: 160px; padding: 15px; border-radius: 8px; cursor: pointer; transition: all 0.3s; text-align: center; font-size: 13px; }
.reward-card:hover { transform: scale(1.05); box-shadow: 0 5px 20px rgba(92,74,138,0.5); }

/* Shop */
.shop-items { display: flex; flex-direction: column; gap: 10px; max-height: 60vh; overflow-y: auto; padding: 10px; width: 90%; max-width: 600px; }
.shop-item { display: flex; align-items: center; justify-content: space-between; padding: 12px; border: 1px solid #3a2f5e; background: rgba(26, 16, 48, 0.6); border-radius: 6px; }
.shop-item-info { flex: 1; }
.shop-item-name { font-weight: bold; color: #d4c5a9; }
.shop-item-desc { font-size: 12px; color: #a89878; }

/* Event */
.event-text { max-width: 500px; text-align: center; margin-bottom: 30px; line-height: 1.6; font-size: 16px; padding: 20px; border: 1px solid #3a2f5e; border-radius: 8px; background: rgba(26, 16, 48, 0.6); }
.event-choices { display: flex; flex-direction: column; gap: 10px; width: 300px; }

/* Rest */
.rest-options { display: flex; gap: 20px; margin-top: 20px; }

/* Game Over / Victory */
.game-over-text { font-size: 48px; color: #c44; text-shadow: 0 0 30px rgba(200,60,60,0.5); }
.victory-text { font-size: 48px; color: #da3; text-shadow: 0 0 30px rgba(218,179,51,0.5); }

/* Title */
.game-title { font-size: 42px; color: #c9a0dc; text-shadow: 0 0 30px rgba(201, 160, 220, 0.4); margin-bottom: 5px; }
.game-subtitle { font-size: 18px; color: #7a6a9a; margin-bottom: 30px; }

/* Combat log */
#combat-log { position: absolute; bottom: 200px; left: 50%; transform: translateX(-50%); width: 400px; max-height: 100px; overflow-y: auto; font-size: 12px; color: #8a7a6a; text-align: center; pointer-events: none; }
.log-entry { padding: 2px 0; opacity: 0.9; }

/* Damage numbers */
.damage-number { position: absolute; font-weight: bold; font-size: 24px; color: #f55; animation: floatUp 1s forwards; pointer-events: none; z-index: 200; text-shadow: 0 0 5px rgba(0,0,0,0.8); }
@keyframes floatUp { 0% { opacity: 1; transform: translateY(0); } 100% { opacity: 0; transform: translateY(-40px); } }

/* Potion bar */
#potion-bar { position: absolute; right: 15px; bottom: 200px; display: flex; flex-direction: column; gap: 8px; z-index: 50; }
.potion-slot { width: 40px; height: 40px; border-radius: 50%; border: 2px solid #6a5aaa; background: rgba(26, 16, 48, 0.9); display: flex; align-items: center; justify-content: center; cursor: pointer; font-size: 18px; transition: all 0.2s; }
.potion-slot:hover { transform: scale(1.15); box-shadow: 0 0 10px rgba(106, 90, 170, 0.5); }

/* Deck info */
#deck-info { position: absolute; left: 15px; bottom: 200px; font-size: 12px; color: #8a7a6a; z-index: 50; text-align: left; }
</style>
</head>
<body>
<div id="game-container">
  <div id="screen-class-select" class="screen"></div>
  <div id="screen-map" class="screen hidden"></div>
  <div id="screen-combat" class="screen hidden"></div>
  <div id="screen-rewards" class="screen hidden"></div>
  <div id="screen-shop" class="screen hidden"></div>
  <div id="screen-event" class="screen hidden"></div>
  <div id="screen-rest" class="screen hidden"></div>
  <div id="screen-game-over" class="screen hidden"></div>
  <div id="screen-victory" class="screen hidden"></div>
</div>
<script>
(function () {
'use strict';
var __mods = {};
var __cache = {};
var __map = {"src/main.ts":{"./state":"src/state.ts","./ui":"src/ui.ts"},"src/cards.ts":{"./types":"src/types.ts"},"src/enemies.ts":{"./types":"src/types.ts"},"src/relics.ts":{"./types":"src/types.ts"},"src/potions.ts":{"./types":"src/types.ts"},"src/state.ts":{"./types":"src/types.ts","./cards":"src/cards.ts","./enemies":"src/enemies.ts"},"src/combat.ts":{"./state":"src/state.ts","./cards":"src/cards.ts","./types":"src/types.ts"},"src/ui.ts":{"./state":"src/state.ts","./combat":"src/combat.ts","./cards":"src/cards.ts","./relics":"src/relics.ts","./potions":"src/potions.ts"}};
function __require(id) {
  if (__cache[id]) return __cache[id].exports;
  var module = __cache[id] = { exports: {} };
  var factory = __mods[id];
  if (!factory) throw new Error("Module not found: " + id);
  factory(module.exports, function (spec) {
    var target = (__map[id] && __map[id][spec]) || spec;
    return __require(target);
  }, module);
  return module.exports;
}

// ── module: src/main.ts ──
__mods["src/main.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const state_1 = require("./state");
const ui_1 = require("./ui");
// Initialize game state
(0, state_1.setState)((0, state_1.initGame)());
// Start rendering
(0, ui_1.render)();
};

// ── module: src/types.ts ──
__mods["src/types.ts"] = function (exports, require, module) {
"use strict";
// Core type definitions for Shadows of the Abyss
Object.defineProperty(exports, "__esModule", { value: true });
};

// ── module: src/cards.ts ──
__mods["src/cards.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.COLORLESS_CARD_IDS = exports.CLASS_CARD_POOLS = exports.CARD_DEFS = void 0;
exports.getStartingDeck = getStartingDeck;
exports.createCard = createCard;
exports.getCardDef = getCardDef;
// All card definitions from the GDD
exports.CARD_DEFS = {};
const registerCard = (c) => { exports.CARD_DEFS[c.id] = c; };
// === BASIC CARDS ===
registerCard({ id: 'strike', name: 'Strike', type: 'Attack', cost: 1, rarity: 'Basic', description: 'Deal 6 damage.', upgradedName: 'Strike+', upgradedDescription: 'Deal 8 damage.' });
registerCard({ id: 'defend', name: 'Defend', type: 'Skill', cost: 1, rarity: 'Basic', description: 'Gain 5 Block.', upgradedName: 'Defend+', upgradedDescription: 'Gain 8 Block.' });
// === IMP CLAW (generated token) ===
registerCard({ id: 'imp_claw', name: 'Imp Claw', type: 'Attack', cost: 0, rarity: 'Common', description: 'Deal 4 damage.', exhaust: true });
// === CURSES & STATUS ===
registerCard({ id: 'wound', name: 'Wound', type: 'Curse', cost: -1, rarity: 'Common', description: 'Unplayable. Ethereal.', unplayable: true, ethereal: true, exhaust: true });
registerCard({ id: 'doubt', name: 'Doubt', type: 'Curse', cost: -1, rarity: 'Common', description: 'Unplayable. At end of turn, lose 1 HP.', unplayable: true });
registerCard({ id: 'dazed', name: 'Dazed', type: 'Status', cost: -1, rarity: 'Common', description: 'Unplayable. Ethereal.', unplayable: true, ethereal: true, exhaust: true });
// === BLOOD REAPER CARDS ===
registerCard({ id: 'sanguine_strike', name: 'Sanguine Strike', type: 'Attack', cost: 1, rarity: 'Common', description: 'Deal 8 damage. Heal 2 HP.', upgradedName: 'Sanguine Strike+', upgradedDescription: 'Deal 10 damage. Heal 3 HP.' });
registerCard({ id: 'hemorrhage', name: 'Hemorrhage', type: 'Attack', cost: 1, rarity: 'Common', description: 'Deal 5 damage. Apply 3 Bleed.', upgradedName: 'Hemorrhage+', upgradedDescription: 'Deal 6 damage. Apply 4 Bleed.' });
registerCard({ id: 'bloodletting', name: 'Bloodletting', type: 'Attack', cost: 1, rarity: 'Uncommon', description: 'Lose 3 HP. Deal 12 damage.', upgradedName: 'Bloodletting+', upgradedDescription: 'Lose 2 HP. Deal 15 damage.' });
registerCard({ id: 'crimson_eruption', name: 'Crimson Eruption', type: 'Attack', cost: 2, rarity: 'Rare', description: 'Deal 8 damage to ALL enemies. Lose 2 HP.', upgradedName: 'Crimson Eruption+', upgradedDescription: 'Deal 10 damage to ALL enemies. Lose 2 HP.' });
registerCard({ id: 'crimson_shield', name: 'Crimson Shield', type: 'Skill', cost: 1, rarity: 'Common', description: 'Gain 6 Block. Lose 2 HP.', upgradedName: 'Crimson Shield+', upgradedDescription: 'Gain 8 Block. Lose 2 HP.' });
registerCard({ id: 'blood_ward', name: 'Blood Ward', type: 'Skill', cost: 1, rarity: 'Common', description: 'Gain 3 Block. Gain 1 Regeneration.', upgradedName: 'Blood Ward+', upgradedDescription: 'Gain 4 Block. Gain 2 Regeneration.' });
registerCard({ id: 'sacrificial_barrier', name: 'Sacrificial Barrier', type: 'Skill', cost: 2, rarity: 'Uncommon', description: 'Gain 10 Block. Lose 5 HP.', upgradedName: 'Sacrificial Barrier+', upgradedDescription: 'Gain 13 Block. Lose 5 HP.' });
registerCard({ id: 'vital_surge', name: 'Vital Surge', type: 'Skill', cost: -2, rarity: 'Rare', description: 'Gain Block equal to your missing HP.', exhaust: true, upgradedName: 'Vital Surge+', upgradedDescription: 'Gain Block equal to missing HP + 3.' });
registerCard({ id: 'life_tap', name: 'Life Tap', type: 'Skill', cost: 0, rarity: 'Common', description: 'Draw 2 cards. Lose 3 HP.', upgradedName: 'Life Tap+', upgradedDescription: 'Draw 3 cards. Lose 3 HP.' });
registerCard({ id: 'rend_flesh', name: 'Rend Flesh', type: 'Skill', cost: 1, rarity: 'Uncommon', description: 'Apply 5 Bleed to ALL enemies. Lose 2 HP.', upgradedName: 'Rend Flesh+', upgradedDescription: 'Apply 7 Bleed to ALL enemies. Lose 2 HP.' });
registerCard({ id: 'soul_siphon', name: 'Soul Siphon', type: 'Power', cost: 2, rarity: 'Uncommon', description: 'At start of your turn, gain 1 Energy and lose 1 HP.', upgradedName: 'Soul Siphon+', upgradedDescription: 'Cost reduced to 1. At start of your turn, gain 1 Energy and lose 1 HP.' });
registerCard({ id: 'blood_pact', name: 'Blood Pact', type: 'Power', cost: 1, rarity: 'Rare', description: 'Whenever you lose HP from a card, gain 1 Strength.', upgradedName: 'Blood Pact+', upgradedDescription: 'Whenever you lose HP from a card, gain 2 Strength.' });
// === SHADOWMANCER CARDS ===
registerCard({ id: 'shadow_bolt', name: 'Shadow Bolt', type: 'Attack', cost: 1, rarity: 'Common', description: 'Deal 6 damage. Apply 1 Weak.', upgradedName: 'Shadow Bolt+', upgradedDescription: 'Deal 8 damage. Apply 2 Weak.' });
registerCard({ id: 'grasp_of_despair', name: 'Grasp of Despair', type: 'Attack', cost: 1, rarity: 'Common', description: 'Deal 4 damage. Apply 1 Vulnerable.', upgradedName: 'Grasp of Despair+', upgradedDescription: 'Deal 5 damage. Apply 2 Vulnerable.' });
registerCard({ id: 'nightmare_lash', name: 'Nightmare Lash', type: 'Attack', cost: 2, rarity: 'Uncommon', description: 'Deal 7 damage. If enemy has Weak, deal 7 more.', upgradedName: 'Nightmare Lash+', upgradedDescription: 'Deal 9 damage. If Weak, deal 9 more.' });
registerCard({ id: 'eternal_darkness', name: 'Eternal Darkness', type: 'Attack', cost: 2, rarity: 'Rare', description: 'Deal 3 damage to a random enemy 3 times.', upgradedName: 'Eternal Darkness+', upgradedDescription: 'Deal 4 damage to a random enemy 3 times.' });
registerCard({ id: 'cloak_of_shadows', name: 'Cloak of Shadows', type: 'Skill', cost: 1, rarity: 'Common', description: 'Gain 5 Block. Draw 1 card.', upgradedName: 'Cloak of Shadows+', upgradedDescription: 'Gain 7 Block. Draw 1 card.' });
registerCard({ id: 'haunting_mist', name: 'Haunting Mist', type: 'Skill', cost: 1, rarity: 'Common', description: 'Gain 7 Block. Apply 1 Weak to ALL enemies.', upgradedName: 'Haunting Mist+', upgradedDescription: 'Gain 9 Block. Apply 1 Weak to ALL enemies.' });
registerCard({ id: 'phantom_armor', name: 'Phantom Armor', type: 'Skill', cost: 1, rarity: 'Uncommon', description: 'Gain 8 Block. Next turn, gain 2 Dexterity.', upgradedName: 'Phantom Armor+', upgradedDescription: 'Gain 10 Block. Next turn, gain 3 Dexterity.' });
registerCard({ id: 'whispering_shroud', name: 'Whispering Shroud', type: 'Skill', cost: 1, rarity: 'Common', description: 'Gain 4 Block. Next turn, gain 4 Block.', upgradedName: 'Whispering Shroud+', upgradedDescription: 'Gain 5 Block. Next turn, gain 5 Block.' });
registerCard({ id: 'shadowform', name: 'Shadowform', type: 'Skill', cost: 2, rarity: 'Uncommon', description: 'Gain 2 Intangible.', exhaust: true, upgradedName: 'Shadowform+', upgradedDescription: 'Gain 3 Intangible.' });
registerCard({ id: 'curse_of_misfortune', name: 'Curse of Misfortune', type: 'Skill', cost: 1, rarity: 'Common', description: 'Enemy loses 3 Strength this turn. Apply 1 Vulnerable.', upgradedName: 'Curse of Misfortune+', upgradedDescription: 'Enemy loses 4 Strength this turn. Apply 2 Vulnerable.' });
registerCard({ id: 'dark_ritual', name: 'Dark Ritual', type: 'Skill', cost: 0, rarity: 'Uncommon', description: 'Gain 2 Energy. Shuffle a Dazed into your discard pile.', upgradedName: 'Dark Ritual+', upgradedDescription: 'Same effect.' });
registerCard({ id: 'umbral_mastery', name: 'Umbral Mastery', type: 'Power', cost: 2, rarity: 'Rare', description: 'At start of turn, apply 1 Weak to ALL enemies.', upgradedName: 'Umbral Mastery+', upgradedDescription: 'At start of turn, apply 2 Weak to ALL enemies.' });
// === HELLFORGED CARDS ===
registerCard({ id: 'firebolt', name: 'Firebolt', type: 'Attack', cost: 1, rarity: 'Common', description: 'Deal 7 damage. Apply 2 Burn.', upgradedName: 'Firebolt+', upgradedDescription: 'Deal 9 damage. Apply 3 Burn.' });
registerCard({ id: 'hellfire_blast', name: 'Hellfire Blast', type: 'Attack', cost: 2, rarity: 'Uncommon', description: 'Deal 9 damage to ALL enemies.', upgradedName: 'Hellfire Blast+', upgradedDescription: 'Deal 12 damage to ALL enemies.' });
registerCard({ id: 'searing_strike', name: 'Searing Strike', type: 'Attack', cost: 1, rarity: 'Common', description: 'Deal 6 damage. Gain 1 Energy next turn.', upgradedName: 'Searing Strike+', upgradedDescription: 'Deal 8 damage. Gain 1 Energy next turn.' });
registerCard({ id: 'immolate', name: 'Immolate', type: 'Attack', cost: 2, rarity: 'Rare', description: 'Deal 12 damage.', exhaust: true, upgradedName: 'Immolate+', upgradedDescription: 'Deal 16 damage.' });
registerCard({ id: 'obsidian_skin', name: 'Obsidian Skin', type: 'Skill', cost: 1, rarity: 'Common', description: 'Gain 7 Block.', upgradedName: 'Obsidian Skin+', upgradedDescription: 'Gain 10 Block.' });
registerCard({ id: 'flame_ward', name: 'Flame Ward', type: 'Skill', cost: 1, rarity: 'Common', description: 'Gain 5 Block. Apply 2 Burn to a random enemy.', upgradedName: 'Flame Ward+', upgradedDescription: 'Gain 6 Block. Apply 3 Burn to a random enemy.' });
registerCard({ id: 'demonic_resilience', name: 'Demonic Resilience', type: 'Skill', cost: 1, rarity: 'Uncommon', description: 'Gain 4 Block. Heal 2 HP.', upgradedName: 'Demonic Resilience+', upgradedDescription: 'Gain 5 Block. Heal 3 HP.' });
registerCard({ id: 'brimstone_shield', name: 'Brimstone Shield', type: 'Skill', cost: 1, rarity: 'Rare', description: 'Gain 3 Block. Gain 2 Strength this turn.', upgradedName: 'Brimstone Shield+', upgradedDescription: 'Gain 4 Block. Gain 3 Strength this turn.' });
registerCard({ id: 'summon_imp', name: 'Summon Imp', type: 'Skill', cost: 1, rarity: 'Common', description: 'Add an Imp Claw to your hand.', exhaust: true, upgradedName: 'Summon Imp+', upgradedDescription: 'Add an Imp Claw+ to your hand.' });
registerCard({ id: 'infernal_pact', name: 'Infernal Pact', type: 'Skill', cost: 0, rarity: 'Uncommon', description: 'Lose 2 HP. Gain 2 Energy. Add an Imp Claw.', upgradedName: 'Infernal Pact+', upgradedDescription: 'Lose 1 HP. Gain 2 Energy. Add an Imp Claw+.' });
registerCard({ id: 'hellfire_aura', name: 'Hellfire Aura', type: 'Power', cost: 2, rarity: 'Rare', description: 'At start of turn, deal 3 damage to ALL enemies.', upgradedName: 'Hellfire Aura+', upgradedDescription: 'At start of turn, deal 5 damage to ALL enemies.' });
registerCard({ id: 'soul_burn', name: 'Soul Burn', type: 'Skill', cost: 1, rarity: 'Uncommon', description: 'Apply 8 Burn to an enemy. Draw 1 card.', upgradedName: 'Soul Burn+', upgradedDescription: 'Apply 10 Burn to an enemy. Draw 1 card.' });
// === COLORLESS CARDS (Shop only) ===
registerCard({ id: 'flash_of_insight', name: 'Flash of Insight', type: 'Skill', cost: 1, rarity: 'Common', description: 'Draw 2 cards.', upgradedName: 'Flash of Insight+', upgradedDescription: 'Draw 3 cards.' });
registerCard({ id: 'iron_will', name: 'Iron Will', type: 'Skill', cost: 1, rarity: 'Common', description: 'Gain 8 Block.', upgradedName: 'Iron Will+', upgradedDescription: 'Gain 11 Block.' });
registerCard({ id: 'quick_slash', name: 'Quick Slash', type: 'Attack', cost: 1, rarity: 'Common', description: 'Deal 7 damage.', upgradedName: 'Quick Slash+', upgradedDescription: 'Deal 9 damage.' });
registerCard({ id: 'potent_brew', name: 'Potent Brew', type: 'Skill', cost: 0, rarity: 'Uncommon', description: 'Gain 1 Energy.', exhaust: true, upgradedName: 'Potent Brew+', upgradedDescription: 'Gain 2 Energy.' });
// Class card pools
exports.CLASS_CARD_POOLS = {
    blood_reaper: ['sanguine_strike', 'hemorrhage', 'bloodletting', 'crimson_eruption', 'crimson_shield', 'blood_ward', 'sacrificial_barrier', 'vital_surge', 'life_tap', 'rend_flesh', 'soul_siphon', 'blood_pact'],
    shadowmancer: ['shadow_bolt', 'grasp_of_despair', 'nightmare_lash', 'eternal_darkness', 'cloak_of_shadows', 'haunting_mist', 'phantom_armor', 'whispering_shroud', 'shadowform', 'curse_of_misfortune', 'dark_ritual', 'umbral_mastery'],
    hellforged: ['firebolt', 'hellfire_blast', 'searing_strike', 'immolate', 'obsidian_skin', 'flame_ward', 'demonic_resilience', 'brimstone_shield', 'summon_imp', 'infernal_pact', 'hellfire_aura', 'soul_burn'],
};
exports.COLORLESS_CARD_IDS = ['flash_of_insight', 'iron_will', 'quick_slash', 'potent_brew'];
// Starting decks per class
function getStartingDeck(classType) {
    return [
        'strike', 'strike', 'strike', 'strike', 'strike',
        'defend', 'defend', 'defend', 'defend',
        classType === 'blood_reaper' ? 'sanguine_strike' :
            classType === 'shadowmancer' ? 'shadow_bolt' : 'firebolt',
    ];
}
// Create a CardInstance from a defId
function createCard(defId) {
    const def = exports.CARD_DEFS[defId];
    if (!def)
        throw new Error(`Unknown card: ${defId}`);
    return {
        defId, name: def.name, type: def.type, cost: def.cost, rarity: def.rarity,
        description: def.description, upgraded: false,
        exhaust: def.exhaust, ethereal: def.ethereal, unplayable: def.unplayable,
    };
}
// Get card by ID
function getCardDef(id) {
    return exports.CARD_DEFS[id];
}
};

// ── module: src/enemies.ts ──
__mods["src/enemies.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.act3Boss = exports.act3Elites = exports.act3Enemies = exports.act2Boss = exports.act2Elites = exports.act2Enemies = exports.act1Boss = exports.act1Elites = exports.act1Enemies = void 0;
exports.getActEnemyPool = getActEnemyPool;
exports.getActElitePool = getActElitePool;
exports.getActBoss = getActBoss;
// Helper to build intent cycles
const atk = (d) => ({ type: 'attack', damage: d, description: `Attack ${d}` });
const def = (b) => ({ type: 'defend', blockAmount: b, description: `Defend ${b} Block` });
const multiAtk = (hits, dmg) => ({ type: 'multi_attack', hits, hitDamage: dmg, description: `${hits}x${dmg}` });
const debuffWeak = () => ({ type: 'debuff', description: 'Apply 2 Weak' });
const buffStr = (s) => ({ type: 'buff', description: `Buff +${s} Strength` });
// === ACT 1 ENEMIES ===
exports.act1Enemies = {
    skeleton_warrior: { name: 'Skeleton Warrior', hp: 22, strength: 0, intentCycle: [atk(6), atk(6), def(8)] },
    zombie_brute: { name: 'Zombie Brute', hp: 28, strength: 0, intentCycle: [atk(8), debuffWeak(), atk(8)] },
    dark_cultist: { name: 'Dark Cultist', hp: 20, strength: 0, intentCycle: [buffStr(3), atk(5), atk(5)] },
    rat_swarm: { name: 'Rat Swarm', hp: 15, strength: 0, intentCycle: [multiAtk(2, 3), multiAtk(2, 3)] },
};
exports.act1Elites = {
    tomb_guardian: { name: 'Tomb Guardian', hp: 42, strength: 0, intentCycle: [
            { type: 'attack', damage: 6, blockAmount: 8, description: 'Shield Bash 6 + 8 Block' },
            multiAtk(3, 4), atk(12),
        ] },
    blood_witch: { name: 'Blood Witch', hp: 36, strength: 0, intentCycle: [
            { type: 'attack', damage: 5, description: 'Drain Life 5 (heal 4)' },
            { type: 'debuff', description: 'Curse (1 Vuln + 1 Weak)' },
            { type: 'attack', damage: 7, description: 'Blood Ritual 7 (heal 4)' },
        ] },
};
exports.act1Boss = {
    name: 'Lich King', hp: 65, strength: 0, phase2Threshold: 30,
    intentCycle: [
        { type: 'summon', description: 'Summon Skeleton Minion' }, atk(8), def(12),
    ],
    summonEnemy: { name: 'Skeleton Minion', hp: 15, strength: 0, intentCycle: [atk(5)] },
};
// === ACT 2 ENEMIES ===
exports.act2Enemies = {
    wraith: { name: 'Wraith', hp: 30, strength: 0, intentCycle: [
            { type: 'attack', damage: 7, description: 'Attack 7 + 1 Weak' }, atk(7), def(10),
        ] },
    corrupted_beast: { name: 'Corrupted Beast', hp: 38, strength: 0, intentCycle: [atk(12), def(5), atk(12)] },
    thorned_horror: { name: 'Thorned Horror', hp: 25, strength: 0, intentCycle: [multiAtk(3, 4), { type: 'debuff', description: 'Apply 3 Bleed' }, atk(8)] },
    witch_doctor: { name: 'Witch Doctor', hp: 22, strength: 0, intentCycle: [def(4), atk(6), atk(6)] },
};
exports.act2Elites = {
    treant_protector: { name: 'Treant Protector', hp: 50, strength: 0, intentCycle: [
            { type: 'attack', damage: 9, blockAmount: 6, description: 'Attack 9 + 6 Block' },
            { type: 'debuff', description: 'Apply 2 Vulnerable' }, multiAtk(2, 10),
        ] },
    plague_shaman: { name: 'Plague Shaman', hp: 42, strength: 0, intentCycle: [
            { type: 'debuff', description: 'Apply 4 Poison' },
            { type: 'summon', description: 'Summon Plague Rat' }, atk(8),
        ], summonEnemy: { name: 'Plague Rat', hp: 18, strength: 0, intentCycle: [atk(5)] } },
};
exports.act2Boss = {
    name: 'Eldritch Treant', hp: 75, strength: 0, phase2Threshold: 40,
    intentCycle: [
        { type: 'attack', damage: 10, description: 'Attack 10 + 2 Weak' },
        { type: 'defend', blockAmount: 15, description: 'Defend 15 + Regen 2' },
        multiAtk(2, 8),
    ],
};
// === ACT 3 ENEMIES ===
exports.act3Enemies = {
    hellhound: { name: 'Hellhound', hp: 26, strength: 0, intentCycle: [
            { type: 'attack', damage: 8, description: 'Attack 8 + 2 Burn' }, atk(8), def(9),
        ] },
    shadow_demon: { name: 'Shadow Demon', hp: 30, strength: 0, intentCycle: [
            { type: 'attack', damage: 7, description: 'Attack 7 + 1 Weak' }, atk(7),
            { type: 'buff', description: 'Gain 1 Intangible' },
        ] },
    infernal_imp: { name: 'Infernal Imp', hp: 18, strength: 0, intentCycle: [atk(5), atk(5), { type: 'summon', description: 'Summon Infernal Imp' }] },
    abyssal_cultist: { name: 'Abyssal Cultist', hp: 24, strength: 0, intentCycle: [buffStr(2), atk(7), atk(7)] },
};
exports.act3Elites = {
    flamespawn: { name: 'Flamespawn', hp: 48, strength: 0, intentCycle: [
            { type: 'attack', damage: 9, description: 'Attack 9 + 3 Burn' },
            { type: 'defend', blockAmount: 10, description: 'Defend 10 + 2 Str' }, multiAtk(2, 8),
        ] },
    dread_knight: { name: 'Dread Knight', hp: 55, strength: 0, intentCycle: [atk(12), { type: 'debuff', description: 'Apply 3 Bleed' }, def(12)] },
};
exports.act3Boss = {
    name: 'Archdemon', hp: 85, strength: 0, phase2Threshold: 45,
    intentCycle: [
        { type: 'summon', description: 'Summon Hellhound' },
        { type: 'attack', damage: 12, description: 'Attack 12 + 2 Burn' },
        { type: 'defend', blockAmount: 15, description: 'Defend 15 + 3 Str' },
    ],
    summonEnemy: exports.act3Enemies.hellhound,
};
// Get enemy pool for an act
function getActEnemyPool(act) {
    if (act === 1)
        return exports.act1Enemies;
    if (act === 2)
        return exports.act2Enemies;
    return exports.act3Enemies;
}
function getActElitePool(act) {
    if (act === 1)
        return exports.act1Elites;
    if (act === 2)
        return exports.act2Elites;
    return exports.act3Elites;
}
function getActBoss(act) {
    if (act === 1)
        return exports.act1Boss;
    if (act === 2)
        return exports.act2Boss;
    return exports.act3Boss;
}
};

// ── module: src/relics.ts ──
__mods["src/relics.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ALL_RELIC_IDS = exports.BOSS_RELIC_IDS = exports.RELIC_DEFS = void 0;
exports.getRelicDef = getRelicDef;
exports.RELIC_DEFS = {};
const reg = (r) => { exports.RELIC_DEFS[r.id] = r; };
reg({ id: 'bloodstone', name: 'Bloodstone', description: 'Whenever you lose HP from a card, heal 1 HP.', rarity: 'Common' });
reg({ id: 'demon_horns', name: 'Demon Horns', description: 'At start of combat, add a random Imp Claw to your hand.', rarity: 'Uncommon', classSpecific: 'hellforged' });
reg({ id: 'shadow_cloak', name: 'Shadow Cloak', description: 'At start of combat, gain 1 Intangible.', rarity: 'Rare' });
reg({ id: 'cursed_amulet', name: 'Cursed Amulet', description: 'At start of combat, apply 1 Weak to ALL enemies.', rarity: 'Common' });
reg({ id: 'tome_of_dark_rituals', name: 'Tome of Dark Rituals', description: 'Whenever you play a Power card, draw 1 card.', rarity: 'Uncommon' });
reg({ id: 'bleeding_edge', name: 'Bleeding Edge', description: 'At start of your turn, apply 1 Bleed to a random enemy.', rarity: 'Common' });
reg({ id: 'soul_ember', name: 'Soul Ember', description: 'Whenever you apply Burn to an enemy, deal 2 additional damage.', rarity: 'Rare' });
reg({ id: 'eternal_hourglass', name: 'Eternal Hourglass', description: 'At start of turn, if no cards in hand, gain 1 Energy.', rarity: 'Uncommon' });
reg({ id: 'sacrificial_dagger', name: 'Sacrificial Dagger', description: 'Your first Attack that costs HP each combat costs 1 less HP.', rarity: 'Common', classSpecific: 'blood_reaper' });
reg({ id: 'vial_of_shadows', name: 'Vial of Shadows', description: 'When obtained, remove a card from your deck. Then does nothing.', rarity: 'Rare' });
reg({ id: 'ashen_armor', name: 'Ashen Armor', description: 'At end of combat, heal 6 HP.', rarity: 'Common' });
reg({ id: 'greedy_imp', name: 'Greedy Imp', description: 'Enemies drop 10 extra Gold.', rarity: 'Common' });
// Boss relics
exports.BOSS_RELIC_IDS = ['cursed_crown', 'ectoplasm', 'philosophers_stone', 'black_blood', 'shadow_amulet'];
reg({ id: 'cursed_crown', name: "Cursed Crown", description: 'Gain 1 Energy at start of turn. Curses can no longer be removed.', rarity: 'Rare' });
reg({ id: 'ectoplasm', name: 'Ectoplasm', description: 'Gain 1 Energy. Lose all Gold and gain no more Gold this run.', rarity: 'Rare' });
reg({ id: 'philosophers_stone', name: "Philosopher's Stone", description: 'Gain 1 Energy. All enemies start with 1 Strength.', rarity: 'Rare' });
reg({ id: 'black_blood', name: 'Black Blood', description: 'At combat start, lose 10% max HP. When you play an Attack, heal 1 HP.', rarity: 'Rare' });
reg({ id: 'shadow_amulet_relic', name: 'Shadow Amulet', description: 'Start each turn with 1 Intangible. Reduce max HP by 15.', rarity: 'Rare' });
function getRelicDef(id) {
    return exports.RELIC_DEFS[id];
}
exports.ALL_RELIC_IDS = Object.keys(exports.RELIC_DEFS).filter(id => !exports.BOSS_RELIC_IDS.includes(id));
};

// ── module: src/potions.ts ──
__mods["src/potions.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ALL_POTION_IDS = exports.POTION_DEFS = void 0;
exports.POTION_DEFS = {};
const reg = (p) => { exports.POTION_DEFS[p.id] = p; };
reg({ id: 'blood_vial', name: 'Blood Vial', description: 'Heal 15 HP.' });
reg({ id: 'firebomb', name: 'Firebomb', description: 'Deal 10 damage to ALL enemies.' });
reg({ id: 'dex_tonic', name: 'Dex Tonic', description: 'Gain 3 Dexterity for 1 turn.' });
reg({ id: 'energy_elixir', name: 'Energy Elixir', description: 'Gain 2 Energy this turn.' });
reg({ id: 'cursed_brew', name: 'Cursed Brew', description: 'Apply 3 Vulnerable to all enemies.' });
reg({ id: 'bleeding_flask', name: 'Bleeding Flask', description: 'Apply 6 Bleed to an enemy.' });
reg({ id: 'imp_in_a_bottle', name: 'Imp-in-a-Bottle', description: 'Add an Imp Claw+ to your hand.' });
reg({ id: 'smoke_bomb', name: 'Smoke Bomb', description: 'Escape from combat, no rewards.' });
exports.ALL_POTION_IDS = Object.keys(exports.POTION_DEFS);
};

// ── module: src/state.ts ──
__mods["src/state.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createCard = void 0;
exports.initGame = initGame;
exports.getState = getState;
exports.setState = setState;
exports.selectClass = selectClass;
exports.generateMap = generateMap;
exports.advanceMap = advanceMap;
exports.startCombat = startCombat;
exports.drawCard = drawCard;
exports.discardHand = discardHand;
exports.addToDiscard = addToDiscard;
exports.removeCardFromDeck = removeCardFromDeck;
exports.upgradeCard = upgradeCard;
exports.getRandomClassCard = getRandomClassCard;
exports.healPlayer = healPlayer;
exports.fullHeal = fullHeal;
const cards_1 = require("./cards");
Object.defineProperty(exports, "createCard", { enumerable: true, get: function () { return cards_1.createCard; } });
const enemies_1 = require("./enemies");
let state;
function initGame() {
    return {
        screen: 'class_select',
        act: 1, floor: 0, playerClass: 'blood_reaper', gold: 99,
        deck: [], relics: [], potions: [], mapNodes: [], currentNodeIndex: -1,
    };
}
function getState() { return state; }
function setState(s) { state = s; }
// Select class and start run
function selectClass(classType) {
    state.playerClass = classType;
    const deckIds = (0, cards_1.getStartingDeck)(classType);
    state.deck = deckIds.map(id => (0, cards_1.createCard)(id));
    state.screen = 'map';
    generateMap(1);
}
// Shuffle array in place (Fisher-Yates)
function shuffle(arr) {
    for (let i = arr.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [arr[i], arr[j]] = [arr[j], arr[i]];
    }
}
// Generate map for an act
function generateMap(act) {
    state.act = act;
    state.mapNodes = [];
    // Floor layout per GDD: fixed node types at specific floors
    const floorLayout = [
        'enemy', // floor 2
        'enemy', // floor 3
        'event', // floor 4
        'shop', // floor 5
        'enemy', // floor 6
        'rest', // floor 7
        'enemy', // floor 8
        'elite', // floor 9
        'event', // floor 10
        'enemy', // floor 11
        'elite', // floor 12
        'enemy', // floor 13
        'rest', // floor 14
        'boss', // floor 15
    ];
    for (let i = 0; i < floorLayout.length; i++) {
        const node = {
            type: floorLayout[i],
            x: Math.floor(Math.random() * 3) + 1, // columns 1-3
            y: i + 2, // floors 2-15
            visited: false,
        };
        if (floorLayout[i] === 'enemy' || floorLayout[i] === 'elite') {
            const pool = floorLayout[i] === 'elite' ? (0, enemies_1.getActElitePool)(act) : (0, enemies_1.getActEnemyPool)(act);
            const keys = Object.keys(pool);
            const chosenKey = keys[Math.floor(Math.random() * keys.length)];
            node.enemyData = [pool[chosenKey]];
        }
        else if (floorLayout[i] === 'boss') {
            node.enemyData = [(0, enemies_1.getActBoss)(act)];
        }
        state.mapNodes.push(node);
    }
    state.currentNodeIndex = -1; // before first node
}
// Advance to next map node
function advanceMap() {
    if (state.currentNodeIndex + 1 < state.mapNodes.length) {
        state.currentNodeIndex++;
        const node = state.mapNodes[state.currentNodeIndex];
        node.visited = true;
        state.floor = node.y;
        switch (node.type) {
            case 'enemy':
            case 'elite':
                startCombat(node.enemyData, node.type === 'elite');
                break;
            case 'boss':
                startCombat(node.enemyData, false);
                break;
            case 'rest':
                state.screen = 'rest';
                break;
            case 'shop':
                state.screen = 'shop';
                break;
            case 'event':
                state.screen = 'event';
                break;
        }
    }
}
// Start combat
function startCombat(enemyTemplates, isElite) {
    const enemies = enemyTemplates.map((t, i) => ({
        id: `enemy_${i}_${Date.now()}`,
        name: t.name, hp: t.hp, maxHp: t.hp, block: 0, strength: t.strength || 0,
        buffs: { Strength: 0, Dexterity: 0, Regeneration: 0, Intangible: 0 },
        debuffs: [], intentCycle: t.intentCycle, intentIndex: 0, phase: 1,
    }));
    // Shuffle deck for draw pile
    const drawPile = [...state.deck];
    shuffle(drawPile);
    state.combat = {
        player: {
            hp: state.combat?.player.hp ?? 70,
            maxHp: state.combat?.player.maxHp ?? 70,
            block: 0, energy: 3, maxEnergy: 3,
            buffs: { Strength: 0, Dexterity: 0, Regeneration: 0, Intangible: 0 },
            debuffs: [],
        },
        enemies, hand: [], drawPile, discardPile: [], exhaustPile: [],
        turn: 'player', floorNumber: state.floor,
    };
    // Draw initial hand of 5
    for (let i = 0; i < 5; i++) {
        drawCard();
    }
    state.screen = 'combat';
}
// Draw a card from draw pile to hand
function drawCard() {
    const c = state.combat;
    if (c.drawPile.length === 0) {
        // Shuffle discard into draw (excluding exhausted/ethereal cards already removed)
        if (c.discardPile.length > 0) {
            c.drawPile = [...c.discardPile];
            shuffle(c.drawPile);
            c.discardPile = [];
        }
    }
    if (c.drawPile.length > 0) {
        const card = c.drawPile.pop();
        c.hand.push(card);
    }
}
// Discard hand to discard pile
function discardHand() {
    const c = state.combat;
    // Handle ethereal cards (exhaust them instead)
    for (let i = c.hand.length - 1; i >= 0; i--) {
        const card = c.hand[i];
        if (card.ethereal || card.exhaust) {
            c.exhaustPile.push(card);
            c.hand.splice(i, 1);
        }
        else {
            c.discardPile.push(card);
        }
    }
    // Remove exhausted cards from deck tracking too
    state.deck = state.deck.filter(d => !c.exhaustPile.find(e => e === d));
}
// Add card to discard pile (for effects like Dark Ritual)
function addToDiscard(card) {
    state.combat.discardPile.push(card);
    state.deck.push(card);
}
// Remove a card from deck permanently
function removeCardFromDeck(index) {
    // Also remove from combat piles if in combat
    const card = state.deck[index];
    if (state.combat) {
        const c = state.combat;
        c.hand = c.hand.filter(h => h !== card);
        c.drawPile = c.drawPile.filter(d => d !== card);
        c.discardPile = c.discardPile.filter(d => d !== card);
    }
    state.deck.splice(index, 1);
}
// Upgrade a card
function upgradeCard(index) {
    const card = state.deck[index];
    if (!card)
        return;
    const def = (0, cards_1.getCardDef)(card.defId);
    if (!def || !def.upgradedName)
        return;
    card.name = def.upgradedName;
    card.description = def.upgradedDescription;
    card.upgraded = true;
    // Also update in combat piles
    if (state.combat) {
        const c = state.combat;
        for (const pile of [c.hand, c.drawPile, c.discardPile]) {
            for (const hc of pile) {
                if (hc === card) {
                    hc.name = def.upgradedName;
                    hc.description = def.upgradedDescription;
                    hc.upgraded = true;
                }
            }
        }
    }
}
// Get a random card from class pool with rarity weighting
function getRandomClassCard(preferRare = false) {
    const pools = {
        blood_reaper: ['sanguine_strike', 'hemorrhage', 'bloodletting', 'crimson_eruption', 'crimson_shield', 'blood_ward', 'sacrificial_barrier', 'vital_surge', 'life_tap', 'rend_flesh', 'soul_siphon', 'blood_pact'],
        shadowmancer: ['shadow_bolt', 'grasp_of_despair', 'nightmare_lash', 'eternal_darkness', 'cloak_of_shadows', 'haunting_mist', 'phantom_armor', 'whispering_shroud', 'shadowform', 'curse_of_misfortune', 'dark_ritual', 'umbral_mastery'],
        hellforged: ['firebolt', 'hellfire_blast', 'searing_strike', 'immolate', 'obsidian_skin', 'flame_ward', 'demonic_resilience', 'brimstone_shield', 'summon_imp', 'infernal_pact', 'hellfire_aura', 'soul_burn']
    };
    const pool = pools[state.playerClass] || [];
    const weights = preferRare ? [0.5, 0.3, 0.2] : [0.6, 0.3, 0.1];
    const r = Math.random();
    let rarity;
    if (r < weights[0])
        rarity = 'Common';
    else if (r < weights[0] + weights[1])
        rarity = 'Uncommon';
    else
        rarity = 'Rare';
    const filtered = pool.filter(id => {
        const def = (0, cards_1.getCardDef)(id);
        return def && def.rarity === rarity;
    });
    if (filtered.length > 0) {
        return (0, cards_1.createCard)(filtered[Math.floor(Math.random() * filtered.length)]);
    }
    // Fallback: any card from pool
    const fallback = pool[Math.floor(Math.random() * pool.length)];
    return (0, cards_1.createCard)(fallback);
}
// Heal player (after boss) - exported for UI use
function healPlayer(amount) {
    if (!state.combat)
        return;
    state.combat.player.hp = Math.min(state.combat.player.maxHp, state.combat.player.hp + amount);
}
// Full heal after boss
function fullHeal() {
    if (state.combat) {
        state.combat.player.hp = state.combat.player.maxHp;
    }
}
};

// ── module: src/combat.ts ──
__mods["src/combat.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.playCard = playCard;
exports.setTargetEnemy = setTargetEnemy;
exports.healPlayer = healPlayer;
exports.endPlayerTurn = endPlayerTurn;
exports.processEnemyTurn = processEnemyTurn;
exports.handleBossSummon = handleBossSummon;
const state_1 = require("./state");
const state_2 = require("./state");
// === CARD PLAY ENGINE ===
function playCard(cardIndex) {
    const gs = (0, state_1.getState)();
    if (!gs.combat)
        return false;
    const c = gs.combat;
    const card = c.hand[cardIndex];
    if (!card || card.unplayable)
        return false;
    if (c.player.energy < card.cost && card.cost > 0)
        return false;
    // Pay energy cost
    if (card.cost > 0) {
        c.player.energy -= card.cost;
    }
    // Execute card effect
    executeCardEffect(card, c);
    // Remove from hand
    c.hand.splice(cardIndex, 1);
    // Handle Power cards - they go to a special zone (not discard)
    if (card.type === 'Power') {
        // Powers stay in deck but don't get discarded normally
        // For simplicity, we'll add them back to draw pile at end of combat
        // Actually per GDD: "goes into a power zone" - let's just not discard them
        // They remain in the deck for future draws
    }
    else if (card.exhaust) {
        c.exhaustPile.push(card);
        gs.deck = gs.deck.filter(d => d !== card);
    }
    else {
        c.discardPile.push(card);
    }
    // Check if all enemies dead after playing card
    if (c.enemies.every(e => e.hp <= 0)) {
        combatVictory();
    }
    return true;
}
function executeCardEffect(card, combat) {
    const defId = card.defId;
    const upg = card.upgraded;
    // === BASIC CARDS ===
    if (defId === 'strike') {
        dealDamageToTarget(combat, upg ? 8 : 6);
    }
    else if (defId === 'defend') {
        gainBlock(combat, upg ? 8 : 5);
    }
    // === BLOOD REAPER ===
    else if (defId === 'sanguine_strike') {
        dealDamageToTarget(combat, upg ? 10 : 8);
        healPlayer(upg ? 3 : 2);
    }
    else if (defId === 'hemorrhage') {
        dealDamageToTarget(combat, upg ? 6 : 5);
        applyBleedToTarget(combat, upg ? 4 : 3);
    }
    else if (defId === 'bloodletting') {
        loseHpFromCard(combat, upg ? 2 : 3);
        dealDamageToTarget(combat, upg ? 15 : 12);
    }
    else if (defId === 'crimson_eruption') {
        dealDamageToAll(combat, upg ? 10 : 8);
        loseHpFromCard(combat, 2);
    }
    else if (defId === 'crimson_shield') {
        gainBlock(combat, upg ? 8 : 6);
        loseHpFromCard(combat, 2);
    }
    else if (defId === 'blood_ward') {
        gainBlock(combat, upg ? 4 : 3);
        addBuff(combat.player, 'Regeneration', upg ? 2 : 1);
    }
    else if (defId === 'sacrificial_barrier') {
        gainBlock(combat, upg ? 13 : 10);
        loseHpFromCard(combat, 5);
    }
    else if (defId === 'vital_surge') {
        const missing = combat.player.maxHp - combat.player.hp;
        gainBlock(combat, missing + (upg ? 3 : 0));
    }
    else if (defId === 'life_tap') {
        for (let i = 0; i < (upg ? 3 : 2); i++)
            (0, state_2.drawCard)();
        loseHpFromCard(combat, 3);
    }
    else if (defId === 'rend_flesh') {
        applyBleedToAll(combat, upg ? 7 : 5);
        loseHpFromCard(combat, 2);
    }
    else if (defId === 'soul_siphon') { /* Power: handled at start of turn */ }
    else if (defId === 'blood_pact') { /* Power: handled on HP loss from cards */ }
    // === SHADOWMANCER ===
    else if (defId === 'shadow_bolt') {
        dealDamageToTarget(combat, upg ? 8 : 6);
        applyWeakToTarget(combat, upg ? 2 : 1);
    }
    else if (defId === 'grasp_of_despair') {
        dealDamageToTarget(combat, upg ? 5 : 4);
        applyVulnerableToTarget(combat, upg ? 2 : 1);
    }
    else if (defId === 'nightmare_lash') {
        const base = upg ? 9 : 7;
        const bonus = upg ? 9 : 7;
        dealDamageToTarget(combat, base);
        // Check if target has Weak
        const target = getTargetEnemy(combat);
        if (target && hasDebuff(target, 'Weak')) {
            dealDamageToSpecific(combat, target, bonus);
        }
    }
    else if (defId === 'eternal_darkness') {
        for (let i = 0; i < 3; i++)
            dealDamageToRandom(combat, upg ? 4 : 3);
    }
    else if (defId === 'cloak_of_shadows') {
        gainBlock(combat, upg ? 7 : 5);
        (0, state_2.drawCard)();
    }
    else if (defId === 'haunting_mist') {
        gainBlock(combat, upg ? 9 : 7);
        applyWeakToAll(combat, 1);
    }
    else if (defId === 'phantom_armor') {
        gainBlock(combat, upg ? 10 : 8);
        addBuff(combat.player, 'Dexterity', upg ? 3 : 2);
    }
    else if (defId === 'whispering_shroud') {
        gainBlock(combat, upg ? 5 : 4); /* next turn block handled in state */
    }
    else if (defId === 'shadowform') {
        addBuff(combat.player, 'Intangible', upg ? 3 : 2);
    }
    else if (defId === 'curse_of_misfortune') {
        const t = getTargetEnemy(combat);
        if (t) {
            t.strength -= (upg ? 4 : 3);
            applyVulnerableToSpecific(combat, t, upg ? 2 : 1);
        }
    }
    else if (defId === 'dark_ritual') {
        combat.player.energy += 2;
        (0, state_2.addToDiscard)((0, state_2.createCard)('dazed'));
    }
    else if (defId === 'umbral_mastery') { /* Power: handled at start of turn */ }
    // === HELLFORGED ===
    else if (defId === 'firebolt') {
        dealDamageToTarget(combat, upg ? 9 : 7);
        applyBurnToTarget(combat, upg ? 3 : 2);
    }
    else if (defId === 'hellfire_blast') {
        dealDamageToAll(combat, upg ? 12 : 9);
    }
    else if (defId === 'searing_strike') {
        dealDamageToTarget(combat, upg ? 8 : 6); /* next turn energy handled in state */
    }
    else if (defId === 'immolate') {
        dealDamageToTarget(combat, upg ? 16 : 12);
    }
    else if (defId === 'obsidian_skin') {
        gainBlock(combat, upg ? 10 : 7);
    }
    else if (defId === 'flame_ward') {
        gainBlock(combat, upg ? 6 : 5);
        applyBurnToRandom(combat, upg ? 3 : 2);
    }
    else if (defId === 'demonic_resilience') {
        gainBlock(combat, upg ? 5 : 4);
        healPlayer(upg ? 3 : 2);
    }
    else if (defId === 'brimstone_shield') {
        gainBlock(combat, upg ? 4 : 3);
        addBuff(combat.player, 'Strength', upg ? 3 : 2);
    }
    else if (defId === 'summon_imp') {
        addToHand(combat, (0, state_2.createCard)('imp_claw')); /* Imp Claw is generated */
    }
    else if (defId === 'infernal_pact') {
        loseHpFromCard(combat, upg ? 1 : 2);
        combat.player.energy += 2;
        addToHand(combat, (0, state_2.createCard)('imp_claw'));
    }
    else if (defId === 'hellfire_aura') { /* Power: handled at start of turn */ }
    else if (defId === 'soul_burn') {
        applyBurnToTarget(combat, upg ? 10 : 8);
        (0, state_2.drawCard)();
    }
    // === COLORLESS ===
    else if (defId === 'flash_of_insight') {
        for (let i = 0; i < (upg ? 3 : 2); i++)
            (0, state_2.drawCard)();
    }
    else if (defId === 'iron_will') {
        gainBlock(combat, upg ? 11 : 8);
    }
    else if (defId === 'quick_slash') {
        dealDamageToTarget(combat, upg ? 9 : 7);
    }
    else if (defId === 'potent_brew') {
        combat.player.energy += (upg ? 2 : 1);
    }
    // === CURSES/STATUS ===
    else if (defId === 'doubt') { /* Unplayable - shouldn't reach here */ }
}
function addToHand(combat, card) {
    combat.hand.push(card);
}
// === DAMAGE & BLOCK HELPERS ===
let targetEnemyIndex = 0; // tracks which enemy is targeted
function setTargetEnemy(index) {
    targetEnemyIndex = index;
}
function getTargetEnemy(combat) {
    if (combat.enemies.length === 0)
        return undefined;
    const idx = Math.min(targetEnemyIndex, combat.enemies.length - 1);
    return combat.enemies[idx];
}
function dealDamageToTarget(combat, baseDmg) {
    const target = getTargetEnemy(combat);
    if (!target)
        return;
    dealDamageToSpecific(combat, target, baseDmg);
}
function dealDamageToSpecific(combat, enemy, baseDmg) {
    // Player strength bonus
    const totalStr = combat.player.buffs.Strength || 0;
    let dmg = baseDmg + totalStr;
    // Check for Weak on player (reduces damage)
    const weakStacks = getDebuffStacks(combat.player, 'Weak');
    if (weakStacks > 0) {
        dmg = Math.floor(dmg * Math.pow(0.75, weakStacks));
    }
    // Check for Vulnerable on enemy (increases damage)
    const vulnStacks = getDebuffStacks(enemy, 'Vulnerable');
    if (vulnStacks > 0) {
        dmg = Math.floor(dmg * Math.pow(1.5, vulnStacks));
    }
    // Soul Ember relic: +2 damage when applying Burn
    const gs = (0, state_1.getState)();
    if (gs.relics.find(r => r.id === 'soul_ember') && hasDebuff(enemy, 'Burn')) {
        dmg += 2;
    }
    applyDamageToEnemy(combat, enemy, dmg);
}
function dealDamageToAll(combat, baseDmg) {
    for (const enemy of combat.enemies) {
        const totalStr = combat.player.buffs.Strength || 0;
        let dmg = baseDmg + totalStr;
        const weakStacks = getDebuffStacks(combat.player, 'Weak');
        if (weakStacks > 0)
            dmg = Math.floor(dmg * Math.pow(0.75, weakStacks));
        const vulnStacks = getDebuffStacks(enemy, 'Vulnerable');
        if (vulnStacks > 0)
            dmg = Math.floor(dmg * Math.pow(1.5, vulnStacks));
        applyDamageToEnemy(combat, enemy, dmg);
    }
}
function dealDamageToRandom(combat, baseDmg) {
    if (combat.enemies.length === 0)
        return;
    const target = combat.enemies[Math.floor(Math.random() * combat.enemies.length)];
    dealDamageToSpecific(combat, target, baseDmg);
}
function applyDamageToEnemy(combat, enemy, dmg) {
    let remaining = dmg;
    if (enemy.block > 0) {
        const blocked = Math.min(enemy.block, remaining);
        enemy.block -= blocked;
        remaining -= blocked;
    }
    enemy.hp -= remaining;
}
function applyDamageToPlayer(combat, dmg) {
    // Intangible reduces all damage to 1 per stack
    const intangible = combat.player.buffs.Intangible || 0;
    if (intangible > 0) {
        dmg = Math.min(dmg, 1);
    }
    let remaining = dmg;
    if (combat.player.block > 0) {
        const blocked = Math.min(combat.player.block, remaining);
        combat.player.block -= blocked;
        remaining -= blocked;
    }
    combat.player.hp -= remaining;
}
function gainBlock(combat, amount) {
    const dexBonus = (combat.player.buffs.Dexterity || 0) * amount; // Dexterity increases block gained
    combat.player.block += amount + Math.floor(dexBonus / 3); // simplified: each Dex adds ~1/3 of base block
}
function healPlayer(amount) {
    const gs = (0, state_1.getState)();
    if (!gs.combat)
        return;
    gs.combat.player.hp = Math.min(gs.combat.player.maxHp, gs.combat.player.hp + amount);
}
function loseHpFromCard(combat, amount) {
    const intangible = combat.player.buffs.Intangible || 0;
    let actualLoss = intangible > 0 ? 1 : amount;
    // Bloodstone relic: heal 1 when losing HP from card
    const gs = (0, state_1.getState)();
    if (gs.relics.find(r => r.id === 'bloodstone')) {
        combat.player.hp = Math.min(combat.player.maxHp, combat.player.hp + 1);
    }
    // Blood Pact power: gain Strength when losing HP from card
    const hasBloodPact = gs.deck.some(c => c.defId === 'blood_pact');
    if (hasBloodPact) {
        const pactUpgraded = gs.deck.find(c => c.defId === 'blood_pact')?.upgraded;
        combat.player.buffs.Strength += pactUpgraded ? 2 : 1;
    }
    combat.player.hp -= actualLoss;
}
// === STATUS EFFECT HELPERS ===
function getDebuffStacks(entity, name) {
    const debuff = entity.debuffs.find(d => d.name === name);
    return debuff ? debuff.stacks : 0;
}
function hasDebuff(entity, name) {
    return getDebuffStacks(entity, name) > 0;
}
function addBuff(entity, name, amount) {
    entity.buffs[name] = (entity.buffs[name] || 0) + amount;
}
function applyBleedToTarget(combat, stacks) {
    const target = getTargetEnemy(combat);
    if (!target)
        return;
    addDebuff(target, 'Bleed', stacks);
}
function applyBurnToTarget(combat, stacks) {
    const target = getTargetEnemy(combat);
    if (!target)
        return;
    addDebuff(target, 'Burn', stacks);
}
function applyBurnToRandom(combat, stacks) {
    if (combat.enemies.length === 0)
        return;
    const target = combat.enemies[Math.floor(Math.random() * combat.enemies.length)];
    addDebuff(target, 'Burn', stacks);
}
function applyWeakToTarget(combat, stacks) {
    const target = getTargetEnemy(combat);
    if (!target)
        return;
    addDebuff(target, 'Weak', stacks);
}
function applyVulnerableToTarget(combat, stacks) {
    const target = getTargetEnemy(combat);
    if (!target)
        return;
    addDebuff(target, 'Vulnerable', stacks);
}
function applyVulnerableToSpecific(combat, enemy, stacks) {
    addDebuff(enemy, 'Vulnerable', stacks);
}
function applyBleedToAll(combat, stacks) {
    for (const e of combat.enemies)
        addDebuff(e, 'Bleed', stacks);
}
function applyWeakToAll(combat, stacks) {
    for (const e of combat.enemies)
        addDebuff(e, 'Weak', stacks);
}
function addDebuff(entity, name, stacks) {
    const existing = entity.debuffs.find(d => d.name === name);
    if (existing) {
        existing.stacks += stacks;
        existing.duration = Math.max(existing.duration || 0, stacks > 1 ? 3 : 2); // duration for non-Bleed/Burn debuffs
    }
    else {
        entity.debuffs.push({ name, stacks, duration: name === 'Bleed' || name === 'Burn' ? undefined : 2 });
    }
}
// === TURN MANAGEMENT ===
function endPlayerTurn() {
    const gs = (0, state_1.getState)();
    if (!gs.combat)
        return;
    const c = gs.combat;
    // Doubt curse: lose 1 HP at end of turn if in hand
    for (const card of c.hand) {
        if (card.defId === 'doubt') {
            c.player.hp -= 1;
        }
    }
    // Discard hand
    (0, state_2.discardHand)();
    // Reset block
    c.player.block = 0;
    // Process player debuffs at start of enemy turn phase
    processDebuffs(c.player);
    // Switch to enemy turn
    c.turn = 'enemy';
}
function processEnemyTurn() {
    const gs = (0, state_1.getState)();
    if (!gs.combat)
        return;
    const c = gs.combat;
    for (const enemy of c.enemies) {
        if (enemy.hp <= 0)
            continue;
        // Process enemy debuffs at start of their turn
        processDebuffs(enemy);
        // Execute intent
        executeIntent(c, enemy);
    }
    // Check if all enemies dead
    if (c.enemies.every(e => e.hp <= 0)) {
        combatVictory();
        return;
    }
    // Regeneration at end of turn
    const regen = c.player.buffs.Regeneration || 0;
    if (regen > 0) {
        healPlayer(regen);
        c.player.buffs.Regeneration = Math.max(0, regen - 1);
    }
    // Switch back to player turn
    c.turn = 'player';
    // Reset block at start of player turn
    c.player.block = 0;
    // Process player debuffs (Bleed/Burn/Poison)
    processDebuffs(c.player);
    // Intangible decrement
    if (c.player.buffs.Intangible > 0) {
        c.player.buffs.Intangible--;
    }
    // Gain energy
    let energy = 3;
    // Cursed Crown / Ectoplasm / Philosopher's Stone: +1 Energy
    if (gs.relics.find(r => r.id === 'cursed_crown' || r.id === 'ectoplasm' || r.id === 'philosophers_stone')) {
        energy += 1;
    }
    // Soul Siphon power: +1 Energy, -1 HP
    const hasSoulSiphon = gs.deck.some(d => d.defId === 'soul_siphon');
    if (hasSoulSiphon) {
        energy += 1;
        loseHpFromCard(c, 1);
    }
    // Shadow Amulet relic: +1 Intangible at start of turn
    if (gs.relics.find(r => r.id === 'shadow_amulet_relic')) {
        c.player.buffs.Intangible += 1;
    }
    c.player.energy = energy;
    // Eternal Hourglass: if no cards in hand, gain 1 Energy
    if (c.hand.length === 0 && gs.relics.find(r => r.id === 'eternal_hourglass')) {
        c.player.energy += 1;
    }
    // Bleeding Edge relic: apply 1 Bleed to random enemy at start of turn
    if (gs.relics.find(r => r.id === 'bleeding_edge') && c.enemies.some(e => e.hp > 0)) {
        const alive = c.enemies.filter(e => e.hp > 0);
        const target = alive[Math.floor(Math.random() * alive.length)];
        addDebuff(target, 'Bleed', 1);
    }
    // Umbral Mastery: apply Weak to all enemies at start of turn
    const hasUmbralMastery = gs.deck.find(d => d.defId === 'umbral_mastery');
    if (hasUmbralMastery) {
        const stacks = hasUmbralMastery.upgraded ? 2 : 1;
        applyWeakToAll(c, stacks);
    }
    // Hellfire Aura: deal damage to all enemies at start of turn
    const hasHellfireAura = gs.deck.find(d => d.defId === 'hellfire_aura');
    if (hasHellfireAura) {
        const dmg = hasHellfireAura.upgraded ? 5 : 3;
        for (const e of c.enemies) {
            if (e.hp > 0)
                applyDamageToEnemy(c, e, dmg);
        }
    }
    // Draw 5 cards
    for (let i = 0; i < 5; i++)
        (0, state_2.drawCard)();
    // Check player death
    if (c.player.hp <= 0) {
        gs.screen = 'game_over';
    }
}
function processDebuffs(entity) {
    for (let i = entity.debuffs.length - 1; i >= 0; i--) {
        const d = entity.debuffs[i];
        if (d.name === 'Bleed' || d.name === 'Burn') {
            // Lose HP equal to stacks, then halve stacks
            if (entity.hp !== undefined) {
                entity.hp -= d.stacks;
            }
            d.stacks = Math.floor(d.stacks / 2);
            if (d.stacks <= 0) {
                entity.debuffs.splice(i, 1);
            }
        }
        else if (d.name === 'Poison') {
            // Lose HP equal to stacks, then reduce by 1
            if (entity.hp !== undefined) {
                entity.hp -= d.stacks;
            }
            d.stacks--;
            if (d.stacks <= 0) {
                entity.debuffs.splice(i, 1);
            }
        }
        else {
            // Weak/Vulnerable: decrement duration
            if (d.duration !== undefined) {
                d.duration--;
                if (d.duration <= 0) {
                    entity.debuffs.splice(i, 1);
                }
            }
        }
    }
}
function executeIntent(combat, enemy) {
    const intent = enemy.intentCycle[enemy.intentIndex % enemy.intentCycle.length];
    switch (intent.type) {
        case 'attack':
            applyDamageToPlayer(combat, (intent.damage || 0) + enemy.strength);
            break;
        case 'defend':
            enemy.block += intent.blockAmount || 0;
            break;
        case 'multi_attack':
            for (let i = 0; i < (intent.hits || 1); i++) {
                applyDamageToPlayer(combat, (intent.hitDamage || 0) + enemy.strength);
            }
            break;
        case 'buff':
            // Enemy buffs self - simplified: just increase strength or gain block
            if (intent.description?.includes('Strength')) {
                const strMatch = intent.description.match(/\+(\d+)/);
                if (strMatch)
                    enemy.strength += parseInt(strMatch[1]);
            }
            break;
        case 'debuff':
            // Apply debuff to player - simplified handling
            if (intent.description?.includes('Weak')) {
                addDebuff(combat.player, 'Weak', 2);
            }
            else if (intent.description?.includes('Vulnerable') || intent.description?.includes('Curse')) {
                addDebuff(combat.player, 'Vulnerable', 1);
                addDebuff(combat.player, 'Weak', 1);
            }
            else if (intent.description?.includes('Bleed')) {
                const bleedMatch = intent.description.match(/(\d+)/);
                addDebuff(combat.player, 'Bleed', parseInt(bleedMatch?.[0] || '3'));
            }
            else if (intent.description?.includes('Poison')) {
                const poisonMatch = intent.description.match(/(\d+)/);
                addDebuff(combat.player, 'Poison', parseInt(poisonMatch?.[0] || '4'));
            }
            break;
        case 'summon':
            // Boss summon logic handled separately
            break;
    }
    enemy.intentIndex++;
}
// === BOSS SUMMON LOGIC ===
function handleBossSummon(combat, bossEnemy) {
    const gs = (0, state_1.getState)();
    if (!gs.combat)
        return;
    // Check for summon enemy template in the boss data
    // We need to access the original template - stored in a special property
    const summonTemplate = bossEnemy.summonTemplate;
    if (!summonTemplate || combat.enemies.filter(e => e !== bossEnemy && e.hp > 0).length >= 2)
        return;
    const newEnemy = {
        id: `minion_${Date.now()}`,
        name: summonTemplate.name, hp: summonTemplate.hp, maxHp: summonTemplate.hp,
        block: 0, strength: 0,
        buffs: { Strength: 0, Dexterity: 0, Regeneration: 0, Intangible: 0 },
        debuffs: [], intentCycle: summonTemplate.intentCycle, intentIndex: 0, phase: 1,
    };
    combat.enemies.push(newEnemy);
}
// === COMBAT VICTORY/DEFEAT ===
function combatVictory() {
    const gs = (0, state_1.getState)();
    if (!gs.combat)
        return;
    // Ashen Armor relic: heal 6 HP at end of combat
    if (gs.relics.find(r => r.id === 'ashen_armor')) {
        gs.combat.player.hp = Math.min(gs.combat.player.maxHp, gs.combat.player.hp + 6);
    }
    // Check if boss
    const node = gs.mapNodes[gs.currentNodeIndex];
    if (node?.type === 'boss') {
        (0, state_3.fullHeal)();
        gs.screen = 'rewards';
        gs._rewardType = 'boss';
    }
    else {
        gs.screen = 'rewards';
        gs._rewardType = node?.type || 'enemy';
    }
}
const state_3 = require("./state");
};

// ── module: src/ui.ts ──
__mods["src/ui.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.showScreen = showScreen;
exports.renderClassSelect = renderClassSelect;
exports.renderMap = renderMap;
exports.renderCombat = renderCombat;
exports.renderRewards = renderRewards;
exports.renderShop = renderShop;
exports.renderEvent = renderEvent;
exports.renderRest = renderRest;
exports.renderGameOver = renderGameOver;
exports.renderVictory = renderVictory;
exports.render = render;
const state_1 = require("./state");
const combat_1 = require("./combat");
const cards_1 = require("./cards");
const state_2 = require("./state");
const relics_1 = require("./relics");
const potions_1 = require("./potions");
const state_3 = require("./state");
// === SCREEN MANAGEMENT ===
function showScreen(screenId) {
    document.querySelectorAll('.screen').forEach(s => s.classList.add('hidden'));
    const el = document.getElementById(`screen-${screenId}`);
    if (el)
        el.classList.remove('hidden');
}
function ds(el, key) { return el.dataset?.[key] ?? ''; }
// === CLASS SELECT ===
function renderClassSelect() {
    showScreen('class-select');
    const container = document.getElementById('screen-class-select');
    const classes = [
        { id: 'blood_reaper', name: 'Blood Reaper', desc: 'Sacrifice HP for power. Life steal and Bleed mastery.', icon: '🩸' },
        { id: 'shadowmancer', name: 'Shadowmancer', desc: 'Debuffs, Intangible, and card manipulation.', icon: '👻' },
        { id: 'hellforged', name: 'Hellforged', desc: 'Fire damage, Burn, and Imp summoning.', icon: '🔥' },
    ];
    container.innerHTML = `
    <h1 class="game-title">Shadows of the Abyss</h1>
    <p class="game-subtitle">Choose your cursed archetype</p>
    <div class="class-cards">
      ${classes.map(c => `<div class="class-card" data-class="${c.id}"><div style="font-size:40px;margin-bottom:10px">${c.icon}</div><h2>${c.name}</h2><p>${c.desc}</p></div>`).join('')}
    </div>
  `;
    container.querySelectorAll('.class-card').forEach(card => {
        card.addEventListener('click', () => {
            (0, state_2.selectClass)(ds(card, 'class'));
            renderMap();
        });
    });
}
// === MAP ===
function renderMap() {
    showScreen('map');
    const gs = (0, state_1.getState)();
    const container = document.getElementById('screen-map');
    let nodesHtml = '';
    for (let i = 0; i < gs.mapNodes.length; i++) {
        const node = gs.mapNodes[i];
        const isAvailable = (i === gs.currentNodeIndex + 1);
        const statusClass = node.visited ? 'visited' : (isAvailable ? 'available' : '');
        const topPx = 650 - (node.y * 42);
        const leftPx = 175 + (node.x - 2) * 80;
        const iconMap = { enemy: '⚔️', elite: '💀', boss: '👹', rest: '🏕️', shop: '🛒', event: '❓' };
        const icon = iconMap[node.type] || '?';
        nodesHtml += `<div class="map-node node-${node.type} ${statusClass}" data-index="${i}" style="top:${topPx}px;left:${leftPx}px">${icon}</div>`;
    }
    container.innerHTML = `
    <div id="hud">
      <span class="hud-stat hud-hp">❤️ ${gs.combat?.player.hp ?? 70}/${gs.combat?.player.maxHp ?? 70}</span>
      <span class="hud-stat hud-gold">💰 ${gs.gold}</span>
      <span style="font-size:13px">Deck: ${gs.deck.length} | Relics: ${gs.relics.length} | Potions: ${gs.potions.length}/3</span>
      <span class="hud-stat">Act ${gs.act} - Floor ${gs.floor}</span>
    </div>
    <div id="map-area"><div class="map-grid">${nodesHtml}</div></div>
  `;
    container.querySelectorAll('.map-node.available').forEach(node => {
        node.addEventListener('click', () => { (0, state_3.advanceMap)(); render(); });
    });
}
// === COMBAT ===
function renderCombat() {
    showScreen('combat');
    const gs = (0, state_1.getState)();
    if (!gs.combat)
        return;
    const c = gs.combat;
    const container = document.getElementById('screen-combat');
    let enemiesHtml = '';
    for (let i = 0; i < c.enemies.length; i++) {
        const e = c.enemies[i];
        const deadClass = e.hp <= 0 ? 'dead' : '';
        const intent = e.intentCycle[e.intentIndex % e.intentCycle.length];
        enemiesHtml += `<div class="enemy-display ${deadClass}" data-enemy="${i}">
      <div class="enemy-name">${e.name}</div>
      <div class="enemy-hp-bar"><div class="enemy-hp-fill" style="width:${Math.max(0, e.hp / e.maxHp * 100)}%"></div></div>
      <div>${Math.max(0, e.hp)}/${e.maxHp}</div>
      ${e.block > 0 ? `<div style="color:#5af;font-size:12px">🛡️${e.block}</div>` : ''}
      ${e.strength > 0 ? `<div style="color:#f88;font-size:12px">⚔️+${e.strength}</div>` : ''}
      <div class="enemy-intent">${intent.description}</div>
    </div>`;
    }
    let handHtml = '';
    for (let i = 0; i < c.hand.length; i++) {
        const card = c.hand[i];
        const canPlay = !card.unplayable && c.player.energy >= card.cost && card.cost >= 0;
        handHtml += `<div class="card card-${card.type.toLowerCase()}" data-card="${i}" style="${canPlay ? '' : 'opacity:0.5;cursor:not-allowed'}">
      <div class="card-cost">${card.cost === -1 ? '✕' : card.cost}</div>
      <div class="card-name">${card.name}</div>
      <div class="card-desc">${card.description}</div>
    </div>`;
    }
    let debuffsHtml = '';
    for (const d of c.player.debuffs) {
        const icon = { Weak: '🟡', Vulnerable: '🔴', Bleed: '💧', Burn: '🔥', Poison: '☠️' }[d.name] || '?';
        debuffsHtml += `<span title="${d.name}">${icon}${d.stacks}</span>`;
    }
    let buffsHtml = '';
    if (c.player.buffs.Strength > 0)
        buffsHtml += `⚔️${c.player.buffs.Strength} `;
    if (c.player.buffs.Dexterity > 0)
        buffsHtml += `🎯${c.player.buffs.Dexterity} `;
    if (c.player.buffs.Regeneration > 0)
        buffsHtml += `💚${c.player.buffs.Regeneration} `;
    if (c.player.buffs.Intangible > 0)
        buffsHtml += `👻${c.player.buffs.Intangible}`;
    let potionsHtml = '';
    for (let i = 0; i < gs.potions.length; i++) {
        const pId = gs.potions[i];
        const pDef = potions_1.POTION_DEFS[pId];
        if (!pDef)
            continue;
        const icon = { blood_vial: '🩸', firebomb: '💣', dex_tonic: '⚡', energy_elixir: '⚡', cursed_brew: '☠️', bleeding_flask: '🩸', imp_in_a_bottle: '👹', smoke_bomb: '💨' }[pId] || '🧪';
        potionsHtml += `<div class="potion-slot" data-potion="${i}" title="${pDef.name}: ${pDef.description}">${icon}</div>`;
    }
    container.innerHTML = `
    <div id="combat-area">
      <div id="hud">
        <span class="hud-stat hud-hp">❤️ ${c.player.hp}/${c.player.maxHp}</span>
        <span class="hud-stat hud-block">🛡️ ${c.player.block}</span>
        <span class="hud-stat hud-energy">⚡ ${c.player.energy}/${c.player.maxEnergy}</span>
        <span>${buffsHtml}${debuffsHtml}</span>
      </div>
      <div id="enemy-zone">${enemiesHtml}</div>
      <div id="combat-log"></div>
      <div id="player-zone">
        <div style="display:flex;justify-content:space-between;padding:0 20px;margin-bottom:5px;">
          <span style="font-size:13px;color:#8a7a6a">Draw: ${c.drawPile.length} | Discard: ${c.discardPile.length}</span>
          <button class="btn btn-danger" id="end-turn-btn">End Turn</button>
        </div>
        <div id="hand-area">${handHtml}</div>
      </div>
      <div id="potion-bar">${potionsHtml}</div>
    </div>`;
    container.querySelectorAll('.card').forEach(card => {
        card.addEventListener('click', () => {
            if (c.turn !== 'player')
                return;
            const idx = parseInt(ds(card, 'card'));
            const handCard = c.hand[idx];
            if (!handCard || handCard.unplayable)
                return;
            if (c.player.energy < handCard.cost && handCard.cost > 0) {
                addCombatLog('Not enough energy!');
                return;
            }
            (0, combat_1.playCard)(idx);
            render(); // Use main render to handle screen transitions (e.g., victory)
        });
    });
    container.querySelectorAll('.enemy-display').forEach(el => {
        el.addEventListener('click', () => { (0, combat_1.setTargetEnemy)(parseInt(ds(el, 'enemy'))); render(); });
    });
    document.getElementById('end-turn-btn')?.addEventListener('click', () => {
        if (c.turn !== 'player')
            return;
        (0, combat_1.endPlayerTurn)();
        setTimeout(() => {
            (0, combat_1.processEnemyTurn)();
            const gs2 = (0, state_1.getState)();
            if (gs2.combat) {
                for (const e of gs2.combat.enemies) {
                    const prevIntent = e.intentCycle[(e.intentIndex - 1 + e.intentCycle.length) % e.intentCycle.length];
                    if (prevIntent?.type === 'summon' && e.hp > 0)
                        (0, combat_1.handleBossSummon)(gs2.combat, e);
                }
            }
            render(); // Use main render to handle screen transitions
        }, 300);
    });
    container.querySelectorAll('.potion-slot').forEach(slot => {
        slot.addEventListener('click', () => {
            if (c.turn !== 'player')
                return;
            usePotion(parseInt(ds(slot, 'potion')));
            render();
        });
    });
}
function addCombatLog(msg) {
    const log = document.getElementById('combat-log');
    if (!log)
        return;
    const entry = document.createElement('div');
    entry.className = 'log-entry';
    entry.textContent = msg;
    log.appendChild(entry);
    log.scrollTop = log.scrollHeight;
}
function usePotion(index) {
    const gs = (0, state_1.getState)();
    if (!gs.combat || index >= gs.potions.length)
        return;
    const pId = gs.potions[index];
    const c = gs.combat;
    switch (pId) {
        case 'blood_vial':
            (0, state_3.healPlayer)(15);
            break;
        case 'firebomb':
            for (const e of c.enemies)
                if (e.hp > 0)
                    e.hp -= 10;
            break;
        case 'dex_tonic':
            c.player.buffs.Dexterity += 3;
            break;
        case 'energy_elixir':
            c.player.energy += 2;
            break;
        case 'cursed_brew':
            for (const e of c.enemies)
                addDebuffTo(e, 'Vulnerable', 3);
            break;
        case 'bleeding_flask':
            {
                const t = c.enemies[0];
                if (t && t.hp > 0)
                    addDebuffTo(t, 'Bleed', 6);
            }
            break;
        case 'imp_in_a_bottle':
            c.hand.push((0, cards_1.createCard)('imp_claw'));
            break;
        case 'smoke_bomb':
            gs.screen = 'map';
            return;
    }
    gs.potions.splice(index, 1);
}
function addDebuffTo(entity, name, stacks) {
    const existing = entity.debuffs.find(d => d.name === name);
    if (existing)
        existing.stacks += stacks;
    else
        entity.debuffs.push({ name, stacks, duration: name === 'Bleed' || name === 'Burn' ? undefined : 2 });
}
// === REWARDS ===
function renderRewards() {
    showScreen('rewards');
    const gs = (0, state_1.getState)();
    const container = document.getElementById('screen-rewards');
    const isBoss = gs._rewardType === 'boss';
    const isElite = gs._rewardType === 'elite';
    let goldReward;
    if (isBoss)
        goldReward = 50;
    else if (isElite)
        goldReward = Math.floor(Math.random() * 11) + 25;
    else
        goldReward = Math.floor(Math.random() * 11) + 10;
    if (gs.relics.find(r => r.id === 'greedy_imp'))
        goldReward += 10;
    gs.gold += goldReward;
    const preferRare = isBoss || isElite;
    const rewardCards = [(0, state_2.getRandomClassCard)(preferRare), (0, state_2.getRandomClassCard)(preferRare), (0, state_2.getRandomClassCard)(preferRare)];
    let potionDrop = false;
    let potionCount = 1;
    if (isBoss) {
        potionDrop = true;
        potionCount = 2;
    }
    else if (isElite && Math.random() < 0.7)
        potionDrop = true;
    else if (!isElite && Math.random() < 0.4)
        potionDrop = true;
    let relicReward = null;
    if (isElite) {
        const available = relics_1.ALL_RELIC_IDS.filter(id => !gs.relics.find(r => r.id === id));
        if (available.length > 0)
            relicReward = available[Math.floor(Math.random() * available.length)];
    }
    let bossRelicChoices = [];
    if (isBoss) {
        const available = relics_1.BOSS_RELIC_IDS.filter(id => !gs.relics.find(r => r.id === id));
        for (let i = 0; i < Math.min(3, available.length); i++)
            bossRelicChoices.push(available[Math.floor(Math.random() * available.length)]);
    }
    container.innerHTML = `
    <h2 style="margin-bottom:15px;color:#da3">Victory!</h2>
    <p style="color:#a89878;margin-bottom:20px">+${goldReward} Gold</p>
    <h3 style="margin-bottom:10px">Choose a card (or skip):</h3>
    <div class="reward-cards" id="card-rewards">
      ${rewardCards.map((c, i) => `<div class="reward-card card-${c.type.toLowerCase()}" data-idx="${i}"><div style="font-weight:bold;margin-bottom:5px">${c.name}</div><div style="font-size:12px;color:#a89878">${c.description}</div></div>`).join('')}
    </div>
    <button class="btn" id="skip-card-btn">Skip</button>`;
    const advance = () => {
        if (potionDrop)
            showPotionReward();
        else if (relicReward)
            showRelicReward(relicReward);
        else if (bossRelicChoices.length > 0)
            showBossRelicChoice(bossRelicChoices);
        else
            finishRewards();
    };
    container.querySelectorAll('.reward-card').forEach(card => {
        card.addEventListener('click', () => { gs.deck.push(rewardCards[parseInt(ds(card, 'idx'))]); advance(); });
    });
    document.getElementById('skip-card-btn')?.addEventListener('click', advance);
    function showPotionReward() {
        const count = potionCount;
        for (let i = 0; i < count; i++) {
            if (gs.potions.length < 3)
                gs.potions.push(potions_1.ALL_POTION_IDS[Math.floor(Math.random() * potions_1.ALL_POTION_IDS.length)]);
        }
        container.innerHTML += `<p style="color:#5af;margin-top:10px">+ Potion obtained!</p>`;
        setTimeout(() => { if (relicReward)
            showRelicReward(relicReward);
        else if (bossRelicChoices.length > 0)
            showBossRelicChoice(bossRelicChoices);
        else
            finishRewards(); }, 800);
    }
    function showRelicReward(relicId) {
        const relicDef = relics_1.RELIC_DEFS[relicId];
        if (!relicDef)
            return;
        gs.relics.push(relicDef);
        container.innerHTML += `<p style="color:#da3;margin-top:10px">+ Relic: ${relicDef.name}</p>`;
        setTimeout(finishRewards, 800);
    }
    function showBossRelicChoice(choices) {
        const relicHtml = `<h3 style="margin:20px 0 10px">Choose a Boss Relic:</h3><div class="reward-cards" id="relic-rewards">${choices.map(id => { const rDef = relics_1.RELIC_DEFS[id]; return `<div class="reward-card card-skill" data-relic="${id}"><div style="font-weight:bold;margin-bottom:5px">${rDef?.name || id}</div><div style="font-size:12px;color:#a89878">${rDef?.description || ''}</div></div>`; }).join('')}</div>`;
        container.innerHTML += relicHtml;
        container.querySelectorAll('#relic-rewards .reward-card').forEach(card => {
            card.addEventListener('click', () => { applyBossRelic(ds(card, 'relic')); finishRewards(); });
        });
    }
    function finishRewards() {
        if (isBoss) {
            (0, state_3.fullHeal)();
            if (gs.act >= 3) {
                gs.screen = 'victory';
                renderVictory();
                return;
            }
            gs.act++;
            (0, state_3.generateMap)(gs.act);
            gs.currentNodeIndex = -1;
        }
        gs.screen = 'map';
        renderMap();
    }
}
function applyBossRelic(id) {
    const gs = (0, state_1.getState)();
    switch (id) {
        case 'cursed_crown':
            if (gs.combat)
                gs.combat.player.maxEnergy += 1;
            break;
        case 'ectoplasm':
            if (gs.combat)
                gs.combat.player.maxEnergy += 1;
            gs.gold = 0;
            break;
        case 'philosophers_stone':
            if (gs.combat)
                gs.combat.player.maxEnergy += 1;
            break;
        case 'black_blood':
            if (gs.combat)
                gs.combat.player.hp -= Math.floor(gs.combat.player.maxHp * 0.1);
            break;
        case 'shadow_amulet_relic':
            if (gs.combat) {
                gs.combat.player.maxHp -= 15;
                gs.combat.player.hp = Math.min(gs.combat.player.hp, gs.combat.player.maxHp);
            }
            break;
    }
    const relicDef = relics_1.RELIC_DEFS[id];
    if (relicDef)
        gs.relics.push(relicDef);
}
// === SHOP ===
function renderShop() {
    showScreen('shop');
    const gs = (0, state_1.getState)();
    const container = document.getElementById('screen-shop');
    const shopCards = [(0, state_2.getRandomClassCard)(false), (0, state_2.getRandomClassCard)(false), (0, state_2.getRandomClassCard)(false)];
    const colorlessId = ['flash_of_insight', 'iron_will', 'quick_slash', 'potent_brew'][Math.floor(Math.random() * 4)];
    shopCards.push((0, cards_1.createCard)(colorlessId));
    const shopRelics = [];
    for (let i = 0; i < 2; i++) {
        const available = relics_1.ALL_RELIC_IDS.filter(id => !gs.relics.find(r => r.id === id));
        if (available.length > 0)
            shopRelics.push(available[Math.floor(Math.random() * available.length)]);
    }
    const shopPotions = [];
    for (let i = 0; i < 3; i++)
        shopPotions.push(potions_1.ALL_POTION_IDS[Math.floor(Math.random() * potions_1.ALL_POTION_IDS.length)]);
    let html = `<h2 style="margin-bottom:15px">🛒 Shop</h2><div class="hud-stat hud-gold" style="font-size:18px;margin-bottom:15px">💰 ${gs.gold} Gold</div><div class="shop-items">`;
    for (const card of shopCards) {
        const price = card.rarity === 'Rare' ? 150 : card.rarity === 'Uncommon' ? 75 : 50;
        html += `<div class="shop-item"><div class="shop-item-info"><div class="shop-item-name">${card.name} (${card.type})</div><div class="shop-item-desc">${card.description}</div></div><button class="btn btn-gold shop-buy" data-type="card" data-price="${price}" data-card-def="${card.defId}">Buy ${price}g</button></div>`;
    }
    for (const rId of shopRelics) {
        const rDef = relics_1.RELIC_DEFS[rId];
        if (!rDef)
            continue;
        html += `<div class="shop-item"><div class="shop-item-info"><div class="shop-item-name">${rDef.name}</div><div class="shop-item-desc">${rDef.description}</div></div><button class="btn btn-gold shop-buy" data-type="relic" data-price="150" data-relic-id="${rId}">Buy 150g</button></div>`;
    }
    for (const pId of shopPotions) {
        const pDef = potions_1.POTION_DEFS[pId];
        if (!pDef)
            continue;
        html += `<div class="shop-item"><div class="shop-item-info"><div class="shop-item-name">${pDef.name}</div><div class="shop-item-desc">${pDef.description}</div></div><button class="btn btn-gold shop-buy" data-type="potion" data-price="50" data-potion-id="${pId}">Buy 50g</button></div>`;
    }
    html += `<div class="shop-item"><div class="shop-item-info"><div class="shop-item-name">Remove a card from your deck</div><div class="shop-item-desc">Permanently remove one card</div></div><button class="btn btn-gold shop-buy" data-type="remove" data-price="75">75g</button></div>`;
    html += `</div><br><button class="btn" id="leave-shop-btn">Leave Shop</button>`;
    container.innerHTML = html;
    container.querySelectorAll('.shop-buy').forEach(btn => {
        btn.addEventListener('click', () => {
            const price = parseInt(ds(btn, 'price'));
            if (gs.gold < price)
                return;
            gs.gold -= price;
            switch (ds(btn, 'type')) {
                case 'card':
                    gs.deck.push((0, cards_1.createCard)(ds(btn, 'cardDef')));
                    break;
                case 'relic':
                    {
                        const r = relics_1.RELIC_DEFS[ds(btn, 'relicId')];
                        if (r)
                            gs.relics.push(r);
                    }
                    break;
                case 'potion':
                    if (gs.potions.length < 3)
                        gs.potions.push(ds(btn, 'potionId'));
                    else
                        return;
                    break;
                case 'remove':
                    showCardRemoval();
                    return;
            }
            renderShop();
        });
    });
    document.getElementById('leave-shop-btn')?.addEventListener('click', () => { gs.screen = 'map'; renderMap(); });
}
function showCardRemoval() {
    const gs = (0, state_1.getState)();
    const container = document.getElementById('screen-shop');
    let deckHtml = '';
    for (let i = 0; i < gs.deck.length; i++) {
        const card = gs.deck[i];
        deckHtml += `<div class="card card-${card.type.toLowerCase()}" data-idx="${i}" style="width:100px;height:130px;margin:5px;display:inline-block"><div class="card-name" style="font-size:11px">${card.name}</div></div>`;
    }
    container.innerHTML = `<h2 style="margin-bottom:15px">Choose a card to remove:</h2><div style="display:flex;flex-wrap:wrap;justify-content:center;padding:20px">${deckHtml}</div><button class="btn" id="cancel-remove-btn">Cancel</button>`;
    container.querySelectorAll('.card').forEach(card => {
        card.addEventListener('click', () => { gs.gold -= 75; (0, state_3.removeCardFromDeck)(parseInt(ds(card, 'idx'))); renderShop(); });
    });
    document.getElementById('cancel-remove-btn')?.addEventListener('click', () => renderShop());
}
// === EVENTS ===
function renderEvent() {
    showScreen('event');
    const gs = (0, state_1.getState)();
    const container = document.getElementById('screen-event');
    const events = [
        { text: 'A blood-stained altar hums with dark power.', choices: [
                { text: '[Offer 15 HP] → Obtain a random relic', action: () => { if (gs.combat)
                        gs.combat.player.hp -= 15; const rId = relics_1.ALL_RELIC_IDS[Math.floor(Math.random() * relics_1.ALL_RELIC_IDS.length)]; gs.relics.push(relics_1.RELIC_DEFS[rId]); } },
                { text: '[Pray] → Heal 10 HP, gain a Curse', action: () => { if (gs.combat)
                        gs.combat.player.hp = Math.min(gs.combat.player.maxHp, gs.combat.player.hp + 10); gs.deck.push((0, cards_1.createCard)('doubt')); } },
                { text: '[Leave]', action: () => { } },
            ] },
        { text: 'A hooded figure offers a trade.', choices: [
                { text: '[Trade a card] → Remove one, gain 100 Gold', action: () => { if (gs.deck.length > 0)
                        (0, state_3.removeCardFromDeck)(0); gs.gold += 100; } },
                { text: '[Buy wares] → Lose 50g, get Potion + Relic', action: () => { gs.gold -= 50; if (gs.potions.length < 3)
                        gs.potions.push(potions_1.ALL_POTION_IDS[Math.floor(Math.random() * potions_1.ALL_POTION_IDS.length)]); const rId = relics_1.ALL_RELIC_IDS[Math.floor(Math.random() * relics_1.ALL_RELIC_IDS.length)]; gs.relics.push(relics_1.RELIC_DEFS[rId]); } },
                { text: '[Leave]', action: () => { } },
            ] },
        { text: 'A spring bubbles with dark water.', choices: [
                { text: '[Drink] → Lose 10 HP, remove all Curses', action: () => { if (gs.combat)
                        gs.combat.player.hp -= 10; gs.deck = gs.deck.filter(c => c.type !== 'Curse'); } },
                { text: '[Bottle it] → Obtain a Cursed Brew potion', action: () => { if (gs.potions.length < 3)
                        gs.potions.push('cursed_brew'); } },
                { text: '[Leave]', action: () => { } },
            ] },
        { text: 'Ghosts offer a bargain.', choices: [
                { text: '[Accept] → Lose 20 HP, upgrade 2 random cards', action: () => { if (gs.combat)
                        gs.combat.player.hp -= 20; for (let i = 0; i < 2 && gs.deck.length > 0; i++) {
                        const idx = Math.floor(Math.random() * gs.deck.length);
                        (0, state_3.upgradeCard)(idx);
                    } } },
                { text: '[Refuse]', action: () => { } },
            ] },
        { text: 'A grinning imp challenges you.', choices: [
                { text: '[Bet 30 Gold] → 50% chance to double or lose it all', action: () => { gs.gold -= 30; if (Math.random() < 0.5)
                        gs.gold += 60; } },
                { text: '[Wager a card] → Remove random card', action: () => { if (gs.deck.length > 0)
                        (0, state_3.removeCardFromDeck)(Math.floor(Math.random() * gs.deck.length)); } },
                { text: '[Leave]', action: () => { } },
            ] },
        { text: 'Dusty tomes contain forgotten knowledge.', choices: [
                { text: '[Study] → Lose 5 HP, gain a random Power card', action: () => { if (gs.combat)
                        gs.combat.player.hp -= 5; const powerCards = ['soul_siphon', 'blood_pact', 'umbral_mastery', 'hellfire_aura']; gs.deck.push((0, cards_1.createCard)(powerCards[Math.floor(Math.random() * powerCards.length)])); } },
                { text: '[Read forbidden page] → Gain random card, get Doubt', action: () => { gs.deck.push((0, state_2.getRandomClassCard)(false)); gs.deck.push((0, cards_1.createCard)('doubt')); } },
                { text: '[Leave]', action: () => { } },
            ] },
    ];
    const event = events[Math.floor(Math.random() * events.length)];
    container.innerHTML = `<div class="event-text">${event.text}</div><div class="event-choices">${event.choices.map((c, i) => `<button class="btn" data-choice="${i}">${c.text}</button>`).join('')}</div>`;
    container.querySelectorAll('.event-choices .btn').forEach(btn => {
        btn.addEventListener('click', () => { event.choices[parseInt(ds(btn, 'choice'))].action(); gs.screen = 'map'; renderMap(); });
    });
}
// === REST ===
function renderRest() {
    showScreen('rest');
    const gs = (0, state_1.getState)();
    const container = document.getElementById('screen-rest');
    container.innerHTML = `<h2 style="margin-bottom:20px">🏕️ Rest Site</h2><div class="rest-options"><button class="btn" id="rest-heal-btn">Rest (Heal 25% HP)</button><button class="btn" id="rest-forge-btn">Forge (Upgrade card)</button><button class="btn" id="rest-meditate-btn">Meditate (Remove card)</button></div><br><button class="btn" id="leave-rest-btn">Leave</button>`;
    document.getElementById('rest-heal-btn')?.addEventListener('click', () => { if (gs.combat)
        gs.combat.player.hp = Math.min(gs.combat.player.maxHp, gs.combat.player.hp + Math.floor(gs.combat.player.maxHp * 0.25)); gs.screen = 'map'; renderMap(); });
    document.getElementById('rest-forge-btn')?.addEventListener('click', showForge);
    document.getElementById('rest-meditate-btn')?.addEventListener('click', showMeditate);
    document.getElementById('leave-rest-btn')?.addEventListener('click', () => { gs.screen = 'map'; renderMap(); });
}
function showForge() {
    const gs = (0, state_1.getState)();
    const container = document.getElementById('screen-rest');
    let deckHtml = '';
    for (let i = 0; i < gs.deck.length; i++) {
        if (gs.deck[i].upgraded)
            continue;
        deckHtml += `<div class="card card-${gs.deck[i].type.toLowerCase()}" data-idx="${i}" style="width:100px;height:130px;margin:5px;display:inline-block"><div class="card-name" style="font-size:11px">${gs.deck[i].name}</div></div>`;
    }
    container.innerHTML = `<h2 style="margin-bottom:15px">Choose a card to upgrade:</h2><div style="display:flex;flex-wrap:wrap;justify-content:center;padding:20px">${deckHtml || '<p>No cards available</p>'}</div><button class="btn" id="cancel-forge-btn">Cancel</button>`;
    container.querySelectorAll('.card').forEach(card => { card.addEventListener('click', () => { (0, state_3.upgradeCard)(parseInt(ds(card, 'idx'))); gs.screen = 'map'; renderMap(); }); });
    document.getElementById('cancel-forge-btn')?.addEventListener('click', () => renderRest());
}
function showMeditate() {
    const gs = (0, state_1.getState)();
    const container = document.getElementById('screen-rest');
    let deckHtml = '';
    for (let i = 0; i < gs.deck.length; i++) {
        deckHtml += `<div class="card card-${gs.deck[i].type.toLowerCase()}" data-idx="${i}" style="width:100px;height:130px;margin:5px;display:inline-block"><div class="card-name" style="font-size:11px">${gs.deck[i].name}</div></div>`;
    }
    container.innerHTML = `<h2 style="margin-bottom:15px">Choose a card to remove:</h2><div style="display:flex;flex-wrap:wrap;justify-content:center;padding:20px">${deckHtml}</div><button class="btn" id="cancel-meditate-btn">Cancel</button>`;
    container.querySelectorAll('.card').forEach(card => { card.addEventListener('click', () => { (0, state_3.removeCardFromDeck)(parseInt(ds(card, 'idx'))); gs.screen = 'map'; renderMap(); }); });
    document.getElementById('cancel-meditate-btn')?.addEventListener('click', () => renderRest());
}
// === GAME OVER / VICTORY ===
function renderGameOver() {
    showScreen('game-over');
    const container = document.getElementById('screen-game-over');
    container.innerHTML = `<h1 class="game-over-text">Run Over</h1><p style="color:#a89878;margin:20px 0">The abyss claims another soul...</p><button class="btn" id="restart-btn">Try Again</button>`;
    document.getElementById('restart-btn')?.addEventListener('click', () => { (0, state_1.setState)((0, state_2.initGame)()); renderClassSelect(); });
}
function renderVictory() {
    showScreen('victory');
    const container = document.getElementById('screen-victory');
    container.innerHTML = `<h1 class="victory-text">Victory!</h1><p style="color:#a89878;margin:20px 0;font-size:18px">You have conquered the Abyssal Spire and defeated the Archdemon.</p><button class="btn" id="restart-btn">Play Again</button>`;
    document.getElementById('restart-btn')?.addEventListener('click', () => { (0, state_1.setState)((0, state_2.initGame)()); renderClassSelect(); });
}
// === MAIN RENDER LOOP ===
function render() {
    const gs = (0, state_1.getState)();
    switch (gs.screen) {
        case 'class_select':
            renderClassSelect();
            break;
        case 'map':
            renderMap();
            break;
        case 'combat':
            renderCombat();
            break;
        case 'rewards':
            renderRewards();
            break;
        case 'shop':
            renderShop();
            break;
        case 'event':
            renderEvent();
            break;
        case 'rest':
            renderRest();
            break;
        case 'game_over':
            renderGameOver();
            break;
        case 'victory':
            renderVictory();
            break;
    }
}
};

// ── entry ──
__require("src/main.ts");
})();
</script>
</body>
</html>
<!-- agent-meta {"model":"thinkingcap-qwen3.6-27b","provider":"lmstudio","persona":"typescript","sessionId":"68fc7565-6bd9-4284-8dce-6b49c5ca5e85","tokensIn":4990223,"tokensOut":53427,"tokensTotal":5043650,"cost":0,"turns":77,"toolCalls":76,"failedToolCalls":0,"timestamp":"2026-07-31T21:41:14.262Z"} -->