sotc-foundry-suite/sotc-clash-arrow/sotc-clash-arrow-spec.md

6.3 KiB
Raw Blame History

sotc-clash-arrow — Spécification Technique v1.0

Vue d'ensemble

Module FoundryVTT v11 permettant de tracer des flèches courbées entre les Dés de Vitesse du module Stars Initiative Overlay (SIO) de Vani, pour visualiser les clashes dans Star of the City (SotC).

S'appuie sur le module SBSA (clash-resolver) pour lire les compétences assignées aux dés.


Dépendances

Module Rôle
stars-initiative-overlay Fournit les marqueurs PIXI des Dés de Vitesse
clash-resolver (SBSA) Fournit les compétences stockées par dé via flags

Logique des couleurs

Couleur Condition
Bleu #4a9eff A cible B, mais B n'a pas de compétence active sur son dé
Jaune #ffd84a A→B ET B→A existent simultanément (clash mutuel automatique)
Gris #888899 Flèche de preview pendant le drag (avant relâchement)

La détection du clash mutuel est automatique : dès que la flèche A→B est créée alors que B→A existe déjà, les deux flèches passent en jaune.


Interactions utilisateur

Tracer une flèche

  1. Maintenir clic gauche sur un Dé de Vitesse SIO
  2. Déplacer la souris vers un autre dé — la flèche preview change de couleur en temps réel selon la cible survolée
  3. Relâcher sur le dé cible → la flèche devient persistante

Qui peut tracer ? Tous les utilisateurs (GM et joueurs), depuis n'importe quel token.

Supprimer une flèche

  • Clic droit sur un Dé de Vitesse → supprime toutes les flèches depuis/vers ce dé

Reset global

  • Automatique au début d'un nouveau round (hook updateCombat + hook SIO sioRoundReset)
  • Automatique à la fin du combat (deleteCombat)
  • Manuel via le bouton GM dans la barre de contrôles de scène (icône ×)

Architecture des fichiers

sotc-clash-arrow/
├── module.json
├── styles/
│   └── sotc-clash-arrow.css
├── lang/
│   ├── fr.json
│   └── en.json
└── scripts/
    ├── main.js              ← point d'entrée
    ├── Hooks.js             ← enregistrement des hooks FoundryVTT
    ├── ArrowStore.js        ← store centralisé + sync socket
    ├── ClashArrowLayer.js   ← couche PIXI (dessin des flèches)
    ├── DieInteraction.js    ← gestion du drag souris
    └── SIOBridge.js         ← intégration SIO + détection compétences SBSA

Description des modules JS

main.js

  • Point d'entrée unique chargé par module.json
  • Expose globalThis.sotcClashArrow pour débogage console
  • Vérifie la présence du module SIO au ready

ArrowStore.js

  • Store en mémoire (Map<id, Arrow>)
  • Détecte automatiquement le clash mutuel à chaque addArrow()
  • Synchronise via game.socket (événement module.sotc-clash-arrow) pour que tous les clients voient les mêmes flèches
  • Émet un événement change → ClashArrowLayer se redessine

Structure d'une flèche :

{
  id        : "tokenA:0→tokenB:1",
  fromToken : "tokenA_id",
  fromDie   : 0,
  toToken   : "tokenB_id",
  toDie     : 1,
  x1, y1    : number,   // coords canvas du centre du dé source
  x2, y2    : number,   // coords canvas du centre du dé cible
  mutual    : boolean,  // true = flèche jaune
}

ClashArrowLayer.js

  • Hérite de CanvasLayer (FoundryVTT v11)
  • zIndex: 180 → au-dessus des tokens (100), sous l'UI (900+)
  • Deux PIXI.Graphics séparés : flèches persistantes + preview
  • Courbe de Bézier cubique avec pointe de flèche trigonométrique
  • BEZIER_CURVE = 0.35 : facteur de courbure ajustable

DieInteraction.js

  • Écoute pointerdown (via hook interne sotcca:diePointerDown) → démarre le drag
  • pointermove → met à jour la preview avec la couleur calculée en temps réel
  • pointerup → crée la flèche dans ArrowStore si une cible valide est sous le curseur

SIOBridge.js

  • getSIODieCenter() : lit token._initiativeMarkers[i].getBounds() pour les coords canvas
  • findDieUnderPoint() : parcourt tous les tokens/marqueurs, hit-test à ±24px
  • tokenHasActiveSkillOnDie() : combine état SIO (diceStates[i] !== 0) ET présence d'une compétence SBSA (flag "clash-resolver" → "dieSkills"[i])
  • hookSIOMarkers() : attache les listeners sur les marqueurs PIXI existants + futurs (via hook refreshToken)

Hooks.js

  • init : enregistrement du layer dans CONFIG.Canvas.layers
  • canvasReady : init socket + interactions + hook SIO markers
  • canvasTearDown : ArrowStore.clear()
  • updateCombat (nouveau round) + sioRoundReset + deleteCombat → reset
  • getSceneControlButtons : bouton reset GM
  • sotcca:mutualClash : message chat signalant un clash mutuel

Chemins de données supposés (à vérifier)

⚠️ Ces chemins sont des hypothèses basées sur l'analyse du module SIO et SBSA. À valider lors des tests avec les modules installés.

Donnée Chemin supposé
Marqueurs PIXI SIO token._initiativeMarkers[]
États des dés SIO tokenDoc.getFlag("stars-initiative-overlay", "diceStates") → int[]
Nombre de dés actor.system.speed_dice.num_dice
Compétences par dé (SBSA) tokenDoc.getFlag("clash-resolver", "dieSkills") → string[]
Hook reset SIO "sioRoundReset" (à confirmer dans la source SIO)

Synchronisation multi-clients

Toutes les modifications du store sont broadcastées via game.socket.emit("module.sotc-clash-arrow", payload).

Les autres clients reçoivent le payload et appliquent la même modification localement sans re-broadcaster, pour éviter les boucles.

Actions socket :

  • add : nouvelle flèche (+ mise à jour éventuelle de la flèche inverse)
  • remove : suppression d'une flèche (+ dés-mutualisation de l'inverse)
  • clear : reset total

Notes d'implémentation

  • Le layer PIXI est enregistré dans CONFIG.Canvas.layers au hook init, avant la construction du canvas
  • Les listeners sur les marqueurs SIO sont attachés avec un délai de 50ms après refreshToken pour laisser SIO finir de recréer ses containers PIXI
  • Un marqueur déjà hookié est marqué marker._sotcca_hooked = true pour éviter les doublons
  • La flèche de preview utilise alpha = 0.55 pour la distinguer des flèches persistantes (alpha = 0.92)