feat: cartes Événement (pioche partagée de 18 cartes, 6 effets, synergies, ciblage)
- Nouveau server/src/game/events.js : 6 événements (Récolte exceptionnelle, Épidémie, Levée des troupes, Accord royal, Complot découvert, Grande fête au château), deck PARTAGÉ de 18 cartes (3 exemplaires de chacun) mélangé au démarrage de la partie. - Room.js : buyEventDraw() (coût fixe 1 point dans chacune des 4 jauges, effet immédiat contrairement aux objets/bâtiments — pas de conflit de stock possible), playEventCard() (choix de jouer une carte de sa main, max 1 par tour, avec ciblage optionnel), _resolvePendingEventPlays() (résolution de TOUS les événements du tour AVANT le calcul des gains de cartes personnage, défausse systématique, protection "Complot découvert" pour soi-même uniquement). Les 6 effets incluent leurs synergies avec les objets/bâtiments existants (Charrue, Trousse+Église pour Épidémie, Trébuchet, Sceau Royal, Château Royal → pioche bonus). - IMPORTANT : le ciblage de joueur (Accord royal, variante Trousse d'Épidémie) transite par teamIndex (identifiant public) et non socketId (jamais exposé au client via getPlayersInfo/getStateFor) — le serveur résout teamIndex -> joueur réel au moment de la résolution. - Nouvel event socket 'buy-event-draw' (effet immédiat) et 'play-event' (résolution différée), eventResults inclus dans round-result. - Client : events.js (miroir), EventCardObject.js (carte épurée façon CardObject, badge rouge "!" pour les événements à effet négatif). BootScene génère les textures plein cadre (méthode _generateClippedTexture généralisée, réutilisée avec les personnages). - GameScene : bouton de pioche à droite du bouton de confirmation (état grisé selon jauges/main pleine/pioche déjà tentée), seconde main de cartes événement (max 2) au-dessus de ce bouton, sélection d'une carte pour la jouer avec séquence de ciblage interactive (surbrillance des slots adversaires cliquables) pour Accord royal et la variante Trousse d'Épidémie. - 61 nouveaux tests unitaires serveur (events.js + Room.js : pioche, choix de jouer, résolution des 6 effets avec/sans synergie, Complot découvert, ordre événements-avant-personnages, deck partagé). - Nouveaux helpers et tests d'intégration E2E Playwright (e2e/tests/events.spec.js) pour la pioche, la limite de main à 2, et les 6 effets — certains scénarios restent probabilistes (pioche aléatoire dans le deck partagé) et peuvent nécessiter une stabilisation supplémentaire du timing.
This commit is contained in:
1 parent
9139989fa7
commit
1726f8f96b
17 files changed
+1952
-16
No files matched your search
@@ -3,6 +3,7 @@ import { CARD_W, CARD_H, RADIUS } from '../objects/cardLayout'
|
||||
import { ITEM_CARD_W, ITEM_IMAGE_H, ITEM_RADIUS } from '../objects/itemLayout'
|
||||
import { ITEMS } from '../items'
|
||||
import { BUILDINGS } from '../buildings'
|
||||
import { EVENTS } from '../events'
|
||||
|
||||
const CARD_IMAGES = [
|
||||
{ id: 'queen', file: 'reine.png' },
|
||||
@@ -58,12 +59,17 @@ export class BootScene extends Phaser.Scene {
|
||||
BUILDINGS.forEach(({ id, image }) => {
|
||||
this.load.image(`raw-building-${id}`, `/buildings/${image}`)
|
||||
})
|
||||
|
||||
// Charger les images brutes des cartes Événement
|
||||
EVENTS.forEach(({ id, image }) => {
|
||||
this.load.image(`raw-event-${id}`, `/events/${image}`)
|
||||
})
|
||||
}
|
||||
|
||||
create() {
|
||||
// Pour chaque personnage, générer une texture clippée via Canvas 2D
|
||||
CARD_IMAGES.forEach(({ id }) => {
|
||||
this._generateClippedTexture(id)
|
||||
this._generateClippedTexture(`raw-${id}`, `card-${id}`)
|
||||
})
|
||||
|
||||
// Pour chaque objet, générer une texture portrait (zone haute uniquement,
|
||||
@@ -77,18 +83,23 @@ export class BootScene extends Phaser.Scene {
|
||||
this._generatePortraitTexture(`raw-building-${id}`, `building-${id}`)
|
||||
})
|
||||
|
||||
// Pour chaque carte Événement, texture plein cadre (mêmes proportions
|
||||
// que les cartes personnage) — la mécanique diffère mais le rendu visuel
|
||||
// se veut cohérent avec le style épuré de CardObject.
|
||||
EVENTS.forEach(({ id }) => {
|
||||
this._generateClippedTexture(`raw-event-${id}`, `event-${id}`)
|
||||
})
|
||||
|
||||
this.scene.start('GameScene')
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée une texture `card-{id}` de dimensions CARD_W × CARD_H
|
||||
* avec l'image clippée en rectangle arrondi via Canvas 2D natif.
|
||||
* Pas de masque Phaser, pas de RenderTexture — juste du canvas.
|
||||
* Crée une texture `outKey` de dimensions CARD_W × CARD_H avec l'image
|
||||
* clippée en rectangle arrondi via Canvas 2D natif (pas de masque Phaser,
|
||||
* pas de RenderTexture). Réutilisée pour les personnages ET les cartes
|
||||
* Événement, qui partagent le même format "portrait plein cadre".
|
||||
*/
|
||||
_generateClippedTexture(id) {
|
||||
const rawKey = `raw-${id}`
|
||||
const outKey = `card-${id}`
|
||||
|
||||
_generateClippedTexture(rawKey, outKey) {
|
||||
if (!this.textures.exists(rawKey)) return
|
||||
if (this.textures.exists(outKey)) return
|
||||
|
||||
|
||||
Reference in new issue
Block a user