Compare commits
3 Commits
refine_doo
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 6fe693c2fc | |||
| c8cc35772f | |||
| 83dc2b0234 |
41
DEVLOG.md
@@ -2,6 +2,47 @@
|
||||
|
||||
Este documento sirve para llevar un control diario del desarrollo, decisiones técnicas y nuevas funcionalidades implementadas en el proyecto.
|
||||
|
||||
## [2025-12-29] - Sistema Avanzado de Mapeo de Tiles
|
||||
|
||||
### Funcionalidades Implementadas
|
||||
- **TileDefinitions.js:** Nuevo módulo centralizado con definiciones de todas las tiles (rooms, corridors, L-shapes, T-junctions).
|
||||
- Cada tile incluye: dimensiones, tipo, imagen, matriz de walkability, y exits.
|
||||
- Matriz de walkability: 0 = no pisable, 1-8 = pisable con capa/altura, 9 = escaleras.
|
||||
|
||||
- **Sistema de Deck Abstracto:**
|
||||
- El deck ahora contiene tipos abstractos (e.g., 'L', 'corridor') en lugar de tiles específicas.
|
||||
- Composición: 8 rooms 4x4, 4 rooms 4x6, 12 corridors, 10 L-shapes, 8 T-junctions.
|
||||
- Cuando se dibuja un tipo, el sistema selecciona aleatoriamente entre las variantes que encajan.
|
||||
|
||||
- **Validación de Conexiones:**
|
||||
- `canConnectTiles()`: Verifica compatibilidad de tipos, dirección de salidas, y alineación de walkability.
|
||||
- Reglas de conexión: Rooms ↔ Rooms/Corridors, Corridors ↔ Rooms/Corridors/L/T, L/T ↔ Corridors.
|
||||
- Validación de dirección: Si sales por N, la nueva tile debe tener salida S.
|
||||
|
||||
- **Alineación de Walkability:**
|
||||
- `validateWalkabilityAlignment()`: Maneja tiles de diferentes tamaños (corridor 2x6 vs room 4x4).
|
||||
- Prueba offset 0 primero, luego offset 2 (ancho del corridor) si es necesario.
|
||||
- Sistema de offset para desplazar L-shapes y T-junctions y alinear áreas pisables.
|
||||
|
||||
- **Filtrado de Orientación:**
|
||||
- Corridors se filtran por orientación: puertas E/W requieren corridors EW, puertas N/S requieren corridors NS.
|
||||
- Selección exhaustiva: Cuando se dibuja una L o T, se prueban todas las variantes antes de descartar.
|
||||
|
||||
### Cambios Técnicos
|
||||
- Modificado `DungeonDecks.js` para usar sistema de deck abstracto.
|
||||
- Actualizado `exploreRoom()` en `main.js` para trabajar con tipos abstractos y seleccionar variantes concretas.
|
||||
- Nuevas funciones: `validateWalkabilityAlignment()`, `canConnectTiles()`, `getEdgeCells()`, `shouldPlaceDoor()`.
|
||||
- Actualizado `renderRoom()` para usar `room.tileDef` en lugar de `ASSETS.tiles`.
|
||||
|
||||
### Problemas Conocidos
|
||||
- **Offset de L/T:** La alineación de L-shapes y T-junctions todavía presenta desplazamientos incorrectos en algunos casos.
|
||||
- **Frecuencia de L/T:** Aunque se aumentó la cantidad en el deck, las L y T solo aparecen cuando se conectan desde corridors, limitando su frecuencia.
|
||||
|
||||
### Próximos Pasos
|
||||
- Depurar y corregir el cálculo del offset para L-shapes y T-junctions.
|
||||
- Revisar la lógica de aplicación del offset según la dirección de conexión (N/S vs E/W).
|
||||
- Considerar ajustar las reglas de conexión para permitir más variedad en la generación.
|
||||
|
||||
## [2025-12-28] - Fase 1: Arquitectura Híbrida y Servidor
|
||||
|
||||
### Infraestructura
|
||||
|
||||
BIN
assets/images/dungeons/L_NE.png
Normal file
|
After Width: | Height: | Size: 757 KiB |
BIN
assets/images/dungeons/L_SE.png
Normal file
|
After Width: | Height: | Size: 761 KiB |
BIN
assets/images/dungeons/L_WN.png
Normal file
|
After Width: | Height: | Size: 760 KiB |
BIN
assets/images/dungeons/L_WS.png
Normal file
|
After Width: | Height: | Size: 758 KiB |
BIN
assets/images/dungeons/T_NES.png
Normal file
|
After Width: | Height: | Size: 1017 KiB |
BIN
assets/images/dungeons/T_WNE.png
Normal file
|
After Width: | Height: | Size: 1013 KiB |
BIN
assets/images/dungeons/T_WNS.png
Normal file
|
After Width: | Height: | Size: 1015 KiB |
BIN
assets/images/dungeons/T_WSE.png
Normal file
|
After Width: | Height: | Size: 1012 KiB |
BIN
assets/images/dungeons/corridor1_EW.png
Normal file
|
After Width: | Height: | Size: 670 KiB |
BIN
assets/images/dungeons/corridor1_NS.png
Normal file
|
After Width: | Height: | Size: 667 KiB |
BIN
assets/images/dungeons/corridor2_EW.png
Normal file
|
After Width: | Height: | Size: 745 KiB |
BIN
assets/images/dungeons/corridor2_NS.png
Normal file
|
After Width: | Height: | Size: 741 KiB |
BIN
assets/images/dungeons/corridor3_EW.png
Normal file
|
After Width: | Height: | Size: 744 KiB |
BIN
assets/images/dungeons/corridor3_NS.png
Normal file
|
After Width: | Height: | Size: 739 KiB |
BIN
assets/images/dungeons/room_4x4_circle.png
Normal file
|
After Width: | Height: | Size: 905 KiB |
BIN
assets/images/dungeons/room_4x4_normal.png
Normal file
|
After Width: | Height: | Size: 907 KiB |
BIN
assets/images/dungeons/room_4x4_squeleton.png
Normal file
|
After Width: | Height: | Size: 968 KiB |
BIN
assets/images/dungeons/room_4x6_altar.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
assets/images/dungeons/room_4x6_tomb.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
141
src/dungeon/DungeonDecks.js
Normal file
@@ -0,0 +1,141 @@
|
||||
import { ROOMS, CORRIDORS, L_SHAPES, T_JUNCTIONS } from './TileDefinitions.js';
|
||||
|
||||
/**
|
||||
* DungeonDeck - Manages the deck of dungeon tiles
|
||||
*
|
||||
* New approach: Deck contains abstract tile types, not specific tiles
|
||||
* When a type is drawn, we select a fitting variant from available options
|
||||
*/
|
||||
|
||||
export class DungeonDeck {
|
||||
constructor() {
|
||||
this.deck = [];
|
||||
this.discardPile = [];
|
||||
this.shuffleDeck();
|
||||
}
|
||||
|
||||
shuffleDeck() {
|
||||
// Create a deck with abstract tile types
|
||||
this.deck = [
|
||||
// 8 rooms 4x4 (abstract)
|
||||
{ type: 'room_4x4' },
|
||||
{ type: 'room_4x4' },
|
||||
{ type: 'room_4x4' },
|
||||
{ type: 'room_4x4' },
|
||||
{ type: 'room_4x4' },
|
||||
{ type: 'room_4x4' },
|
||||
{ type: 'room_4x4' },
|
||||
{ type: 'room_4x4' },
|
||||
|
||||
// 4 rooms 4x6 (abstract)
|
||||
{ type: 'room_4x6' },
|
||||
{ type: 'room_4x6' },
|
||||
{ type: 'room_4x6' },
|
||||
{ type: 'room_4x6' },
|
||||
|
||||
// 12 corridors (abstract)
|
||||
{ type: 'corridor' },
|
||||
{ type: 'corridor' },
|
||||
{ type: 'corridor' },
|
||||
{ type: 'corridor' },
|
||||
{ type: 'corridor' },
|
||||
{ type: 'corridor' },
|
||||
{ type: 'corridor' },
|
||||
{ type: 'corridor' },
|
||||
{ type: 'corridor' },
|
||||
{ type: 'corridor' },
|
||||
{ type: 'corridor' },
|
||||
{ type: 'corridor' },
|
||||
|
||||
// 10 L-shapes (abstract) - increased from 6
|
||||
{ type: 'L' },
|
||||
{ type: 'L' },
|
||||
{ type: 'L' },
|
||||
{ type: 'L' },
|
||||
{ type: 'L' },
|
||||
{ type: 'L' },
|
||||
{ type: 'L' },
|
||||
{ type: 'L' },
|
||||
{ type: 'L' },
|
||||
{ type: 'L' },
|
||||
|
||||
// 8 T-junctions (abstract) - increased from 4
|
||||
{ type: 'T' },
|
||||
{ type: 'T' },
|
||||
{ type: 'T' },
|
||||
{ type: 'T' },
|
||||
{ type: 'T' },
|
||||
{ type: 'T' },
|
||||
{ type: 'T' },
|
||||
{ type: 'T' }
|
||||
];
|
||||
|
||||
// Fisher-Yates shuffle
|
||||
for (let i = this.deck.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[this.deck[i], this.deck[j]] = [this.deck[j], this.deck[i]];
|
||||
}
|
||||
console.log("Dungeon Deck Shuffled:", this.deck.length, "cards");
|
||||
}
|
||||
|
||||
drawCard() {
|
||||
if (this.deck.length === 0) {
|
||||
console.warn("Deck empty! Reshuffling discards...");
|
||||
if (this.discardPile.length === 0) {
|
||||
console.error("No cards left!");
|
||||
return null;
|
||||
}
|
||||
this.deck = [...this.discardPile];
|
||||
this.discardPile = [];
|
||||
this.shuffleDeck();
|
||||
}
|
||||
|
||||
const card = this.deck.pop();
|
||||
this.discardPile.push(card);
|
||||
return card;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a compatible abstract tile type
|
||||
* @param {string} originTileType - Type of the origin tile ('room', 'corridor', 'L', 'T')
|
||||
* @param {number} maxAttempts - Maximum number of cards to try
|
||||
* @returns {object|null} - Abstract tile card or null if none found
|
||||
*/
|
||||
drawCompatibleCard(originTileType, maxAttempts = 10) {
|
||||
const validTypes = this.getCompatibleTypes(originTileType);
|
||||
|
||||
for (let i = 0; i < maxAttempts && this.deck.length > 0; i++) {
|
||||
const card = this.drawCard();
|
||||
|
||||
// Check if this abstract type is compatible
|
||||
if (validTypes.includes(card.type)) {
|
||||
return card;
|
||||
}
|
||||
|
||||
// Put incompatible card back at the bottom of the deck
|
||||
this.deck.unshift(card);
|
||||
this.discardPile.pop();
|
||||
}
|
||||
|
||||
console.warn(`Could not find compatible tile for ${originTileType} after ${maxAttempts} attempts`);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get compatible tile types for a given origin type
|
||||
* @param {string} originType - Type of the origin tile
|
||||
* @returns {string[]} - Array of compatible abstract tile types
|
||||
*/
|
||||
getCompatibleTypes(originType) {
|
||||
const connectionRules = {
|
||||
'room': ['room_4x4', 'room_4x6', 'corridor'],
|
||||
'corridor': ['room_4x4', 'room_4x6', 'corridor', 'L', 'T'],
|
||||
'L': ['corridor'],
|
||||
'T': ['corridor']
|
||||
};
|
||||
|
||||
return connectionRules[originType] || [];
|
||||
}
|
||||
}
|
||||
|
||||
export const dungeonDeck = new DungeonDeck();
|
||||
41
src/dungeon/EventDeck.js
Normal file
@@ -0,0 +1,41 @@
|
||||
export const EVENTS = [
|
||||
{
|
||||
id: 'ev_nothing',
|
||||
title: 'Silencio',
|
||||
description: 'La mazmorra está en calma... sospechosamente tranquila.',
|
||||
type: 'NADA'
|
||||
},
|
||||
{
|
||||
id: 'ev_monster_1',
|
||||
title: '¡Emboscada!',
|
||||
description: '¡Monstruos surgen de las sombras!',
|
||||
type: 'MONSTRUO',
|
||||
count: 2
|
||||
},
|
||||
{
|
||||
id: 'ev_trap_1',
|
||||
title: 'Trampa de Pinchos',
|
||||
description: 'Un click resuena bajo tus pies. ¡Pinchos surgen del suelo!',
|
||||
type: 'TRAMPA',
|
||||
damage: 1
|
||||
},
|
||||
{
|
||||
id: 'ev_wind',
|
||||
title: 'Viento Helado',
|
||||
description: 'Una corriente de aire apaga vuestras antorchas.',
|
||||
type: 'PELIGRO'
|
||||
}
|
||||
];
|
||||
|
||||
export class EventDeck {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
drawCard() {
|
||||
// Simple random draw for now
|
||||
const randIndex = Math.floor(Math.random() * EVENTS.length);
|
||||
return EVENTS[randIndex];
|
||||
}
|
||||
}
|
||||
|
||||
export const eventDeck = new EventDeck();
|
||||
431
src/dungeon/TileDefinitions.js
Normal file
@@ -0,0 +1,431 @@
|
||||
/**
|
||||
* TileDefinitions.js
|
||||
*
|
||||
* Defines all dungeon tiles with their properties:
|
||||
* - Dimensions (width x height in cells)
|
||||
* - Walkability matrix (0 = not walkable, 1-8 = walkable layer/height, 9 = stairs)
|
||||
* - Tile type (room, corridor, L, T)
|
||||
* - Exit points
|
||||
* - Image path
|
||||
*/
|
||||
|
||||
// ============================================================================
|
||||
// ROOMS (4x4 and 4x6)
|
||||
// ============================================================================
|
||||
|
||||
const ROOM_4X4_NORMAL = {
|
||||
id: 'room_4x4_normal',
|
||||
tileType: 'room',
|
||||
width: 4,
|
||||
height: 4,
|
||||
image: '/assets/images/dungeons/room_4x4_normal.png',
|
||||
walkability: [
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1]
|
||||
],
|
||||
exits: ['N', 'S', 'E', 'W']
|
||||
};
|
||||
|
||||
const ROOM_4X4_CIRCLE = {
|
||||
id: 'room_4x4_circle',
|
||||
tileType: 'room',
|
||||
width: 4,
|
||||
height: 4,
|
||||
image: '/assets/images/dungeons/room_4x4_circle.png',
|
||||
walkability: [
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1]
|
||||
],
|
||||
exits: ['N', 'S', 'E', 'W']
|
||||
};
|
||||
|
||||
const ROOM_4X4_SKELETON = {
|
||||
id: 'room_4x4_skeleton',
|
||||
tileType: 'room',
|
||||
width: 4,
|
||||
height: 4,
|
||||
image: '/assets/images/dungeons/room_4x4_squeleton.png',
|
||||
walkability: [
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1]
|
||||
],
|
||||
exits: ['N', 'S', 'E', 'W']
|
||||
};
|
||||
|
||||
const ROOM_4X6_ALTAR = {
|
||||
id: 'room_4x6_altar',
|
||||
tileType: 'room',
|
||||
width: 4,
|
||||
height: 6,
|
||||
image: '/assets/images/dungeons/room_4x6_altar.png',
|
||||
walkability: [
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1]
|
||||
],
|
||||
exits: ['N', 'S', 'E', 'W']
|
||||
};
|
||||
|
||||
const ROOM_4X6_TOMB = {
|
||||
id: 'room_4x6_tomb',
|
||||
tileType: 'room',
|
||||
width: 4,
|
||||
height: 6,
|
||||
image: '/assets/images/dungeons/room_4x6_tomb.png',
|
||||
walkability: [
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1]
|
||||
],
|
||||
exits: ['N', 'S', 'E', 'W']
|
||||
};
|
||||
|
||||
// Example room with stairs (2 levels)
|
||||
const ROOM_4X6_STAIRS = {
|
||||
id: 'room_4x6_stairs',
|
||||
tileType: 'room',
|
||||
width: 4,
|
||||
height: 6,
|
||||
image: '/assets/images/dungeons/room_4x6_altar.png', // Using altar image as placeholder
|
||||
walkability: [
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 9, 9, 1], // Stairs connecting level 1 and 2
|
||||
[1, 2, 2, 1],
|
||||
[2, 2, 2, 2],
|
||||
[2, 2, 2, 2]
|
||||
],
|
||||
exits: ['N', 'S']
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// L-SHAPES (4x4 with 2-tile rows)
|
||||
// ============================================================================
|
||||
|
||||
const L_NE = {
|
||||
id: 'L_NE',
|
||||
tileType: 'L',
|
||||
width: 4,
|
||||
height: 4,
|
||||
image: '/assets/images/dungeons/L_NE.png',
|
||||
walkability: [
|
||||
[1, 1, 0, 0],
|
||||
[1, 1, 0, 0],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1]
|
||||
],
|
||||
exits: ['N', 'E']
|
||||
};
|
||||
|
||||
const L_SE = {
|
||||
id: 'L_SE',
|
||||
tileType: 'L',
|
||||
width: 4,
|
||||
height: 4,
|
||||
image: '/assets/images/dungeons/L_SE.png',
|
||||
walkability: [
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 0, 0],
|
||||
[1, 1, 0, 0]
|
||||
],
|
||||
exits: ['S', 'E']
|
||||
};
|
||||
|
||||
const L_WS = {
|
||||
id: 'L_WS',
|
||||
tileType: 'L',
|
||||
width: 4,
|
||||
height: 4,
|
||||
image: '/assets/images/dungeons/L_WS.png',
|
||||
walkability: [
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[0, 0, 1, 1],
|
||||
[0, 0, 1, 1]
|
||||
],
|
||||
exits: ['W', 'S']
|
||||
};
|
||||
|
||||
const L_WN = {
|
||||
id: 'L_WN',
|
||||
tileType: 'L',
|
||||
width: 4,
|
||||
height: 4,
|
||||
image: '/assets/images/dungeons/L_WN.png',
|
||||
walkability: [
|
||||
[0, 0, 1, 1],
|
||||
[0, 0, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1]
|
||||
],
|
||||
exits: ['W', 'N']
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// T-JUNCTIONS (4x6 or 6x4 with 2-tile rows)
|
||||
// ============================================================================
|
||||
|
||||
const T_NES = {
|
||||
id: 'T_NES',
|
||||
tileType: 'T',
|
||||
width: 4,
|
||||
height: 6,
|
||||
image: '/assets/images/dungeons/T_NES.png',
|
||||
walkability: [
|
||||
[1, 1, 0, 0],
|
||||
[1, 1, 0, 0],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 0, 0],
|
||||
[1, 1, 0, 0]
|
||||
],
|
||||
exits: ['N', 'E', 'S']
|
||||
};
|
||||
|
||||
const T_WNE = {
|
||||
id: 'T_WNE',
|
||||
tileType: 'T',
|
||||
width: 6,
|
||||
height: 4,
|
||||
image: '/assets/images/dungeons/T_WNE.png',
|
||||
walkability: [
|
||||
[0, 0, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 0, 0],
|
||||
[1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1]
|
||||
],
|
||||
exits: ['W', 'N', 'E']
|
||||
};
|
||||
|
||||
const T_WSE = {
|
||||
id: 'T_WSE',
|
||||
tileType: 'T',
|
||||
width: 6,
|
||||
height: 4,
|
||||
image: '/assets/images/dungeons/T_WSE.png',
|
||||
walkability: [
|
||||
[1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1],
|
||||
[0, 0, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 0, 0]
|
||||
],
|
||||
exits: ['W', 'S', 'E']
|
||||
};
|
||||
|
||||
const T_WNS = {
|
||||
id: 'T_WNS',
|
||||
tileType: 'T',
|
||||
width: 4,
|
||||
height: 6,
|
||||
image: '/assets/images/dungeons/T_WNS.png',
|
||||
walkability: [
|
||||
[0, 0, 1, 1],
|
||||
[0, 0, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[0, 0, 1, 1],
|
||||
[0, 0, 1, 1]
|
||||
],
|
||||
exits: ['W', 'N', 'S']
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// CORRIDORS (2x6 or 6x2 with 2-tile rows)
|
||||
// ============================================================================
|
||||
|
||||
// Corridor 1 - East-West (horizontal)
|
||||
const CORRIDOR1_EW = {
|
||||
id: 'corridor1_EW',
|
||||
tileType: 'corridor',
|
||||
width: 6,
|
||||
height: 2,
|
||||
image: '/assets/images/dungeons/corridor1_EW.png',
|
||||
walkability: [
|
||||
[1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1]
|
||||
],
|
||||
exits: ['E', 'W']
|
||||
};
|
||||
|
||||
// Corridor 1 - North-South (vertical)
|
||||
const CORRIDOR1_NS = {
|
||||
id: 'corridor1_NS',
|
||||
tileType: 'corridor',
|
||||
width: 2,
|
||||
height: 6,
|
||||
image: '/assets/images/dungeons/corridor1_NS.png',
|
||||
walkability: [
|
||||
[1, 1],
|
||||
[1, 1],
|
||||
[1, 1],
|
||||
[1, 1],
|
||||
[1, 1],
|
||||
[1, 1]
|
||||
],
|
||||
exits: ['N', 'S']
|
||||
};
|
||||
|
||||
// Corridor 2 - East-West (horizontal)
|
||||
const CORRIDOR2_EW = {
|
||||
id: 'corridor2_EW',
|
||||
tileType: 'corridor',
|
||||
width: 6,
|
||||
height: 2,
|
||||
image: '/assets/images/dungeons/corridor2_EW.png',
|
||||
walkability: [
|
||||
[1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1]
|
||||
],
|
||||
exits: ['E', 'W']
|
||||
};
|
||||
|
||||
// Corridor 2 - North-South (vertical)
|
||||
const CORRIDOR2_NS = {
|
||||
id: 'corridor2_NS',
|
||||
tileType: 'corridor',
|
||||
width: 2,
|
||||
height: 6,
|
||||
image: '/assets/images/dungeons/corridor2_NS.png',
|
||||
walkability: [
|
||||
[1, 1],
|
||||
[1, 1],
|
||||
[1, 1],
|
||||
[1, 1],
|
||||
[1, 1],
|
||||
[1, 1]
|
||||
],
|
||||
exits: ['N', 'S']
|
||||
};
|
||||
|
||||
// Corridor 3 - East-West (horizontal)
|
||||
const CORRIDOR3_EW = {
|
||||
id: 'corridor3_EW',
|
||||
tileType: 'corridor',
|
||||
width: 6,
|
||||
height: 2,
|
||||
image: '/assets/images/dungeons/corridor3_EW.png',
|
||||
walkability: [
|
||||
[1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1]
|
||||
],
|
||||
exits: ['E', 'W']
|
||||
};
|
||||
|
||||
// Corridor 3 - North-South (vertical)
|
||||
const CORRIDOR3_NS = {
|
||||
id: 'corridor3_NS',
|
||||
tileType: 'corridor',
|
||||
width: 2,
|
||||
height: 6,
|
||||
image: '/assets/images/dungeons/corridor3_NS.png',
|
||||
walkability: [
|
||||
[1, 1],
|
||||
[1, 1],
|
||||
[1, 1],
|
||||
[1, 1],
|
||||
[1, 1],
|
||||
[1, 1]
|
||||
],
|
||||
exits: ['N', 'S']
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// TILE COLLECTIONS
|
||||
// ============================================================================
|
||||
|
||||
export const TILE_DEFINITIONS = {
|
||||
// Rooms
|
||||
room_4x4_normal: ROOM_4X4_NORMAL,
|
||||
room_4x4_circle: ROOM_4X4_CIRCLE,
|
||||
room_4x4_skeleton: ROOM_4X4_SKELETON,
|
||||
room_4x6_altar: ROOM_4X6_ALTAR,
|
||||
room_4x6_tomb: ROOM_4X6_TOMB,
|
||||
room_4x6_stairs: ROOM_4X6_STAIRS,
|
||||
|
||||
// L-shapes
|
||||
L_NE: L_NE,
|
||||
L_SE: L_SE,
|
||||
L_WS: L_WS,
|
||||
L_WN: L_WN,
|
||||
|
||||
// T-junctions
|
||||
T_NES: T_NES,
|
||||
T_WNE: T_WNE,
|
||||
T_WSE: T_WSE,
|
||||
T_WNS: T_WNS,
|
||||
|
||||
// Corridors
|
||||
corridor1_EW: CORRIDOR1_EW,
|
||||
corridor1_NS: CORRIDOR1_NS,
|
||||
corridor2_EW: CORRIDOR2_EW,
|
||||
corridor2_NS: CORRIDOR2_NS,
|
||||
corridor3_EW: CORRIDOR3_EW,
|
||||
corridor3_NS: CORRIDOR3_NS
|
||||
};
|
||||
|
||||
// Collections by type for easy filtering
|
||||
export const ROOMS = [
|
||||
ROOM_4X4_NORMAL,
|
||||
ROOM_4X4_CIRCLE,
|
||||
ROOM_4X4_SKELETON,
|
||||
ROOM_4X6_ALTAR,
|
||||
ROOM_4X6_TOMB,
|
||||
ROOM_4X6_STAIRS
|
||||
];
|
||||
|
||||
export const L_SHAPES = [
|
||||
L_NE,
|
||||
L_SE,
|
||||
L_WS,
|
||||
L_WN
|
||||
];
|
||||
|
||||
export const T_JUNCTIONS = [
|
||||
T_NES,
|
||||
T_WNE,
|
||||
T_WSE,
|
||||
T_WNS
|
||||
];
|
||||
|
||||
export const CORRIDORS = [
|
||||
CORRIDOR1_EW,
|
||||
CORRIDOR1_NS,
|
||||
CORRIDOR2_EW,
|
||||
CORRIDOR2_NS,
|
||||
CORRIDOR3_EW,
|
||||
CORRIDOR3_NS
|
||||
];
|
||||
|
||||
// Helper function to get tile definition by ID
|
||||
export function getTileDefinition(tileId) {
|
||||
return TILE_DEFINITIONS[tileId] || null;
|
||||
}
|
||||
|
||||
// Helper function to get tiles by type
|
||||
export function getTilesByType(tileType) {
|
||||
switch (tileType) {
|
||||
case 'room':
|
||||
return ROOMS;
|
||||
case 'L':
|
||||
return L_SHAPES;
|
||||
case 'T':
|
||||
return T_JUNCTIONS;
|
||||
case 'corridor':
|
||||
return CORRIDORS;
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
913
src/main.js
68
src/systems/TurnManager.js
Normal file
@@ -0,0 +1,68 @@
|
||||
export const PHASES = {
|
||||
POWER: 'POWER', // Roll for events
|
||||
HERO: 'HERO', // Player actions
|
||||
EXPLORATION: 'EXPLORATION', // Room reveal
|
||||
MONSTER: 'MONSTER', // AI actions
|
||||
END: 'END' // Cleanup
|
||||
};
|
||||
|
||||
class TurnManager extends EventTarget {
|
||||
constructor() {
|
||||
super();
|
||||
this.currentTurn = 1;
|
||||
this.currentPhase = PHASES.POWER;
|
||||
this.isCombat = false;
|
||||
}
|
||||
|
||||
startTurn() {
|
||||
this.currentPhase = PHASES.POWER;
|
||||
this.dispatchEvent(new CustomEvent('phaseChange', { detail: this.currentPhase }));
|
||||
console.log(`--- TURN ${this.currentTurn} START ---`);
|
||||
|
||||
// Simulating Power Phase trigger
|
||||
this.processPowerPhase();
|
||||
}
|
||||
|
||||
processPowerPhase() {
|
||||
// Winds of Magic Roll (1d6)
|
||||
const roll = Math.floor(Math.random() * 6) + 1;
|
||||
console.log(`Winds of Magic Roll: ${roll}`);
|
||||
|
||||
let message = `Vientos de Magia: ${roll}`;
|
||||
this.dispatchEvent(new CustomEvent('message', { detail: message }));
|
||||
|
||||
if (roll === 1) {
|
||||
console.log("EVENTO INESPERADO!");
|
||||
this.dispatchEvent(new CustomEvent('eventTriggered', {
|
||||
detail: {
|
||||
source: 'POWER_PHASE',
|
||||
event: { title: 'Evento Inesperado', description: 'Algo se mueve en la oscuridad...', type: 'MISTERIO' }
|
||||
}
|
||||
}));
|
||||
// In a real game, we'd draw from a specific Event Deck here
|
||||
} else {
|
||||
console.log("¡Poder obtenido!");
|
||||
}
|
||||
|
||||
// Auto-advance to Hero Phase after a brief pause to show the roll
|
||||
setTimeout(() => this.setPhase(PHASES.HERO), 2000);
|
||||
}
|
||||
|
||||
setPhase(phase) {
|
||||
this.currentPhase = phase;
|
||||
this.dispatchEvent(new CustomEvent('phaseChange', { detail: this.currentPhase }));
|
||||
console.log(`Phase changed to: ${phase}`);
|
||||
|
||||
if (phase === PHASES.END) {
|
||||
this.endTurn();
|
||||
}
|
||||
}
|
||||
|
||||
endTurn() {
|
||||
console.log(`--- TURN ${this.currentTurn} END ---`);
|
||||
this.currentTurn++;
|
||||
this.startTurn();
|
||||
}
|
||||
}
|
||||
|
||||
export const turnManager = new TurnManager();
|
||||