diff --git a/CMakeLists.txt b/CMakeLists.txt index 70df771..b3dcc80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,6 +101,7 @@ set(APP_SOURCES source/game/map/tilemap.cpp source/game/map/tilemap_writer.cpp source/game/map/paint_layer.cpp + source/game/levels/level_manager.cpp # Mòdul editor (només activa contingut en Debug via `#ifdef _DEBUG`). # En Release el fitxer compila a un object buit i l'enllaçador no # arrossega cap símbol del joc final. diff --git a/data/input/keys.yaml b/data/input/keys.yaml index 147eb2e..0c889e4 100644 --- a/data/input/keys.yaml +++ b/data/input/keys.yaml @@ -47,6 +47,12 @@ keys: - id: editor_picker code: "T" desc: "Obri/tanca el tilepicker dins de l'editor" + - id: prev_room + code: "[" + desc: "Salta a la sala anterior del levels.yaml (només Debug)" + - id: next_room + code: "]" + desc: "Salta a la sala següent del levels.yaml (només Debug)" - id: exit code: "Escape" desc: "Eixir (confirmar amb segona pulsació)" diff --git a/data/locale/ca.yaml b/data/locale/ca.yaml index b14899a..1edf63b 100644 --- a/data/locale/ca.yaml +++ b/data/locale/ca.yaml @@ -37,10 +37,13 @@ hud: room: "Sala" # Textos de la transició d'entrada/sortida de sala (FSM de GameScene). -# `room_intro` accepta el placeholder `{n}` que es substitueix amb -# l'índex de sala actual; veure `GameScene::formatRoomTitle`. +# Les dues primeres claus es renderitzen com a línies separades durant +# l'INTRO (preparades per ser animades de manera independent en el +# futur). Accepten els placeholders `{p}` (piràmide) i `{r}` (sala) que +# es substitueixen amb els valors actuals del LevelManager. game: - room_intro: "Sala {n}" + room_intro_pyramid: "Piramide {p}" + room_intro_room: "Sala {r}" room_complete: "Fase completada" menu: diff --git a/data/locale/en.yaml b/data/locale/en.yaml index 72b3020..faae49c 100644 --- a/data/locale/en.yaml +++ b/data/locale/en.yaml @@ -36,11 +36,14 @@ hud: pyramid: "Pyramid" room: "Room" -# Room transition texts (GameScene FSM intro/outro). The `room_intro` -# string accepts a `{n}` placeholder that is replaced with the current -# room index; see `GameScene::formatRoomTitle`. +# Room transition texts (GameScene FSM intro/outro). The two pyramid / +# room strings render as independent lines during INTRO (so they can +# be animated separately in the future). They accept `{p}` (pyramid) +# and `{r}` (room) placeholders, replaced with the current LevelManager +# values. game: - room_intro: "Room {n}" + room_intro_pyramid: "Pyramid {p}" + room_intro_room: "Room {r}" room_complete: "Stage complete" menu: diff --git a/data/maps/levels.yaml b/data/maps/levels.yaml new file mode 100644 index 0000000..56bcc56 --- /dev/null +++ b/data/maps/levels.yaml @@ -0,0 +1,45 @@ +# Índex ordenat de les 30 sales del joc (5 piràmides × 6 sales). El +# LevelManager carrega aquesta llista a l'arrencada i la fa servir com a +# font de veritat per a `currentPath()`, `advance()`, `setIndex()` i la +# resta de consultes que li facin la GameScene, l'Editor i els salts de +# debug. Per reordenar la progressió, canvia l'ordre d'aquesta seqüència +# (no cal renombrar fitxers). Per afegir una sala, crea el YAML i posa +# una entrada nova; els camps `pyramid` i `room` són purament informatius +# (apareixen als logs i al text d'intro de sala) — l'únic camp que +# realment carrega l'engine és `file`. +# +# Convenció de nomenclatura del fitxer: `data/maps/p/r.yaml` per +# dins la piràmide N, sala M. La carpeta `p/` agruparà més endavant +# les metadades comunes de la piràmide (tileset, paleta, música). + +sequence: + - { pyramid: 1, room: 1, file: data/maps/p1/r1.yaml } + - { pyramid: 1, room: 2, file: data/maps/p1/r2.yaml } + - { pyramid: 1, room: 3, file: data/maps/p1/r3.yaml } + - { pyramid: 1, room: 4, file: data/maps/p1/r4.yaml } + - { pyramid: 1, room: 5, file: data/maps/p1/r5.yaml } + - { pyramid: 1, room: 6, file: data/maps/p1/r6.yaml } + - { pyramid: 2, room: 1, file: data/maps/p2/r1.yaml } + - { pyramid: 2, room: 2, file: data/maps/p2/r2.yaml } + - { pyramid: 2, room: 3, file: data/maps/p2/r3.yaml } + - { pyramid: 2, room: 4, file: data/maps/p2/r4.yaml } + - { pyramid: 2, room: 5, file: data/maps/p2/r5.yaml } + - { pyramid: 2, room: 6, file: data/maps/p2/r6.yaml } + - { pyramid: 3, room: 1, file: data/maps/p3/r1.yaml } + - { pyramid: 3, room: 2, file: data/maps/p3/r2.yaml } + - { pyramid: 3, room: 3, file: data/maps/p3/r3.yaml } + - { pyramid: 3, room: 4, file: data/maps/p3/r4.yaml } + - { pyramid: 3, room: 5, file: data/maps/p3/r5.yaml } + - { pyramid: 3, room: 6, file: data/maps/p3/r6.yaml } + - { pyramid: 4, room: 1, file: data/maps/p4/r1.yaml } + - { pyramid: 4, room: 2, file: data/maps/p4/r2.yaml } + - { pyramid: 4, room: 3, file: data/maps/p4/r3.yaml } + - { pyramid: 4, room: 4, file: data/maps/p4/r4.yaml } + - { pyramid: 4, room: 5, file: data/maps/p4/r5.yaml } + - { pyramid: 4, room: 6, file: data/maps/p4/r6.yaml } + - { pyramid: 5, room: 1, file: data/maps/p5/r1.yaml } + - { pyramid: 5, room: 2, file: data/maps/p5/r2.yaml } + - { pyramid: 5, room: 3, file: data/maps/p5/r3.yaml } + - { pyramid: 5, room: 4, file: data/maps/p5/r4.yaml } + - { pyramid: 5, room: 5, file: data/maps/p5/r5.yaml } + - { pyramid: 5, room: 6, file: data/maps/p5/r6.yaml } diff --git a/data/maps/p1/r1.yaml b/data/maps/p1/r1.yaml new file mode 100644 index 0000000..76b1506 --- /dev/null +++ b/data/maps/p1/r1.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 1 +room: 1 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p1/r2.yaml b/data/maps/p1/r2.yaml new file mode 100644 index 0000000..c9f8a2b --- /dev/null +++ b/data/maps/p1/r2.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 1 +room: 2 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p1/r3.yaml b/data/maps/p1/r3.yaml new file mode 100644 index 0000000..a9f9709 --- /dev/null +++ b/data/maps/p1/r3.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 1 +room: 3 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p1/r4.yaml b/data/maps/p1/r4.yaml new file mode 100644 index 0000000..f73b602 --- /dev/null +++ b/data/maps/p1/r4.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 1 +room: 4 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p1/r5.yaml b/data/maps/p1/r5.yaml new file mode 100644 index 0000000..02ac37a --- /dev/null +++ b/data/maps/p1/r5.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 1 +room: 5 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p1/r6.yaml b/data/maps/p1/r6.yaml new file mode 100644 index 0000000..7d6d97b --- /dev/null +++ b/data/maps/p1/r6.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 1 +room: 6 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p2/r1.yaml b/data/maps/p2/r1.yaml new file mode 100644 index 0000000..8cb4456 --- /dev/null +++ b/data/maps/p2/r1.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 2 +room: 1 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p2/r2.yaml b/data/maps/p2/r2.yaml new file mode 100644 index 0000000..3432cc8 --- /dev/null +++ b/data/maps/p2/r2.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 2 +room: 2 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p2/r3.yaml b/data/maps/p2/r3.yaml new file mode 100644 index 0000000..c3f3fbf --- /dev/null +++ b/data/maps/p2/r3.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 2 +room: 3 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p2/r4.yaml b/data/maps/p2/r4.yaml new file mode 100644 index 0000000..9bd79c1 --- /dev/null +++ b/data/maps/p2/r4.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 2 +room: 4 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p2/r5.yaml b/data/maps/p2/r5.yaml new file mode 100644 index 0000000..5d3b4a9 --- /dev/null +++ b/data/maps/p2/r5.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 2 +room: 5 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p2/r6.yaml b/data/maps/p2/r6.yaml new file mode 100644 index 0000000..451af3e --- /dev/null +++ b/data/maps/p2/r6.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 2 +room: 6 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p3/r1.yaml b/data/maps/p3/r1.yaml new file mode 100644 index 0000000..b491c12 --- /dev/null +++ b/data/maps/p3/r1.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 3 +room: 1 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p3/r2.yaml b/data/maps/p3/r2.yaml new file mode 100644 index 0000000..c16ea92 --- /dev/null +++ b/data/maps/p3/r2.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 3 +room: 2 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p3/r3.yaml b/data/maps/p3/r3.yaml new file mode 100644 index 0000000..b8e2f1d --- /dev/null +++ b/data/maps/p3/r3.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 3 +room: 3 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p3/r4.yaml b/data/maps/p3/r4.yaml new file mode 100644 index 0000000..a45c987 --- /dev/null +++ b/data/maps/p3/r4.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 3 +room: 4 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p3/r5.yaml b/data/maps/p3/r5.yaml new file mode 100644 index 0000000..e66da3b --- /dev/null +++ b/data/maps/p3/r5.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 3 +room: 5 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p3/r6.yaml b/data/maps/p3/r6.yaml new file mode 100644 index 0000000..9d1d79b --- /dev/null +++ b/data/maps/p3/r6.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 3 +room: 6 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p4/r1.yaml b/data/maps/p4/r1.yaml new file mode 100644 index 0000000..32a80a9 --- /dev/null +++ b/data/maps/p4/r1.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 4 +room: 1 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p4/r2.yaml b/data/maps/p4/r2.yaml new file mode 100644 index 0000000..ede3b94 --- /dev/null +++ b/data/maps/p4/r2.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 4 +room: 2 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p4/r3.yaml b/data/maps/p4/r3.yaml new file mode 100644 index 0000000..780ef09 --- /dev/null +++ b/data/maps/p4/r3.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 4 +room: 3 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p4/r4.yaml b/data/maps/p4/r4.yaml new file mode 100644 index 0000000..09c8696 --- /dev/null +++ b/data/maps/p4/r4.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 4 +room: 4 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p4/r5.yaml b/data/maps/p4/r5.yaml new file mode 100644 index 0000000..590e01a --- /dev/null +++ b/data/maps/p4/r5.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 4 +room: 5 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p4/r6.yaml b/data/maps/p4/r6.yaml new file mode 100644 index 0000000..f76058e --- /dev/null +++ b/data/maps/p4/r6.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 4 +room: 6 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p5/r1.yaml b/data/maps/p5/r1.yaml new file mode 100644 index 0000000..e346bff --- /dev/null +++ b/data/maps/p5/r1.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 5 +room: 1 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p5/r2.yaml b/data/maps/p5/r2.yaml new file mode 100644 index 0000000..d67f75f --- /dev/null +++ b/data/maps/p5/r2.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 5 +room: 2 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p5/r3.yaml b/data/maps/p5/r3.yaml new file mode 100644 index 0000000..8de253c --- /dev/null +++ b/data/maps/p5/r3.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 5 +room: 3 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p5/r4.yaml b/data/maps/p5/r4.yaml new file mode 100644 index 0000000..b8dd31e --- /dev/null +++ b/data/maps/p5/r4.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 5 +room: 4 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p5/r5.yaml b/data/maps/p5/r5.yaml new file mode 100644 index 0000000..ea6f183 --- /dev/null +++ b/data/maps/p5/r5.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 5 +room: 5 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/data/maps/p5/r6.yaml b/data/maps/p5/r6.yaml new file mode 100644 index 0000000..864d24b --- /dev/null +++ b/data/maps/p5/r6.yaml @@ -0,0 +1,140 @@ +# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif. +# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles +# en el tilemap però només 1.5 visibles al canvas, així que la textura es +# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240. +# +# Format del tilemap: +# `data` és una llista de files; cada fila és una llista d'índexs del +# tileset (lineal esq→dre, dalt→baix). Amb un tileset de 512×256 i tiles +# de 16×16 hi ha 32 tiles per fila. Un valor negatiu (p.ex. -1) deixa +# la cel·la buida (transparent), útil per caselles que ocuparà un actor. + +pyramid: 5 +room: 6 +tileset: data/tilesets/tomb.gif +tile_size: 16 +origin: [-8, 0] + +# Índex de tile amb què cada jugador deixa rastre en trepitjar un sòl +# pintable. Un índex per jugador perquè a multijugador local el recorregut +# es distingeix a simple vista. Provisional fins que l'art del pintat +# estigui definit; canviar aquí l'índex és tot el que cal. Omet el camp +# per desactivar el pintat per a aquest jugador. +player1_paint_tile: 0 +player2_paint_tile: 4 + +# Física del contacte entre jugadors. Quan un jugador està quiet i l'altre +# el topa, el segon l'empenta a aquesta fracció de la velocitat normal (i +# ell mateix es ralentitza per mantenir el grup). En head-on, ambdós +# s'anul·len (sense push, sense moviment). +push_factor: 0.30 + +# Geometria lògica de la piràmide (separada del render visual del tileset). +# La graella de sarcòfags, el pitch entre ells i les amplades dels murs +# decideixen els límits del jugador i les seues caixes de col·lisió. Abans +# vivien com a `static constexpr` a map.hpp; ara cada piràmide pot definir +# la seua pròpia forma sense recompilar. +geometry: + grid_cols: 4 + grid_rows: 5 + sarc_w: 48 + sarc_h: 16 + pitch_x: 64 + pitch_y: 32 + hud_h: 24 + back_wall_h: 24 + side_wall_w: 24 + # Columna central del tile transitable de la porta. La porta es renderitza + # com a sprite 48×32 (3 tiles d'amplada) centrat sobre aquesta columna; els + # 16 px centrals (just aquesta columna) són el "forat" del mur trasser per + # on el jugador surt de la sala. Les 2 columnes flanquejants segueixen sent + # mur visible. El spawn dels jugadors també s'alinea amb aquesta columna. + door_col: 10 + +data: + - [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + - [ 1, 91,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 92, 1] + - [ 1, 98,113,113, 95,113, 94,113,113,113,113,113,113,113, 94,113,102,113,113, 96, 1] + - [ 1, 98, 8, 8, 6, 8, 17, 8, 10, 8, 17, 8, 8, 8, 17, 8, 8, 8, 8, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 9, 2, 8, 10, 8, 8, 8, 8, 10, 8, 8, 26, 8, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 8, 26, 8, 8, 9, 8, 8, 8, 8, 8, 10, 8, 6, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 8, 2, 8, 8, 8, 9, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 6, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 17, 8, 10, 8, 8, 10, 2, 8, 8, 26, 8, 8, 8, 8, 10, 8, 17, 96, 1] + - [ 1, 98, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 2, 2, 2, 8, 96, 1] + - [ 1, 98, 8, 10, 6, 6, 17, 8, 8, 8, 17, 8, 9, 8, 17, 8, 2, 8, 8, 96, 1] + - [ 1, 99, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,100, 1] + +# Spawns d'entitats per a aquest nivell. Es llegeixen des de +# EntityManager::loadFromLevel al GameScene. Convencions: +# - sarcophagus → `sarc_position: [sarc_col, sarc_row]` en la graella de +# sarcòfags (4×5). EntityManager calcula el rect píxel via +# Map::getSarcRect i l'ancoratge de tile per al perímetre. +# - la resta (torch, door, mummy, rolling_rock, wall_trap, floor_trap) +# → `position: [tile_col, tile_row]` en coordenades del tilemap +# (origen `[-8, 0]` per defecte). Pixel = tile*16 + tilemap_origin. +# +# Dos sarcòfags en cantonades oposades → perímetres aïllats (cap tile en +# comú). La porta va al centre inferior, on el tilemap té els tiles +# d'obertura (262/263). La momia al corredor central. L'antorxa al costat +# superior esquerre per verificar render d'una entitat decorativa. +entities: + - type: torch + position: [4, 2] + - type: torch + position: [8, 2] + - type: torch + position: [12, 2] + - type: torch + position: [16, 2] + - type: sarcophagus + sarc_position: [0, 0] + - type: sarcophagus + sarc_position: [1, 0] + - type: sarcophagus + sarc_position: [2, 0] + - type: sarcophagus + sarc_position: [3, 0] + - type: sarcophagus + sarc_position: [0, 1] + - type: sarcophagus + sarc_position: [1, 1] + - type: sarcophagus + sarc_position: [2, 1] + - type: sarcophagus + sarc_position: [3, 1] + - type: sarcophagus + sarc_position: [0, 2] + - type: sarcophagus + sarc_position: [1, 2] + - type: sarcophagus + sarc_position: [2, 2] + - type: sarcophagus + sarc_position: [3, 2] + - type: sarcophagus + sarc_position: [0, 3] + - type: sarcophagus + sarc_position: [1, 3] + - type: sarcophagus + sarc_position: [2, 3] + - type: sarcophagus + sarc_position: [3, 3] + - type: sarcophagus + sarc_position: [0, 4] + - type: sarcophagus + sarc_position: [1, 4] + - type: sarcophagus + sarc_position: [2, 4] + - type: sarcophagus + sarc_position: [3, 4] + - type: door + # Sense `position`: la porta sempre viu al mur trasser. La columna + # transitable la dicta `geometry.door_col`; el render i la caixa + # de col·lisió es deriven d'aquesta dada al loadFromLevel. + - type: mummy + position: [10, 7] + - type: mummy + position: [7, 9] diff --git a/source/core/system/director.cpp b/source/core/system/director.cpp index dbca5d3..3515074 100644 --- a/source/core/system/director.cpp +++ b/source/core/system/director.cpp @@ -27,6 +27,7 @@ #include "core/system/event_buffer.hpp" #include "core/ui/ui_config.hpp" #include "game/debug_config.hpp" +#include "game/levels/level_manager.hpp" #include "game/options.hpp" #include "game/scenes/game_scene.hpp" #include "game/scenes/intro_scene.hpp" @@ -182,6 +183,13 @@ Director::Director() { DebugConfig::createDefaultIfMissing(DEBUG_YAML); const auto START = DebugConfig::resolveStartScene(DEBUG_YAML); const auto STARTING_PLAYERS = DebugConfig::resolveStartingPlayers(DEBUG_YAML); + // `starting_level` (opcional) sobreescriu l'índex inicial del + // LevelManager abans de crear cap GameScene. Si la clau no està o el + // (pyramid, room) no apareix al levels.yaml, el LevelManager + // continua a la primera entrada (P1-R1). + if (const auto SL = DebugConfig::resolveStartingLevel(DEBUG_YAML); SL.has_value()) { + Levels::LevelManager::get().setStartingPoint(SL->pyramid, SL->room); + } #else const auto START = DebugConfig::StartScene::LOGO; const auto STARTING_PLAYERS = DebugConfig::StartingPlayers::BOTH; @@ -189,6 +197,12 @@ Director::Director() { std::cout << "Director: start_scene=" << DebugConfig::toString(START) << " starting_players=" << DebugConfig::toString(STARTING_PLAYERS) << '\n'; + // El branch Release inicialitza STARTING_PLAYERS amb una constant + // literal i clang considera la captura redundant; en Debug el valor és + // runtime i la captura sí és imprescindible. La lambda viu dins de + // IntroScene, més enllà del scope d'aquest ctor — capturar per + // referència seria UB. + // NOLINTNEXTLINE(clang-diagnostic-unused-lambda-capture) auto make_game = [STARTING_PLAYERS]() -> std::unique_ptr { auto cfg = GameScene::defaultConfig(); cfg.starting_players = STARTING_PLAYERS; diff --git a/source/game/debug_config.cpp b/source/game/debug_config.cpp index 7ff9291..c14cf54 100644 --- a/source/game/debug_config.cpp +++ b/source/game/debug_config.cpp @@ -103,6 +103,34 @@ namespace DebugConfig { return parseStartingPlayers(CONTENT); } + auto parseStartingLevel(const std::string& yaml_content) -> std::optional { + if (yaml_content.empty()) { return std::nullopt; } + try { + auto yaml = fkyaml::node::deserialize(yaml_content); + if (!yaml.contains("starting_level")) { return std::nullopt; } + const auto& sl = yaml["starting_level"]; + if (!sl.contains("pyramid") || !sl.contains("room")) { + std::cerr << "debug.yaml: starting_level necessita els camps `pyramid` i `room` — ignorat\n"; + return std::nullopt; + } + return StartingLevel{ + .pyramid = sl["pyramid"].get_value(), + .room = sl["room"].get_value(), + }; + } catch (const std::exception& e) { + std::cerr << "debug.yaml: error parsejant starting_level: " << e.what() << " — ignorat\n"; + return std::nullopt; + } + } + + auto resolveStartingLevel(const std::string& file_path) -> std::optional { + std::error_code error; + if (!std::filesystem::exists(file_path, error)) { return std::nullopt; } + const auto CONTENT = readFile(file_path); + if (CONTENT.empty()) { return std::nullopt; } + return parseStartingLevel(CONTENT); + } + auto toString(StartScene scene) -> const char* { switch (scene) { case StartScene::LOGO: @@ -140,6 +168,9 @@ namespace DebugConfig { file << "# debug.yaml — ajust personal de dev (no versionat).\n"; file << "# start_scene: LOGO | TITLE | INTRO | GAME\n"; file << "# starting_players: P1 | P2 | BOTH\n"; + file << "# starting_level (opcional): { pyramid: N, room: M } — salta a la sala\n"; + file << "# corresponent del levels.yaml. Sense la\n"; + file << "# clau, comença a la primera (P1-R1).\n"; file << "start_scene: GAME\n"; file << "starting_players: BOTH\n"; std::cout << "debug.yaml: creat a " << file_path << " amb start_scene=GAME starting_players=BOTH\n"; diff --git a/source/game/debug_config.hpp b/source/game/debug_config.hpp index 182fd21..56bbcba 100644 --- a/source/game/debug_config.hpp +++ b/source/game/debug_config.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include // Configuració personal de desenvolupament, carregada de `debug.yaml` dins la @@ -37,6 +38,18 @@ namespace DebugConfig { [[nodiscard]] auto parseStartingPlayers(const std::string& yaml_content) -> StartingPlayers; [[nodiscard]] auto resolveStartingPlayers(const std::string& file_path) -> StartingPlayers; + // Punt d'arrencada dins de la progressió de sales (consumit pel + // `Levels::LevelManager`). YAML: + // starting_level: { pyramid: 2, room: 3 } + // L'absència de la clau és el cas habitual i deixa la progressió a + // la primera entrada del `levels.yaml`. + struct StartingLevel { + int pyramid{0}; + int room{0}; + }; + [[nodiscard]] auto parseStartingLevel(const std::string& yaml_content) -> std::optional; + [[nodiscard]] auto resolveStartingLevel(const std::string& file_path) -> std::optional; + // Nom canònic de l'enum (útil per a logs): "LOGO" / "TITLE" / "INTRO" / "GAME". [[nodiscard]] auto toString(StartScene scene) -> const char*; [[nodiscard]] auto toString(StartingPlayers players) -> const char*; diff --git a/source/game/editor/editor.cpp b/source/game/editor/editor.cpp index 85a13ac..5a26db9 100644 --- a/source/game/editor/editor.cpp +++ b/source/game/editor/editor.cpp @@ -14,6 +14,7 @@ #include "core/resources/resource_cache.hpp" #include "core/resources/resource_helper.hpp" #include "core/system/event_buffer.hpp" +#include "game/levels/level_manager.hpp" #include "game/map/tilemap.hpp" #include "utils/defaults.hpp" #include "utils/defines.hpp" @@ -76,11 +77,13 @@ void Editor::exit(Tilemap& tilemap) { if (!active_) { return; } active_ = false; picker_open_ = false; - // Resolem la ruta via Resource::Helper perquè en Debug el root de - // dades és AEE_SOURCE_DIR (ruta absoluta al repo), no el CWD. Sense - // això, el writer obriria `data/maps/pyramid.yaml` relatiu al CWD - // i fallaria sempre excepte si el binari es llança des del repo root. - const auto ABS_PATH = Resource::Helper::resolve(Defaults::Editor::SAVE_PATH); + // El writer salva sempre sobre la sala actualment carregada (segons + // el LevelManager): així el "9" de l'editor desa el que tens davant, + // no una constant fixa. Resolem la ruta via Resource::Helper perquè + // en Debug el root de dades és AEE_SOURCE_DIR (ruta absoluta al repo), + // no el CWD; sense això, el writer obriria el path relatiu al CWD i + // fallaria si el binari no es llança des del repo root. + const auto ABS_PATH = Resource::Helper::resolve(Levels::LevelManager::get().currentPath()); const bool SAVED = tilemap.save(ABS_PATH); Notification::notify(Locale::get().text(SAVED ? "input.editor_off" : "input.editor_save_error")); } diff --git a/source/game/levels/level_manager.cpp b/source/game/levels/level_manager.cpp new file mode 100644 index 0000000..1839433 --- /dev/null +++ b/source/game/levels/level_manager.cpp @@ -0,0 +1,104 @@ +#include "game/levels/level_manager.hpp" + +#include +#include +#include +#include + +#include "core/resources/resource_helper.hpp" +#include "external/fkyaml_node.hpp" +#include "utils/defaults.hpp" + +namespace Levels { + + auto LevelManager::get() -> LevelManager& { + static LevelManager instance_; + return instance_; + } + + LevelManager::LevelManager() { loadIndex(); } + + void LevelManager::loadIndex() { + const std::string PATH = Defaults::Pyramid::LEVELS_YAML; + auto bytes = Resource::Helper::loadFile(PATH); + if (bytes.empty()) { + throw std::runtime_error("LevelManager: no s'ha pogut obrir " + PATH); + } + const auto* begin = reinterpret_cast(bytes.data()); + const auto* end = begin + bytes.size(); + auto yaml = fkyaml::node::deserialize(begin, end); + + if (!yaml.contains("sequence") || !yaml["sequence"].is_sequence()) { + throw std::runtime_error("LevelManager: manca o és invàlid `sequence:` a " + PATH); + } + const auto& seq = yaml["sequence"]; + entries_.clear(); + entries_.reserve(seq.size()); + for (const auto& e : seq) { + Entry entry{ + .pyramid = e["pyramid"].get_value(), + .room = e["room"].get_value(), + .file = e["file"].get_value(), + }; + entries_.push_back(std::move(entry)); + } + if (entries_.empty()) { + throw std::runtime_error("LevelManager: la seqüència de " + PATH + " és buida"); + } + index_ = 0; + std::cout << "LevelManager: " << entries_.size() << " sales carregades de " + << PATH << " (començant a " << currentLabel() << ")\n"; + } + + auto LevelManager::currentPath() const -> const std::string& { + return entries_[index_].file; + } + + auto LevelManager::currentPyramid() const -> int { return entries_[index_].pyramid; } + auto LevelManager::currentRoom() const -> int { return entries_[index_].room; } + + auto LevelManager::currentLabel() const -> std::string { + return "P" + std::to_string(currentPyramid()) + "-R" + std::to_string(currentRoom()); + } + + auto LevelManager::index() const -> int { return index_; } + auto LevelManager::count() const -> int { return static_cast(entries_.size()); } + + auto LevelManager::advance() -> bool { + if (index_ + 1 >= count()) { return false; } + ++index_; + std::cout << "LevelManager: avança a " << currentLabel() + << " (" << currentPath() << ")\n"; + return true; + } + + void LevelManager::restart() { + index_ = 0; + std::cout << "LevelManager: restart a " << currentLabel() << '\n'; + } + + void LevelManager::setIndex(int new_index) { + const int CLAMPED = std::clamp(new_index, 0, count() - 1); + if (CLAMPED != index_) { + index_ = CLAMPED; + std::cout << "LevelManager: setIndex(" << new_index << ") → " + << currentLabel() << " (" << currentPath() << ")\n"; + } + } + + auto LevelManager::setStartingPoint(int pyramid, int room) -> bool { + for (std::size_t i = 0; i < entries_.size(); ++i) { + if (entries_[i].pyramid == pyramid && entries_[i].room == room) { + index_ = static_cast(i); + std::cout << "LevelManager: starting_point P" << pyramid << "-R" << room + << " trobat a l'índex " << i << " (" << currentPath() << ")\n"; + return true; + } + } + std::cerr << "LevelManager: starting_point P" << pyramid << "-R" << room + << " no trobat a levels.yaml — es manté l'índex actual (" + << currentLabel() << ")\n"; + return false; + } + +} // namespace Levels diff --git a/source/game/levels/level_manager.hpp b/source/game/levels/level_manager.hpp new file mode 100644 index 0000000..9fe0763 --- /dev/null +++ b/source/game/levels/level_manager.hpp @@ -0,0 +1,81 @@ +#pragma once + +#include +#include + +namespace Levels { + + // Font de veritat de la progressió de sales del joc. Carrega + // `data/maps/levels.yaml` a la primera crida a `get()` i exposa l'estat + // "on sóc ara" + les operacions per moure'm. La GameScene, l'Editor i + // els salts de debug consulten aquest singleton; ningú no manté el seu + // propi índex de progressió. + // + // Meyers singleton: la destrucció estàtica només toca std::string i + // std::vector, així que és segura sense ordenació explícita. + class LevelManager { + public: + static auto get() -> LevelManager&; + + LevelManager(const LevelManager&) = delete; + LevelManager(LevelManager&&) = delete; + auto operator=(const LevelManager&) -> LevelManager& = delete; + auto operator=(LevelManager&&) -> LevelManager& = delete; + + // Una entrada del `levels.yaml`. `file` és la ruta relativa al data + // root (mateixa convenció que la resta de YAML del joc); pyramid i + // room són purament informatius (logs i text d'intro). + struct Entry { + int pyramid{0}; + int room{0}; + std::string file; + }; + + // Ruta del nivell actualment apuntat. Sempre vàlida un cop carregat + // l'índex (entries_ no pot estar buit). Pensada per a `Map::loadFrom`, + // `EntityManager::reload` i l'Editor. + [[nodiscard]] auto currentPath() const -> const std::string&; + [[nodiscard]] auto currentPyramid() const -> int; + [[nodiscard]] auto currentRoom() const -> int; + // "P1-R3" — útil per a logs i el text d'intro de sala. + [[nodiscard]] auto currentLabel() const -> std::string; + + // Posició dins de la seqüència. `count()` és el total de sales + // carregades del YAML (no necessàriament 30: si afegeixes/treus + // entrades de `levels.yaml`, el manager s'adapta). + [[nodiscard]] auto index() const -> int; + [[nodiscard]] auto count() const -> int; + + // Avança al següent nivell. Retorna true si avança, false si ja + // estava a l'últim. NO fa loop — la GameScene decideix la política + // (loop a la primera, fi de joc, etc.) segons el context. + auto advance() -> bool; + + // Torna al primer nivell. + void restart(); + + // Salta a un índex concret. Clamp als bordes [0, count()-1]. + // Pensat per als hotkeys debug. + void setIndex(int new_index); + + // Posiciona l'índex a la primera entrada que coincideix amb + // (pyramid, room). Retorna true si trobada; si no, l'índex no + // es modifica i el caller decideix què fer (típicament ignorar i + // arrencar des de la primera sala). Pensat per al + // `debug.yaml.starting_level` i per a futures lookups per coords. + auto setStartingPoint(int pyramid, int room) -> bool; + + private: + LevelManager(); + ~LevelManager() = default; + + // Carrega `data/maps/levels.yaml` via `Resource::Helper::loadFile`. + // Si manca, és invàlid o té la seqüència buida, llança — no té sentit + // continuar sense progressió de sales. + void loadIndex(); + + std::vector entries_; + int index_{0}; + }; + +} // namespace Levels diff --git a/source/game/scenes/game_scene.cpp b/source/game/scenes/game_scene.cpp index 425dda2..1f591a7 100644 --- a/source/game/scenes/game_scene.cpp +++ b/source/game/scenes/game_scene.cpp @@ -32,6 +32,7 @@ #include "game/entities/entity_loader.hpp" #include "game/entities/event_bus.hpp" #include "game/entities/player.hpp" +#include "game/levels/level_manager.hpp" #include "game/map/map.hpp" #include "game/options.hpp" #include "game/ui/hud.hpp" @@ -221,8 +222,11 @@ namespace { } // namespace auto GameScene::defaultConfig() -> Config { + // El path del mapa el dicta el LevelManager (que ja ha llegit `levels.yaml` + // a la primera invocació). Així `defaultConfig()` no coneix cap fitxer + // concret de sala — només cap a on apunta la progressió ara mateix. return { - .map_yaml = Defaults::Pyramid::MAP_YAML, + .map_yaml = Levels::LevelManager::get().currentPath(), .player_sprite = Defaults::Pyramid::PLAYER_SPRITE, .player_yaml = Defaults::Pyramid::PLAYER_YAML, .player2_sprite = Defaults::Pyramid::PLAYER_SPRITE_P2, @@ -235,6 +239,12 @@ auto GameScene::defaultConfig() -> Config { GameScene::GameScene(Config config) : config_(std::move(config)), tilemap_(makeTilemap(config_.map_yaml)) { + // El text d'INTRO i el HUD demanaran piràmide/sala directament al + // LevelManager — `GameScene` ja no manté un mirror local. La + // sincronització "una vegada per càrrega de sala" la fa `loadRoom` + // (per al HUD) i `renderRoomText` (per al text d'INTRO, llegint el + // valor a cada frame de la transició). + // Convenció: el Resource::Cache indexa per basename del fitxer, perquè // la mateixa clau l'usa el parseador d'animació (YAML > tileSetFile). // Lambda perquè tenim dos conjunts d'assets (sam/morcus) i l'alta al @@ -404,6 +414,13 @@ GameScene::GameScene(Config config) // només P1). Mentre els events del bus no porten `player_id`, els hits // segueixen aplicant-se a P1 (veure TODO a Hud::onPlayerHit). if (USE_P2) { hud_->activatePlayer(2); } + // Sincronització inicial dels comptadors de piràmide/sala del HUD amb + // el LevelManager (després de cada `loadRoom` també es refresca; ací + // és el primer ajust per a la sala d'arrencada). + { + const auto& mgr = Levels::LevelManager::get(); + hud_->setPyramidRoom(mgr.currentPyramid(), mgr.currentRoom()); + } // Música de fons en bucle infinit. El track ja està al Resource::Cache // (preload al Director), així que playMusic només mou el punter cap a @@ -455,12 +472,13 @@ auto GameScene::computeSpawn() -> PlayerSpawn { }; } -void GameScene::resetRoom() { - // Recarregar les entitats des del YAML del mapa: la porta torna a +void GameScene::loadRoom(const std::string& yaml_path) { + // Recarregar les entitats des del YAML donat: la porta torna a // CLOSED (amb l'open=false a Map al loadFrom), els sarcs tornen a // CLOSED amb visited buit, momies i altres actors a la posició inicial. - Map::loadFrom(config_.map_yaml); - entity_manager_.reload(config_.map_yaml); + config_.map_yaml = yaml_path; + Map::loadFrom(yaml_path); + entity_manager_.reload(yaml_path); // Tornem a fixar el comptador de "esperats" amb només els slots // actius — un slot DISABLED permanent (single-player) no compta. const int ACTIVE_COUNT = std::ranges::count(players_starts_active_, true); @@ -474,10 +492,45 @@ void GameScene::resetRoom() { // el primer. for (auto& p : players_) { p->disable(); } - std::cout << "[ROOM] reset: entities reloaded, paint cleared, " + // Refresca el marcador (piràmide / sala) amb el LevelManager. El + // GameScene no manté els valors a part: la lectura sempre és a + // través del singleton, així no es desincronitzen mai entre + // hotkeys de salt, debug.yaml i creuament natural de porta. + if (hud_) { + const auto& mgr = Levels::LevelManager::get(); + hud_->setPyramidRoom(mgr.currentPyramid(), mgr.currentRoom()); + } + + std::cout << "[ROOM] load " << yaml_path << ": entities reloaded, paint cleared, " << ACTIVE_COUNT << " active player(s) disabled (awaiting spawn cinematic)\n"; } +void GameScene::advanceToNextRoom() { + auto& mgr = Levels::LevelManager::get(); + if (!mgr.advance()) { + // Política temporal mentre no hi haja pantalla de "Fi de joc": + // arribar al final del levels.yaml fa loop a la primera sala. + std::cout << "[ROOM] final del levels.yaml — bucle a la primera sala\n"; + mgr.restart(); + } + loadRoom(mgr.currentPath()); + enterRoomIntro(); +} + +void GameScene::enterRoomIntro() { + // Anotem la transició al log si veníem d'un altre estat; si ja + // estàvem a INTRO (cas típic d'un salt debug) també queda ben clar. + if (state_ != RoomFsm::State::ROOM_INTRO) { + std::cout << "[ROOM] " << RoomFsm::stateName(state_) << " -> ROOM_INTRO\n"; + } else { + std::cout << "[ROOM] ROOM_INTRO restart (cinemàtica reiniciada)\n"; + } + state_ = RoomFsm::State::ROOM_INTRO; + transition_ = {}; + room_intro_elapsed_ms_ = 0; + players_spawned_in_intro_ = false; +} + void GameScene::triggerActivePlayerSpawn() { if (players_spawned_in_intro_) { return; } players_spawned_in_intro_ = true; @@ -504,7 +557,6 @@ void GameScene::triggerActivePlayerSpawn() { void GameScene::setState(RoomFsm::State new_state) { if (new_state == state_) { return; } std::cout << "[ROOM] " << RoomFsm::stateName(state_) << " -> " << RoomFsm::stateName(new_state) << '\n'; - const auto PREV = state_; state_ = new_state; transition_ = {}; // En entrar a un nou cicle d'INTRO, resetegem el timer i el flag de @@ -513,13 +565,12 @@ void GameScene::setState(RoomFsm::State new_state) { room_intro_elapsed_ms_ = 0; players_spawned_in_intro_ = false; } - // En tornar a ROOM_INTRO des de ROOM_OUTRO (placeholder de - // "torna a la mateixa sala"), reseteja completament l'estat del - // nivell. Si la transició és la inicial (PREV també és ROOM_INTRO, - // imposible amb el guard de dalt) o ve d'un altre estat, no fa res. - if (new_state == RoomFsm::State::ROOM_INTRO && PREV == RoomFsm::State::ROOM_OUTRO) { - resetRoom(); - } + // L'avanç de sala (OUTRO → INTRO) NO viu ací: el dispara + // `updateRoomTransition` quan la FSM detecta el final de l'OUTRO, + // cridant directament `advanceToNextRoom`. Això manté `setState` + // com una transició pura, sense efectes col·laterals que + // recarreguen sales — necessari per als salts debug que també + // entren a INTRO sense passar per OUTRO. } void GameScene::updateRoomTransition(int delta_ms) { @@ -535,7 +586,18 @@ void GameScene::updateRoomTransition(int delta_ms) { } const auto NEXT = RoomFsm::advance(state_, transition_, transition_config_, delta_ms); - if (NEXT != state_) { setState(NEXT); } + if (NEXT != state_) { + // El final de l'OUTRO no es resol amb un setState normal: cal + // demanar al LevelManager el següent nivell i carregar-lo abans + // d'entrar a INTRO. `advanceToNextRoom` fa tot el bloc i acaba + // amb la FSM a ROOM_INTRO (via `enterRoomIntro`), així que no + // fa falta el setState d'aquesta branca. + if (NEXT == RoomFsm::State::ROOM_INTRO && state_ == RoomFsm::State::ROOM_OUTRO) { + advanceToNextRoom(); + } else { + setState(NEXT); + } + } } void GameScene::renderRoomFade() { @@ -567,70 +629,83 @@ void GameScene::renderRoomFade() { void GameScene::renderRoomText() { // Text de la transició de sala. Reusa la font cachejada per a la // pausa (mateix tipus de lletra, mateix índex de color), i fa el - // mateix patró esquerra → centre → esquerra que el text de pausa - // però amb les durades pròpies de la transició. + // mateix patró esquerra → centre → dreta que el text de pausa però + // amb les durades pròpies de la transició. // // Mapatge per estat (només els estats amb text actiu hi entren): - // ROOM_INTRO: phases 2..4 → enter / hold / exit; text = sala N - // ROOM_OUTRO: phases 0..2 → enter / hold / exit; text = "fase completada" + // ROOM_INTRO: phases 2..4 → enter / hold / exit; dues línies + // (piràmide damunt, sala davall) que comparteixen + // animació però es dibuixen amb writeDX independents + // per deixar la porta oberta a desacoblar-les. + // ROOM_OUTRO: phases 0..2 → enter / hold / exit; una línia + // ("fase completada"). if (!pause_font_) { return; } - std::string text; - int phase_enter = 0; - int phase_exit = 0; - int dur_enter = 0; - int dur_exit = 0; - if (state_ == RoomFsm::State::ROOM_INTRO && transition_.phase >= 2 && transition_.phase <= 4) { - text = RoomFsm::formatRoomTitle(room_index_); - phase_enter = 2; - phase_exit = 4; - dur_enter = transition_config_.intro_text_enter_ms; - dur_exit = transition_config_.intro_text_exit_ms; - } else if (state_ == RoomFsm::State::ROOM_OUTRO && transition_.phase >= 0 && transition_.phase <= 2) { - text = Locale::get().text("game.room_complete"); - phase_enter = 0; - phase_exit = 2; - dur_enter = transition_config_.outro_text_enter_ms; - dur_exit = transition_config_.outro_text_exit_ms; - } else { - return; - } - constexpr int KERNING = 0; - const int W = pause_font_->length(text, KERNING); - // El text entra des de l'esquerra (off-screen amb el seu cantó dret - // a x=0) i, després del hold, surt cap a la dreta (off-screen amb - // el seu cantó esquerre a x=WIDTH). Així el text "travessa" la - // pantalla en una sola direcció en compte de tornar enrere. - const int OFF_LEFT = -W; - const int OFF_RIGHT = GameCanvas::WIDTH; - int x = GameCanvas::CENTER_X; - - if (transition_.phase == phase_enter) { - const float T = (dur_enter > 0) - ? std::clamp(static_cast(transition_.elapsed_ms) / static_cast(dur_enter), 0.0F, 1.0F) - : 1.0F; - const auto CURVE = (transition_config_.text_enter_curve != nullptr) ? transition_config_.text_enter_curve : &Easing::linear; - x = Easing::lerpInt(OFF_LEFT, GameCanvas::CENTER_X, CURVE(T)); - } else if (transition_.phase == phase_exit) { - const float T = (dur_exit > 0) - ? std::clamp(static_cast(transition_.elapsed_ms) / static_cast(dur_exit), 0.0F, 1.0F) - : 1.0F; - const auto CURVE = (transition_config_.text_exit_curve != nullptr) ? transition_config_.text_exit_curve : &Easing::linear; - x = Easing::lerpInt(GameCanvas::CENTER_X, OFF_RIGHT, CURVE(T)); - } - constexpr Uint8 OUTLINE_WHITE = 255; constexpr Uint8 STROKE_DIST = 1; - const int Y = GameCanvas::CENTER_Y - (pause_font_->getLineHeight() / 2); - pause_font_->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG | Text::STROKE4_FLAG, - x, - Y, - text, - KERNING, - UiConfig::get().notificationText(), - STROKE_DIST, - OUTLINE_WHITE); + + // Calcula la X animada d'una línia: entra des de l'esquerra + // (off-screen amb el seu cantó dret a x=0), s'atura al CENTER_X + // durant el hold i surt cap a la dreta (off-screen amb el cantó + // esquerre a x=WIDTH). El càlcul depèn de l'amplada de la línia + // — per això la passem com a paràmetre. + auto compute_x = [&](int width, int phase_enter, int phase_exit, int dur_enter, int dur_exit) -> int { + const int OFF_LEFT = -width; + const int OFF_RIGHT = GameCanvas::WIDTH; + if (transition_.phase == phase_enter) { + const float T = (dur_enter > 0) + ? std::clamp(static_cast(transition_.elapsed_ms) / static_cast(dur_enter), 0.0F, 1.0F) + : 1.0F; + const auto CURVE = (transition_config_.text_enter_curve != nullptr) ? transition_config_.text_enter_curve : &Easing::linear; + return Easing::lerpInt(OFF_LEFT, GameCanvas::CENTER_X, CURVE(T)); + } + if (transition_.phase == phase_exit) { + const float T = (dur_exit > 0) + ? std::clamp(static_cast(transition_.elapsed_ms) / static_cast(dur_exit), 0.0F, 1.0F) + : 1.0F; + const auto CURVE = (transition_config_.text_exit_curve != nullptr) ? transition_config_.text_exit_curve : &Easing::linear; + return Easing::lerpInt(GameCanvas::CENTER_X, OFF_RIGHT, CURVE(T)); + } + return GameCanvas::CENTER_X; + }; + + auto draw_line = [&](const std::string& text, int x, int y) { + pause_font_->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG | Text::STROKE4_FLAG, + x, + y, + text, + KERNING, + UiConfig::get().notificationText(), + STROKE_DIST, + OUTLINE_WHITE); + }; + + if (state_ == RoomFsm::State::ROOM_INTRO && transition_.phase >= 2 && transition_.phase <= 4) { + const auto& mgr = Levels::LevelManager::get(); + const std::string LINE_PYRAMID = RoomFsm::formatIntroPyramidLine(mgr.currentPyramid()); + const std::string LINE_ROOM = RoomFsm::formatIntroRoomLine(mgr.currentRoom()); + const int W_PYRAMID = pause_font_->length(LINE_PYRAMID, KERNING); + const int W_ROOM = pause_font_->length(LINE_ROOM, KERNING); + const int DUR_ENTER = transition_config_.intro_text_enter_ms; + const int DUR_EXIT = transition_config_.intro_text_exit_ms; + const int X_PYRAMID = compute_x(W_PYRAMID, 2, 4, DUR_ENTER, DUR_EXIT); + const int X_ROOM = compute_x(W_ROOM, 2, 4, DUR_ENTER, DUR_EXIT); + // Bloc de dues línies centrat al voltant de CENTER_Y: la + // piràmide ocupa la línia de damunt, la sala la de davall. Si + // un dia el font canvia d'alçada, `getLineHeight` ho reflecteix. + const int LINE_HEIGHT = pause_font_->getLineHeight(); + const int Y_PYRAMID = GameCanvas::CENTER_Y - LINE_HEIGHT; + const int Y_ROOM = GameCanvas::CENTER_Y; + draw_line(LINE_PYRAMID, X_PYRAMID, Y_PYRAMID); + draw_line(LINE_ROOM, X_ROOM, Y_ROOM); + } else if (state_ == RoomFsm::State::ROOM_OUTRO && transition_.phase >= 0 && transition_.phase <= 2) { + const std::string TEXT = Locale::get().text("game.room_complete"); + const int W = pause_font_->length(TEXT, KERNING); + const int X = compute_x(W, 0, 2, transition_config_.outro_text_enter_ms, transition_config_.outro_text_exit_ms); + const int Y = GameCanvas::CENTER_Y - (pause_font_->getLineHeight() / 2); + draw_line(TEXT, X, Y); + } } void GameScene::spawnDust(float feet_x_center, float feet_y, bool is_landing) { @@ -743,6 +818,20 @@ namespace { return ev.type == SDL_EVENT_KEY_DOWN && ev.key.scancode == SC; }); } + + // Retorna -1 si s'ha premut prev_room, +1 si next_room, 0 si cap. + // Si tots dos arriben en el mateix frame (poc probable amb teclat), + // prev té prioritat — l'usuari sempre pot tornar a prémer next. + auto detectRoomJump() -> int { + const SDL_Scancode PREV_SC = KeyConfig::get().scancode("prev_room"); + const SDL_Scancode NEXT_SC = KeyConfig::get().scancode("next_room"); + for (const auto& ev : EventBuffer::events) { + if (ev.type != SDL_EVENT_KEY_DOWN) { continue; } + if (PREV_SC != SDL_SCANCODE_UNKNOWN && ev.key.scancode == PREV_SC) { return -1; } + if (NEXT_SC != SDL_SCANCODE_UNKNOWN && ev.key.scancode == NEXT_SC) { return +1; } + } + return 0; + } } // namespace #endif @@ -762,6 +851,19 @@ void GameScene::update(int delta_ms) { if (pause_.state == PauseState::IDLE && detectEditorToggle()) { editor_.toggle(tilemap_); } + + // Salts debug entre sales (`[` / `]`). Mútuament excloents amb la + // pausa i amb l'editor: si qualsevol està actiu, ignorem la tecla + // perquè el salt recarrega entitats i invalidaria l'estat editat. + if (pause_.state == PauseState::IDLE && !editor_.active()) { + const int DELTA = detectRoomJump(); + if (DELTA != 0) { + auto& mgr = Levels::LevelManager::get(); + mgr.setIndex(mgr.index() + DELTA); + loadRoom(mgr.currentPath()); + enterRoomIntro(); + } + } #endif GlobalInputs::update(delta_ms); diff --git a/source/game/scenes/game_scene.hpp b/source/game/scenes/game_scene.hpp index e588cf7..f975f8e 100644 --- a/source/game/scenes/game_scene.hpp +++ b/source/game/scenes/game_scene.hpp @@ -183,12 +183,6 @@ class GameScene : public Scene { // reseteja a {0, 0}. RoomFsm::Transition transition_{}; - // Índex de sala que es passa com a paràmetre {n} al text d'intro. - // Avui és sempre 1 (no hi ha itinerari de sales encara). Quan - // arribi l'itinerari, és el camp que es modificarà al transicionar - // de ROOM_OUTRO → ROOM_INTRO per saltar a la pròxima. - int room_index_{1}; - // Píxels del fade negre i del text de la transició de sala. // Cridats des de `render()` entre el bloc d'actors i el HUD — // així marcador, notificacions i service menu queden per damunt. @@ -208,11 +202,27 @@ class GameScene : public Scene { }; [[nodiscard]] static auto computeSpawn() -> PlayerSpawn; - // Reset complet de la sala: reload de l'EntityManager (sarcs/porta/ - // momies des de zero), neteja del PaintLayer i respawn dels jugadors - // a la posició calculada per `computeSpawn`. Cridat des de - // `setState(ROOM_INTRO)` quan la transició anterior era OUTRO. - void resetRoom(); + // Recarrega la sala apuntada per `yaml_path`: refresca Map (geometria, + // porta tancada), entitats (sarcs/porta/momies des de zero), neteja + // el PaintLayer i deixa els jugadors a DISABLED esperant la cinemàtica + // d'spawn aeri del nou cicle d'INTRO. També actualitza + // `config_.map_yaml` perquè futurs consumidors (l'Editor en guardar, + // logs, etc.) sàpiguen quina sala està viva. + void loadRoom(const std::string& yaml_path); + + // Demana al LevelManager el següent nivell i el carrega via + // `loadRoom`, deixant la FSM al començament d'un nou cicle d'INTRO. + // Si ja era a l'última entrada, fa loop a la primera (política + // temporal mentre no hi haja pantalla de fi de joc). Cridat des de + // `updateRoomTransition` quan l'OUTRO arriba a la fase final. + void advanceToNextRoom(); + + // Inicia (o reinicia) el cicle d'entrada de sala: posa l'estat a + // ROOM_INTRO i reseteja `transition_`, `room_intro_elapsed_ms_` i el + // flag d'spawn aeri. Idempotent quan ja s'estava a INTRO (els + // timers tornen a començar des de zero — útil per als salts debug + // que recarreguen la sala estant ja en INTRO). + void enterRoomIntro(); #ifdef _DEBUG // Editor modal del tilemap. Mútuament excloent amb la pausa: si la diff --git a/source/game/scenes/room_fsm.cpp b/source/game/scenes/room_fsm.cpp index 1016108..ee1c461 100644 --- a/source/game/scenes/room_fsm.cpp +++ b/source/game/scenes/room_fsm.cpp @@ -99,22 +99,35 @@ namespace RoomFsm { t.elapsed_ms -= DURS[t.phase]; ++t.phase; } - // Placeholder fins a l'itinerari de sales: l'OUTRO recau a INTRO. - // TODO(itinerari): aquest mateix retorn sortirà cap a una nova - // sala (incrementant `room_index_` i recreant tilemap/entitats al - // GameScene) abans de tornar a ROOM_INTRO. + // Final de l'OUTRO → ROOM_INTRO de la sala SEGÜENT. La FSM no + // sap quina és — només avisa del canvi d'estat. La GameScene, + // dins `setState(ROOM_INTRO)` amb PREV=OUTRO, demana al + // LevelManager el següent nivell i recarrega tilemap/entitats. if (t.phase >= static_cast(DURS.size())) { return State::ROOM_INTRO; } return current; } - auto formatRoomTitle(int n) -> std::string { - auto tpl = Locale::get().text("game.room_intro"); - constexpr std::string_view PLACEHOLDER = "{n}"; - auto pos = tpl.find(PLACEHOLDER); - if (pos != std::string::npos) { - tpl.replace(pos, PLACEHOLDER.size(), std::to_string(n)); + namespace { + // Substitueix la primera ocurrència de `placeholder` dins de `tpl` + // pel valor d'`n` convertit a string. Utilitzat per les dues + // formatadores d'INTRO; si la clau del Locale no porta el + // placeholder (traducció buida o ja substituïda), retorna la + // plantilla intacta. + auto substitute(std::string tpl, std::string_view placeholder, int n) -> std::string { + auto pos = tpl.find(placeholder); + if (pos != std::string::npos) { + tpl.replace(pos, placeholder.size(), std::to_string(n)); + } + return tpl; } - return tpl; + } // namespace + + auto formatIntroPyramidLine(int pyramid) -> std::string { + return substitute(Locale::get().text("game.room_intro_pyramid"), "{p}", pyramid); + } + + auto formatIntroRoomLine(int room) -> std::string { + return substitute(Locale::get().text("game.room_intro_room"), "{r}", room); } auto stateName(State s) -> const char* { diff --git a/source/game/scenes/room_fsm.hpp b/source/game/scenes/room_fsm.hpp index 0e357c5..a4c8684 100644 --- a/source/game/scenes/room_fsm.hpp +++ b/source/game/scenes/room_fsm.hpp @@ -66,10 +66,15 @@ namespace RoomFsm { // (això ho fa `GameScene::setState`). Funció pura sobre l'argument. [[nodiscard]] auto advance(State current, Transition& t, const Config& cfg, int delta_ms) -> State; - // Substitueix `{n}` de la clau "game.room_intro" del Locale per - // l'enter passat. Si la clau no està traduïda, retorna la pròpia - // clau (fallback de Locale::text). - [[nodiscard]] auto formatRoomTitle(int n) -> std::string; + // Substitueix `{p}` de la clau "game.room_intro_pyramid" del Locale + // per l'enter passat. Pensat per a la primera línia del text d'INTRO. + // Si la clau no està traduïda, retorna la pròpia clau (fallback de + // Locale::text). + [[nodiscard]] auto formatIntroPyramidLine(int pyramid) -> std::string; + + // Equivalent per a `game.room_intro_room` amb el placeholder `{r}`. + // Es renderitza com a segona línia del text d'INTRO. + [[nodiscard]] auto formatIntroRoomLine(int room) -> std::string; // Nom textual per a logs i tests. No es fa servir per a lògica. [[nodiscard]] auto stateName(State s) -> const char*; diff --git a/source/utils/defaults.hpp b/source/utils/defaults.hpp index 0b4149e..9392e36 100644 --- a/source/utils/defaults.hpp +++ b/source/utils/defaults.hpp @@ -206,8 +206,6 @@ namespace Defaults { namespace Editor { // Color del rectangle 1 px que envolta el canvas durant l'edició. constexpr std::uint32_t BORDER_ARGB = 0xFF2244FFU; - // Ruta de persistència: writer surgical sobre la font del repo. - constexpr const char* SAVE_PATH = "data/maps/pyramid.yaml"; // Píxels entre el canvas i el rectangle del TilePicker per totes // les vores. Prou perquè el border blau de l'editor no es // superpose amb la graella del picker. @@ -231,7 +229,12 @@ namespace Defaults { // en contingui cap literal; afegir una piràmide nova serà un altre // conjunt de constants + un Config distint passat al ctor. namespace Pyramid { - constexpr const char* MAP_YAML = "data/maps/pyramid.yaml"; + // Índex ordenat de les 30 sales (5 piràmides × 6 sales). El consumeix + // `Levels::LevelManager` a la primera invocació; cada entrada apunta + // a un `data/maps/p/r.yaml`. Cap altre punt del codi hauria de + // hardcodejar el path d'una sala concreta — pregunteu-li al + // `LevelManager` (`currentPath()`) i deixeu que ell decidisca. + constexpr const char* LEVELS_YAML = "data/maps/levels.yaml"; constexpr const char* PLAYER_SPRITE = "data/player/sam.gif"; constexpr const char* PLAYER_YAML = "data/player/sam.yaml"; // Personatge del segon jugador. Clonat de sam amb repaletat (roig→blau); diff --git a/source/utils/defines.hpp b/source/utils/defines.hpp index 356380e..1fcbdd0 100644 --- a/source/utils/defines.hpp +++ b/source/utils/defines.hpp @@ -3,7 +3,7 @@ namespace Texts { constexpr const char* WINDOW_TITLE = "© 2026 Aventures en Egipte — JailDesigner"; constexpr const char* COPYRIGHT = "© 2026 JailDesigner"; - constexpr const char* VERSION = "0.25.0"; // Single source of truth — Makefile el grep + constexpr const char* VERSION = "0.26.0"; // Single source of truth — Makefile el grep } // namespace Texts namespace GameCanvas { diff --git a/tests/test_game_fsm.cpp b/tests/test_game_fsm.cpp index bf2a638..b11703c 100644 --- a/tests/test_game_fsm.cpp +++ b/tests/test_game_fsm.cpp @@ -8,8 +8,8 @@ // T6 advance — PLAYING és sumidor: no avança res ni canvia d'estat. // T7 advance — ROOM_OUTRO consumeix les 4 sub-fases i recau a ROOM_INTRO. // T8 advance — un delta gran salta més d'una sub-fase en un sol pas. -// T9 formatRoomTitle — substitueix `{n}` quan el Locale té la clau. -// T10 formatRoomTitle — sense Locale, retorna la pròpia clau (fallback). +// T9 formatIntroPyramidLine / formatIntroRoomLine — substitució amb Locale. +// T10 formatIntroPyramidLine / formatIntroRoomLine — fallback sense Locale. // T11 stateName — strings esperats per a cada State. // // El render no es testeja: la FSM és pura i no pinta res. Les regles de @@ -189,23 +189,29 @@ namespace { } void testFormatRoomTitleWithLocale() { - std::cout << "T9 formatRoomTitle — substitució amb Locale\n"; + std::cout << "T9 formatIntroPyramidLine / formatIntroRoomLine — substitució amb Locale\n"; const auto PATH = (std::filesystem::temp_directory_path() / "aee_test_locale.yaml").string(); - writeTemp(PATH, "game:\n room_intro: \"Sala {n}\"\n"); + writeTemp(PATH, + "game:\n" + " room_intro_pyramid: \"Piramide {p}\"\n" + " room_intro_room: \"Sala {r}\"\n"); Locale::get().load(PATH); - CHECK(RoomFsm::formatRoomTitle(1) == "Sala 1"); - CHECK(RoomFsm::formatRoomTitle(7) == "Sala 7"); + CHECK(RoomFsm::formatIntroPyramidLine(1) == "Piramide 1"); + CHECK(RoomFsm::formatIntroPyramidLine(5) == "Piramide 5"); + CHECK(RoomFsm::formatIntroRoomLine(1) == "Sala 1"); + CHECK(RoomFsm::formatIntroRoomLine(7) == "Sala 7"); std::filesystem::remove(PATH); } void testFormatRoomTitleNoLocale() { - std::cout << "T10 formatRoomTitle — fallback sense traducció\n"; + std::cout << "T10 formatIntroPyramidLine / formatIntroRoomLine — fallback sense traducció\n"; const auto PATH = (std::filesystem::temp_directory_path() / "aee_test_locale_empty.yaml").string(); writeTemp(PATH, "other: foo\n"); Locale::get().load(PATH); - // Sense la clau "game.room_intro", Locale retorna la pròpia clau, - // i com que no porta `{n}`, la substitució no canvia res. - CHECK(RoomFsm::formatRoomTitle(3) == "game.room_intro"); + // Sense les claus, Locale retorna la pròpia clau i com que no + // porten `{p}`/`{r}`, la substitució no canvia res. + CHECK(RoomFsm::formatIntroPyramidLine(3) == "game.room_intro_pyramid"); + CHECK(RoomFsm::formatIntroRoomLine(2) == "game.room_intro_room"); std::filesystem::remove(PATH); }