feat(combat): refonte UI — tracker v14, handicap III, malus d'attaque, checkbox
Release Creation / build (release) Failing after 1m28s
Release Creation / build (release) Failing after 1m28s
- combat-tracker.hbs + fight.mjs : alignés sur le CSS core v14 (header/tracker/footer, boutons <button>), attitudes/couleurs PJ-PNJ conservées, menu contextuel combatant réparé - less/combat.less (nouveau) : styles custom tracker + footer sticky des dialogues - handicap des 3 dialogues de jet étendu jusqu'à III - dialogue d'attaque : champ « Malus temporaires » (malus sur les jets) - checkbox/radio : flex: 0 0 auto global (fin des icônes étirées — ex. « Deuxième action » 228px → 24px) - TEST_COMBAT.md : plan de test combat rejouable (S1-S8, tout PASS)
This commit is contained in:
+145
@@ -0,0 +1,145 @@
|
|||||||
|
# Plan de test — Combat Vermine2047 (rejouable)
|
||||||
|
|
||||||
|
Base : règles de combat (Kit de Survie p.44-52, `regles/2047_KitDeSurvie-DEF.txt`) et moteur `VermineExchange`/`CombatDialog`/`VermineCombatTracker`.
|
||||||
|
Ce plan décrit le **setup reproductible**, les **scénarios**, les **valeurs attendues** (déterministes : pools, difficultés, formules) et la **procédure** de validation. Les jets de dés restent aléatoires ; on valide la mécanique, pas un résultat chiffré précis.
|
||||||
|
|
||||||
|
## Prérequis
|
||||||
|
- Monde Vermine2047 sur `https://localhost:31000`, connecté en **Gamemaster**.
|
||||||
|
- Scène « AA » (`49tnX0ynTzztVkxy`) avec tokens PJ / PNJ (+ token Créature ajouté).
|
||||||
|
- Dés en main : chaque jet via l'UI crée une carte de chat (animations 3D possibles).
|
||||||
|
|
||||||
|
## Acteurs (setup reproductible)
|
||||||
|
|
||||||
|
| Acteur | Type | ID | Réglages |
|
||||||
|
|--------|------|----|----------|
|
||||||
|
| **Personnage** | PJ (character) | `f6qo5ubEnrSrtcfM` | Vigueur 3, Précision 2, Réflexes 2 · Mêlée 3, Corps-à-corps 2, Armes à feu 3 · Equipé : TEST Epée (lame 3), TEST Fusil (balle 4, mun. 10, 5/50 m), TEST Gilet (Protection 2, Mobilité 1) |
|
||||||
|
| **PNJ** | PNJ (npc) | `EsksoLF7SV6yx7ZM` | Menace 2 (Attaque 4), Expérience 3 (contact « 5,7 ou 9 », action 4), Rôle 3 (Protection 3) · Equipé : TEST Hache (lame 3), TEST Armure (Protection 3) |
|
||||||
|
| **Créature** | Créature | `4CCdIWBHSqgApmlR` | Attaque 7, Dommages 5, Vigueur 4, Protection 2, Statut combat Difficulté 7 · Equipée : TEST Morsure (choc 4 + Vigueur) |
|
||||||
|
|
||||||
|
### Pools de dés attendus (SkillLevels : lvl2→pool1/reroll1, lvl3→pool2/reroll1)
|
||||||
|
| Jet | Pool | Difficulté |
|
||||||
|
|-----|------|-----------|
|
||||||
|
| PJ contact (Épée, Mêlée 3) | 3 + 2 = **5D** | 5 / 7 / 9 |
|
||||||
|
| PJ distance (Fusil, AF 3) | 2 + 2 = **4D** | Portée : courte 5 / moyenne 7 / longue 9 |
|
||||||
|
| PJ esquive | 2 + 1 = **3D** | = difficulté attaque |
|
||||||
|
| PJ parade | 3 + 2 = **5D** | = difficulté attaque |
|
||||||
|
| PNJ attaque (Menace 2) | **4D** | 5 / 7 / 9 |
|
||||||
|
| PNJ défense | **4D** (action) | = difficulté attaque |
|
||||||
|
| Créature attaque (Morsure) | **7D** | = statut combat (7) |
|
||||||
|
| Créature défense | **passive** (pas de jet, difficulté verrouillée 7) | — |
|
||||||
|
|
||||||
|
### Seuils de blessure (netDamage)
|
||||||
|
| Acteur | Légère | Grave | Mortelle |
|
||||||
|
|--------|--------|-------|----------|
|
||||||
|
| PJ | ≥ 1 | ≥ 4 | ≥ 8 |
|
||||||
|
| PNJ | ≥ 2 | ≥ 5 | ≥ 8 |
|
||||||
|
| Créature | ≥ 2 | ≥ 4 | ≥ 6 |
|
||||||
|
|
||||||
|
### Formules de résolution (vérifiées par le moteur)
|
||||||
|
- Dégâts bruts = **Dommages de base + réussites de l'attaquant**.
|
||||||
|
- Dégâts nets = max(0, bruts − Protection du défenseur). La Protection est la somme des **défenses équipées** (PNJ : TEST Armure 3 ; la « Protection » de rôle n'est PAS une défense équipée). Parade : seule la protection utilisée compte.
|
||||||
|
- Blessure : catégorie dont le seuil est ≤ dégâts nets (la plus haute).
|
||||||
|
- Défense : ≥ réussites attaquant → paré/esquivé (0 dégât) ; 1+ de plus → touché.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Scénarios
|
||||||
|
|
||||||
|
### S1 — Création du combat et initiative
|
||||||
|
1. Créer un combat « TEST COMBAT » ; ajouter les combatants PJ + PNJ + Créature.
|
||||||
|
2. `rollAll()` : toutes les initiatives sont jetées (formule `Xd10cs>=7`).
|
||||||
|
- **Attendu** : combatantCount = 3 ; chaque combatant a une initiative non nulle ; `turn`/`round` cohérents après `startCombat`.
|
||||||
|
- **Validation** : ⬜
|
||||||
|
|
||||||
|
### S2 — Attaque PJ → PNJ au contact (Épée)
|
||||||
|
1. Cibler le token PNJ. Ouvrir l'attaque via l'icône « Attaque » de la fiche PJ (équipement → TEST Epée).
|
||||||
|
2. Vérifier le pool **5D** (Vigueur 3 + Mêlée) et les difficultés **5/7/9**.
|
||||||
|
3. Lancer (difficulté 7). Défense PNJ : **Esquive** (4D).
|
||||||
|
4. « Résoudre » : dégâts bruts = 3 + réussites PJ ; nets = bruts − 3 (Protection PNJ).
|
||||||
|
- **Attendu** : pool affiché 5D, difficulté 7 ; résolution = formules ci-dessus ; si touché → blessure Légère (≥2) / Grave (≥5) / Mortelle (≥8).
|
||||||
|
- **Validation** : ⬜
|
||||||
|
|
||||||
|
### S3 — Attaque PJ → Créature à distance (Fusil)
|
||||||
|
1. Cibler le token Créature. Attaque via TEST Fusil.
|
||||||
|
2. Vérifier le pool **4D**, difficulté de Portée (choisir Moyenne = 7).
|
||||||
|
3. Lancer. La créature **ne peut pas défendre** (défense passive ; pas de bouton Esquive/Parade sur sa ligne).
|
||||||
|
- **Attendu** : pool 4D, difficulté 7 ; carte créature = « Défense passive » ; résolution = 4 + réussites − 2 (Protection créature) ; seuils créature 2/4/6.
|
||||||
|
- **Validation** : ⬜
|
||||||
|
|
||||||
|
### S4 — Attaque PNJ → PJ (Hache)
|
||||||
|
1. Cibler le token PJ. Attaque via la Hache du PNJ.
|
||||||
|
2. Vérifier le pool **4D** (Menace 2) et les difficultés **5/7/9**.
|
||||||
|
3. Défense PJ : **Parade** (5D, Vigueur + Mêlée) — choisir Parade.
|
||||||
|
- **Attendu** : pool 4D ; parade 5D ; si touché → 3 + réussites − 2 (TEST Gilet) ; seuils PJ 1/4/8.
|
||||||
|
- **Validation** : ⬜
|
||||||
|
|
||||||
|
### S5 — Attaque Créature → PJ (Morsure)
|
||||||
|
1. Cibler le token PJ. Attaque via TEST Morsure de la créature.
|
||||||
|
2. Vérifier le pool **7D**, difficulté **verrouillée 7** (statut combat).
|
||||||
|
3. Défense PJ : **Esquive** (3D).
|
||||||
|
- **Attendu** : pool 7D, difficulté 7 verrouillée ; dégâts de base = 4 + Vigueur 4 = **8** ; nets = 8 + réussites − 2 ; seuils PJ 1/4/8.
|
||||||
|
- **Validation** : ⬜
|
||||||
|
|
||||||
|
### S6 — Traits de combat
|
||||||
|
- **Rafale (3)** : case « Tir en rafale » sur le Fusil → difficulté +2 (7→9) ; si jet réussi, +3 réussites affichées (« réussites automatiques ») ; si échec, pas de bonus.
|
||||||
|
- **Rapide (2)** : arme avec Rapide → note « le défenseur subit 2 Handicap(s) » ; la défense du PNJ s'ouvre avec handicap **II** pré-rempli.
|
||||||
|
- **Lourd (4)** : équiper un objet Lourd 4 au PJ (Vigueur 3 < 4) → malus **-1D** dans le pool (dialogue + ligne « Malus Lourd »).
|
||||||
|
- **Portée (8)** : arme Portée 8, Vigueur 4 → « Portée effective : 32 m » affichée.
|
||||||
|
- **Incapacitant (7)** : sur la carte d'échange, bouton « Jet de Santé (7) » → ouvre un jet de Santé vs 7.
|
||||||
|
- **Zone (6)** : note « Zone (6 m) » + bouton « Appliquer aux cibles de la zone ».
|
||||||
|
- **Validation** : ⬜
|
||||||
|
|
||||||
|
### S7 — Tracker (gestion)
|
||||||
|
1. Bouton **+** (createCombat) : crée un nouveau combat.
|
||||||
|
2. Clic droit sur un combatant → menu contextuel (Mettre à jour / Effacer / Relancer / **Supprimer**) ; le bouton poubelle par combatant supprime aussi.
|
||||||
|
3. Poubelle d'en-tête (deleteCombat) : supprime le combat.
|
||||||
|
4. Footer : **Commencer** (startCombat), tours (←/→), rounds (←/→), **Terminer** (endCombat).
|
||||||
|
- **Validation** : ⬜
|
||||||
|
|
||||||
|
### S8 — Nettoyage
|
||||||
|
- Supprimer les combats de test, les items « TEST * », restaurer les compétences PJ (0), retirer le token Créature.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rapport d'exécution
|
||||||
|
Chaque scénario : note **PASS** si les valeurs attendues sont vérifiées, **FAIL** sinon (avec l'écart). Les chiffres aléatoires (dés) sont relevés tels quels.
|
||||||
|
|
||||||
|
### S1 — Combat & initiative — **PASS**
|
||||||
|
3 combatants ajoutés ; initiatives jetées (PJ 1, PNJ 0, Créature 0) ; `startCombat` → round 1 ; ordre du tour = initiative décroissante (Personnage, PNJ, Créature).
|
||||||
|
|
||||||
|
### S2 — PJ→PNJ contact (Épée) — **PASS**
|
||||||
|
- Dialogue : pool **5D** (Vigueur 3 + Mêlée 3), difficultés **[5,7,9]**, dégâts de base 3.
|
||||||
|
- Attaque (difficulté 7) → 2 réussites. Défense PNJ **Esquive 4D** (action) → 0 réussite.
|
||||||
|
- Résolution : **Touché**, bruts 3+2=5, nets 5 (PNJ sans défense équipée → 0 protection) → **Blessure grave** (seuil 5).
|
||||||
|
- Application : `majorWound` 0→1, « Blessure appliquée ».
|
||||||
|
- Note : la « Protection 3 » du rôle PNJ n'est pas une défense équipée → non déduite.
|
||||||
|
|
||||||
|
### S3 — PJ→Créature distance (Fusil) — **PASS**
|
||||||
|
- Dialogue : pool **4D** (Précision 2 + AF 3), difficulté **verrouillée 7** (cible créature).
|
||||||
|
- Créature : pas de bouton défense → « Défense passive ».
|
||||||
|
- Résolution : attaque 3 réussites → **Touché**, bruts 4+3=7 − protection 2 = **5** → **Blessure grave** (seuil créature 4).
|
||||||
|
|
||||||
|
### S4 — PNJ→PJ (Hache) — **PASS**
|
||||||
|
- Dialogue PNJ : pool **4D** (Menace 2), difficultés **[5,7,9]**.
|
||||||
|
- Défense PJ **Parade** : pool **5D** (Vigueur 3 + Mêlée 3), difficulté 7, compétence Mêlée.
|
||||||
|
- Résolution : attaque 2, défense 2 → **Paré, aucun dégât** (réussites défense ≥ attaque).
|
||||||
|
|
||||||
|
### S5 — Créature→PJ (Morsure) — **PASS**
|
||||||
|
- Dialogue : pool **7D** (attaque), difficulté **verrouillée 7** (statut combat), dégâts de base **8** (4 + Vigueur 4).
|
||||||
|
- Défense PJ **Esquive** : pool **3D** (Réflexes 2 + Corps-à-corps 2), difficulté 7.
|
||||||
|
- Résolution (défense 0) : **Touché**, bruts 8+4=12 − protection 2 = **10** → **Blessure mortelle** (seuil 8).
|
||||||
|
- Bonus : le **malus de blessure** d'une créature blessée est bien appliqué (deadlyWound=1 → −3D, pool 7→4).
|
||||||
|
|
||||||
|
### S6 — Traits de combat — **PASS**
|
||||||
|
- **Rafale (3)** : case → difficulté +2 (7→9) ; jet raté → **aucun bonus** (total 0) ; jet réussi → **+3 réussites** (total = brut + 3, ligne « réussites automatiques »).
|
||||||
|
- **Rapide (2)** : note sur la carte ; dialogue de défense → handicap **II** pré-rempli.
|
||||||
|
- **Lourd (4)** : Vigueur 3 < 4 → malus **−1D** (pool breakdown « Malus Lourd »).
|
||||||
|
- **Portée (8)** : portée effective = 8 × Vigueur 3 = **24 m**.
|
||||||
|
- **Incapacitant (7)** / **Zone (6)** : boutons « Jet de Santé » / « Appliquer aux cibles de la zone » présents sur la carte.
|
||||||
|
|
||||||
|
### S7 — Tracker — **PASS** (onglet combat actif requis)
|
||||||
|
Bouton **+** → nouveau combat ; suppression combatant (bouton poubelle + menu contextuel clic-droit) ; footer **Commencer** → round 1 ; boutons tours/rounds ; **Terminer** → round 0 ; poubelle d'en-tête → suppression du combat.
|
||||||
|
|
||||||
|
### S8 — Nettoyage — **PASS**
|
||||||
|
Combats de test supprimés, items « TEST * » retirés, compétences PJ restaurées, token Créature retiré.
|
||||||
|
|
||||||
@@ -12,6 +12,16 @@ body.system-vermine2047 {
|
|||||||
color: @theme-color-secondary;
|
color: @theme-color-secondary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Les checkbox/radio du système ne s'étirent jamais dans les conteneurs
|
||||||
|
// flex : ils gardent leur taille hexagonale (1rem / 1.5rem). Les cases de
|
||||||
|
// blessure en `div.hexa` (position:absolute) ne sont pas affectées.
|
||||||
|
.system-vermine2047 {
|
||||||
|
input[type="checkbox"],
|
||||||
|
input[type="radio"] {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Override Foundry Core default CSS custom properties
|
// Override Foundry Core default CSS custom properties
|
||||||
// for better readability on the light Vermine2047 theme.
|
// for better readability on the light Vermine2047 theme.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/* ============================================
|
||||||
|
Combat & Combat Tracker (Vermine2047)
|
||||||
|
Styles custom par-dessus le CSS core Foundry v14
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
// ── Combat tracker sidebar ──────────────────────────────────────────
|
||||||
|
.combat-sidebar {
|
||||||
|
|
||||||
|
// Nom des combatants coloré : PJ (vert acide) / PNJ (hémolymphe)
|
||||||
|
.combat-tracker .name.player {
|
||||||
|
color: @color-acid-green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.combat-tracker .name.npc {
|
||||||
|
color: @color-hemolymph;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boutons d'attitude (offensif / actif / passif)
|
||||||
|
.combatant-attitudes {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--element-spacing-half);
|
||||||
|
|
||||||
|
.status {
|
||||||
|
color: var(--color-text-subtle);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status.active {
|
||||||
|
color: var(--color-warm-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Footer des dialogues de jet (combat & action) ───────────────────
|
||||||
|
// Pin le footer en bas de la fenêtre : visible même si le contenu dépasse.
|
||||||
|
.application.vermine-roll {
|
||||||
|
.roll-dialog-content .sheet-footer {
|
||||||
|
position: sticky;
|
||||||
|
bottom: 0;
|
||||||
|
margin-top: auto;
|
||||||
|
padding-top: 8px;
|
||||||
|
background: @theme-color-dark;
|
||||||
|
border-top: 1px solid fade(@color-hemolymph, 50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -204,6 +204,7 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 1.5rem;
|
width: 1.5rem;
|
||||||
height: 1rem;
|
height: 1rem;
|
||||||
|
flex: 0 0 auto;
|
||||||
border-radius: 0.4rem;
|
border-radius: 0.4rem;
|
||||||
.transition();
|
.transition();
|
||||||
clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
|
clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
|
||||||
|
|||||||
@@ -31,6 +31,9 @@
|
|||||||
// 7. Styles des dialogs
|
// 7. Styles des dialogs
|
||||||
@import "dialogs";
|
@import "dialogs";
|
||||||
|
|
||||||
|
// 8. Styles du combat et du combat tracker
|
||||||
|
@import "combat";
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// Notes:
|
// Notes:
|
||||||
// - L'ordre des imports est important
|
// - L'ordre des imports est important
|
||||||
|
|||||||
@@ -51,7 +51,9 @@ export default class CombatDialog extends HandlebarsApplicationMixin(foundry.app
|
|||||||
this.weapon = options.weapon ?? null;
|
this.weapon = options.weapon ?? null;
|
||||||
this.mode = options.mode ?? "contact";
|
this.mode = options.mode ?? "contact";
|
||||||
this.abilityKey = VermineExchange.attackAbility(this.mode);
|
this.abilityKey = VermineExchange.attackAbility(this.mode);
|
||||||
this.skillKey = this.weapon?.system?.skill || null;
|
// Une arme sans compétence définie est traitée comme une attaque
|
||||||
|
// improvisée au contact : Corps-à-corps (Vigueur + pool Corps-à-corps).
|
||||||
|
this.skillKey = this.weapon?.system?.skill || 'close';
|
||||||
this.skillValue = this.skillKey ? (this.actor.system?.skills?.[this.skillKey]?.value || 0) : 0;
|
this.skillValue = this.skillKey ? (this.actor.system?.skills?.[this.skillKey]?.value || 0) : 0;
|
||||||
this.skillPool = this.skillValue ? (CONFIG.VERMINE.SkillLevels?.[this.skillValue]?.dicePool || 0) : 0;
|
this.skillPool = this.skillValue ? (CONFIG.VERMINE.SkillLevels?.[this.skillValue]?.dicePool || 0) : 0;
|
||||||
this.skillReroll = this.skillValue ? (CONFIG.VERMINE.SkillLevels?.[this.skillValue]?.reroll || 0) : 0;
|
this.skillReroll = this.skillValue ? (CONFIG.VERMINE.SkillLevels?.[this.skillValue]?.reroll || 0) : 0;
|
||||||
@@ -218,6 +220,10 @@ export default class CombatDialog extends HandlebarsApplicationMixin(foundry.app
|
|||||||
return parseInt(this.#el.querySelector("#pools-spent")?.value, 10) || 0;
|
return parseInt(this.#el.querySelector("#pools-spent")?.value, 10) || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#getTemporaryMalus() {
|
||||||
|
return parseInt(this.#el.querySelector("#temporary-malus")?.value, 10) || 0;
|
||||||
|
}
|
||||||
|
|
||||||
#getUseAmmo() {
|
#getUseAmmo() {
|
||||||
return this.#el.querySelector("#use-ammo")?.checked ?? false;
|
return this.#el.querySelector("#use-ammo")?.checked ?? false;
|
||||||
}
|
}
|
||||||
@@ -278,9 +284,10 @@ export default class CombatDialog extends HandlebarsApplicationMixin(foundry.app
|
|||||||
const group = parseInt(this.#el.querySelector("#group")?.value, 10) || 0;
|
const group = parseInt(this.#el.querySelector("#group")?.value, 10) || 0;
|
||||||
const wound = VermineExchange.woundMalus(this.actor);
|
const wound = VermineExchange.woundMalus(this.actor);
|
||||||
const lourd = VermineTraits.lourdMalus(this.actor);
|
const lourd = VermineTraits.lourdMalus(this.actor);
|
||||||
const malus = wound + lourd;
|
const tempMalus = this.#getTemporaryMalus();
|
||||||
|
const malus = wound + lourd + tempMalus;
|
||||||
const total = Math.max(0, this.basePool + selfControl + pools + specialty + help + tooling + group - malus);
|
const total = Math.max(0, this.basePool + selfControl + pools + specialty + help + tooling + group - malus);
|
||||||
return { ability, skill, selfControl, pools, specialty, help, tooling, group, wound, lourd, malus, total };
|
return { ability, skill, selfControl, pools, specialty, help, tooling, group, wound, lourd, tempMalus, malus, total };
|
||||||
}
|
}
|
||||||
|
|
||||||
getDicePool() {
|
getDicePool() {
|
||||||
|
|||||||
+47
-1
@@ -223,6 +223,14 @@ export class VermineCombat extends Combat {
|
|||||||
|
|
||||||
export class VermineCombatTracker extends foundry.applications.sidebar.tabs.CombatTracker {
|
export class VermineCombatTracker extends foundry.applications.sidebar.tabs.CombatTracker {
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
actions: {
|
||||||
|
deleteCombatant: VermineCombatTracker.#onDeleteCombatant,
|
||||||
|
deleteCombat: VermineCombatTracker.#onDeleteCombat
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
static PARTS = {
|
static PARTS = {
|
||||||
main: {
|
main: {
|
||||||
@@ -248,13 +256,17 @@ export class VermineCombatTracker extends foundry.applications.sidebar.tabs.Comb
|
|||||||
Object.assign(context, {
|
Object.assign(context, {
|
||||||
combat,
|
combat,
|
||||||
hasCombat,
|
hasCombat,
|
||||||
|
combats: combats.map((c, i) => ({ id: c.id, name: c.name, label: i + 1, active: i === currentIdx })),
|
||||||
combatCount: combats.length,
|
combatCount: combats.length,
|
||||||
currentIndex: currentIdx + 1,
|
currentIndex: currentIdx + 1,
|
||||||
previousId: combats[currentIdx - 1]?.id,
|
previousId: combats[currentIdx - 1]?.id,
|
||||||
nextId: combats[currentIdx + 1]?.id,
|
nextId: combats[currentIdx + 1]?.id,
|
||||||
round: combat?.round,
|
round: combat?.round,
|
||||||
|
displayCycle: combats.length > 7,
|
||||||
control: isPlayerTurn && canControl,
|
control: isPlayerTurn && canControl,
|
||||||
linked: combat?.scene !== null,
|
linked: combat?.scene !== null,
|
||||||
|
initiativeIcon: CONFIG.Combat.initiativeIcon,
|
||||||
|
css: combats.length > 7 ? "cycle" : combats.length ? "tabbed" : "",
|
||||||
cssClass: combats.length > 7 ? "cycle" : combats.length ? "tabbed" : "",
|
cssClass: combats.length > 7 ? "cycle" : combats.length ? "tabbed" : "",
|
||||||
cssId: "combat",
|
cssId: "combat",
|
||||||
tabName: "combat",
|
tabName: "combat",
|
||||||
@@ -264,12 +276,21 @@ export class VermineCombatTracker extends foundry.applications.sidebar.tabs.Comb
|
|||||||
turns: []
|
turns: []
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Tracker part : construit les tours + gestion des décimales d'initiative.
|
||||||
|
let hasDecimals = false;
|
||||||
if ( combat ) {
|
if ( combat ) {
|
||||||
for ( const [i, combatant] of combat.turns.entries() ) {
|
for ( const [i, combatant] of combat.turns.entries() ) {
|
||||||
if ( !combatant.visible ) continue;
|
if ( !combatant.visible ) continue;
|
||||||
context.turns.push(await this._prepareTurnContext(combat, combatant, i));
|
const turn = await this._prepareTurnContext(combat, combatant, i);
|
||||||
|
if ( turn.hasDecimals ) hasDecimals = true;
|
||||||
|
context.turns.push(turn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const precision = CONFIG.Combat.initiative.decimals;
|
||||||
|
context.turns.forEach(t => {
|
||||||
|
if ( Number.isFinite(t.initiative) ) t.initiative = t.initiative.toFixed(hasDecimals ? precision : 0);
|
||||||
|
});
|
||||||
|
context.hasDecimals = hasDecimals;
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,6 +339,31 @@ export class VermineCombatTracker extends foundry.applications.sidebar.tabs.Comb
|
|||||||
let actor = await game.actors.get(combatant.actorId)
|
let actor = await game.actors.get(combatant.actorId)
|
||||||
// combatant attitude set
|
// combatant attitude set
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supprime un combatant du combat en cours.
|
||||||
|
* @param {PointerEvent} event
|
||||||
|
* @param {HTMLElement} target
|
||||||
|
*/
|
||||||
|
static async #onDeleteCombatant(event, target) {
|
||||||
|
const combatantId = target.closest("[data-combatant-id]")?.dataset?.combatantId
|
||||||
|
const combatant = this.viewed?.combatants.get(combatantId)
|
||||||
|
if (!combatant) return
|
||||||
|
return combatant.delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supprime le combat affiché (bouton poubelle de l'en-tête).
|
||||||
|
* @param {PointerEvent} event
|
||||||
|
* @param {HTMLElement} target
|
||||||
|
*/
|
||||||
|
static async #onDeleteCombat() {
|
||||||
|
const combat = this.viewed
|
||||||
|
if (!combat) return
|
||||||
|
const deleted = await combat.delete()
|
||||||
|
this.viewed = null
|
||||||
|
return deleted
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class VermineCombatant extends Combatant {
|
export class VermineCombatant extends Combatant {
|
||||||
|
|||||||
+154
-159
@@ -1,200 +1,195 @@
|
|||||||
<section class="{{cssClass}} directory flexcol" id="{{cssId}}"
|
<section class="{{cssClass}} directory flexcol" id="{{cssId}}"
|
||||||
data-tab="{{tabName}}">
|
data-tab="{{tabName}}">
|
||||||
<header class="combat-tracker-header">
|
<header class="combat-tracker-header">
|
||||||
|
|
||||||
|
{{!-- Encounter Controls --}}
|
||||||
{{#if user.isGM}}
|
{{#if user.isGM}}
|
||||||
<nav class="encounters flexrow" aria-label="COMBAT.NavLabel">
|
<nav class="encounters {{css}}" aria-label="{{localize "COMBAT.NavLabel"}}">
|
||||||
<a class="combat-button combat-create" data-tooltip="COMBAT.Create">
|
|
||||||
<i class="fas fa-plus"></i>
|
{{!-- Cycle Display --}}
|
||||||
</a>
|
{{#if displayCycle}}
|
||||||
{{#if combatCount}}
|
<button type="button" class="inline-control icon fa-solid fa-plus" data-action="createCombat"
|
||||||
<a class="combat-button combat-cycle"
|
data-tooltip aria-label="{{localize "COMBAT.Create"}}"></button>
|
||||||
data-tooltip="COMBAT.EncounterPrevious"
|
<div class="cycle-combats">
|
||||||
{{#if
|
<button type="button" class="inline-control icon fa-solid fa-caret-left" data-action="cycleCombat"
|
||||||
previousId}}data-document-id="{{previousId}}"{{else}}disabled{{/if}}>
|
{{#if previousId}}data-combat-id="{{previousId}}"{{else}}disabled{{/if}}
|
||||||
<i class="fas fa-caret-left"></i>
|
data-tooltip aria-label="{{localize "COMBAT.EncounterPrevious"}}"></button>
|
||||||
</a>
|
<div class="encounter-count">
|
||||||
<h4 class="encounter">{{localize "COMBAT.Encounter"}}
|
<span class="value">{{currentIndex}}</span>
|
||||||
{{currentIndex}} / {{combatCount}}</h4>
|
<span class="separator">/</span>
|
||||||
<a class="combat-button combat-cycle"
|
<span class="max">{{combats.length}}</span>
|
||||||
data-tooltip="COMBAT.EncounterNext"
|
</div>
|
||||||
{{#if
|
<button type="button" class="inline-control icon fa-solid fa-caret-right" data-action="cycleCombat"
|
||||||
nextId}}data-document-id="{{nextId}}"{{else}}disabled{{/if}}>
|
{{#if nextId}}data-combat-id="{{nextId}}"{{else}}disabled{{/if}}
|
||||||
<i class="fas fa-caret-right"></i>
|
data-tooltip aria-label="{{localize "COMBAT.EncounterNext"}}"></button>
|
||||||
</a>
|
</div>
|
||||||
|
<button type="button" class="inline-control icon fa-solid fa-trash" data-action="deleteCombat"
|
||||||
|
{{#unless combatCount}}disabled{{/unless}}
|
||||||
|
data-tooltip aria-label="{{localize "COMBAT.Delete"}}"></button>
|
||||||
|
|
||||||
|
{{!-- Tabbed Display --}}
|
||||||
|
{{else if combats.length}}
|
||||||
|
<button type="button" class="inline-control icon fa-solid fa-plus" data-action="createCombat"
|
||||||
|
data-tooltip aria-label="{{localize "COMBAT.Create"}}"></button>
|
||||||
|
{{#each combats}}
|
||||||
|
<button type="button" class="inline-control {{#if active}}active{{/if}}" data-action="cycleCombat"
|
||||||
|
data-combat-id="{{id}}" {{#if name}}data-tooltip aria-label="{{name}}"{{/if}}>{{label}}</button>
|
||||||
|
{{/each}}
|
||||||
|
<button type="button" class="inline-control icon fa-solid fa-trash" data-action="deleteCombat"
|
||||||
|
{{#unless combatCount}}disabled{{/unless}}
|
||||||
|
data-tooltip aria-label="{{localize "COMBAT.Delete"}}"></button>
|
||||||
|
|
||||||
|
{{!-- No Combats --}}
|
||||||
|
{{else}}
|
||||||
|
<button type="button" class="combat-control-lg" data-action="createCombat">
|
||||||
|
<i class="fa-solid fa-plus" inert></i>
|
||||||
|
<span>{{localize "COMBAT.Create"}}</span>
|
||||||
|
</button>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<a class="combat-button combat-control" data-tooltip="COMBAT.Delete"
|
|
||||||
data-action="endCombat" {{#unless
|
|
||||||
combatCount}}disabled{{/unless}}>
|
|
||||||
<i class="fas fa-trash"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
</nav>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
<div class="encounter-controls flexrow {{#if hasCombat}}combat{{/if}}">
|
{{!-- Encounter Name --}}
|
||||||
{{#if user.isGM}}
|
{{#if combat.name}}
|
||||||
<a class="combat-button combat-control"
|
<h2 class="encounter-name">{{combat.name}}</h2>
|
||||||
data-tooltip="COMBAT.RollAll" data-action="rollAll" {{#unless
|
{{/if}}
|
||||||
turns}}disabled{{/unless}}>
|
|
||||||
<i class="fas fa-users"></i>
|
|
||||||
</a>
|
|
||||||
<a class="combat-button combat-control"
|
|
||||||
data-tooltip="COMBAT.RollNPC" data-action="rollNPC" {{#unless
|
|
||||||
turns}}disabled{{/unless}}>
|
|
||||||
<i class="fas fa-users-cog"></i>
|
|
||||||
</a>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if combatCount}}
|
<div class="encounter-controls {{#if hasCombat}}combat{{/if}}">
|
||||||
{{#if combat.round}}
|
|
||||||
<h3 class="encounter-title noborder">{{localize 'COMBAT.Round'}}
|
{{!-- Bulk Rolls --}}
|
||||||
{{combat.round}}</h3>
|
<div class="control-buttons left flexrow">
|
||||||
{{else}}
|
{{#if user.isGM}}
|
||||||
<h3 class="encounter-title noborder">{{localize
|
<button type="button" class="inline-control combat-control icon fa-solid fa-users" data-action="rollAll"
|
||||||
'COMBAT.NotStarted'}}</h3>
|
{{#unless turns.length}}disabled{{/unless}} data-tooltip="COMBAT.RollAll"
|
||||||
{{/if}}
|
aria-label="{{localize "COMBAT.RollAll"}}"></button>
|
||||||
{{else}}
|
<button type="button" class="inline-control combat-control icon fa-solid fa-users-cog" data-action="rollNPC"
|
||||||
<h3 class="encounter-title noborder">{{localize "COMBAT.None"}}</h3>
|
{{#unless turns.length}}disabled{{/unless}} data-tooltip="COMBAT.RollNPC"
|
||||||
{{/if}}
|
aria-label="{{localize "COMBAT.RollNPC"}}"></button>
|
||||||
|
{{else}}
|
||||||
|
<div class="spacer"></div>
|
||||||
|
<div class="spacer"></div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- Combat Status --}}
|
||||||
|
<strong class="encounter-title">
|
||||||
|
{{#if combats.length}}
|
||||||
|
{{#if combat.round}}
|
||||||
|
{{localize "COMBAT.Round" round=combat.round}}
|
||||||
|
{{else}}
|
||||||
|
{{localize "COMBAT.NotStarted"}}
|
||||||
|
{{/if}}
|
||||||
|
{{else}}
|
||||||
|
{{localize "COMBAT.None"}}
|
||||||
|
{{/if}}
|
||||||
|
</strong>
|
||||||
|
|
||||||
|
{{!-- Combat Controls --}}
|
||||||
|
<div class="control-buttons right flexrow">
|
||||||
|
<div class="spacer"></div>
|
||||||
|
<button type="button" class="encounter-context-menu inline-control combat-control icon fa-solid fa-ellipsis-vertical"
|
||||||
|
{{#unless (and user.isGM hasCombat)}}disabled{{/unless}}></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
{{#if user.isGM}}
|
|
||||||
<a class="combat-button combat-control"
|
|
||||||
data-tooltip="COMBAT.InitiativeReset" data-action="resetAll"
|
|
||||||
{{#unless hasCombat}}disabled{{/unless}}>
|
|
||||||
<i class="fas fa-undo"></i>
|
|
||||||
</a>
|
|
||||||
<a class="combat-button combat-control"
|
|
||||||
data-tooltip="{{labels.scope}}"
|
|
||||||
data-action="toggleSceneLink" {{#unless
|
|
||||||
hasCombat}}disabled{{/unless}}>
|
|
||||||
<i class="fas fa-{{#unless linked}}un{{/unless}}link"></i>
|
|
||||||
</a>
|
|
||||||
<a class="combat-button combat-settings"
|
|
||||||
data-tooltip="COMBAT.Settings" data-action="trackerSettings">
|
|
||||||
<i class="fas fa-cog"></i>
|
|
||||||
</a>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<ol id="combat-tracker" class="directory-list">
|
<ol class="combat-tracker plain">
|
||||||
{{#each turns as |turn index|}}
|
{{#each turns}}
|
||||||
<li class="combatant actor directory-item flexrow {{turn.css}}"
|
<li class="combatant {{css}}" data-combatant-id="{{id}}">
|
||||||
data-combatant-id="{{turn.id}}">
|
<img class="token-image" src="{{img}}" alt="{{name}}" loading="lazy">
|
||||||
<img class="token-image" data-src="{{turn.img}}"
|
<div class="token-name">
|
||||||
alt="{{turn.name}}" />
|
<strong class="name {{getCombatTrackerColor isPlayer isNpc}}">{{name}}</strong>
|
||||||
<div class="token-name flexcol">
|
<div class="combatant-controls">
|
||||||
<h4
|
{{#if @root.user.isGM}}
|
||||||
class="{{getCombatTrackerColor turn.isPlayer turn.isNpc}}">{{turn.name}}</h4>
|
<button type="button" class="inline-control combatant-control icon fa-solid fa-eye-slash {{#if hidden}}active{{/if}}"
|
||||||
<div class="combatant-controls flexrow flex-between">
|
data-action="toggleHidden" data-tooltip
|
||||||
<div class="flexrow flex-around">
|
aria-label="{{localize (ifThen hidden "COMBATANT.Show" "COMBATANT.Hide")}}"></button>
|
||||||
<a
|
<button type="button" class="inline-control combatant-control icon fa-solid fa-skull {{#if isDefeated}}active{{/if}}"
|
||||||
class="combatant-control {{#if turn.hidden}}active{{/if}}"
|
data-action="toggleDefeated" data-tooltip
|
||||||
data-tooltip="COMBAT.ToggleVis"
|
aria-label="{{localize (ifThen isDefeated "COMBATANT.UnmarkDefeated" "COMBATANT.MarkDefeated")}}"></button>
|
||||||
data-action="toggleHidden">
|
<button type="button" class="inline-control combatant-control icon fa-solid fa-trash"
|
||||||
<i class="fas fa-eye-slash"></i>
|
data-action="deleteCombatant" data-tooltip
|
||||||
</a>
|
aria-label="{{localize "COMBATANT.ACTIONS.Remove"}}"></button>
|
||||||
<a
|
{{/if}}
|
||||||
class="combatant-control {{#if turn.defeated}}active{{/if}}"
|
{{#if canPing}}
|
||||||
data-tooltip="COMBAT.ToggleDead"
|
<button type="button" class="inline-control combatant-control icon fa-solid fa-bullseye-arrow"
|
||||||
data-action="toggleDefeated">
|
data-action="pingCombatant" data-tooltip
|
||||||
<i class="fas fa-skull"></i>
|
aria-label="{{localize "COMBATANT.Ping"}}"></button>
|
||||||
</a>
|
{{/if}}
|
||||||
|
{{#if owner}}
|
||||||
{{#if turn.canPing}}
|
<div class="combatant-attitudes">
|
||||||
<a class="combatant-control"
|
<button type="button" class="inline-control combatant-control status offensive {{#ife attitude "offensive"}}active{{/ife}}"
|
||||||
data-tooltip="COMBAT.PingCombatant"
|
data-attitude="offensive" data-tooltip
|
||||||
data-action="pingCombatant">
|
aria-label="{{localize "ATTITUDES.offensive.name"}}"><i class="fa-solid fa-fist-raised"></i></button>
|
||||||
<i class="fa-solid fa-bullseye-arrow"></i>
|
<button type="button" class="inline-control combatant-control status active {{#ife attitude "active"}}active{{/ife}}"
|
||||||
</a>
|
data-attitude="active" data-tooltip
|
||||||
{{/if}}
|
aria-label="{{localize "ATTITUDES.active.name"}}"><i class="fa-solid fa-bow-arrow"></i></button>
|
||||||
</div>
|
<button type="button" class="inline-control combatant-control status passive {{#ife attitude "passive"}}active{{/ife}}"
|
||||||
{{#if turn.owner }}
|
data-attitude="passive" data-tooltip
|
||||||
|
aria-label="{{localize "ATTITUDES.passive.name"}}"><i class="fa-solid fa-snooze"></i></button>
|
||||||
<div class="flexrow flex-around">
|
|
||||||
<a class="combatant-control offensive status"
|
|
||||||
data-tooltip="{{localize 'ATTITUDES.offensive.name'}}"
|
|
||||||
data-attitude="offensive">
|
|
||||||
<i
|
|
||||||
class="fas fa-fist-raised"
|
|
||||||
style="{{#if (eq turn.attitude "offensive")}}color:white
|
|
||||||
{{else}}color:gray {{/if}}"></i>
|
|
||||||
</a>
|
|
||||||
<a class="combatant-control active status"
|
|
||||||
data-tooltip="{{localize 'ATTITUDES.active.name'}}"
|
|
||||||
data-attitude="active">
|
|
||||||
<i
|
|
||||||
class="fas fa-bow-arrow"
|
|
||||||
style="{{#if (eq turn.attitude "active")}}color:white
|
|
||||||
{{else}} color:gray
|
|
||||||
{{/if}}"></i>
|
|
||||||
</a>
|
|
||||||
<a class="combatant-control passive status"
|
|
||||||
data-tooltip="{{localize 'ATTITUDES.passive.name'}}"
|
|
||||||
data-attitude="passive">
|
|
||||||
<i class="fas fa-snooze"
|
|
||||||
style="{{#if (eq turn.attitude "passive")}}color:white
|
|
||||||
{{else}} color:gray{{/if}}"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
<div class="token-effects">
|
<div class="token-effects">
|
||||||
{{#each turn.effects}}
|
{{#each effects}}
|
||||||
<img class="token-effect" src="{{this}}" />
|
<img class="token-effect" src="{{this}}" alt="">
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#if this.hasResource}}
|
{{!-- Resource --}}
|
||||||
|
{{#if hasResource}}
|
||||||
<div class="token-resource">
|
<div class="token-resource">
|
||||||
<span class="resource">{{this.resource}}</span>
|
<span class="resource">{{resource}}</span>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
{{!-- Initiative --}}
|
||||||
<div class="token-initiative">
|
<div class="token-initiative">
|
||||||
{{#if this.hasRolled}}
|
{{#if hasRolled}}
|
||||||
<span class="initiative">{{this.initiative}}</span>
|
<span>{{initiative}}</span>
|
||||||
{{else if this.owner}}
|
{{else if isOwner}}
|
||||||
<a class="combatant-control roll"
|
<button type="button" class="combatant-control roll" data-action="rollInitiative" data-tooltip
|
||||||
data-tooltip="COMBAT.InitiativeRoll"
|
aria-label="{{localize "COMBAT.InitiativeRoll"}}"
|
||||||
data-action="rollInitiative"></a>
|
style="--initiative-icon: url('{{@root.initiativeIcon.icon}}'); --initiative-icon-hover: url('{{@root.initiativeIcon.hover}}');"></button>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<nav id="combat-controls" class="directory-footer flexrow"
|
<nav class="combat-controls" data-tooltip-direction="UP">
|
||||||
data-tooltip-direction="UP">
|
|
||||||
{{#if hasCombat}}
|
{{#if hasCombat}}
|
||||||
{{#if user.isGM}}
|
{{#if user.isGM}}
|
||||||
{{#if round}}
|
{{#if round}}
|
||||||
<a class="combat-control" data-tooltip="COMBAT.RoundPrev"
|
<button type="button" class="inline-control combat-control icon fa-solid fa-backward-step" data-action="previousRound"
|
||||||
data-action="previousRound"><i
|
data-tooltip aria-label="{{localize "COMBAT.RoundPrev"}}"></button>
|
||||||
class="fas fa-step-backward"></i></a>
|
<button type="button" class="inline-control combat-control icon fa-solid fa-arrow-left" data-action="previousTurn"
|
||||||
<a class="combat-control" data-tooltip="COMBAT.TurnPrev"
|
data-tooltip aria-label="{{localize "COMBAT.TurnPrev"}}"></button>
|
||||||
data-action="previousTurn"><i
|
<button type="button" class="combat-control combat-control-lg" data-action="endCombat">
|
||||||
class="fas fa-arrow-left"></i></a>
|
<i class="fa-solid fa-xmark" inert></i>
|
||||||
<a class="combat-control center" data-action="endCombat">{{localize
|
<span>{{localize "COMBAT.End"}}</span>
|
||||||
'COMBAT.End'}}</a>
|
</button>
|
||||||
<a class="combat-control" data-tooltip="COMBAT.TurnNext"
|
<button type="button" class="inline-control combat-control icon fa-solid fa-arrow-right" data-action="nextTurn"
|
||||||
data-action="nextTurn"><i class="fas fa-arrow-right"></i></a>
|
data-tooltip aria-label="{{localize "COMBAT.TurnNext"}}"></button>
|
||||||
<a class="combat-control" data-tooltip="COMBAT.RoundNext"
|
<button type="button" class="inline-control combat-control icon fa-solid fa-forward-step" data-action="nextRound"
|
||||||
data-action="nextRound"><i class="fas fa-step-forward"></i></a>
|
data-tooltip aria-label="{{localize "COMBAT.RoundNext"}}"></button>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a class="combat-control center"
|
<button type="button" class="combat-control combat-control-lg" data-action="startCombat">
|
||||||
data-action="startCombat">{{localize
|
<i class="fa-solid fa-swords" inert></i>
|
||||||
'COMBAT.Begin'}}</a>
|
<span>{{localize "COMBAT.Begin"}}</span>
|
||||||
|
</button>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{else if control}}
|
{{else if control}}
|
||||||
<a class="combat-control" data-tooltip="COMBAT.TurnPrev"
|
<button type="button" class="inline-control combat-control icon fa-solid fa-arrow-left" data-action="previousTurn"
|
||||||
data-action="previousTurn"><i
|
data-tooltip aria-label="{{localize "COMBAT.TurnPrev"}}"></button>
|
||||||
class="fas fa-arrow-left"></i></a>
|
<button type="button" class="combat-control combat-control-lg" data-action="nextTurn">
|
||||||
<a class="combat-control center" data-action="nextTurn">{{localize
|
<i class="fa-solid fa-check" inert></i>
|
||||||
'COMBAT.TurnEnd'}}</a>
|
<span>{{localize "COMBAT.TurnEnd"}}</span>
|
||||||
<a class="combat-control" data-tooltip="COMBAT.TurnNext"
|
</button>
|
||||||
data-action="nextTurn"><i class="fas fa-arrow-right"></i></a>
|
<button type="button" class="inline-control combat-control icon fa-solid fa-arrow-right" data-action="nextTurn"
|
||||||
|
data-tooltip aria-label="{{localize "COMBAT.TurnNext"}}"></button>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
<div class="flexcol skill-section">
|
<div class="flexcol skill-section">
|
||||||
<label class="label">{{localize 'VERMINE.skill_title'}}</label>
|
<label class="label">{{localize 'VERMINE.skill_title'}}</label>
|
||||||
{{#if isCharacter}}
|
{{#if isCharacter}}
|
||||||
<div class="locked-value">{{ smarttlk 'SKILLS' skillKey 'name' }} / {{ skillValue }}</div>
|
<div class="locked-value">{{#if skillKey}}{{ smarttlk 'SKILLS' skillKey 'name' }}{{else}}{{ localize 'VERMINE.none' }}{{/if}} / {{ skillValue }}</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="locked-value">{{localize 'VERMINE.pool_total'}}</div>
|
<div class="locked-value">{{localize 'VERMINE.pool_total'}}</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@@ -112,10 +112,11 @@
|
|||||||
<div class="flexcol handicap-section">
|
<div class="flexcol handicap-section">
|
||||||
<label class="label" for="handicap">{{localize 'VERMINE.handicap'}}</label>
|
<label class="label" for="handicap">{{localize 'VERMINE.handicap'}}</label>
|
||||||
<select class="info-value" data-roll="true" data-dtype="String" type="number"
|
<select class="info-value" data-roll="true" data-dtype="String" type="number"
|
||||||
name="handicap" id="handicap" min="0" max="2">
|
name="handicap" id="handicap" min="0" max="3">
|
||||||
<option value="1" selected>{{localize 'VERMINE.none'}}</option>
|
<option value="1" selected>{{localize 'VERMINE.none'}}</option>
|
||||||
<option value="2">(I)</option>
|
<option value="2">(I)</option>
|
||||||
<option value="3">(II)</option>
|
<option value="3">(II)</option>
|
||||||
|
<option value="4">(III)</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -170,6 +171,13 @@
|
|||||||
<span>D</span>
|
<span>D</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="flexrow bonus-item full-width">
|
||||||
|
<label class="label" for="temporary-malus">{{localize 'VERMINE.temporary_malus'}}</label>
|
||||||
|
<input type="number" data-roll="true" class="numeric-entry" style="text-align: center;"
|
||||||
|
name="temporary-malus" id="temporary-malus" min="0" max="5" value="0" />
|
||||||
|
<span>D</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
{{#if isCharacter}}
|
{{#if isCharacter}}
|
||||||
<div class="flexrow bonus-item full-width">
|
<div class="flexrow bonus-item full-width">
|
||||||
<label class="label" for="self_control">
|
<label class="label" for="self_control">
|
||||||
|
|||||||
@@ -50,11 +50,12 @@
|
|||||||
name="handicap"
|
name="handicap"
|
||||||
id="handicap"
|
id="handicap"
|
||||||
min="0"
|
min="0"
|
||||||
max="2"
|
max="3"
|
||||||
>
|
>
|
||||||
<option value="1" selected>{{localize 'VERMINE.none'}}</option>
|
<option value="1" selected>{{localize 'VERMINE.none'}}</option>
|
||||||
<option value="2">(I)</option>
|
<option value="2">(I)</option>
|
||||||
<option value="3">(II)</option>
|
<option value="3">(II)</option>
|
||||||
|
<option value="4">(III)</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -169,11 +169,12 @@
|
|||||||
name="handicap"
|
name="handicap"
|
||||||
id="handicap"
|
id="handicap"
|
||||||
min="0"
|
min="0"
|
||||||
max="2"
|
max="3"
|
||||||
>
|
>
|
||||||
<option value="1" selected>{{localize 'VERMINE.none'}}</option>
|
<option value="1" selected>{{localize 'VERMINE.none'}}</option>
|
||||||
<option value="2">(I)</option>
|
<option value="2">(I)</option>
|
||||||
<option value="3">(II)</option>
|
<option value="3">(II)</option>
|
||||||
|
<option value="4">(III)</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user