diff --git a/src/engine/dungeon/DungeonDeck.js b/src/engine/dungeon/DungeonDeck.js index d983b48..8b7265e 100644 --- a/src/engine/dungeon/DungeonDeck.js +++ b/src/engine/dungeon/DungeonDeck.js @@ -9,7 +9,7 @@ export class DungeonDeck { } generateMissionDeck(objectiveTileId) { - console.log("πŸ” Inspecting TILES object keys:", Object.keys(TILES)); + this.cards = []; // 1. Create a "Pool" of standard dungeon tiles @@ -65,7 +65,7 @@ export class DungeonDeck { // --- Step 5: Stack --- this.cards = [...topPool, ...bottomPool]; - console.log(`Deck Generated: ${this.cards.length} cards.`); + } shuffleArray(array) { diff --git a/src/engine/dungeon/DungeonGenerator.js b/src/engine/dungeon/DungeonGenerator.js index 25887f1..50759a1 100644 --- a/src/engine/dungeon/DungeonGenerator.js +++ b/src/engine/dungeon/DungeonGenerator.js @@ -41,7 +41,7 @@ export class DungeonGenerator { } this.placeCardFinal(firstCard, 0, 0, DIRECTIONS.NORTH); - console.log(`🏰 Dungeon started with ${firstCard.name}`); + // 2. Transition to door selection this.state = PLACEMENT_STATE.WAITING_DOOR; @@ -52,9 +52,7 @@ export class DungeonGenerator { * Player selects a door to expand from */ selectDoor(exitPoint) { - console.log('[DungeonGenerator] selectDoor called with:', exitPoint); - console.log('[DungeonGenerator] Current state:', this.state); - console.log('[DungeonGenerator] Available exits:', this.availableExits); + if (this.state !== PLACEMENT_STATE.WAITING_DOOR) { console.warn("Not in door selection mode"); @@ -81,7 +79,7 @@ export class DungeonGenerator { // Draw next card this.currentCard = this.deck.draw(); if (!this.currentCard) { - console.log("Deck empty - dungeon complete"); + this.state = PLACEMENT_STATE.COMPLETE; this.notifyStateChange(); return false; @@ -113,7 +111,7 @@ export class DungeonGenerator { this.notifyPlacementUpdate(); this.notifyStateChange(); - console.log(`πŸ“¦ Placing ${this.currentCard.name} at (${this.placementX}, ${this.placementY})`); + return true; } @@ -127,7 +125,7 @@ export class DungeonGenerator { const currentIndex = rotations.indexOf(this.placementRotation); this.placementRotation = rotations[(currentIndex + 1) % 4]; - console.log(`πŸ”„ Rotated to ${this.placementRotation}`); + this.notifyPlacementUpdate(); } @@ -140,7 +138,7 @@ export class DungeonGenerator { this.placementX += dx; this.placementY += dy; - console.log(`↔️ Moved to (${this.placementX}, ${this.placementY})`); + this.notifyPlacementUpdate(); } @@ -168,13 +166,13 @@ export class DungeonGenerator { return false; } - console.log(`[confirmPlacement] Placing at (${this.placementX}, ${this.placementY}) rotation: ${this.placementRotation}`); + // Round to integers (tiles must be on grid cells) const finalX = Math.round(this.placementX); const finalY = Math.round(this.placementY); - console.log(`[confirmPlacement] Rounded to (${finalX}, ${finalY})`); + // Place the tile this.placeCardFinal( @@ -191,7 +189,7 @@ export class DungeonGenerator { this.notifyPlacementUpdate(); // Clear preview this.notifyStateChange(); - console.log("βœ… Tile placed successfully"); + return true; } @@ -199,12 +197,7 @@ export class DungeonGenerator { * Internal: Actually place a card on the grid */ placeCardFinal(card, x, y, rotation) { - console.log('[placeCardFinal] Card:', card); - console.log('[placeCardFinal] Card.variants:', card.variants); - console.log('[placeCardFinal] Rotation:', rotation, 'Type:', typeof rotation); - const variant = card.variants[rotation]; - console.log('[placeCardFinal] Variant:', variant); const instance = { id: `tile_${this.placedTiles.length}`, @@ -224,9 +217,7 @@ export class DungeonGenerator { * Update list of exits player can choose from */ updateAvailableExits(instance, variant, anchorX, anchorY) { - console.log('[updateAvailableExits] ===== NUEVO CODIGO ===== Called for tile:', instance.id); - console.log('[updateAvailableExits] Variant exits:', variant.exits); - console.log('[updateAvailableExits] Anchor:', anchorX, anchorY); + // Add new exits from this tile for (const ex of variant.exits) { @@ -236,7 +227,7 @@ export class DungeonGenerator { const leadingTo = this.neighbor(gx, gy, ex.direction); const isOccupied = this.grid.isOccupied(leadingTo.x, leadingTo.y); - console.log(`[updateAvailableExits] Exit at (${gx}, ${gy}) dir ${ex.direction} -> leads to (${leadingTo.x}, ${leadingTo.y}) occupied: ${isOccupied}`); + if (!isOccupied) { this.availableExits.push({ @@ -245,11 +236,11 @@ export class DungeonGenerator { direction: ex.direction, tileId: instance.id }); - console.log('[updateAvailableExits] βœ“ Added exit'); + } } - console.log('[updateAvailableExits] Total available exits now:', this.availableExits.length); + // Remove exits that are now blocked or connected this.availableExits = this.availableExits.filter(exit => { diff --git a/src/engine/dungeon/DungeonGenerator.js.temp b/src/engine/dungeon/DungeonGenerator.js.temp deleted file mode 100644 index d018998..0000000 --- a/src/engine/dungeon/DungeonGenerator.js.temp +++ /dev/null @@ -1,50 +0,0 @@ - - tryPlaceCard(card, targetExit) { - const requiredDirection = this.opposite(targetExit.direction); - const targetCell = this.neighbor(targetExit.x, targetExit.y, targetExit.direction); - - const rotations = [DIRECTIONS.NORTH, DIRECTIONS.EAST, DIRECTIONS.SOUTH, DIRECTIONS.WEST]; - // const shuffled = this.shuffle(rotations); - - // πŸ”§ DEBUG: Force SOUTH rotation only - const forcedRotations = [DIRECTIONS.SOUTH]; - console.log('⚠️ FORCED ROTATION TO SOUTH ONLY FOR TESTING'); - - let bestPlacement = null; - let maxConnections = -1; - - for (const rotation of forcedRotations) { - const rotatedExits = this.rotateExits(card.exits, rotation); - const candidates = rotatedExits.filter(e => e.direction === requiredDirection); - - for (const candidate of candidates) { - const anchorX = targetCell.x - candidate.x; - const anchorY = targetCell.y - candidate.y; - - if (this.grid.canPlace(card, anchorX, anchorY, rotation)) { - let score = 0; - for (const exit of rotatedExits) { - const globalX = anchorX + exit.x; - const globalY = anchorY + exit.y; - const neighbor = this.neighbor(globalX, globalY, exit.direction); - if (this.grid.occupiedCells.has(`${neighbor.x},${neighbor.y}`)) { - score++; - } - } - - if (score > maxConnections) { - maxConnections = score; - bestPlacement = { card, anchorX, anchorY, rotation }; - } - } - } - } - - if (bestPlacement) { - this.placeTileAt(bestPlacement.card, bestPlacement.anchorX, bestPlacement.anchorY, bestPlacement.rotation); - console.log(`βœ… Best Placement Selected: Score ${maxConnections}`); - return true; - } - - return false; - } diff --git a/src/engine/dungeon/GridSystem.js b/src/engine/dungeon/GridSystem.js index de2a7a5..bc159c1 100644 --- a/src/engine/dungeon/GridSystem.js +++ b/src/engine/dungeon/GridSystem.js @@ -67,7 +67,6 @@ export class GridSystem { } } this.tiles.push(tileInstance); - console.log(`[Grid] Placed ${tileInstance.id} at ${anchorX},${anchorY} (Rot: ${tileInstance.rotation})`); } /** diff --git a/src/engine/dungeon/TileDefinitions.js b/src/engine/dungeon/TileDefinitions.js index d1ff467..9a9d0de 100644 --- a/src/engine/dungeon/TileDefinitions.js +++ b/src/engine/dungeon/TileDefinitions.js @@ -100,6 +100,11 @@ export const TILES = { textures: ['/assets/images/dungeon1/tiles/L.png'], variants: { [DIRECTIONS.NORTH]: { + // Shape: Top and Left are solid. + // 1111 (Top-Most) + // 1111 + // 1100 + // 1100 width: 4, height: 4, layout: [ [1, 1, 1, 1], @@ -113,19 +118,30 @@ export const TILES = { ] }, [DIRECTIONS.EAST]: { + // Rotated 90 CW: Top -> Right, Left -> Top. + // Shape: Top and Right are solid. + // 1111 (Top-Most) + // 1111 + // 0011 + // 0011 width: 4, height: 4, layout: [ - [1, 1, 0, 0], - [1, 1, 0, 0], [1, 1, 1, 1], - [1, 1, 1, 1] + [1, 1, 1, 1], + [0, 0, 1, 1], + [0, 0, 1, 1] ], exits: [ - { x: 0, y: 0, direction: DIRECTIONS.SOUTH }, { x: 1, y: 0, direction: DIRECTIONS.SOUTH }, - { x: 2, y: 3, direction: DIRECTIONS.NORTH }, { x: 3, y: 3, direction: DIRECTIONS.NORTH } + { x: 3, y: 0, direction: DIRECTIONS.SOUTH }, { x: 2, y: 0, direction: DIRECTIONS.SOUTH }, + { x: 0, y: 3, direction: DIRECTIONS.WEST }, { x: 0, y: 2, direction: DIRECTIONS.WEST } ] }, [DIRECTIONS.SOUTH]: { + // Rotated 180: Bottom and Right are solid. + // 0011 + // 0011 + // 1111 + // 1111 width: 4, height: 4, layout: [ [0, 0, 1, 1], @@ -139,16 +155,21 @@ export const TILES = { ] }, [DIRECTIONS.WEST]: { + // Rotated 270: Bottom and Left are solid. + // 1100 + // 1100 + // 1111 + // 1111 width: 4, height: 4, layout: [ + [1, 1, 0, 0], + [1, 1, 0, 0], [1, 1, 1, 1], - [1, 1, 1, 1], - [0, 0, 1, 1], - [0, 0, 1, 1] + [1, 1, 1, 1] ], exits: [ - { x: 3, y: 2, direction: DIRECTIONS.EAST }, { x: 3, y: 3, direction: DIRECTIONS.EAST }, - { x: 0, y: 1, direction: DIRECTIONS.WEST }, { x: 0, y: 0, direction: DIRECTIONS.WEST } + { x: 3, y: 1, direction: DIRECTIONS.EAST }, { x: 3, y: 0, direction: DIRECTIONS.EAST }, + { x: 0, y: 3, direction: DIRECTIONS.NORTH }, { x: 1, y: 3, direction: DIRECTIONS.NORTH } ] } } @@ -164,6 +185,11 @@ export const TILES = { textures: ['/assets/images/dungeon1/tiles/T.png'], variants: { [DIRECTIONS.NORTH]: { + // T Shape (Top bar) + // 111111 + // 111111 + // 001100 + // 001100 width: 6, height: 4, layout: [ [1, 1, 1, 1, 1, 1], @@ -178,22 +204,36 @@ export const TILES = { ] }, [DIRECTIONS.EAST]: { + // Rotated 90 CW: Bar is at Right (East) + // 0011 + // 0011 + // 1111 + // 1111 + // 0011 + // 0011 width: 4, height: 6, layout: [ - [1, 1, 0, 0], - [1, 1, 0, 0], + [0, 0, 1, 1], + [0, 0, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], - [1, 1, 0, 0], - [1, 1, 0, 0] + [0, 0, 1, 1], + [0, 0, 1, 1] ], exits: [ - { x: 2, y: 0, direction: DIRECTIONS.SOUTH }, { x: 3, y: 0, direction: DIRECTIONS.SOUTH }, + // Stem points Left (West) + { x: 0, y: 2, direction: DIRECTIONS.WEST }, { x: 0, y: 3, direction: DIRECTIONS.WEST }, + // Bar Top/Bottom { x: 2, y: 5, direction: DIRECTIONS.NORTH }, { x: 3, y: 5, direction: DIRECTIONS.NORTH }, - { x: 0, y: 2, direction: DIRECTIONS.WEST }, { x: 0, y: 3, direction: DIRECTIONS.WEST } + { x: 2, y: 0, direction: DIRECTIONS.SOUTH }, { x: 3, y: 0, direction: DIRECTIONS.SOUTH } ] }, [DIRECTIONS.SOUTH]: { + // Rotated 180: Bar is Bottom + // 001100 + // 001100 + // 111111 + // 111111 width: 6, height: 4, layout: [ [0, 0, 1, 1, 0, 0], @@ -208,17 +248,26 @@ export const TILES = { ] }, [DIRECTIONS.WEST]: { + // Rotated 270: Bar is Left (West) + // 1100 + // 1100 + // 1111 + // 1111 + // 1100 + // 1100 width: 4, height: 6, layout: [ - [0, 0, 1, 1], - [0, 0, 1, 1], + [1, 1, 0, 0], + [1, 1, 0, 0], [1, 1, 1, 1], [1, 1, 1, 1], - [0, 0, 1, 1], - [0, 0, 1, 1] + [1, 1, 0, 0], + [1, 1, 0, 0] ], exits: [ + // Stem points Right (East) { x: 3, y: 2, direction: DIRECTIONS.EAST }, { x: 3, y: 3, direction: DIRECTIONS.EAST }, + // Bar Top/Bottom { x: 0, y: 5, direction: DIRECTIONS.NORTH }, { x: 1, y: 5, direction: DIRECTIONS.NORTH }, { x: 0, y: 0, direction: DIRECTIONS.SOUTH }, { x: 1, y: 0, direction: DIRECTIONS.SOUTH } ] diff --git a/src/engine/dungeon/old/DungeonGenerator.js b/src/engine/dungeon/old/DungeonGenerator.js deleted file mode 100644 index b151796..0000000 --- a/src/engine/dungeon/old/DungeonGenerator.js +++ /dev/null @@ -1,181 +0,0 @@ -import { DIRECTIONS } from './Constants.js'; -import { GridSystem } from './GridSystem.js'; -import { DungeonDeck } from './DungeonDeck.js'; - -export class DungeonGenerator { - constructor() { - this.grid = new GridSystem(); - this.deck = new DungeonDeck(); - this.pendingExits = []; - this.placedTiles = []; - this.isComplete = false; - } - - startDungeon(missionConfig) { - const objectiveId = missionConfig?.type === 'quest' ? 'room_objective' : 'room_dungeon'; - this.deck.generateMissionDeck(objectiveId); - - const firstCard = this.deck.draw(); - if (!firstCard) { - console.error("❌ Deck empty!"); - return; - } - - // Place first tile with NORTH variant - this.placeTileAt(firstCard, 0, 0, DIRECTIONS.NORTH); - console.log(`🏰 Dungeon started with ${firstCard.name}`); - } - - step() { - if (this.isComplete || this.pendingExits.length === 0) { - this.isComplete = true; - return false; - } - - const card = this.deck.draw(); - if (!card) { - this.isComplete = true; - return false; - } - - const targetExit = this.pendingExits.shift(); - const placed = this.tryPlaceCard(card, targetExit); - - if (!placed) { - this.pendingExits.push(targetExit); - console.warn(`⚠️ Failed to place ${card.name} - returning exit to pending queue`); - } - - return true; - } - - tryPlaceCard(card, targetExit) { - console.log(`\nπŸƒ Trying to place card: ${card.name} (ID: ${card.id})`); - - // Use standard opposite logic for Directions (String) since names don't change - const requiredDirection = this.opposite(targetExit.direction); - const targetCell = this.neighbor(targetExit.x, targetExit.y, targetExit.direction); - - const rotations = [DIRECTIONS.NORTH, DIRECTIONS.EAST, DIRECTIONS.SOUTH, DIRECTIONS.WEST]; - const shuffled = this.shuffle(rotations); - - let bestPlacement = null; - let maxConnections = -1; - - // Try ALL rotations - for (const rotation of shuffled) { - // 1. Get the pre-calculated VARIANT for this rotation - const variant = card.variants[rotation]; - if (!variant) continue; - - const variantExits = variant.exits; - - // 2. Find candidate exits on this variant that face the required direction - // Note: variant.exits are ALREADY correctly oriented for this rotation - const candidates = variantExits.filter(e => e.direction === requiredDirection); - - for (const candidate of candidates) { - // Determine absolute anchor position - // Since variant coords are all positive relative to (0,0), anchor calculation is simple subtraction - const anchorX = targetCell.x - candidate.x; - const anchorY = targetCell.y - candidate.y; - - if (this.grid.canPlace(card, anchorX, anchorY, rotation)) { - // Start Score at 0 - let score = 0; - - // Calculate score - for (const exit of variantExits) { - const globalX = anchorX + exit.x; - const globalY = anchorY + exit.y; - - const neighbor = this.neighbor(globalX, globalY, exit.direction); - const neighborKey = `${neighbor.x},${neighbor.y}`; - - if (this.grid.occupiedCells.has(neighborKey)) { - score++; - } - } - - // Prefer higher score. - if (score > maxConnections) { - maxConnections = score; - bestPlacement = { card, anchorX, anchorY, rotation }; - } - } - } - } - - if (bestPlacement) { - this.placeTileAt(bestPlacement.card, bestPlacement.anchorX, bestPlacement.anchorY, bestPlacement.rotation); - console.log(`βœ… Placed ${card.name} at (${bestPlacement.anchorX}, ${bestPlacement.anchorY}) Rot:${bestPlacement.rotation} Score:${maxConnections}`); - return true; - } - - console.log(`❌ Could not place ${card.name} in any rotation`); - return false; - } - - placeTileAt(tileDef, x, y, rotation) { - const instance = { - id: `tile_${this.placedTiles.length}`, - defId: tileDef.id, - x, y, rotation - }; - - this.grid.placeTile(instance, tileDef); // Grid system now handles looking up the variant - this.placedTiles.push(instance); - - // Add exits from the variant - const variant = tileDef.variants[rotation]; - - for (const exit of variant.exits) { - const globalX = x + exit.x; - const globalY = y + exit.y; - const neighborCell = this.neighbor(globalX, globalY, exit.direction); - const key = `${neighborCell.x},${neighborCell.y}`; - - // Only add exit if it leads to empty space - if (!this.grid.occupiedCells.has(key)) { - this.pendingExits.push({ - x: globalX, - y: globalY, - direction: exit.direction - }); - } - } - - // Cleanup pending exits that are now connected - this.pendingExits = this.pendingExits.filter(ex => { - const n = this.neighbor(ex.x, ex.y, ex.direction); - return !this.grid.occupiedCells.has(`${n.x},${n.y}`); - }); - } - - neighbor(x, y, direction) { - switch (direction) { - case DIRECTIONS.NORTH: return { x, y: y + 1 }; - case DIRECTIONS.SOUTH: return { x, y: y - 1 }; - case DIRECTIONS.EAST: return { x: x + 1, y }; - case DIRECTIONS.WEST: return { x: x - 1, y }; - } - } - - opposite(direction) { - switch (direction) { - case DIRECTIONS.NORTH: return DIRECTIONS.SOUTH; - case DIRECTIONS.SOUTH: return DIRECTIONS.NORTH; - case DIRECTIONS.EAST: return DIRECTIONS.WEST; - case DIRECTIONS.WEST: return DIRECTIONS.EAST; - } - } - - shuffle(arr) { - const copy = [...arr]; - for (let i = copy.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - [copy[i], copy[j]] = [copy[j], copy[i]]; - } - return copy; - } -} diff --git a/src/engine/dungeon/old/GridSystem.js b/src/engine/dungeon/old/GridSystem.js deleted file mode 100644 index 780f78f..0000000 --- a/src/engine/dungeon/old/GridSystem.js +++ /dev/null @@ -1,134 +0,0 @@ -import { DIRECTIONS } from './Constants.js'; - -export class GridSystem { - /** - * The GridSystem maintains the "Source of Truth" for the dungeon layout. - * It knows which cells are occupied and by whom. - * Dependencies: Constants.js (DIRECTIONS) - */ - constructor() { - // We use a Map for O(1) lookups. - // Key: "x,y" (String) -> Value: "tileId" (String) - this.occupiedCells = new Map(); - - // We also keep a list of placed tile objects for easier iteration if needed later. - this.tiles = []; - } - - /** - * Checks if a tile can be placed at the given coordinates with the given rotation. - * Needs: The Tile Definition (to know size), the target X,Y, and desired Rotation. - */ - canPlace(tileDef, startX, startY, rotation) { - // 1. Calculate the real-world coordinates of every single cell this tile would occupy. - const cells = this.getGlobalCells(tileDef, startX, startY, rotation); - - // 2. Check each cell against our Map of occupied spots. - for (const cell of cells) { - const key = `${cell.x},${cell.y}`; - if (this.occupiedCells.has(key)) { - return false; // COLLISION! Spot already taken. - } - } - return true; // All clear. - } - - /** - * Officially registers a tile onto the board. - * Should only be called AFTER canPlace returns true. - */ - placeTile(tileInstance, tileDef) { - const cells = this.getGlobalCells(tileDef, tileInstance.x, tileInstance.y, tileInstance.rotation); - - // Record every cell in our Map - for (const cell of cells) { - const key = `${cell.x},${cell.y}`; - this.occupiedCells.set(key, tileInstance.id); - } - - // Store the instance - this.tiles.push(tileInstance); - console.log(`Placed tile ${tileInstance.id} at ${tileInstance.x},${tileInstance.y}`); - } - - /** - * THE CORRECTED MAGIC MATH FUNCTION. - * Now uses Pre-Calculated Variants from TileDefinitions. - * NO DYNAMIC ROTATION MATH performed here. - * All variants are treated as "North" oriented blocks. - */ - getGlobalCells(tileDef, startX, startY, rotation) { - const cells = []; - - // 1. Retrieve the specific variant for this rotation - const variant = tileDef.variants[rotation]; - if (!variant) { - console.error(`Missing variant for rotation ${rotation} in tile ${tileDef.id}`); - return cells; - } - - const layout = variant.layout; - - if (!layout) { - console.error("Variant missing layout. ID:", tileDef?.id, rotation); - return cells; - } - - const numberOfRows = layout.length; - - // Iterate through matrix rows - for (let row = 0; row < numberOfRows; row++) { - const rowData = layout[row]; - const numberOfCols = rowData.length; - - for (let col = 0; col < numberOfCols; col++) { - const cellValue = rowData[col]; - - // Skip empty cells (0) - if (cellValue === 0) continue; - - // Map Matrix (Row, Col) to Local Grid (lx, ly) - // Matrix Row 0 is the "Top" (Max Y) relative to the tile's origin - // Matrix Row (Rows-1) is the "Bottom" (Y=0) - // lx grows right (col) - // ly grows up (rows reversed) - const lx = col; - const ly = (numberOfRows - 1) - row; - - // SIMPLIFIED LOGIC: - // Since the variant layout is ALREADY rotated, we always just ADD the offsets. - // We treat every variant as if it's placed "North-wise" at the anchor point. - - const gx = startX + lx; - const gy = startY + ly; - - cells.push({ x: gx, y: gy, value: cellValue }); - } - } - return cells; - } - - /** - * Transforms a local point (like an exit definition) to Global Coordinates. - * Simplified: Just adds offsets because variants carry pre-rotated coords. - */ - getGlobalPoint(localX, localY, tileInstance) { - const startX = tileInstance.x; - const startY = tileInstance.y; - - // Simple translation. Rotation is handled by the variant properties upstream. - return { - x: startX + localX, - y: startY + localY - }; - } - - /** - * DEPRECATED / LEGACY - * Kept just in case, but shouldn't be needed with explicit variants. - */ - getRotatedDirection(originalDirection, tileRotation) { - // With explicit variants, the exit.direction is ALREADY the final global direction. - return originalDirection; - } -} diff --git a/src/engine/game/GameEngine.js b/src/engine/game/GameEngine.js index 2605e87..962e106 100644 --- a/src/engine/game/GameEngine.js +++ b/src/engine/game/GameEngine.js @@ -18,7 +18,7 @@ export class GameEngine { } startMission(missionConfig) { - console.log('[GameEngine] Starting mission:', missionConfig.name); + this.dungeon.startDungeon(missionConfig); // Create player at center of first tile @@ -40,7 +40,7 @@ export class GameEngine { this.onEntityUpdate(this.player); } - console.log('[GameEngine] Player created at', this.player.x, this.player.y); + } onCellClick(x, y) { @@ -50,7 +50,7 @@ export class GameEngine { if (this.onEntitySelect) { this.onEntitySelect(this.player.id, true); } - console.log('[GameEngine] Player selected'); + return; } @@ -59,7 +59,7 @@ export class GameEngine { if (this.canMoveTo(x, y)) { this.movePlayer(x, y); } else { - console.log('[GameEngine] Cannot move there'); + } } } @@ -86,7 +86,7 @@ export class GameEngine { this.onEntitySelect(this.player.id, false); } - console.log('[GameEngine] Player moved to', x, y); + } isPlayerAdjacentToDoor(doorExit) { diff --git a/src/engine/game/old/GameEngine_20260102.js b/src/engine/game/old/GameEngine_20260102.js deleted file mode 100644 index 3c25e28..0000000 --- a/src/engine/game/old/GameEngine_20260102.js +++ /dev/null @@ -1,196 +0,0 @@ - -import { DungeonGenerator } from '../dungeon/DungeonGenerator.js'; -import { TurnManager } from './TurnManager.js'; -import { GAME_PHASES } from './GameConstants.js'; -import { Entity } from './Entity.js'; - -export class GameEngine { - constructor() { - this.dungeon = new DungeonGenerator(); - this.turnManager = new TurnManager(); - this.missionConfig = null; - - this.player = null; - - this.selectedPath = []; - this.selectedEntityId = null; - - // Simple event callbacks (external systems can assign these) - this.onPathChange = null; // (path) => {} - this.onEntityUpdate = null; // (entity) => {} - this.onEntityMove = null; // (entity, path) => {} - this.onEntitySelect = null; // (entityId, isSelected) => {} - - this.setupEventHooks(); - } - - setupEventHooks() { - this.turnManager.on('phase_changed', (phase) => this.handlePhaseChange(phase)); - } - - startMission(missionConfig) { - this.missionConfig = missionConfig; - console.log(`[GameEngine] Starting mission: ${missionConfig.name}`); - - // 1. Initialize Dungeon (Places the first room) - this.dungeon.startDungeon(missionConfig); - - // 2. Initialize Player - // Find a valid starting spot (first occupied cell) - const startingSpot = this.dungeon.grid.occupiedCells.keys().next().value; - const [startX, startY] = startingSpot ? startingSpot.split(',').map(Number) : [0, 0]; - - console.log(`[GameEngine] Spawning player at valid spot: ${startX}, ${startY}`); - this.player = new Entity('p1', 'Barbaro', 'hero', startX, startY, '/assets/images/dungeon1/standees/barbaro.png'); - if (this.onEntityUpdate) this.onEntityUpdate(this.player); - - // 3. Start the Turn Sequence - this.turnManager.startGame(); - } - - update(deltaTime) { - // Continuous logic - } - - handlePhaseChange(phase) { - console.log(`[GameEngine] Phase Changed to: ${phase}`); - } - - // --- Interaction --- - onCellClick(x, y) { - if (this.turnManager.currentPhase !== GAME_PHASES.HERO) return; - - console.log(`Cell Click: ${x},${y}`); - - // 1. Selector Check (Click on Player?) - if (this.player.x === x && this.player.y === y) { - if (this.selectedEntityId === this.player.id) { - // Deselect - this.selectedEntityId = null; - console.log("Player Deselected"); - if (this.onEntitySelect) this.onEntitySelect(this.player.id, false); - - // Clear path too - this.selectedPath = []; - this._notifyPath(); - } else { - // Select - this.selectedEntityId = this.player.id; - console.log("Player Selected"); - if (this.onEntitySelect) this.onEntitySelect(this.player.id, true); - } - return; - } - - // If nothing selected, ignore floor clicks - if (!this.selectedEntityId) return; - - // 2. Check if valid Floor (Occupied Cell) - if (!this.dungeon.grid.occupiedCells.has(`${x},${y}`)) { - console.log("Invalid cell: Void"); - return; - } - - // 3. Logic: Path Building (Only if Selected) - - // A. If clicking on last selected -> Deselect (Remove last step) - if (this.selectedPath.length > 0) { - const last = this.selectedPath[this.selectedPath.length - 1]; - if (last.x === x && last.y === y) { - this.selectedPath.pop(); - this._notifyPath(); - return; - } - } - - // B. Determine Previous Point (Player or Last Path Node) - let prevX = this.player.x; - let prevY = this.player.y; - - if (this.selectedPath.length > 0) { - const last = this.selectedPath[this.selectedPath.length - 1]; - prevX = last.x; - prevY = last.y; - } - - // Note: Manhattan distance 1 = Adjacency (No diagonals) - const dist = Math.abs(x - prevX) + Math.abs(y - prevY); - - if (dist === 1) { - // Check Path Length Limit (Speed) - if (this.selectedPath.length < this.player.stats.move) { - this.selectedPath.push({ x, y }); - this._notifyPath(); - } else { - console.log("Max movement reached"); - } - } else { - // Restart path if clicking adjacent to player - const distFromPlayer = Math.abs(x - this.player.x) + Math.abs(y - this.player.y); - if (distFromPlayer === 1) { - this.selectedPath = [{ x, y }]; - this._notifyPath(); - } - } - } - - onCellRightClick(x, y) { - if (this.turnManager.currentPhase !== GAME_PHASES.HERO) return; - if (!this.selectedEntityId) return; // Must satisfy selection rule - - // Must be clicking the last tile of the path to confirm - if (this.selectedPath.length === 0) return; - - const last = this.selectedPath[this.selectedPath.length - 1]; - if (last.x === x && last.y === y) { - console.log("Confirming Move..."); - this.confirmMove(); - } - } - - confirmMove() { - if (this.selectedPath.length === 0) return; - - const target = this.selectedPath[this.selectedPath.length - 1]; - const pathCopy = [...this.selectedPath]; - - // 1. Trigger Animation Sequence - if (this.onEntityMove) this.onEntityMove(this.player, pathCopy); - - // 2. Update Logical Position - this.player.setPosition(target.x, target.y); - - // 3. Cleanup - this.selectedPath = []; - this._notifyPath(); - - // Note: Exploration is now manual via door interaction - } - - _notifyPath() { - if (this.onPathChange) this.onPathChange(this.selectedPath); - } - - exploreExit(exitCell) { - console.log('[GameEngine] Exploring exit:', exitCell); - - // Find this exit in pendingExits - const exit = this.dungeon.pendingExits.find(ex => ex.x === exitCell.x && ex.y === exitCell.y); - - if (exit) { - // Prioritize this exit - const idx = this.dungeon.pendingExits.indexOf(exit); - if (idx > -1) { - this.dungeon.pendingExits.splice(idx, 1); - this.dungeon.pendingExits.unshift(exit); - } - - // Trigger exploration - this.turnManager.triggerExploration(); - this.dungeon.step(); - this.turnManager.setPhase(GAME_PHASES.HERO); - } else { - console.warn('[GameEngine] Exit not found in pendingExits'); - } - } -} diff --git a/src/main.js b/src/main.js index bb246a0..14e4291 100644 --- a/src/main.js +++ b/src/main.js @@ -4,7 +4,7 @@ import { CameraManager } from './view/CameraManager.js'; import { UIManager } from './view/UIManager.js'; import { MissionConfig, MISSION_TYPES } from './engine/dungeon/MissionConfig.js'; -console.log("πŸ—οΈ Warhammer Quest - Manual Dungeon Construction"); + // 1. Setup Mission const mission = new MissionConfig({ @@ -65,7 +65,7 @@ renderer.onHeroFinishedMove = (x, y) => { // 5. Connect Generator State to UI generator.onStateChange = (state) => { - console.log(`[Main] State: ${state}`); + if (state === 'PLACING_TILE') { ui.showPlacementControls(true); @@ -87,7 +87,7 @@ generator.onPlacementUpdate = (preview) => { const handleClick = (x, y, doorMesh) => { // PRIORITY 1: Tile Placement Mode - ignore all clicks if (generator.state === 'PLACING_TILE') { - console.log('[Main] Use placement controls to place tile'); + return; } @@ -96,7 +96,7 @@ const handleClick = (x, y, doorMesh) => { const doorExit = doorMesh.userData.cells[0]; if (game.isPlayerAdjacentToDoor(doorExit)) { - console.log('[Main] πŸšͺ Opening door and drawing tile...'); + // Open door visually renderer.openDoor(doorMesh); @@ -109,7 +109,7 @@ const handleClick = (x, y, doorMesh) => { console.error('[Main] Door missing exitData'); } } else { - console.log('[Main] ⚠️ Move adjacent to the door first'); + } return; } @@ -127,7 +127,7 @@ renderer.setupInteraction( ); // 7. Start -console.log("--- Starting Game ---"); + game.startMission(mission); // 8. Render Loop @@ -140,4 +140,4 @@ const animate = (time) => { }; animate(0); -console.log("βœ… Ready - Move barbarian next to a door and click it"); + diff --git a/src/old/main_20260102.js b/src/old/main_20260102.js deleted file mode 100644 index a9fc59d..0000000 --- a/src/old/main_20260102.js +++ /dev/null @@ -1,172 +0,0 @@ - -import { GameEngine } from './engine/game/GameEngine.js'; -import { GameRenderer } from './view/GameRenderer.js'; -import { CameraManager } from './view/CameraManager.js'; -import { UIManager } from './view/UIManager.js'; -import { DoorModal } from './view/DoorModal.js'; -import { MissionConfig, MISSION_TYPES } from './engine/dungeon/MissionConfig.js'; - -console.log("Initializing Warhammer Quest Engine... SYSTEM: MANUAL_PLACEMENT_V2"); -window.TEXTURE_DEBUG = true; - -// 1. Setup Mission -const mission = new MissionConfig({ - id: 'mission_1', - name: 'The First Dive', - type: MISSION_TYPES.ESCAPE, - minTiles: 6 -}); - -// 2. Initialize Core Systems -const renderer = new GameRenderer('app'); -const cameraManager = new CameraManager(renderer); -const game = new GameEngine(); - -// 3. Initialize UI -const ui = new UIManager(cameraManager, game); -const doorModal = new DoorModal(); - -// Global Access for Debugging -window.GAME = game; -window.RENDERER = renderer; - -// 4. Bridge Logic & View -const generator = game.dungeon; -const originalPlaceTile = generator.grid.placeTile.bind(generator.grid); - -// Override placeTile to trigger rendering -generator.grid.placeTile = (instance, variant, def) => { - originalPlaceTile(instance, variant); - - const cells = generator.grid.calculateCells(variant, instance.x, instance.y); - renderer.addTile(cells, def.type, def, instance); - - // Update exits visualization - setTimeout(() => { - renderer.renderExits(generator.availableExits); - }, 50); -}; - -// 5. Connect Generator State Changes to UI -generator.onStateChange = (state) => { - console.log(`[Main] Generator state: ${state}`); - - if (state === 'PLACING_TILE') { - ui.showPlacementControls(true); - } else { - ui.showPlacementControls(false); - } - - if (state === 'WAITING_DOOR') { - // Enable door selection mode - renderer.enableDoorSelection(true); - } else { - renderer.enableDoorSelection(false); - } -}; - -// 6. Connect Placement Updates to Renderer -generator.onPlacementUpdate = (preview) => { - if (preview) { - renderer.showPlacementPreview(preview); - ui.updatePlacementStatus(preview.isValid); - } else { - renderer.hidePlacementPreview(); - } -}; - -// 7. Handle Door Selection -renderer.onDoorSelected = (exitPoint) => { - console.log('[Main] Door selected:', exitPoint); - generator.selectDoor(exitPoint); -}; - -// 8. Bridge Game Interactions (Player movement, etc.) -game.onEntityUpdate = (entity) => { - renderer.addEntity(entity); - renderer.updateEntityPosition(entity); - - if (entity.id === 'p1' && !entity._centered) { - cameraManager.centerOn(entity.x, entity.y); - entity._centered = true; - } -}; - -game.onEntityMove = (entity, path) => { - renderer.moveEntityAlongPath(entity, path); -}; - -game.onEntitySelect = (entityId, isSelected) => { - renderer.toggleEntitySelection(entityId, isSelected); -}; - -renderer.onHeroFinishedMove = (x, y) => { - cameraManager.centerOn(x, y); -}; - -game.onPathChange = (path) => { - renderer.highlightCells(path); -}; - -// 9. Custom click handler -const handleCellClick = async (x, y, doorMesh) => { - // PRIORITY 1: Check if we're in door selection mode (dungeon building) - if (generator.state === 'WAITING_DOOR') { - if (doorMesh && doorMesh.userData.isExit) { - // This is an exit door that can be selected for expansion - const exitData = doorMesh.userData.exitData; - if (exitData) { - console.log('[Main] Door selected for expansion:', exitData); - generator.selectDoor(exitData); - } - return; // Don't process any other click logic - } - // If not clicking on a door in WAITING_DOOR mode, ignore the click - console.log('[Main] Click ignored - waiting for door selection'); - return; - } - - // PRIORITY 2: Normal door interaction (during gameplay with player) - if (doorMesh && doorMesh.userData.isDoor && !doorMesh.userData.isOpen) { - const player = game.player; - if (!player) { - console.log('[Main] Player not found'); - return; - } - - if (renderer.isPlayerAdjacentToDoor(player.x, player.y, doorMesh)) { - const confirmed = await doorModal.show('ΒΏQuieres abrir la puerta?'); - - if (confirmed) { - renderer.openDoor(doorMesh); - const exitCell = doorMesh.userData.cells[0]; - console.log('[Main] Opening door at exit:', exitCell); - game.exploreExit(exitCell); - } - } else { - console.log('[Main] Player is not adjacent to the door. Move closer first.'); - } - } else if (x !== null && y !== null) { - game.onCellClick(x, y); - } -}; - -renderer.setupInteraction( - () => cameraManager.getCamera(), - handleCellClick, - (x, y) => game.onCellRightClick(x, y) -); - -console.log("--- Starting Game Session ---"); -game.startMission(mission); - -// 10. Render Loop -const animate = (time) => { - requestAnimationFrame(animate); - - game.update(time); - cameraManager.update(time); - renderer.updateAnimations(time); - renderer.render(cameraManager.getCamera()); -}; -animate(0); diff --git a/src/view/GameRenderer.js b/src/view/GameRenderer.js index fc4b088..f165c70 100644 --- a/src/view/GameRenderer.js +++ b/src/view/GameRenderer.js @@ -158,7 +158,7 @@ export class GameRenderer { addEntity(entity) { if (this.entities.has(entity.id)) return; - console.log(`[GameRenderer] Adding entity ${entity.name}`); + // Standee: Larger Size (+30%) // Old: 0.8 x 1.2 -> New: 1.04 x 1.56 const w = 1.04; @@ -296,11 +296,11 @@ export class GameRenderer { const newExits = exits.filter(ex => !existingDoorCells.has(`${ex.x},${ex.y}`)); if (newExits.length === 0) { - console.log('[renderExits] No new doors to render'); + return; } - console.log(`[renderExits] Rendering ${newExits.length} new door cells`); + // Set flag for this render this._pendingExitRender = true; @@ -446,11 +446,11 @@ export class GameRenderer { getTexture(path, onLoad) { if (!this.textureCache.has(path)) { - console.log(`[TextureLoader] Starting load for: ${path}`); + const tex = this.textureLoader.load( path, (texture) => { - console.log(`[TextureLoader] βœ“ Successfully loaded: ${path}`); + texture.needsUpdate = true; if (onLoad) onLoad(texture); }, @@ -478,7 +478,7 @@ export class GameRenderer { // tileDef: The definition object (has textures, dimensions) // tileInstance: The instance object (has x, y, rotation, id) - console.log(`[GameRenderer] Rendering Tile [${type}] ID: ${tileDef?.id} at (${tileInstance?.x}, ${tileInstance?.y}) Rot: ${tileInstance?.rotation}`); + // Draw Texture Plane (The Image) - WAIT FOR TEXTURE TO LOAD if (tileDef && tileInstance && tileDef.textures && tileDef.textures.length > 0) { @@ -508,8 +508,7 @@ export class GameRenderer { const cx = tileInstance.x + (rotWidth - 1) / 2; const cy = tileInstance.y + (rotHeight - 1) / 2; - console.log(`[GameRenderer] Dimensions (Rotated): ${rotWidth}x${rotHeight}`); - console.log(`[GameRenderer] Calculated Center: (${cx}, ${cy})`); + // 3. Use BASE dimensions from NORTH variant for the Plane // (Since we are rotating the plane itself, we start with the un-rotated image size) @@ -549,7 +548,7 @@ export class GameRenderer { plane.receiveShadow = true; this.scene.add(plane); - console.log(`[GameRenderer] βœ“ Tile plane added at (${cx}, 0.01, ${-cy})`); + }); } else { console.warn(`[GameRenderer] details missing for texture render. def: ${!!tileDef}, inst: ${!!tileInstance}`); @@ -565,7 +564,7 @@ export class GameRenderer { doorMesh.material.map = texture; doorMesh.material.needsUpdate = true; doorMesh.userData.isOpen = true; - console.log('[GameRenderer] Door opened'); + }); } @@ -721,7 +720,7 @@ export class GameRenderer { const r = rotMap[rotation] !== undefined ? rotMap[rotation] : 0; floatingTile.rotation.z = -r * (Math.PI / 2); - console.log(`[Preview] Rotation: ${rotation}, Center: (${cx}, ${cy})`); + floatingTile.position.set(cx, 3, -cy); this.previewGroup.add(floatingTile);