From 63ca75ea78fcfe480936cd5c7aeab1b60a99b027 Mon Sep 17 00:00:00 2001 From: Stephanie Gredell Date: Fri, 5 Sep 2025 17:50:47 -0700 Subject: [PATCH] clean up --- src/data/cards.js | 28 ++++++------ src/engine/battle.js | 6 +++ src/engine/events.js | 74 +++++++++++++++---------------- src/input/InputManager.js | 92 +++++++++++++++++++-------------------- src/ui/render.js | 64 +++------------------------ style.css | 19 ++++---- 6 files changed, 117 insertions(+), 166 deletions(-) diff --git a/src/data/cards.js b/src/data/cards.js index f503713..05ae8dd 100644 --- a/src/data/cards.js +++ b/src/data/cards.js @@ -132,12 +132,12 @@ export const CARDS = { ctx.log("Recursion activates and strikes again!"); ctx.enemy.hp = 1; ctx.deal(ctx.enemy, ctx.scalarFromWeak(5)); - + // Check for battle end after second attack - if (ctx.enemy.hp <= 0) { - ctx.enemy.hp = 0; - ctx.onWin(); - return; + if (ctx.enemy.hp <= 0) { + ctx.enemy.hp = 0; + ctx.onWin(); + return; } } } @@ -167,13 +167,13 @@ export const CARDS = { ctx.log("No cards left in deck to review."); return; } - + // Store selection state for modal ctx.root._codeReviewCards = topCards; ctx.root._codeReviewCallback = (selectedIndex) => { // Get the selected card const selectedCard = topCards[selectedIndex]; - + // Remove the peeked cards from draw pile (they were only peeked) topCards.forEach((card, i) => { const drawIndex = ctx.root.player.draw.findIndex(id => id === card.id); @@ -181,21 +181,21 @@ export const CARDS = { ctx.root.player.draw.splice(drawIndex, 1); } }); - + // Add selected card to hand ctx.addToHand(selectedCard); - + // Put remaining cards on bottom of deck topCards.forEach((card, i) => { if (i !== selectedIndex) { ctx.putOnBottom(card.id); } }); - + ctx.log(`Code review complete. Added ${selectedCard.name} to hand.`); ctx.render(); }; - + // Show selection modal if (window.gameModules?.render?.renderCodeReviewSelection) { window.gameModules.render.renderCodeReviewSelection(ctx.root, topCards); @@ -291,12 +291,10 @@ export const CARDS = { }, rubber_duck: { - id: "rubber_duck", name: "Rubber Duck Debug", cost: 0, type: "skill", text: "Draw 1. Reveal enemy intent.", + id: "rubber_duck", name: "Rubber Duck Debug", cost: 0, type: "skill", text: "Draw 1.", art: "Monk_31.png", effect: (ctx) => { ctx.draw(1); - const intent = ctx.enemy.intent; - ctx.log(`Rubber duck reveals: Enemy will ${intent.type} for ${intent.value || 'unknown'} next turn.`); } }, @@ -370,7 +368,7 @@ export const CARDS = { export const STARTER_DECK = [ "strike", "strike", "defend", "defend", "segfault", "coffee_rush", "skill_issue", "git_commit", - "stack_trace", "stack_trace" + "stack_trace", "stack_trace", "git_push_force", "code_review" ]; export const CARD_POOL = [ diff --git a/src/engine/battle.js b/src/engine/battle.js index 67e9c78..8748e67 100644 --- a/src/engine/battle.js +++ b/src/engine/battle.js @@ -125,6 +125,12 @@ export function playCard(ctx, handIndex) { if (ctx.enemy.hp <= 0) { ctx.enemy.hp = 0; ctx.onWin(); return; } if (ctx.player.hp <= 0) { ctx.onLose(); return; } + + // Don't render if Code Review modal is active + if (ctx.root._codeReviewCards) { + return; + } + ctx.render(); } diff --git a/src/engine/events.js b/src/engine/events.js index 169e085..6a08d5d 100644 --- a/src/engine/events.js +++ b/src/engine/events.js @@ -10,7 +10,7 @@ export class EventHandler { this.keyHandlers = new Map(); // Track keyboard shortcuts this.globalHandlers = new Set(); // Track global event handlers this.currentScreen = null; - + this.setupGlobalEvents(); } @@ -26,17 +26,17 @@ export class EventHandler { handler(e); } }; - + document.addEventListener('keydown', this.globalKeyHandler); this.globalHandlers.add('keydown'); - + // Global escape handler for modals this.globalEscapeHandler = (e) => { if (e.key === 'Escape') { this.closeTopModal(); } }; - + document.addEventListener('keydown', this.globalEscapeHandler); this.globalHandlers.add('escape'); } @@ -55,7 +55,7 @@ export class EventHandler { */ on(element, event, handler, options = {}) { if (!element) return; - + const wrappedHandler = (e) => { try { handler(e); @@ -63,9 +63,9 @@ export class EventHandler { console.error(`Event handler error (${event}):`, error); } }; - + element.addEventListener(event, wrappedHandler, options); - + // Track for cleanup if (!this.listeners.has(element)) { this.listeners.set(element, []); @@ -92,7 +92,7 @@ export class EventHandler { */ setupBattleEvents() { this.switchScreen('battle'); - + // Card play events this.root.app.querySelectorAll("[data-play]").forEach(btn => { this.on(btn, "mouseenter", () => { @@ -141,11 +141,11 @@ export class EventHandler { this.addKeyHandler(i.toString(), (e) => { const cardIndex = i - 1; const hand = this.root.player.hand; - + if (cardIndex >= hand.length) return; - + const card = hand[cardIndex]; - + if (this.root.selectedCardIndex === cardIndex) { // Second press - play the card if (this.root.player.energy >= card.cost) { @@ -168,11 +168,11 @@ export class EventHandler { */ setupMapEvents() { this.switchScreen('map'); - + // Node navigation this.root.app.querySelectorAll("[data-node]").forEach(el => { if (!el.dataset.node) return; - + this.on(el, "click", () => this.root.go(el.dataset.node)); }); @@ -206,14 +206,14 @@ export class EventHandler { */ setupRewardEvents(choices) { this.switchScreen('reward'); - + this.root.app.querySelectorAll("[data-pick]").forEach(btn => { this.on(btn, "click", () => { const idx = parseInt(btn.dataset.pick, 10); this.root.takeReward(idx); }); }); - + const skipBtn = this.root.app.querySelector("[data-skip]"); if (skipBtn) { this.on(skipBtn, "click", () => this.root.skipReward()); @@ -225,7 +225,7 @@ export class EventHandler { this.root.takeReward(i - 1); }, `Select Reward ${i}`); } - + this.addKeyHandler('s', () => this.root.skipReward(), 'Skip Reward'); } @@ -234,10 +234,10 @@ export class EventHandler { */ setupRestEvents() { this.switchScreen('rest'); - + const healBtn = this.root.app.querySelector("[data-act='heal']"); const upgradeBtn = this.root.app.querySelector("[data-act='upgrade']"); - + if (healBtn) { this.on(healBtn, "click", () => { const heal = Math.floor(this.root.player.maxHp * 0.2); @@ -246,7 +246,7 @@ export class EventHandler { this.root.afterNode(); }); } - + if (upgradeBtn) { this.on(upgradeBtn, "click", () => { // Import and call renderUpgrade @@ -266,7 +266,7 @@ export class EventHandler { */ setupShopEvents(shopCards = [], shopRelic = null) { this.switchScreen('shop'); - + // Card purchase events this.root.app.querySelectorAll("[data-buy-card]").forEach(btn => { this.on(btn, "click", () => { @@ -278,7 +278,7 @@ export class EventHandler { this.root.log(`Bought ${card.name} for 50 gold.`); btn.disabled = true; btn.textContent = "SOLD"; - + this.updateGoldDisplay(); this.updateShopAffordability(); } else { @@ -303,7 +303,7 @@ export class EventHandler { relicBtn.disabled = true; relicBtn.textContent = "SOLD"; - + this.updateGoldDisplay(); this.updateShopAffordability(); } else { @@ -329,7 +329,7 @@ export class EventHandler { */ setupEventEvents(event) { this.switchScreen('event'); - + this.root.app.querySelectorAll("[data-choice]").forEach(btn => { this.on(btn, "click", () => { const idx = parseInt(btn.dataset.choice, 10); @@ -352,7 +352,7 @@ export class EventHandler { */ setupRelicSelectionEvents(relicChoices) { this.switchScreen('relic-selection'); - + this.root.app.querySelectorAll("[data-relic]").forEach(btn => { this.on(btn, "click", () => { const relicId = btn.dataset.relic; @@ -369,11 +369,11 @@ export class EventHandler { // Keyboard shortcuts for (let i = 1; i <= relicChoices.length; i++) { this.addKeyHandler(i.toString(), () => { - const relicBtn = this.root.app.querySelector(`[data-relic="${relicChoices[i-1]}"]`); + const relicBtn = this.root.app.querySelector(`[data-relic="${relicChoices[i - 1]}"]`); relicBtn?.click(); }, `Select Relic ${i}`); } - + this.addKeyHandler('m', () => this.showMessagesModal(), 'Show Messages'); } @@ -382,15 +382,15 @@ export class EventHandler { */ setupEndGameEvents() { this.switchScreen('endgame'); - + const replayBtn = this.root.app.querySelector("[data-replay]"); const restartAct2Btn = this.root.app.querySelector("[data-restart-act2]"); const menuBtn = this.root.app.querySelector("[data-menu]"); - + if (replayBtn) { this.on(replayBtn, "click", () => this.root.reset()); } - + if (restartAct2Btn) { this.on(restartAct2Btn, "click", async () => { if (this.root.loadAct2Checkpoint()) { @@ -401,7 +401,7 @@ export class EventHandler { } }); } - + if (menuBtn) { this.on(menuBtn, "click", () => this.root.reset()); } @@ -455,10 +455,10 @@ export class EventHandler { showTooltip(event) { const tooltip = document.getElementById('custom-tooltip'); if (!tooltip) return; - + const node = event.target.closest('.spire-node'); if (!node) return; - + const content = node.dataset.tooltip; const avatarPath = node.dataset.avatar; @@ -514,7 +514,7 @@ export class EventHandler { modal.innerHTML = `
-

Messages for Prime

+

Inbox

@@ -565,7 +565,7 @@ export class EventHandler { } } this.listeners.clear(); - + // Clear keyboard handlers this.keyHandlers.clear(); } @@ -575,7 +575,7 @@ export class EventHandler { */ destroy() { this.cleanup(); - + // Remove global handlers if (this.globalHandlers.has('keydown')) { document.removeEventListener('keydown', this.globalKeyHandler); @@ -583,7 +583,7 @@ export class EventHandler { if (this.globalHandlers.has('escape')) { document.removeEventListener('keydown', this.globalEscapeHandler); } - + this.globalHandlers.clear(); } -} \ No newline at end of file +} diff --git a/src/input/InputManager.js b/src/input/InputManager.js index d05df91..b3deebe 100644 --- a/src/input/InputManager.js +++ b/src/input/InputManager.js @@ -18,7 +18,7 @@ export class InputManager { this.root = gameRoot; this.activeHandlers = new Map(); // Track active event listeners for cleanup this.globalHandlers = new Set(); // Track global document listeners - + // Bind methods to preserve 'this' context this.handleGlobalKeydown = this.handleGlobalKeydown.bind(this); this.handleGlobalClick = this.handleGlobalClick.bind(this); @@ -31,7 +31,7 @@ export class InputManager { // Global keyboard handling document.addEventListener('keydown', this.handleGlobalKeydown); this.globalHandlers.add('keydown'); - + // Global click handling for data attributes document.addEventListener('click', this.handleGlobalClick); this.globalHandlers.add('click'); @@ -45,7 +45,7 @@ export class InputManager { if (event.key === 'Escape') { this.handleEscapeKey(event); } - + // Handle number keys for code review selection if (this.root._codeReviewCards && event.key >= '1' && event.key <= '3') { const selectedIndex = parseInt(event.key, 10) - 1; @@ -58,7 +58,7 @@ export class InputManager { } } } - + // Add other global shortcuts here as needed } @@ -67,90 +67,90 @@ export class InputManager { */ handleGlobalClick(event) { const target = event.target; - + // Event delegation for game interactions - + // Handle clicks on elements with data attributes (check both direct and parent elements) - + // Check for card play (battle-card with data-play) const cardElement = target.closest('[data-play]'); if (cardElement) { this.handleCardPlay(cardElement, event); return; // Early return to avoid duplicate handling } - + // Check for other interactive elements (using closest to handle child elements) const actionElement = target.closest('[data-action]'); if (actionElement) { this.handleActionButton(actionElement, event); return; } - + const actElement = target.closest('[data-act]'); if (actElement) { this.handleRestAction(actElement, event); return; } - + const pickElement = target.closest('[data-pick]'); if (pickElement) { this.handleRewardPick(pickElement, event); return; } - + const choiceElement = target.closest('[data-choice]'); if (choiceElement) { this.handleEventChoice(choiceElement, event); return; } - + const upgradeElement = target.closest('[data-upgrade]'); if (upgradeElement) { this.handleCardUpgrade(upgradeElement, event); return; } - + const buyCardElement = target.closest('[data-buy-card]'); if (buyCardElement) { this.handleShopCardBuy(buyCardElement, event); return; } - + const buyRelicElement = target.closest('[data-buy-relic]'); if (buyRelicElement) { this.handleShopRelicBuy(buyRelicElement, event); return; } - + const leaveElement = target.closest('[data-leave]'); if (leaveElement) { this.handleLeaveShop(leaveElement, event); return; } - + const relicElement = target.closest('[data-relic]'); if (relicElement) { this.handleRelicSelection(relicElement, event); return; } - + const codeReviewElement = target.closest('[data-code-review-pick]'); if (codeReviewElement) { this.handleCodeReviewPick(codeReviewElement, event); return; } - + // Check for direct data attributes on target (fallback) if (target.dataset.node !== undefined) { this.handleMapNodeClick(target, event); } - + // Handle spire node clicks (check if clicked element is inside a spire-node) const spireNode = target.closest('.spire-node'); if (spireNode && spireNode.dataset.node) { this.handleMapNodeClick(spireNode, event); } - + // Handle other specific buttons this.handleSpecificButtons(target, event); } @@ -160,21 +160,21 @@ export class InputManager { */ handleCardPlay(element, event) { if (!element.classList.contains('playable')) return; - + const index = parseInt(element.dataset.play, 10); const card = this.root.player.hand[index]; - + if (!card) return; if (this.root.player.energy < card.cost) return; - + try { // Play sound this.playSound('played-card.mp3'); - + // Create and execute PlayCardCommand const command = new PlayCardCommand(this.root, index); const success = this.root.commandInvoker.execute(command); - + if (success) { // Clear card selection this.root.selectedCardIndex = null; @@ -192,7 +192,7 @@ export class InputManager { */ handleMapNodeClick(element, event) { if (!element.dataset.node) return; - + try { // Create and execute MapMoveCommand const command = new MapMoveCommand(this.root, element.dataset.node); @@ -207,7 +207,7 @@ export class InputManager { */ handleRewardPick(element, event) { const idx = parseInt(element.dataset.pick, 10); - + try { // Create and execute RewardPickCommand const command = new RewardPickCommand(this.root, idx); @@ -235,7 +235,7 @@ export class InputManager { handleCardUpgrade(element, event) { const deckIndex = parseInt(element.dataset.upgrade, 10); const oldCardId = this.root.player.deck[deckIndex]; - + // Find the upgraded version and replace it const { CARDS } = window.gameModules?.cards || {}; if (CARDS && CARDS[oldCardId]?.upgrades) { @@ -259,16 +259,16 @@ export class InputManager { this.root.log(`Bought ${card.name} for 50 gold.`); element.disabled = true; element.textContent = "SOLD"; - + // Update gold display const goldDisplay = this.root.app.querySelector('.gold-amount'); if (goldDisplay) { goldDisplay.textContent = this.root.player.gold; } - + // Update affordability of remaining items this.updateShopAffordability(); - + // Save immediately to persist purchase this.root.save(); } else { @@ -293,7 +293,7 @@ export class InputManager { const newRelicIds = [...currentRelicIds, relic.id]; attachRelics(this.root, newRelicIds); }); - + element.disabled = true; element.textContent = "SOLD"; @@ -305,7 +305,7 @@ export class InputManager { // Update affordability of remaining items this.updateShopAffordability(); - + // Save immediately to persist purchase this.root.save(); } else { @@ -388,12 +388,12 @@ export class InputManager { */ handleCodeReviewPick(element, event) { const selectedIndex = parseInt(element.dataset.codeReviewPick, 10); - + if (this.root._codeReviewCallback && this.root._codeReviewCards) { try { // Execute the callback with selected index this.root._codeReviewCallback(selectedIndex); - + // Clean up state this.root._codeReviewCards = null; this.root._codeReviewCallback = null; @@ -408,7 +408,7 @@ export class InputManager { */ handleActionButton(element, event) { const action = element.dataset.action; - + switch (action) { case 'show-messages': this.handleShowMessages(); @@ -426,7 +426,7 @@ export class InputManager { */ handleRestAction(element, event) { const action = element.dataset.act; - + try { // Create and execute RestActionCommand const command = new RestActionCommand(this.root, action); @@ -444,7 +444,7 @@ export class InputManager { // Create and execute EndTurnCommand const command = new EndTurnCommand(this.root); const success = this.root.commandInvoker.execute(command); - + if (success) { // Clear card selection this.root.selectedCardIndex = null; @@ -507,7 +507,7 @@ export class InputManager { if (this.root.currentShopRelic && this.root.player.gold >= 100) { this.root.player.gold -= 100; this.root.log(`Bought ${this.root.currentShopRelic.name} for 100 gold.`); - + // Add relic logic here element.disabled = true; element.textContent = "SOLD"; @@ -536,7 +536,7 @@ export class InputManager { this.root.render(); return; } - + // Close any open modals const modals = document.querySelectorAll('.messages-modal-overlay'); modals.forEach(modal => modal.remove()); @@ -555,7 +555,7 @@ export class InputManager { modal.innerHTML = `
-

Messages for Prime

+

Messages

@@ -576,10 +576,10 @@ export class InputManager { // Close functionality const closeModal = () => modal.remove(); - + const closeBtn = modal.querySelector('.messages-close-btn'); closeBtn.addEventListener('click', closeModal); - + // Close on overlay click modal.addEventListener('click', (e) => { if (e.target === modal) closeModal(); @@ -615,7 +615,7 @@ export class InputManager { try { const audio = new Audio(`assets/sounds/${soundFile}`); audio.volume = 0.3; - audio.play().catch(() => {}); // Ignore audio play failures + audio.play().catch(() => { }); // Ignore audio play failures } catch (e) { // Ignore audio errors } @@ -632,7 +632,7 @@ export class InputManager { if (this.globalHandlers.has('click')) { document.removeEventListener('click', this.handleGlobalClick); } - + this.globalHandlers.clear(); this.activeHandlers.clear(); } @@ -643,7 +643,7 @@ function playSound(soundFile) { try { const audio = new Audio(`assets/sounds/${soundFile}`); audio.volume = 0.3; - audio.play().catch(() => {}); // Ignore failures in restrictive environments + audio.play().catch(() => { }); // Ignore failures in restrictive environments } catch (e) { // Audio not supported or file missing, ignore } diff --git a/src/ui/render.js b/src/ui/render.js index 040a8a4..095a849 100644 --- a/src/ui/render.js +++ b/src/ui/render.js @@ -10,62 +10,8 @@ function playSound(soundFile) { } } -async function showMessagesModal() { - const { getAllMessages } = await import("../data/messages.js"); - const messages = getAllMessages(); - - const modal = document.createElement('div'); - modal.className = 'messages-modal-overlay'; - modal.innerHTML = ` -
-
-

Messages for Prime

- -
-
- ${messages.length > 0 ? messages.map((msg, index) => ` -
-
From: ${msg.from}
-
${msg.message}
-
- `).join('') : ` -
-

No messages added yet!

-

Add your birthday messages to src/data/messages.js

-
- `} -
-
- `; - - // Close functionality - const closeModal = () => { - modal.remove(); - }; - - const closeBtn = modal.querySelector('.messages-close-btn'); - closeBtn.addEventListener('click', closeModal); - - // Close on overlay click - modal.addEventListener('click', (e) => { - if (e.target === modal) closeModal(); - }); - - // Close on Escape key - const handleEscape = (e) => { - if (e.key === 'Escape') { - closeModal(); - document.removeEventListener('keydown', handleEscape); - } - }; - document.addEventListener('keydown', handleEscape); - - // Add to DOM - document.body.appendChild(modal); -} - - export function showDamageNumber(damage, target, isPlayer = false) { + console.log('this is shown - damage number') const targetElement = isPlayer ? document.querySelector('.player-battle-zone') : document.querySelector('.enemy-battle-zone'); @@ -1459,7 +1405,7 @@ export async function renderWin(root) { export async function renderCodeReviewSelection(root, cards) { const { CARDS } = await import("../data/cards.js"); - + if (!cards || cards.length === 0) { root.log("No cards available for code review."); return; @@ -1475,8 +1421,8 @@ export async function renderCodeReviewSelection(root, cards) {
${cards.map((card, index) => { - const cardType = card.type === 'attack' ? 'attack' : card.type === 'skill' ? 'skill' : 'power'; - return ` + const cardType = card.type === 'attack' ? 'attack' : card.type === 'skill' ? 'skill' : 'power'; + return `
@@ -1499,7 +1445,7 @@ export async function renderCodeReviewSelection(root, cards) {
Click to choose
`; - }).join('')} + }).join('')}