forked from public/foundryvtt-reve-de-dragon
Nouveau roll-dialog: mode attaque / defense
This commit is contained in:
@@ -12,8 +12,8 @@ Pseudo : LeRatierBretonnien
|
||||
|
||||
Mainteneur/Développeur : LeRatierBretonnien
|
||||
Développeur : VincentVk
|
||||
Tests, Compendiums, Données: Fred, Fab, Grendel
|
||||
Styles/CSS : Mandar
|
||||
Tests, Compendiums, Données: Fred, Fab, Grendel, LeRatierBretonnien, VincentVk
|
||||
Styles/CSS : Mandar, VincentVk
|
||||
|
||||
# Mentions Légales
|
||||
|
||||
@@ -23,6 +23,6 @@ La carte des Terres Médianes du Rêve est une illustration de **Jidus**, utilis
|
||||
Les silhouettes des créatures, humanoïdes et entités sont des illustrations de **Roland Barthélémy**, et sont utilisés dans le cadre de ce projet avec son aimable autorisation.
|
||||
Merci à eux !!
|
||||
|
||||
Toute la propriété intellectuelle leur appartient, ce système est une adpatation destinée à fonctionner sous FoundryVTT.
|
||||
Toute la propriété intellectuelle leur appartient, ce système est une adaptation destinée à fonctionner sous FoundryVTT.
|
||||
|
||||
L'ensemble du code est sous licence Creative Commons.
|
66
assets/actions/weak.svg
Normal file
66
assets/actions/weak.svg
Normal file
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 323.9906 329.83231"
|
||||
version="1.1"
|
||||
id="svg6"
|
||||
sodipodi:docname="weak.svg"
|
||||
width="323.9906"
|
||||
height="329.83231"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata12">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs10" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2230"
|
||||
inkscape:window-height="1388"
|
||||
id="namedview8"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:zoom="1.4355469"
|
||||
inkscape:cx="157.6092"
|
||||
inkscape:cy="192.4342"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg6" />
|
||||
<g
|
||||
class=""
|
||||
transform="translate(-98.3908,-91.5658)"
|
||||
id="g4">
|
||||
<path
|
||||
d="M 200.094,21.094 213.969,164.814 83.72,58.343 156.344,198.249 78.624,168.779 112.906,230.905 30.844,228.843 135.874,297 31.75,327.03 141.188,348.188 c 8.39,-48.802 49.597,-85.194 97.75,-105.344 28.916,-12.1 60.67,-18.762 90.75,-18.594 19.237,0.108 37.776,3.024 54.437,9.063 l 48,-119.375 L 350,196.5 369.22,34.72 327.344,130.688 313.47,92.03 l -32.69,83.5 z m 255.78,190.687 c -17.883,-0.093 -38.852,9.04 -55.937,26.126 a 100.103,100.103 0 0 0 -13.562,16.875 C 357.123,237.155 314,237.977 273.095,250.877 c -9.17,2.484 -18.214,5.537 -26.94,9.188 -43.676,18.277 -78.503,49.837 -86.218,89.625 -6.61,30.108 5.37,63.223 47.438,94.843 H 88.062 l -26.437,47.75 H 318.78 l -88.467,-103.25 c 24.27,-26.707 67.457,-43.703 97,-45.06 13.792,45.096 36.233,113.496 71.718,148.31 h 60.876 c -43.07,-46.546 -76.57,-109.087 -81.97,-179.842 a 33.579,33.579 0 0 0 6.314,8.78 c 18.664,18.664 55.945,11.618 83.28,-15.718 27.337,-27.336 34.384,-64.618 15.72,-83.28 -7,-7 -16.645,-10.382 -27.375,-10.44 z"
|
||||
fill="#ffffff"
|
||||
fill-opacity="1"
|
||||
transform="matrix(0.7,0,0,0.7,76.8,76.8)"
|
||||
id="path2" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
13
changelog.md
13
changelog.md
@@ -3,6 +3,19 @@
|
||||
## 13.0.9 - Le combat d'Illysis
|
||||
- Fix
|
||||
- La montée en TMR fonctionne
|
||||
- Nouvelle fenêtre de jets de dés
|
||||
- avancement du mode attaque
|
||||
- choix de tactique
|
||||
- choix des dommages mortel/non-mortel, affichage
|
||||
- affichage du statut de surprise de l'attaquant
|
||||
- affichage du statut de surprise du défenseur
|
||||
- prise en compte des significatives (force insuffisante, demi-surprises)
|
||||
- avancement du mode défense
|
||||
- sélection esquive/parade
|
||||
- affichage du statut de surprise du défenseur
|
||||
- prise en compte des significatives (demi-surprises, armes disparates,
|
||||
force insuffisante, particulière en finesse)
|
||||
|
||||
|
||||
## 13.0.8 - Le renouveau d'Illysis
|
||||
|
||||
|
@@ -526,6 +526,7 @@ select,
|
||||
grid-area: selection;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: 0.1rem 0;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-img {
|
||||
display: flex;
|
||||
@@ -549,11 +550,20 @@ select,
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-detail subline {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: 0.1rem 0;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-detail subline div.poesie-extrait {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-detail subline span.status-surprise {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-flow: wrap;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-detail subline span.status-surprise img {
|
||||
filter: invert(0.8);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-section selected-numeric-value {
|
||||
display: flow;
|
||||
width: 2.5rem;
|
||||
@@ -608,6 +618,11 @@ select,
|
||||
margin: 0 0.2rem;
|
||||
padding: 0;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog :is(roll-choix, roll-conditions, roll-carac, roll-comp) img.button-effect-img {
|
||||
max-width: 1rem;
|
||||
max-height: 1rem;
|
||||
margin: 0 0.1rem;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .roll-dialog roll-carac select[name="select-carac"] {
|
||||
max-width: 6rem;
|
||||
}
|
||||
|
@@ -66,6 +66,7 @@
|
||||
"StatusRestrained": "Immobilisé",
|
||||
"StatusComma": "Comma",
|
||||
"StatusDead": "Mort",
|
||||
"StatusDemiReve": "Demi-rêve"
|
||||
"StatusDemiReve": "Demi-rêve",
|
||||
"StatusForceWeak": "Force insuffisante"
|
||||
}
|
||||
}
|
@@ -83,11 +83,14 @@
|
||||
gap: 0.2rem;
|
||||
align-items: start;
|
||||
|
||||
|
||||
subline {
|
||||
grid-area: selection;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: 0.1rem 0;
|
||||
}
|
||||
|
||||
roll-part-img {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -110,10 +113,19 @@
|
||||
subline {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: 0.1rem 0;
|
||||
div.poesie-extrait{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
span.status-surprise{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-flow: wrap;
|
||||
img {
|
||||
filter: invert(0.8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,6 +190,11 @@
|
||||
margin: 0 0.2rem;
|
||||
padding: 0;
|
||||
}
|
||||
img.button-effect-img {
|
||||
max-width: 1rem;
|
||||
max-height: 1rem;
|
||||
margin: 0 0.1rem;
|
||||
}
|
||||
}
|
||||
|
||||
roll-carac select[name="select-carac"] {
|
||||
|
@@ -49,7 +49,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
|
||||
});
|
||||
foundry.utils.mergeObject(formData.calc, {
|
||||
surenc: this.actor.computeMalusSurEncombrement(),
|
||||
surprise: RdDBonus.find(this.actor.getSurprise(false)).descr,
|
||||
surprise: RdDBonus.find(this.actor.getSurprise(false)).label,
|
||||
resumeBlessures: this.actor.computeResumeBlessure(this.actor.system.blessures),
|
||||
caracTotal: RdDCarac.computeTotal(this.actor.system.carac, this.actor.system.beaute),
|
||||
surEncombrementMessage: this.actor.isSurenc() ? "Sur-Encombrement!" : "",
|
||||
|
@@ -31,7 +31,7 @@ export class ActorToken {
|
||||
|
||||
constructor(token) {
|
||||
this.name = token.name ?? token.actor.name
|
||||
this.img = token.texture.src ?? token.actor.img
|
||||
this.img = token.actor.isToken && token.texture.src ? token.texture.src : token.actor.img
|
||||
this.actor = token.actor
|
||||
this.id = token.actor?.id
|
||||
this.token = token
|
||||
|
@@ -14,7 +14,7 @@ import { STATUSES } from "./settings/status-effects.js";
|
||||
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
|
||||
import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
|
||||
import { Draconique } from "./tmr/draconique.js";
|
||||
import { LIST_CARAC_PERSONNAGE, RdDCarac } from "./rdd-carac.js";
|
||||
import { CARACS, LIST_CARAC_PERSONNAGE, RdDCarac } from "./rdd-carac.js";
|
||||
import { DialogConsommer } from "./dialog-item-consommer.js";
|
||||
import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js";
|
||||
import { RollDataAjustements } from "./rolldata-ajustements.js";
|
||||
@@ -31,9 +31,8 @@ import { ITEM_TYPES } from "./constants.js";
|
||||
import { RdDBaseActorSang } from "./actor/base-actor-sang.js";
|
||||
import { RdDCoeur } from "./coeur/rdd-coeur.js";
|
||||
import { DialogChoixXpCarac } from "./dialog-choix-xp-carac.js";
|
||||
import { RdDCombatManager } from "./rdd-combat.js";
|
||||
|
||||
import { RdDItemArme } from "./item/arme.js";
|
||||
import { ATTAQUE_TYPE, RdDItemArme } from "./item/arme.js";
|
||||
import { RdDItemBlessure } from "./item/blessure.js";
|
||||
import { RdDItemTete } from "./item/tete.js";
|
||||
import { RdDItemSort } from "./item-sort.js";
|
||||
@@ -167,52 +166,36 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
.find(it => true)
|
||||
}
|
||||
|
||||
isForceInsuffisante(forceRequise) {
|
||||
const force = parseInt(this.system.carac.force.value)
|
||||
return forceRequise > force
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** Retourne une liste triée d'actions d'armes avec le split arme1 main / arme 2 main / lancer */
|
||||
listActionsAttaque() {
|
||||
let actions = [
|
||||
this.$prepareAttaqueArme(RdDItemArme.empoignade(this)),
|
||||
this.$prepareAttaqueArme(RdDItemArme.corpsACorps(this)),
|
||||
]
|
||||
const actions = []
|
||||
const uniques = []
|
||||
|
||||
const armes = this.itemTypes[ITEM_TYPES.arme]
|
||||
.filter(it => RdDItemArme.isAttaque(it))
|
||||
.sort(Misc.ascending(it => it.name));
|
||||
const addAttaque = (arme, main) => {
|
||||
const dommagesArme = RdDItemArme.valeurMain(arme.system.dommages, main)
|
||||
const forceRequise = RdDItemArme.valeurMain(arme.system.force ?? 0, main)
|
||||
const ecaillesEfficacite = arme.system.magique ? arme.system.ecaille_efficacite : 0;
|
||||
|
||||
for (const arme of armes) {
|
||||
if (arme.system.unemain && arme.system.competence) {
|
||||
actions.push(this.$prepareAttaqueArme(arme, '(1 main)'))
|
||||
}
|
||||
if (arme.system.deuxmains && arme.system.competence) {
|
||||
actions.push(this.$prepareAttaqueArme(arme, '(2 mains)'))
|
||||
}
|
||||
if (arme.system.lancer) {
|
||||
actions.push(this.$prepareAttaqueArme(arme, '(lancer)'))
|
||||
}
|
||||
if (arme.system.tir) {
|
||||
actions.push(this.$prepareAttaqueArme(arme, '(tir)'))
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
$prepareAttaqueArme(arme, main) {
|
||||
const comp = this.getCompetence(RdDActor.$getCompetenceAction(arme, main))
|
||||
const unique = [comp.id, arme.name, dommagesArme, forceRequise, ecaillesEfficacite].join('|');
|
||||
if (uniques.includes(unique)) {
|
||||
return
|
||||
}
|
||||
uniques.push(unique);
|
||||
|
||||
const caracCode = RdDActor.$getCaracAction(comp, main)
|
||||
const caracValue = this.system.carac[caracCode].value
|
||||
const dommages = arme.system.dommages.toString()
|
||||
|
||||
// TODO: déplacer sur RdDItemArme
|
||||
if (arme.system.unemain && arme.system.deuxmains && !dommages.includes("/")) {
|
||||
ui.notifications.info(`Les dommages de l'arme à 1/2 mains ${arme.name} ne sont pas corrects (ie sous la forme X/Y)`)
|
||||
}
|
||||
const tableauDommages = dommages.includes("/") ? dommages.split("/") : [dommages, dommages]
|
||||
const dmg = main == '(2 mains)' ? tableauDommages[1] : tableauDommages[0]
|
||||
const niveau = comp?.system.niveau ?? (['(lancer)', '(tir)'].includes(main) ? -8 : -6)
|
||||
const ajustement = (arme.parent?.getEtatGeneral() ?? 0) + (arme.system.magique) ? arme.system.ecaille_efficacite : 0
|
||||
const ajustement = (arme.parent?.getEtatGeneral() ?? 0) + ecaillesEfficacite
|
||||
|
||||
return {
|
||||
actions.push({
|
||||
name: arme.name + (main ? ' ' + main : ''),
|
||||
action: 'attaque',
|
||||
initOnly: false,
|
||||
@@ -221,9 +204,25 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
main: main,
|
||||
carac: { key: caracCode, value: caracValue },
|
||||
equipe: arme.system.equipe,
|
||||
dmg: dmg,
|
||||
dommagesArme: dommagesArme,
|
||||
forceRequise: forceRequise,
|
||||
initiative: RdDInitiative.calculInitiative(niveau, caracValue, ajustement)
|
||||
})
|
||||
}
|
||||
|
||||
addAttaque(RdDItemArme.empoignade(this))
|
||||
addAttaque(RdDItemArme.corpsACorps(this))
|
||||
|
||||
this.itemTypes[ITEM_TYPES.arme]
|
||||
.filter(it => it.isAttaque())
|
||||
.sort(Misc.ascending(it => it.name))
|
||||
.forEach(arme => {
|
||||
if (arme.system.unemain && arme.system.competence) { addAttaque(arme, ATTAQUE_TYPE.UNE_MAIN) }
|
||||
if (arme.system.deuxmains && arme.system.competence) { addAttaque(arme, ATTAQUE_TYPE.DEUX_MAINS) }
|
||||
if (arme.system.lancer) { addAttaque(arme, ATTAQUE_TYPE.LANCER) }
|
||||
if (arme.system.tir) { addAttaque(arme, ATTAQUE_TYPE.TIR) }
|
||||
})
|
||||
return actions
|
||||
}
|
||||
|
||||
static $getCaracAction(comp, main) {
|
||||
@@ -239,10 +238,10 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
static $getCompetenceAction(arme, main) {
|
||||
switch (main) {
|
||||
case '(1 main)': return arme.competence1Mains()
|
||||
case '(2 mains)': return arme.competence2Mains()
|
||||
case '(lancer)': return arme.system.lancer
|
||||
case '(tir)': return arme.system.tir
|
||||
case ATTAQUE_TYPE.UNE_MAIN: return arme.competence1Mains()
|
||||
case ATTAQUE_TYPE.DEUX_MAINS: return arme.competence2Mains()
|
||||
case ATTAQUE_TYPE.LANCER: return arme.system.lancer
|
||||
case ATTAQUE_TYPE.TIR: return arme.system.tir
|
||||
default: return arme.system.competence
|
||||
}
|
||||
}
|
||||
@@ -2278,13 +2277,12 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
static _getComposantsCaracDerivee(caracName) {
|
||||
switch (Grammar.toLowerCaseNoAccent(caracName)) {
|
||||
case 'reve-actuel': case 'reve actuel': return ['reve']
|
||||
case 'chance-actuelle': case 'chance actuelle': return ['chance']
|
||||
case 'vie': return ['constitution']
|
||||
case 'tir': return ['vue', 'dexterite']
|
||||
case 'lancer': return ['force', 'dexterite', 'vue']
|
||||
case 'melee': return ['force', 'agilite']
|
||||
case 'derobee': return ['agilite']
|
||||
case CARACS.REVE_ACTUEL: case 'reve actuel': return [CARACS.REVE]
|
||||
case CARACS.CHANCE_ACTUELLE: case 'chance actuelle': return [CARACS.CHANCE]
|
||||
case CARACS.TIR: return [CARACS.DEXTERITE, CARACS.VUE]
|
||||
case CARACS.LANCER: return [CARACS.FORCE, CARACS.DEXTERITE, CARACS.VUE]
|
||||
case CARACS.MELEE: return [CARACS.FORCE, CARACS.AGILITE]
|
||||
case CARACS.DEROBEE: return [CARACS.AGILITE]
|
||||
}
|
||||
return []
|
||||
}
|
||||
@@ -3249,3 +3247,4 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -14,9 +14,9 @@ import { RdDConfirm } from "../rdd-confirm.js";
|
||||
import { RdDCarac } from "../rdd-carac.js";
|
||||
import { RdDRollResult } from "../rdd-roll-result.js";
|
||||
|
||||
import { RdDItemArme } from "../item/arme.js";
|
||||
import { RdDItemCompetence } from "../item-competence.js";
|
||||
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
|
||||
import { RdDItemArme } from "../item/arme.js";
|
||||
|
||||
import { ChatUtility } from "../chat-utility.js";
|
||||
import { DialogValidationEncaissement } from "../dialog-validation-encaissement.js";
|
||||
@@ -80,7 +80,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
getBonusDegat() { return RdDCarac.getCaracDerivee(this.getEncombrementMax()).plusdom }
|
||||
|
||||
getMoralTotal() { return 0 }
|
||||
listeAmoureux() {return []}
|
||||
listeAmoureux() { return [] }
|
||||
getProtectionNaturelle() { return Number(this.system.attributs?.protection?.value ?? 0) }
|
||||
getSConst() { return 0 }
|
||||
|
||||
@@ -113,7 +113,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
|
||||
listActions({ isAttaque = false, isEquipe = false }) {
|
||||
return this.itemTypes[ITEM_TYPES.competencecreature]
|
||||
.filter(it => RdDItemCompetenceCreature.isAttaque(it))
|
||||
.filter(it => it.isAttaque())
|
||||
.map(it => RdDItemCompetenceCreature.attaqueCreature(it))
|
||||
.filter(it => it != undefined);
|
||||
}
|
||||
@@ -191,6 +191,10 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
return RdDItemArme.getArme(armeParadeId ? this.getEmbeddedDocument('Item', armeParadeId) : undefined)
|
||||
}
|
||||
|
||||
isForceInsuffisante(forceRequise) {
|
||||
return false
|
||||
}
|
||||
|
||||
getDraconicOuPossession() { return POSSESSION_SANS_DRACONIC }
|
||||
|
||||
getPossession(possessionId) {
|
||||
@@ -222,8 +226,13 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
/* -------------------------------------------- */
|
||||
isEffectAllowed(effectId) { return false }
|
||||
|
||||
getEffects(filter = e => true) {
|
||||
return this.getEmbeddedCollection("ActiveEffect").filter(filter);
|
||||
getEffects(filter = e => true, forceRequise = undefined) {
|
||||
const effects = this.getEmbeddedCollection("ActiveEffect").filter(filter)
|
||||
if (forceRequise && this.isForceInsuffisante(forceRequise)) {
|
||||
/// TODO
|
||||
effects.push(StatusEffects.prepareActiveEffect(STATUSES.StatusForceWeak))
|
||||
}
|
||||
return effects
|
||||
}
|
||||
|
||||
getEffectByStatus(statusId) {
|
||||
@@ -259,11 +268,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
}
|
||||
|
||||
getSurprise(isCombat = undefined) {
|
||||
return StatusEffects.typeSurprise(
|
||||
this.getEffects()
|
||||
.map(it => StatusEffects.niveauSurprise(it, isCombat))
|
||||
.reduce(Misc.sum(), 0)
|
||||
)
|
||||
return StatusEffects.getSurprise(this.getEffects(), isCombat)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@@ -5,7 +5,6 @@ import { RdDSheetUtility } from "../rdd-sheet-utility.js";
|
||||
import { Monnaie } from "../item-monnaie.js";
|
||||
import { ITEM_TYPES } from "../constants.js";
|
||||
import { RdDItem } from "../item.js";
|
||||
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
|
||||
import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js";
|
||||
import { ItemAction } from "../item/item-actions.js";
|
||||
|
||||
@@ -56,7 +55,7 @@ export class RdDBaseActorSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
this._appliquerRechercheObjets(formData.conteneurs, formData.inventaires);
|
||||
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
|
||||
formData.competences.filter(it => it.type == ITEM_TYPES.competencecreature)
|
||||
.forEach(it => it.isdommages = RdDItemCompetenceCreature.isDommages(it))
|
||||
.forEach(it => it.isdommages = it.isDommages())
|
||||
|
||||
return formData;
|
||||
}
|
||||
|
@@ -1,64 +1,22 @@
|
||||
|
||||
import { ITEM_TYPES } from "./constants.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { RdDInitiative } from "./initiative.mjs";
|
||||
import { RdDItem } from "./item.js";
|
||||
|
||||
export const CATEGORIES_COMPETENCES_CREATURES = {
|
||||
"generale": { base: 0, label: "Générale" },
|
||||
"naturelle": { base: 0, label: "Arme naturelle" },
|
||||
"melee": { base: 0, label: "Mêlée" },
|
||||
"parade": { base: 0, label: "Parade" },
|
||||
"tir": { base: 0, label: "Tir" },
|
||||
"lancer": { base: 0, label: "Lancer" },
|
||||
"possession": { base: 0, label: "Possession" },
|
||||
}
|
||||
import { RdDInitiative } from "./initiative.mjs";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RdDItemCompetenceCreature extends Item {
|
||||
export class RdDItemCompetenceCreature extends RdDItem {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static setRollDataCreature(rollData) {
|
||||
const code = Grammar.toLowerCaseNoAccentNoSpace(rollData.competence.name);
|
||||
const selectedCarac = { code: code, label: rollData.competence.name, value: rollData.competence.system.carac_value };
|
||||
rollData.carac = { [code]: selectedCarac }
|
||||
rollData.competence.system.defaut_carac = code
|
||||
rollData.selectedCarac = selectedCarac
|
||||
rollData.arme = RdDItemCompetenceCreature.armeCreature(rollData.competence);
|
||||
}
|
||||
static get ITEM_TYPE() { return ITEM_TYPES.competencecreature }
|
||||
|
||||
static get defaultIcon() { return "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp" }
|
||||
|
||||
isParade() { return this.system.iscombat && (this.system.categorie_parade ?? '') != '' }
|
||||
isBouclier() { return this.system.categorie_parade.includes('bouclier') }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static armeCreature(item) {
|
||||
const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(item)
|
||||
if (categorieAttaque != undefined) {
|
||||
// cloner pour ne pas modifier la compétence
|
||||
return foundry.utils.mergeObject(item, {
|
||||
action: item.isCompetencePossession() ? 'possession' : 'attaque',
|
||||
system: {
|
||||
competence: item.name,
|
||||
cac: categorieAttaque == "naturelle" ? "naturelle" : "",
|
||||
niveau: item.system.niveau,
|
||||
initiative: RdDInitiative.calculInitiative(item.system.niveau, item.system.carac_value),
|
||||
equipe: true,
|
||||
resistance: 100,
|
||||
dommagesReels: item.system.dommages,
|
||||
penetration: 0,
|
||||
force: 0,
|
||||
rapide: true,
|
||||
}
|
||||
}, { inplace: false, });
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
static attaqueCreature(comp) {
|
||||
const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(comp)
|
||||
const categorieAttaque = comp.getCategorieAttaque()
|
||||
if (categorieAttaque != undefined) {
|
||||
const initative = RdDInitiative.calculInitiative(comp.system.niveau, comp.system.carac_value);
|
||||
return {
|
||||
name: comp.name,
|
||||
action: comp.isCompetencePossession() ? 'possession' : 'attaque',
|
||||
initOnly: false,
|
||||
arme: new RdDItem({
|
||||
const armeComp = new RdDItem({
|
||||
name: comp.name,
|
||||
type: ITEM_TYPES.arme,
|
||||
img: comp.img,
|
||||
@@ -67,61 +25,55 @@ export class RdDItemCompetenceCreature extends Item {
|
||||
cac: categorieAttaque == "naturelle" ? "naturelle" : "",
|
||||
niveau: comp.system.niveau,
|
||||
initiative: initative,
|
||||
mortalite: comp.system.mortalite,
|
||||
dommages: comp.system.dommages,
|
||||
equipe: true,
|
||||
resistance: 100,
|
||||
dommagesReels: comp.system.dommages,
|
||||
penetration: 0,
|
||||
force: 0,
|
||||
rapide: true,
|
||||
}
|
||||
}),
|
||||
});
|
||||
const attaque = {
|
||||
name: comp.name,
|
||||
action: comp.isCompetencePossession() ? 'possession' : 'attaque',
|
||||
initOnly: false,
|
||||
arme: armeComp,
|
||||
comp: comp,
|
||||
// main: '',
|
||||
carac: { key: comp.name, value: comp.system.carac_value },
|
||||
equipe: true,
|
||||
mortalite: comp.system.mortalite,
|
||||
dmg: comp.system.dommages,
|
||||
initiative: initative
|
||||
}
|
||||
};
|
||||
return attaque
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isAttaque(item) {
|
||||
return RdDItemCompetenceCreature.getCategorieAttaque(item) != undefined
|
||||
isAttaque() {
|
||||
return this.getCategorieAttaque() != undefined
|
||||
}
|
||||
|
||||
static getCategorieAttaque(item) {
|
||||
if (item.type == ITEM_TYPES.competencecreature) {
|
||||
switch (item.system.categorie) {
|
||||
getCategorieAttaque() {
|
||||
switch (this.system.categorie) {
|
||||
case "melee":
|
||||
case "tir":
|
||||
case "lancer":
|
||||
case "naturelle":
|
||||
case "possession":
|
||||
return item.system.categorie
|
||||
return this.system.categorie
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
static isDommages(item) {
|
||||
if (item.type == ITEM_TYPES.competencecreature) {
|
||||
switch (item.system.categorie) {
|
||||
isDommages() {
|
||||
switch (this.system.categorie) {
|
||||
case "melee":
|
||||
case "tir":
|
||||
case "lancer":
|
||||
case "naturelle":
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
static isParade(item) {
|
||||
if (item.type == ITEM_TYPES.competencecreature) {
|
||||
return item.system.categorie_parade || item.system.isparade
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
@@ -9,7 +9,6 @@ import { RdDSheetUtility } from "./rdd-sheet-utility.js";
|
||||
import { SystemCompendiums } from "./settings/system-compendiums.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
|
||||
import { RdDItem } from "./item.js";
|
||||
import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js";
|
||||
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
|
||||
@@ -106,8 +105,8 @@ export class RdDItemSheetV1 extends foundry.appv1.sheets.ItemSheet {
|
||||
}
|
||||
|
||||
if (this.item.type == ITEM_TYPES.competencecreature) {
|
||||
formData.isparade = RdDItemCompetenceCreature.isParade(this.item)
|
||||
formData.isdommages = RdDItemCompetenceCreature.isDommages(this.item)
|
||||
formData.isparade = this.item.isParade()
|
||||
formData.isdommages = this.item.isDommages()
|
||||
}
|
||||
if (this.item.type == ITEM_TYPES.tache ||
|
||||
this.item.type == ITEM_TYPES.livre ||
|
||||
|
@@ -1,4 +1,7 @@
|
||||
import { ITEM_TYPES } from "./constants.js";
|
||||
import { CATEGORIES_COMPETENCES } from "./item-competence.js";
|
||||
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, CATEGORIES_COMPETENCES_CREATURES } from "./item/base-items.js";
|
||||
import { ITEM_ACTIONS, DEFAULT_ACTIONS, COMMON_ACTIONS } from "./item/item-actions.js";
|
||||
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { Misc } from "./misc.js";
|
||||
@@ -7,10 +10,6 @@ import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { SystemCompendiums } from "./settings/system-compendiums.js";
|
||||
import { RdDRaretes } from "./item/raretes.js";
|
||||
import { CATEGORIES_COMPETENCES } from "./item-competence.js";
|
||||
import { CATEGORIES_COMPETENCES_CREATURES } from "./item-competencecreature.js";
|
||||
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE } from "./item/base-items.js";
|
||||
import { ITEM_ACTIONS, DEFAULT_ACTIONS, COMMON_ACTIONS } from "./item/item-actions.js";
|
||||
|
||||
const typesInventaireMateriel = [
|
||||
ITEM_TYPES.arme,
|
||||
@@ -186,7 +185,10 @@ export class RdDItem extends Item {
|
||||
isMonnaie() { return this.type == ITEM_TYPES.monnaie; }
|
||||
isNourritureBoisson() { return this.type == ITEM_TYPES.nourritureboisson; }
|
||||
isService() { return this.type == ITEM_TYPES.service; }
|
||||
|
||||
isAttaque() { return false }
|
||||
isParade() { return false }
|
||||
isBouclier() { return false }
|
||||
getCategorieAttaque() { return undefined }
|
||||
isCompetence() { return typesObjetsCompetence.includes(this.type) }
|
||||
isEsquive() {
|
||||
return (this.isCompetence()
|
||||
|
@@ -1,10 +1,9 @@
|
||||
import { ITEM_TYPES } from "../constants.js";
|
||||
import { RdDItem } from "../item.js";
|
||||
|
||||
import { RdDItemCompetenceCreature } from "../item-competencecreature.js"
|
||||
import { BASE_CORPS_A_CORPS } from "./base-items.js";
|
||||
import { Grammar } from "../grammar.js";
|
||||
import { RdDInitiative } from "../initiative.mjs";
|
||||
import { MappingCreatureArme } from "./mapping-creature-arme.mjs";
|
||||
|
||||
const nomCategorieParade = {
|
||||
"sans-armes": "Sans arme",
|
||||
@@ -19,24 +18,48 @@ const nomCategorieParade = {
|
||||
"haches": "Haches",
|
||||
"lances": "Lances",
|
||||
}
|
||||
|
||||
export const ATTAQUE_TYPE = {
|
||||
UNE_MAIN: '(1 main)',
|
||||
DEUX_MAINS: '(2 mains)',
|
||||
COMPETENCE: 'competence',
|
||||
TIR: '(tir)',
|
||||
LANCER: '(lancer)'
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
export class RdDItemArme extends RdDItem {
|
||||
|
||||
static get ITEM_TYPE() { return ITEM_TYPES.arme }
|
||||
|
||||
static get defaultIcon() {
|
||||
return defaultItemImgArme
|
||||
//return "systems/foundryvtt-reve-de-dragon/icons/armes_armure/epee_sord.webp";
|
||||
}
|
||||
static get defaultIcon() { return "systems/foundryvtt-reve-de-dragon/icons/armes_armures/epee_gnome.webp" }
|
||||
|
||||
penetration() { return parseInt(this.system.penetration ?? 0) }
|
||||
|
||||
isParade() { return this.system.resistance > 0 && this.system.categorie_parade }
|
||||
isBouclier() { return RdDItemArme.getCategorieParade(this).includes('bouclier') }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static valeurMain(valeurs, main) {
|
||||
valeurs = valeurs?.toString() ?? ""
|
||||
const table = valeurs.includes("/") ? valeurs.split("/") : [valeurs, valeurs]
|
||||
return parseInt(main == ATTAQUE_TYPE.DEUX_MAINS ? table[1] : table[0])
|
||||
}
|
||||
|
||||
static getMainAttaque(competence) {
|
||||
switch (competence.system.categorie) {
|
||||
case 'tir': return ATTAQUE_TYPE.TIR
|
||||
case 'lancer': return ATTAQUE_TYPE.LANCER
|
||||
}
|
||||
if (competence.name.includes('2 main')) {
|
||||
return ATTAQUE_TYPE.DEUX_MAINS
|
||||
}
|
||||
return ATTAQUE_TYPE.UNE_MAIN
|
||||
}
|
||||
|
||||
static getArme(arme) {
|
||||
switch (arme ? arme.type : '') {
|
||||
case ITEM_TYPES.arme: return arme;
|
||||
case ITEM_TYPES.competencecreature:
|
||||
return RdDItemCompetenceCreature.armeCreature(arme);
|
||||
return MappingCreatureArme.armeCreature(arme);
|
||||
}
|
||||
return RdDItemArme.corpsACorps();
|
||||
}
|
||||
@@ -47,11 +70,11 @@ export class RdDItemArme extends RdDItem {
|
||||
return arme.name
|
||||
case ITEM_TYPES.arme:
|
||||
switch (maniement) {
|
||||
case 'competence': return arme.system.competence;
|
||||
case '(1 main)': return arme.competence1Mains()
|
||||
case '(2 mains)': return arme.competence2Mains()
|
||||
case '(tir)': case 'tir': return arme.system.tir
|
||||
case '(lancer)': case 'lancer': return arme.system.lancer;
|
||||
case ATTAQUE_TYPE.COMPETENCE: return arme.system.competence;
|
||||
case ATTAQUE_TYPE.UNE_MAIN: return arme.competence1Mains()
|
||||
case ATTAQUE_TYPE.DEUX_MAINS: return arme.competence2Mains()
|
||||
case ATTAQUE_TYPE.TIR: case 'tir': return arme.system.tir
|
||||
case ATTAQUE_TYPE.LANCER: case 'lancer': return arme.system.lancer;
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
@@ -88,16 +111,13 @@ export class RdDItemArme extends RdDItem {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getCategorieParade(armeData) {
|
||||
if (![ITEM_TYPES.arme, ITEM_TYPES.competencecreature].includes(armeData.type)) {
|
||||
return ''
|
||||
}
|
||||
if (armeData.system.categorie_parade) {
|
||||
return armeData.system.categorie_parade
|
||||
}
|
||||
// pour compatibilité avec des personnages existants
|
||||
if (armeData.type == ITEM_TYPES.competencecreature || armeData.system.categorie == 'creature') {
|
||||
return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : '')
|
||||
}
|
||||
if (!armeData.type.match(/arme|competencecreature/)) {
|
||||
return ''
|
||||
}
|
||||
if (armeData.system.competence == undefined) {
|
||||
return ITEM_TYPES.competencecreature;
|
||||
}
|
||||
@@ -192,7 +212,7 @@ export class RdDItemArme extends RdDItem {
|
||||
return Number(arme.system.dommages)
|
||||
}
|
||||
const tableauDegats = arme.system.dommages.split("/");
|
||||
return Number(tableauDegats[maniement == '(1 main)' ? 0 : 1])
|
||||
return Number(tableauDegats[maniement == ATTAQUE_TYPE.UNE_MAIN ? 0 : 1])
|
||||
}
|
||||
return Number(arme.system.dommages);
|
||||
}
|
||||
@@ -201,7 +221,7 @@ export class RdDItemArme extends RdDItem {
|
||||
static armeUneOuDeuxMains(arme, aUneMain) {
|
||||
if (arme && !arme.system.cac) {
|
||||
arme = foundry.utils.duplicate(arme);
|
||||
arme.system.dommagesReels = RdDItemArme.dommagesReels(arme, aUneMain ? '(1 main)' : '(2 mains)')
|
||||
arme.system.dommagesReels = RdDItemArme.dommagesReels(arme, aUneMain ? ATTAQUE_TYPE.UNE_MAIN : ATTAQUE_TYPE.DEUX_MAINS)
|
||||
}
|
||||
return arme;
|
||||
}
|
||||
@@ -222,24 +242,9 @@ export class RdDItemArme extends RdDItem {
|
||||
return false
|
||||
}
|
||||
|
||||
static isAttaque(arme) {
|
||||
switch (arme.type) {
|
||||
case ITEM_TYPES.arme: return arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0)
|
||||
case ITEM_TYPES.competencecreature: return arme.system.iscombat && RdDItemCompetenceCreature.isAttaque(item)
|
||||
isAttaque() {
|
||||
return this.system.resistance > 0 || this.system.portee_courte > 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
static isParade(arme) {
|
||||
switch (arme.type) {
|
||||
case ITEM_TYPES.arme:
|
||||
return arme.system.resistance > 0 && true/* TODO: regarder la categorie d'arme?*/
|
||||
case ITEM_TYPES.competencecreature:
|
||||
return arme.system.iscombat && RdDItemCompetenceCreature.isParade(arme)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
static corpsACorps(actor) {
|
||||
let competence = actor?.getCompetenceCorpsACorps() ?? BASE_CORPS_A_CORPS
|
||||
|
@@ -18,3 +18,12 @@ export const SANS_COMPETENCE = {
|
||||
img: "systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.webp"
|
||||
}
|
||||
|
||||
export const CATEGORIES_COMPETENCES_CREATURES = {
|
||||
"generale": { base: 0, label: "Générale" },
|
||||
"naturelle": { base: 0, label: "Arme naturelle" },
|
||||
"melee": { base: 0, label: "Mêlée" },
|
||||
"parade": { base: 0, label: "Parade" },
|
||||
"tir": { base: 0, label: "Tir" },
|
||||
"lancer": { base: 0, label: "Lancer" },
|
||||
"possession": { base: 0, label: "Possession" },
|
||||
}
|
||||
|
42
module/item/mapping-creature-arme.mjs
Normal file
42
module/item/mapping-creature-arme.mjs
Normal file
@@ -0,0 +1,42 @@
|
||||
import { Grammar } from "../grammar.js";
|
||||
import { RdDInitiative } from "../initiative.mjs";
|
||||
|
||||
export class MappingCreatureArme {
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static setRollDataCreature(rollData) {
|
||||
const code = Grammar.toLowerCaseNoAccentNoSpace(rollData.competence.name);
|
||||
const selectedCarac = { code: code, label: rollData.competence.name, value: rollData.competence.system.carac_value };
|
||||
rollData.carac = { [code]: selectedCarac }
|
||||
rollData.competence.system.defaut_carac = code
|
||||
rollData.selectedCarac = selectedCarac
|
||||
rollData.arme = MappingCreatureArme.armeCreature(rollData.competence);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static armeCreature(item) {
|
||||
const categorieAttaque = item.getCategorieAttaque()
|
||||
if (categorieAttaque != undefined) {
|
||||
// cloner pour ne pas modifier la compétence
|
||||
return foundry.utils.mergeObject(item, {
|
||||
action: item.isCompetencePossession() ? 'possession' : 'attaque',
|
||||
system: {
|
||||
competence: item.name,
|
||||
cac: categorieAttaque == "naturelle" ? "naturelle" : "",
|
||||
niveau: item.system.niveau,
|
||||
initiative: RdDInitiative.calculInitiative(item.system.niveau, item.system.carac_value),
|
||||
equipe: true,
|
||||
resistance: 100,
|
||||
dommagesReels: item.system.dommages,
|
||||
penetration: 0,
|
||||
force: 0,
|
||||
rapide: true,
|
||||
}
|
||||
}, { inplace: false, });
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
@@ -1,21 +1,24 @@
|
||||
import { RdDCarac } from "./rdd-carac.js";
|
||||
import { RdDItemArme } from "./item/arme.js";
|
||||
import { RdDPossession } from "./rdd-possession.js";
|
||||
|
||||
const conditionsTactiques = [
|
||||
{ type: '', descr: '', dmg: 0, attaque: 0, parade: 0, esquive: true },
|
||||
{ type: 'charge', descr: 'Charge', dmg: 2, attaque: 4, parade: -4, esquive: false },
|
||||
{ type: 'feinte', descr: 'Feinte', dmg: 1, attaque: 1, parade: 0, esquive: true },
|
||||
{ type: 'pret', descr: 'prêt', dmg: 0, attaque: 0, parade: 0, esquive: true },
|
||||
{ type: 'demi', descr: 'Demi-surprise', dmg: 1, attaque: 0, parade: 0, esquive: true },
|
||||
{ type: 'totale', descr: 'Surprise totale', dmg: 10, attaque: 6, parade: 0, esquive: true },
|
||||
{ key: '', label: '', dmg: 0, attaque: 0, parade: 0, esquive: true, isTactique: false },
|
||||
{ key: 'normale', label: 'Attaque normale', dmg: 0, attaque: 0, parade: 0, esquive: true, isTactique: true },
|
||||
{ key: 'charge', label: 'Charge', dmg: 2, attaque: 4, parade: -4, esquive: false, isTactique: true },
|
||||
{ key: 'feinte', label: 'Feinte', dmg: 1, attaque: 1, parade: 0, esquive: true, isTactique: true },
|
||||
{ key: 'pret', label: 'prêt', dmg: 0, attaque: 0, parade: 0, esquive: true, isTactique: false },
|
||||
{ key: 'demi', label: 'Demi-surprise', dmg: 1, attaque: 0, parade: 0, esquive: true, isTactique: false },
|
||||
{ key: 'totale', label: 'Surprise totale', dmg: 10, attaque: 6, parade: 0, esquive: true, isTactique: false },
|
||||
];
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RdDBonus {
|
||||
|
||||
static get tactiques() {
|
||||
return conditionsTactiques.filter(it => it.isTactique)
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static find(condition) {
|
||||
return conditionsTactiques.find(e => e.type == condition) || conditionsTactiques.find(e => e.type == 'pret');
|
||||
return conditionsTactiques.find(e => e.key == condition) || conditionsTactiques[0];
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +35,8 @@ export class RdDBonus {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static dmg(rollData, actor, isEntiteIncarnee = false) {
|
||||
const dmgArme = RdDBonus.dmgArme(rollData.arme)
|
||||
const dmgArme = RdDBonus.dmgArme(rollData.arme, rollData.arme?.system.dommagesReels)
|
||||
const forceRequise = RdDItemArme.valeurMain(rollData.arme?.system.force ?? 0, RdDItemArme.getMainAttaque(rollData.competence))
|
||||
let dmg = {
|
||||
total: 0,
|
||||
dmgArme: dmgArme,
|
||||
@@ -41,39 +45,44 @@ export class RdDBonus {
|
||||
dmgParticuliere: RdDBonus._dmgParticuliere(rollData),
|
||||
dmgSurprise: RdDBonus.dmgBonus(rollData.ajustements?.attaqueDefenseurSurpris.used),
|
||||
mortalite: RdDBonus._calculMortalite(rollData, isEntiteIncarnee),
|
||||
dmgActor: RdDBonus.bonusDmg(actor, rollData.selectedCarac?.label.toLowerCase(), dmgArme)
|
||||
dmgActor: RdDBonus.bonusDmg(actor, rollData.selectedCarac?.label.toLowerCase(), dmgArme),
|
||||
dmgForceInsuffisante: Math.min(0, actor.getForce() - forceRequise)
|
||||
}
|
||||
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere;
|
||||
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere + dmg.dmgForceInsuffisante
|
||||
return dmg;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static description(condition) {
|
||||
return RdDBonus.find(condition).descr;
|
||||
return RdDBonus.find(condition).label
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static dmgBonus(condition) {
|
||||
return RdDBonus.find(condition).dmg;
|
||||
return RdDBonus.find(condition).dmg
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static bonusAttaque(condition) {
|
||||
return RdDBonus.find(condition).attaque;
|
||||
return RdDBonus.find(condition).attaque
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _calculMortalite(rollData, isEntiteIncarnee) {
|
||||
return RdDBonus.mortalite(rollData.dmg?.mortalite, rollData.arme?.system.mortalite, isEntiteIncarnee)
|
||||
}
|
||||
|
||||
static mortalite(mortaliteSelect, mortaliteArme, isEntiteIncarnee) {
|
||||
return isEntiteIncarnee ? "entiteincarnee"
|
||||
: rollData.dmg?.mortalite
|
||||
?? rollData.arme?.system.mortalite
|
||||
: mortaliteSelect
|
||||
?? mortaliteArme
|
||||
?? "mortel";
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static dmgArme(arme) {
|
||||
static dmgArme(arme, dommagesMain) {
|
||||
if (arme) {
|
||||
let dmgBase = arme.system.dommagesReels ?? Number(arme.system.dommages ?? 0);
|
||||
let dmgBase = dommagesMain ?? Number(arme.system.dommages ?? 0);
|
||||
//Le bonus dégats magiques ne peut pas faire dépasser le bonus de l'arme (cf p.278)
|
||||
return dmgBase + Math.min(dmgBase, arme.system.magique ? arme.system.ecaille_efficacite : 0);
|
||||
}
|
||||
@@ -87,13 +96,13 @@ export class RdDBonus {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static bonusDmg(actor, categorie, dmgArme) {
|
||||
const dmgActor = actor.getBonusDegat()
|
||||
if (categorie == undefined) {
|
||||
return 0
|
||||
}
|
||||
const dmgActor = actor.getBonusDegat()
|
||||
switch (categorie) {
|
||||
case "tir": return 0;
|
||||
case "lancer": return Math.max(0, Math.min(dmgArme, dmgActor));
|
||||
case "(tir)": case "tir": return 0
|
||||
case "(lancer)": case "lancer": return Math.max(0, Math.min(dmgArme, dmgActor));
|
||||
}
|
||||
return dmgActor;
|
||||
}
|
||||
|
@@ -52,6 +52,15 @@ export const CARACS = {
|
||||
EMPATHIE: 'empathie',
|
||||
REVE: 'reve',
|
||||
CHANCE: 'chance',
|
||||
PROTECTION: 'protection',
|
||||
BEAUTE: 'beaute',
|
||||
PERCEPTION: 'perception',
|
||||
MELEE: 'melee',
|
||||
TIR: 'tir',
|
||||
LANCER: 'lancer',
|
||||
DEROBEE: 'derobee',
|
||||
CHANCE_ACTUELLE: 'chance-actuelle',
|
||||
REVE_ACTUEL: 'reve-actuel',
|
||||
}
|
||||
export const LIST_CARAC_PERSONNAGE = {
|
||||
[CARACS.TAILLE]: { code: CARACS.TAILLE, label: 'Taille', isCarac: true, path: 'system.carac.taille.value' },
|
||||
@@ -68,21 +77,21 @@ export const LIST_CARAC_PERSONNAGE = {
|
||||
[CARACS.EMPATHIE]: { code: CARACS.EMPATHIE, label: 'Empathie', isCarac: true, path: 'system.carac.empathie.value' },
|
||||
[CARACS.REVE]: { code: CARACS.REVE, label: 'Rêve', isCarac: true, path: 'system.carac.reve.value' },
|
||||
[CARACS.CHANCE]: { code: CARACS.CHANCE, label: 'Chance', isCarac: true, path: 'system.carac.chance.value' },
|
||||
'protection': { code: 'protection', label: 'Protection naturelle', isCarac: false, path: 'system.attributs.protection.value' },
|
||||
'beaute': { code: 'beaute', label: 'Beauté', isCarac: false, path: 'system.background.beaute.value' }
|
||||
[CARACS.PROTECTION]: { code: CARACS.PROTECTION, label: 'Protection naturelle', isCarac: false, path: 'system.attributs.protection.value' },
|
||||
[CARACS.BEAUTE]: { code: CARACS.BEAUTE, label: 'Beauté', isCarac: false, path: 'system.background.beaute.value' }
|
||||
}
|
||||
|
||||
export const LIST_CARAC_AUTRES = {
|
||||
'perception': { code: 'perception', label: 'Perception', path: 'system.carac.perception.value' },
|
||||
[CARACS.PERCEPTION]: { code: 'perception', label: 'Perception', path: 'system.carac.perception.value' },
|
||||
}
|
||||
|
||||
const LIST_CARAC_DERIVEE = {
|
||||
'melee': { code: "melee", label: 'Mêlée', path: 'system.carac.melee.value' },
|
||||
'tir': { code: "tir", label: 'Tir', path: 'system.carac.tir.value' },
|
||||
'lancer': { code: "lancer", label: 'Lancer', path: 'system.carac.lancer.value' },
|
||||
'derobee': { code: "derobee", label: 'Dérobée', path: 'system.carac.derobee.value' },
|
||||
'chance-actuelle': { code: "chance-actuelle", label: 'Chance actuelle', path: 'system.carac.lancer.value' },
|
||||
'reve-actuel': { code: "reve-actuel", label: 'Rêve actuel', path: 'system.reve.reve.value' },
|
||||
[CARACS.MELEE]: { code: CARACS.MELEE, label: 'Mêlée', path: 'system.carac.melee.value' },
|
||||
[CARACS.TIR]: { code: CARACS.TIR, label: 'Tir', path: 'system.carac.tir.value' },
|
||||
[CARACS.LANCER]: { code: CARACS.LANCER, label: 'Lancer', path: 'system.carac.lancer.value' },
|
||||
[CARACS.DEROBEE]: { code: CARACS.DEROBEE, label: 'Dérobée', path: 'system.carac.derobee.value' },
|
||||
[CARACS.CHANCE_ACTUELLE]: { code: CARACS.CHANCE_ACTUELLE, label: 'Chance actuelle', path: 'system.carac.lancer.value' },
|
||||
[CARACS.REVE_ACTUEL]: { code: CARACS.REVE_ACTUEL, label: 'Rêve actuel', path: 'system.reve.reve.value' },
|
||||
}
|
||||
|
||||
export const LIST_CARAC_ROLL = Object.values(LIST_CARAC_PERSONNAGE).filter(it => it.isCarac && it.code != 'taille')
|
||||
@@ -125,11 +134,11 @@ export class RdDCarac {
|
||||
}
|
||||
|
||||
static isIntellect(caracLabel) {
|
||||
return Grammar.toLowerCaseNoAccent(caracLabel) == 'intellect';
|
||||
return Grammar.toLowerCaseNoAccent(caracLabel) == CARACS.INTELLECT
|
||||
}
|
||||
|
||||
static isVolonte(caracLabel) {
|
||||
return Grammar.toLowerCaseNoAccent(caracLabel) == 'volonte';
|
||||
return Grammar.toLowerCaseNoAccent(caracLabel) == CARACS.VOLONTE
|
||||
}
|
||||
static isChance(caracLabel) {
|
||||
return Grammar.toLowerCaseNoAccent(caracLabel)?.match(/chance(( |-)?actuelle)?/);
|
||||
|
@@ -15,6 +15,10 @@ import { RdDItemArme } from "./item/arme.js";
|
||||
import { RdDItemCompetence } from "./item-competence.js";
|
||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
|
||||
import { RdDInitiative } from "./initiative.mjs";
|
||||
import RollDialog from "./roll/roll-dialog.mjs";
|
||||
import { PART_DEFENSE } from "./roll/roll-part-defense.mjs";
|
||||
import { PART_ATTAQUE } from "./roll/roll-part-attaque.mjs";
|
||||
import { RollDialogAdapter } from "./roll/roll-dialog-adapter.mjs";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
const premierRoundInit = [
|
||||
@@ -398,6 +402,7 @@ export class RdDCombat {
|
||||
/* -------------------------------------------- */
|
||||
static registerChatCallbacks(html) {
|
||||
for (let button of [
|
||||
'.defense-button',
|
||||
'.parer-button',
|
||||
'.esquiver-button',
|
||||
'.particuliere-attaque',
|
||||
@@ -466,6 +471,8 @@ export class RdDCombat {
|
||||
|
||||
switch (button) {
|
||||
case '.particuliere-attaque': return await this.choixParticuliere(attackerRoll, event.currentTarget.attributes['data-mode'].value);
|
||||
case '.defense-button': return this.defenseV2(attackerRoll);
|
||||
|
||||
case '.parer-button': return this.parade(attackerRoll, armeParadeId);
|
||||
case '.esquiver-button': return this.esquive(attackerRoll, compId, competence);
|
||||
case '.encaisser-button': return this.encaisser(attackerRoll, defenderRoll);
|
||||
@@ -713,9 +720,6 @@ export class RdDCombat {
|
||||
if (RdDCombat.isReussite(attackerRoll)) {
|
||||
return await this._onAttaqueNormale(attackerRoll)
|
||||
}
|
||||
// if (RdDCombat.isParticuliere(attackerRoll) && attackerRoll.particuliere == undefined) {
|
||||
// return
|
||||
// }
|
||||
if (RdDCombat.isEchecTotal(attackerRoll)) {
|
||||
return await this._onAttaqueEchecTotal(attackerRoll)
|
||||
}
|
||||
@@ -857,7 +861,7 @@ export class RdDCombat {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_filterArmesParade(defender, competence, armeAttaque) {
|
||||
let defenses = defender.items.filter(it => RdDItemArme.isParade(it))
|
||||
let defenses = defender.items.filter(it => it.isParade())
|
||||
defenses = foundry.utils.duplicate(defenses)
|
||||
defenses.forEach(armeDefense => {
|
||||
// Ajout du # d'utilisation ce round
|
||||
@@ -946,6 +950,41 @@ export class RdDCombat {
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
async defenseV2(attackerRoll) {
|
||||
|
||||
// this._prepareParade(attackerRoll, arme, competence);
|
||||
const rollData =
|
||||
{
|
||||
ids: {
|
||||
actorId: this.defender.id,
|
||||
actorTokenId: this.defenderTokenId,
|
||||
opponentTokenId: this.attackerTokenId,
|
||||
opponentId: this.attackerId,
|
||||
},
|
||||
mode: {
|
||||
allowed: ['defense'],
|
||||
current: 'defense'
|
||||
},
|
||||
attaque: RollDialogAdapter.mapActionAttaque(attackerRoll),
|
||||
passeArme: attackerRoll.passeArme,
|
||||
}
|
||||
|
||||
await RollDialog.create(rollData, {
|
||||
onRoll: (dialog) => {
|
||||
this._onCloseRollDialog(),
|
||||
dialog.close()
|
||||
},
|
||||
customChatMessage: true,
|
||||
callbacks: [async (actor, rd) => {
|
||||
this.removeChatMessageActionsPasseArme(rd.passeArme)
|
||||
// defense: esquive / arme de parade / competence de défense
|
||||
await rd.active.actor.incDecItemUse(rd.current[PART_DEFENSE].defense?.id, !RdDCombat.isParticuliere(rd))
|
||||
await this._onDefenseV2(rd)
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_prepareParade(attackerRoll, armeParade, competenceParade) {
|
||||
let defenderRoll = {
|
||||
@@ -971,7 +1010,6 @@ export class RdDCombat {
|
||||
return defenderRoll;
|
||||
}
|
||||
|
||||
|
||||
async _onParade(defenderRoll) {
|
||||
if (RdDCombat.isReussite(defenderRoll)) {
|
||||
await this._onParadeNormale(defenderRoll)
|
||||
@@ -982,6 +1020,16 @@ export class RdDCombat {
|
||||
}
|
||||
await this._onParadeEchec(defenderRoll)
|
||||
}
|
||||
async _onDefenseV2(defenderRoll) {
|
||||
if (RdDCombat.isReussite(defenderRoll)) {
|
||||
await this._onParadeNormale(defenderRoll)
|
||||
if (RdDCombat.isParticuliere(defenderRoll)) {
|
||||
await this._onParadeParticuliere(defenderRoll)
|
||||
}
|
||||
return
|
||||
}
|
||||
await this._onParadeEchec(defenderRoll)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _onParadeParticuliere(defenderRoll) {
|
||||
@@ -1256,3 +1304,7 @@ export class RdDCombat {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction(attackerRoll) {
|
||||
return attackerRoll.diffLibre;
|
||||
}
|
||||
|
@@ -1,10 +1,9 @@
|
||||
/* -------------------------------------------- */
|
||||
import { RdDRoll } from "./rdd-roll.js";
|
||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
|
||||
import { ChatUtility } from "./chat-utility.js";
|
||||
import { STATUSES } from "./settings/status-effects.js";
|
||||
import { ITEM_TYPES } from "./constants.js";
|
||||
import { ChatUtility } from "./chat-utility.js";
|
||||
import { RdDRollResult } from "./rdd-roll-result.js";
|
||||
import { RdDRoll } from "./rdd-roll.js";
|
||||
import { MappingCreatureArme } from "./item/mapping-creature-arme.mjs";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RdDEmpoignade {
|
||||
@@ -186,7 +185,7 @@ export class RdDEmpoignade {
|
||||
malusTaille: RdDEmpoignade.getMalusTaille(empoignade, attacker, defender)
|
||||
}
|
||||
if (attacker.isCreatureEntite()) {
|
||||
RdDItemCompetenceCreature.setRollDataCreature(rollData)
|
||||
MappingCreatureArme.setRollDataCreature(rollData)
|
||||
}
|
||||
if (empoignade.system.pointsemp >= 2) {
|
||||
if (!empoignade.system.ausol) {
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { RdDItemArme } from "./item/arme.js";
|
||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
|
||||
import { ATTAQUE_TYPE, RdDItemArme } from "./item/arme.js";
|
||||
import { ITEM_TYPES } from "./constants.js";
|
||||
|
||||
export class RdDHotbar {
|
||||
@@ -20,10 +19,13 @@ export class RdDHotbar {
|
||||
await game.user.assignHotbarMacro(macro, slot);
|
||||
}
|
||||
|
||||
static $macroNameSuffix(armeCompetence) {
|
||||
switch (armeCompetence) {
|
||||
case '(1 main)': return ' (1 main)';
|
||||
case '(2 mains)': return ' (2 main)';
|
||||
static $macroNameSuffix(maniement) {
|
||||
switch (maniement) {
|
||||
case ATTAQUE_TYPE.UNE_MAIN:
|
||||
case ATTAQUE_TYPE.DEUX_MAINS:
|
||||
case ATTAQUE_TYPE.LANCER:
|
||||
case ATTAQUE_TYPE.TIR:
|
||||
return ' ' + maniement
|
||||
case 'tir': return ' (tir)';
|
||||
case 'lancer': return ' (lancer)';
|
||||
case 'pugilat': return ' (pugilat)';
|
||||
@@ -39,22 +41,22 @@ export class RdDHotbar {
|
||||
// Les armes peuvent avoir plusieurs usages
|
||||
if (item.system.competence != '') {
|
||||
if (item.system.unemain) {
|
||||
await this.createItemMacro(item, slot++, '(1 main)')
|
||||
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.UNE_MAIN)
|
||||
}
|
||||
if (item.system.deuxmains) {
|
||||
await this.createItemMacro(item, slot++, '(2 mains)')
|
||||
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.DEUX_MAINS)
|
||||
}
|
||||
}
|
||||
if (item.system.lancer != '') {
|
||||
await this.createItemMacro(item, slot++, 'lancer')
|
||||
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.LANCER)
|
||||
}
|
||||
if (item.system.tir != '') {
|
||||
await this.createItemMacro(item, slot++, 'lancer')
|
||||
await this.createItemMacro(item, slot++, ATTAQUE_TYPE.TIR)
|
||||
}
|
||||
}
|
||||
return
|
||||
case ITEM_TYPES.competencecreature:
|
||||
const categorie = RdDItemCompetenceCreature.getCategorieAttaque(item) ?? 'competence';
|
||||
const categorie = item.getCategorieAttaque() ?? 'competence';
|
||||
await this.createItemMacro(item, slot, categorie)
|
||||
return
|
||||
default:
|
||||
@@ -127,7 +129,7 @@ export class RdDHotbar {
|
||||
}
|
||||
return actor.rollCompetence(item);
|
||||
case ITEM_TYPES.competencecreature:
|
||||
return item.system.iscombat && !item.system.isparade
|
||||
return item.system.iscombat
|
||||
? actor.rollArme(item, categorieArme)
|
||||
: actor.rollCompetence(item);
|
||||
|
||||
|
@@ -1,9 +1,7 @@
|
||||
import { RdDRoll } from "./rdd-roll.js";
|
||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
|
||||
import { Targets } from "./targets.js";
|
||||
import { ITEM_TYPES } from "./constants.js";
|
||||
import { RdDRollResult } from "./rdd-roll-result.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* On part du principe qu'une entité démarre tjs
|
||||
|
@@ -19,7 +19,7 @@ import { RdDEmpoignade } from "./rdd-empoignade.js";
|
||||
import { ExperienceLog } from "./actor/experience-log.js";
|
||||
import { RdDCoeur } from "./coeur/rdd-coeur.js";
|
||||
import { APP_ASTROLOGIE_REFRESH } from "./sommeil/app-astrologie.js";
|
||||
import { ITEM_TYPES, RDD_CONFIG } from "./constants.js";
|
||||
import { ITEM_TYPES, RDD_CONFIG, SYSTEM_RDD } from "./constants.js";
|
||||
import { RdDBaseActor } from "./actor/base-actor.js";
|
||||
import { RdDCarac } from "./rdd-carac.js";
|
||||
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
|
||||
@@ -271,6 +271,7 @@ export class RdDUtility {
|
||||
|
||||
// foundry et options
|
||||
Handlebars.registerHelper('RDD_CONFIG', path => RDD_CONFIG[path])
|
||||
Handlebars.registerHelper('settings-get', (setting) => game.settings.get(SYSTEM_RDD, setting))
|
||||
Handlebars.registerHelper('linkCompendium', (pack, id, name) => RdDUtility.linkCompendium(pack, id, name));
|
||||
Handlebars.registerHelper('regle-optionnelle', (option) => ReglesOptionnelles.isUsing(option));
|
||||
|
||||
|
@@ -4,6 +4,8 @@ import { PART_COMP } from "./roll-part-comp.mjs";
|
||||
import { RdDResolutionTable } from "../rdd-resolution-table.js";
|
||||
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
|
||||
import { PART_OEUVRE } from "./roll-part-oeuvre.mjs";
|
||||
import { ATTAQUE_TYPE, RdDItemArme } from "../item/arme.js";
|
||||
import { RdDBonus } from "../rdd-bonus.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RollDialogAdapter {
|
||||
@@ -87,4 +89,29 @@ export class RollDialogAdapter {
|
||||
rollData.show.title = rollTitle
|
||||
}
|
||||
|
||||
static mapActionAttaque(attackerRoll) {
|
||||
if (attackerRoll.ids) {
|
||||
return attackerRoll.current[PART_ATTAQUE]
|
||||
}
|
||||
const label = attackerRoll.alias + ' ' + attackerRoll.arme.name;
|
||||
return {
|
||||
// correspond à l'attaque de RollPartAttaque (dans rollDta.current.attaque)
|
||||
label: label,
|
||||
attaque: {
|
||||
// correspond aux actions d'attaques dans RdDActor.listActionsAttaque
|
||||
name: label,
|
||||
// action: 'attaque',
|
||||
arme: attackerRoll.arme,
|
||||
comp: attackerRoll.competence,
|
||||
main: RdDItemArme.getMainAttaque(attackerRoll.competence),
|
||||
equipe: attackerRoll.arme.system.equipe,
|
||||
// carac: { key: caracCode, value: caracValue },
|
||||
// dommagesArme: dommagesArme,
|
||||
},
|
||||
diff: attackerRoll.diffLibre,
|
||||
particuliere: attackerRoll.particuliere,
|
||||
tactique: RdDBonus.find(attackerRoll.tactique),
|
||||
dmg: attackerRoll.dmg,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -187,7 +187,12 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
foundry.applications.handlebars.loadTemplates(ROLL_PARTS.map(p => p.template))
|
||||
ROLL_PARTS.forEach(p => p.onReady())
|
||||
|
||||
Handlebars.registerHelper('roll-centered-array', (base, show) => RollDialog.centeredArray(base, show))
|
||||
Handlebars.registerHelper('roll-centered-array', (base, show) => {
|
||||
show = Math.abs(show)
|
||||
const start = base - show
|
||||
return [...Array(2 * show + 1).keys()].map(it => start + it)
|
||||
})
|
||||
|
||||
Handlebars.registerHelper('roll-list-item-value', (list, key, path = undefined) => {
|
||||
const selected = list.find(p => p.key == key)
|
||||
if (selected && path && path != '') {
|
||||
@@ -195,6 +200,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
}
|
||||
return selected
|
||||
})
|
||||
|
||||
Handlebars.registerHelper('roll-part-context', (rollData, code) => {
|
||||
const rollPart = ROLL_PARTS.find(it => it.code == code)
|
||||
if (rollPart == undefined) {
|
||||
@@ -211,11 +217,6 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
})
|
||||
}
|
||||
|
||||
static centeredArray(base, show) {
|
||||
show = Math.abs(show)
|
||||
const start = base - show
|
||||
return [...Array(2 * show + 1).keys()].map(it => start + it)
|
||||
}
|
||||
|
||||
static async create(rollData, rollOptions = {}) {
|
||||
const rollDialog = new RollDialog(rollData, rollOptions)
|
||||
@@ -267,15 +268,18 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
/** pre-configure les paramètres des différentes parties de la fenêtre (par exemple, prépare les listes de caractéristiques/compétences */
|
||||
$loadParts() {
|
||||
const rollData = this.rollData;
|
||||
const loadedMode = rollData.mode?.current
|
||||
rollData.current = rollData.current ?? {}
|
||||
rollData.selected = rollData.selected ?? {}
|
||||
rollData.mode = rollData.mode ?? {}
|
||||
rollData.mode.retry = rollData.mode.retry ?? false
|
||||
BASIC_PARTS.restore(rollData)
|
||||
|
||||
const loadedMode = ROLL_MODE_TABS.find(m => m.code == rollData.mode?.current)?.code
|
||||
const allowedModes = ROLL_MODE_TABS.filter(m => m.isAllowed(rollData) && m.visible(rollData)).map(m => m.code)
|
||||
|
||||
rollData.mode.allowed = rollData.mode.retry ? [loadedMode] : rollData.mode.allowed ?? ROLL_MODE_TABS.map(m => m.code)
|
||||
rollData.mode.current = loadedMode ?? ROLL_MODE_TABS.find(m => m.isAllowed(rollData) && m.visible(rollData))?.code ?? ROLL_MODE_COMP
|
||||
rollData.mode.current = allowedModes.find(m => m == rollData.mode?.current) ?? (allowedModes.length > 0 ? allowedModes[0] : ROLL_MODE_COMP)
|
||||
|
||||
this.getSelectedMode().setRollDataMode(rollData)
|
||||
|
||||
rollData.refs = this.$prepareRefs(rollData)
|
||||
@@ -360,7 +364,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
this.setModeTitle()
|
||||
|
||||
const visibleRollParts = this.getActiveParts()
|
||||
visibleRollParts.forEach(p => p.setExternalFilter(visibleRollParts, rollData))
|
||||
visibleRollParts.forEach(p => p.applyExternalImpacts(visibleRollParts, rollData))
|
||||
|
||||
this.setSpecialComp(visibleRollParts);
|
||||
|
||||
|
@@ -5,7 +5,7 @@ export class RollModeDefense extends RollMode {
|
||||
get code() { return ROLL_MODE_DEFENSE }
|
||||
get name() { return `Se défendre` }
|
||||
|
||||
title(rollData) { return `se défend${rollData.attacker ? ' de' : ''}` }
|
||||
title(rollData) { return `se défend${rollData.opponent ? ' de' : ''}` }
|
||||
|
||||
getOpponent(rollData) {
|
||||
return rollData.attacker
|
||||
|
@@ -37,6 +37,7 @@ export class RollPartAppelMoral extends RollPartCheckbox {
|
||||
}
|
||||
return '<i class="fa-regular fa-face-meh"></i>'
|
||||
}
|
||||
|
||||
getCheckboxLabel(rollData) { return "Appel au moral" }
|
||||
getCheckboxValue(rollData) { return 1 }
|
||||
}
|
||||
|
@@ -1,12 +1,16 @@
|
||||
import { Grammar } from "../grammar.js"
|
||||
import { RdDBonus } from "../rdd-bonus.js"
|
||||
import { StatusEffects } from "../settings/status-effects.js"
|
||||
import { ROLL_MODE_ATTAQUE } from "./roll-constants.mjs"
|
||||
import { PART_CARAC } from "./roll-part-carac.mjs"
|
||||
import { PART_COMP } from "./roll-part-comp.mjs"
|
||||
import { RollPartSelect } from "./roll-part-select.mjs"
|
||||
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
|
||||
import { PART_SIGN } from "./roll-part-sign.mjs"
|
||||
import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
|
||||
|
||||
export const PART_ATTAQUE = 'attaque'
|
||||
|
||||
const TACTIQUES = RdDBonus.tactiques.filter(it => it.isTactique)
|
||||
|
||||
export class RollPartAttaque extends RollPartSelect {
|
||||
|
||||
get code() { return PART_ATTAQUE }
|
||||
@@ -18,29 +22,71 @@ export class RollPartAttaque extends RollPartSelect {
|
||||
const refs = this.getRefs(rollData)
|
||||
const attaques = rollData.active.actor.listAttaques()
|
||||
refs.attaques = attaques.map(it => RollPartAttaque.$extractAttaque(it, rollData.active.actor))
|
||||
if (refs.attaques.length>0){
|
||||
refs.tactiques = TACTIQUES
|
||||
if (refs.attaques.length > 0) {
|
||||
this.$selectAttaque(rollData)
|
||||
}
|
||||
}
|
||||
|
||||
choices(refs) { return refs.attaques }
|
||||
|
||||
static $extractAttaque(action, actor) {
|
||||
static $extractAttaque(attaque, actor) {
|
||||
return {
|
||||
key: `${action.action}::${action.arme.id}::${action.comp.id}`,
|
||||
label: action.name,
|
||||
action: action,
|
||||
arme: action.arme,
|
||||
comp: action.comp,
|
||||
key: `${attaque.action}::${attaque.name}`,
|
||||
label: attaque.name,
|
||||
attaque: attaque,
|
||||
tactique: TACTIQUES[0],
|
||||
}
|
||||
}
|
||||
|
||||
prepareContext(rollData) {
|
||||
const current = this.getCurrent(rollData)
|
||||
current.defenseur = StatusEffects.getActorEffetSurprise(rollData.opponent?.actor, 0)
|
||||
current.attaquant = StatusEffects.getActorEffetSurprise(rollData.active.actor, current.attaque.forceRequise)
|
||||
current.dmg = this.$dmgRollV2(rollData, current)
|
||||
}
|
||||
|
||||
$dmgRollV2(rollData, current) {
|
||||
const actor = rollData.active.actor
|
||||
const defender = rollData.opponent?.actor
|
||||
const dmgArme = RdDBonus.dmgArme(current.attaque.arme, current.attaque.dommagesArme)
|
||||
const dmg = {
|
||||
total: 0,
|
||||
dmgArme: dmgArme,
|
||||
penetration: current.attaque.arme.penetration(),
|
||||
dmgTactique: current.tactique?.dmg ?? 0,
|
||||
dmgParticuliere: 0, // TODO RdDBonus._dmgParticuliere(rollData),
|
||||
dmgSurprise: current.surpriseDefenseur?.dmg ?? 0,
|
||||
mortalite: RdDBonus.mortalite(current.dmg?.mortalite, current.attaque.arme.system.mortalite, defender?.isEntite()),
|
||||
dmgActor: RdDBonus.bonusDmg(actor, current.attaque.carac.key, dmgArme, current.attaque.forceRequise),
|
||||
dmgForceInsuffisante: Math.min(0, actor.getForce() - current.attaque.forceRequise)
|
||||
}
|
||||
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere + dmg.dmgForceInsuffisante
|
||||
return dmg
|
||||
}
|
||||
|
||||
getAjustements(rollData) {
|
||||
const current = this.getCurrent(rollData)
|
||||
const ajustements = []
|
||||
if (current.tactique) {
|
||||
ajustements.push({ label: current.tactique.label, diff: current.tactique.attaque })
|
||||
}
|
||||
if (current.surpriseDefenseur) {
|
||||
ajustements.push({ label: current.surpriseDefenseur.label, diff: current.surpriseDefenseur.attaque })
|
||||
}
|
||||
return ajustements
|
||||
}
|
||||
|
||||
|
||||
$selectAttaque(rollData, key) {
|
||||
this.selectByKey(rollData, key, 0)
|
||||
this.selectByKey(rollData, key)
|
||||
}
|
||||
|
||||
async _onRender(rollDialog, context, options) {
|
||||
const selectAttaque = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-attaque"]`)
|
||||
const selectTactique = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-tactique"]`)
|
||||
const checkMortalite = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="check-mortalite"]`)
|
||||
const current = this.getCurrent(rollDialog.rollData)
|
||||
|
||||
selectAttaque.addEventListener("change", e => {
|
||||
const selectOptions = e.currentTarget.options
|
||||
@@ -49,18 +95,29 @@ export class RollPartAttaque extends RollPartSelect {
|
||||
rollDialog.setModeTitle()
|
||||
rollDialog.render()
|
||||
})
|
||||
|
||||
selectTactique.addEventListener("change", e => {
|
||||
const selectOptions = e.currentTarget.options
|
||||
const index = selectOptions.selectedIndex
|
||||
current.tactique = RdDBonus.find(selectOptions[index]?.value)
|
||||
rollDialog.render()
|
||||
})
|
||||
|
||||
checkMortalite?.addEventListener("change", e => {
|
||||
current.dmg.mortalite = (e.currentTarget.checked ? 'mortel' : 'non-mortel')
|
||||
rollDialog.render()
|
||||
})
|
||||
}
|
||||
|
||||
getExternalPartsFilter(partCode, rollData) {
|
||||
impactOtherPart(part, rollData) {
|
||||
if (this.visible(rollData)) {
|
||||
const current = this.getCurrent(rollData)
|
||||
switch (partCode) {
|
||||
case PART_CARAC: return p => Grammar.equalsInsensitive(current.action.carac.key, p.key)
|
||||
case PART_COMP: return p => p.label == current.comp?.name
|
||||
switch (part.code) {
|
||||
case PART_CARAC: return part.filterCaracs(rollData, [current.attaque.carac.key])
|
||||
case PART_COMP: return part.filterComps(rollData, [current.attaque.comp?.name])
|
||||
case PART_SIGN: return part.setArme(rollData, current.attaque.forceRequise, false)
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -36,9 +36,13 @@ export class RollPartCarac extends RollPartSelect {
|
||||
}
|
||||
}
|
||||
|
||||
setFilter(rollData, filter) {
|
||||
filterCaracs(rollData, allowed) {
|
||||
allowed = allowed.filter(it => it != undefined)
|
||||
const refs = this.getRefs(rollData)
|
||||
refs.caracs = refs.all.filter(filter)
|
||||
refs.caracs = allowed.length > 0
|
||||
// ? refs.all.filter(it => allowed.includes(Grammar.toLowerCaseNoAccent(it.key)))
|
||||
? refs.all.filter(it => allowed.includes(it.key))
|
||||
: refs.all
|
||||
}
|
||||
|
||||
prepareContext(rollData) {
|
||||
|
@@ -18,8 +18,8 @@ export class RollPartCheckbox extends RollPart {
|
||||
}
|
||||
|
||||
loadRefs(rollData) {
|
||||
const current = this.getCurrent(rollData)
|
||||
current.label = this.getCheckboxLabel(rollData)
|
||||
const refs = this.getRefs(rollData)
|
||||
refs.label = this.getCheckboxLabel(rollData)
|
||||
}
|
||||
|
||||
prepareContext(rollData) {
|
||||
@@ -43,7 +43,7 @@ export class RollPartCheckbox extends RollPart {
|
||||
}
|
||||
|
||||
getCheckboxLabelAjustement(rollData) {
|
||||
return `${this.getCheckboxIcon(rollData)} ${this.getCurrent(rollData).label}`
|
||||
return `${this.getCheckboxIcon(rollData)} ${this.getRefs(rollData).label}`
|
||||
}
|
||||
|
||||
async _onRender(rollDialog, context, options) {
|
||||
|
@@ -45,9 +45,13 @@ export class RollPartComp extends RollPartSelect {
|
||||
}
|
||||
}
|
||||
|
||||
setFilter(rollData, filter) {
|
||||
filterComps(rollData, allowed) {
|
||||
allowed = allowed.filter(it => it != undefined)
|
||||
const refs = this.getRefs(rollData)
|
||||
refs.comps = refs.all.filter(filter)
|
||||
refs.comps = allowed.length > 0
|
||||
// ? refs.all.filter(it => allowed.includes(Grammar.toLowerCaseNoAccent(it.label)))
|
||||
? refs.all.filter(it => allowed.includes(it.label))
|
||||
: refs.all
|
||||
}
|
||||
|
||||
prepareContext(rollData) {
|
||||
|
@@ -1,17 +1,133 @@
|
||||
import { ROLL_MODE_DEFENSE } from "./roll-constants.mjs"
|
||||
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
|
||||
import { ITEM_TYPES } from "../constants.js"
|
||||
import { Grammar } from "../grammar.js"
|
||||
import { ATTAQUE_TYPE, RdDItemArme } from "../item/arme.js"
|
||||
import { RdDBonus } from "../rdd-bonus.js"
|
||||
import { CARACS } from "../rdd-carac.js"
|
||||
import { StatusEffects } from "../settings/status-effects.js"
|
||||
import { DIFF_MODE, ROLL_MODE_DEFENSE } from "./roll-constants.mjs"
|
||||
import { PART_CARAC } from "./roll-part-carac.mjs"
|
||||
import { PART_COMP } from "./roll-part-comp.mjs"
|
||||
import { PART_DIFF } from "./roll-part-diff.mjs"
|
||||
import { RollPartSelect } from "./roll-part-select.mjs"
|
||||
import { PART_SIGN } from "./roll-part-sign.mjs"
|
||||
import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
|
||||
|
||||
export const PART_DEFENSE = 'defense'
|
||||
|
||||
export class RollPartDefense extends RollPart {
|
||||
export class RollPartDefense extends RollPartSelect {
|
||||
|
||||
get code() { return PART_DEFENSE }
|
||||
get section() { return ROLLDIALOG_SECTION.CHOIX }
|
||||
visible(rollData) { return this.isRollMode(rollData, ROLL_MODE_DEFENSE) }
|
||||
|
||||
loadRefs(rollData) {
|
||||
const refs = this.getRefs(rollData)
|
||||
refs.defenses =[]
|
||||
static getDiffAttaque(attackerRoll) {
|
||||
// TODO: rollDataV2?
|
||||
return attackerRoll.diffLibre;
|
||||
}
|
||||
|
||||
loadRefs(rollData) {
|
||||
const refs = this.getRefs(rollData)
|
||||
const attaque = rollData.attaque
|
||||
const defenseur = rollData.active.actor
|
||||
refs.isDistance = [ATTAQUE_TYPE.TIR, ATTAQUE_TYPE.LANCER].find(it => it == attaque?.main)
|
||||
const esquives = refs.isDistance == ATTAQUE_TYPE.TIR ? [] : defenseur.getCompetencesEsquive()
|
||||
.map(it => RollPartDefense.$extractEsquive(it, defenseur))
|
||||
|
||||
const parades = defenseur.items.filter(it => it.isParade() && (!refs.isDistance || it.isBouclier()))
|
||||
.map(it => RollPartDefense.$extractParade(it, attaque?.attaque.arme, defenseur))
|
||||
|
||||
refs.defenses = [...esquives, ...parades].filter(it => it != undefined)
|
||||
this.$selectDefense(rollData)
|
||||
}
|
||||
|
||||
static $extractEsquive(esquive, defenseur) {
|
||||
return {
|
||||
key: esquive.id,
|
||||
label: esquive.name,
|
||||
img: esquive.img,
|
||||
// TODO: carac pour créatures
|
||||
carac: defenseur.isPersonnage() ? CARACS.DEROBEE : esquive.name,
|
||||
comp: esquive
|
||||
}
|
||||
}
|
||||
|
||||
static $extractParade(armeDefense, armeAttaque, defenseur) {
|
||||
const comp = (ITEM_TYPES.competencecreature == armeDefense.type)
|
||||
? armeDefense
|
||||
: defenseur.getCompetence(armeDefense.system.competence)
|
||||
return {
|
||||
key: armeDefense.id,
|
||||
label: 'Parade ' + armeDefense.name,
|
||||
img: armeDefense.img,
|
||||
// TODO: carac pour créatures
|
||||
carac: defenseur.isPersonnage() ? CARACS.MELEE : comp.name,
|
||||
comp: comp,
|
||||
arme: armeDefense,
|
||||
forceRequise: armeDefense ? RdDItemArme.valeurMain(armeDefense.system.force ?? 0, RdDItemArme.getMainAttaque(comp)) : 0,
|
||||
typeParade: armeAttaque ? RdDItemArme.defenseArmeParade(armeDefense, armeAttaque) : 'norm'
|
||||
}
|
||||
}
|
||||
|
||||
prepareContext(rollData) {
|
||||
const current = this.getCurrent(rollData)
|
||||
current.defenseur = StatusEffects.getActorEffetSurprise(rollData.active.actor, current.forceRequise)
|
||||
|
||||
// current.dmg = this.$dmgRollV2(rollData, current)
|
||||
}
|
||||
|
||||
getAjustements(rollData) {
|
||||
return []
|
||||
}
|
||||
|
||||
choices(refs) { return refs.defenses }
|
||||
|
||||
$selectDefense(rollData, key) {
|
||||
this.selectByKey(rollData, key)
|
||||
}
|
||||
|
||||
async _onRender(rollDialog, context, options) {
|
||||
const selectDefense = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-defense"]`)
|
||||
|
||||
selectDefense.addEventListener("change", e => {
|
||||
const selectOptions = e.currentTarget.options
|
||||
const index = selectOptions.selectedIndex
|
||||
this.$selectDefense(rollDialog.rollData, selectOptions[index]?.value)
|
||||
rollDialog.setModeTitle()
|
||||
rollDialog.render()
|
||||
})
|
||||
}
|
||||
|
||||
impactOtherPart(part, rollData) {
|
||||
if (this.visible(rollData)) {
|
||||
const current = this.getCurrent(rollData)
|
||||
switch (part.code) {
|
||||
case PART_CARAC: return part.filterCaracs(rollData, [current.carac])
|
||||
case PART_COMP: return part.filterComps(rollData, [current.comp?.name])
|
||||
case PART_DIFF: return part.setDiff(rollData, this.getDiffDefense(rollData))
|
||||
case PART_SIGN: return part.setArme(rollData, current.forceRequise, this.isArmeDisparate(rollData))
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
isArmeDisparate(rollData) {
|
||||
const armeDefense = this.getCurrent(rollData).arme
|
||||
if (armeDefense) {
|
||||
const armeAttaque = rollData.attaque?.attaque.arme
|
||||
return RdDItemArme.defenseArmeParade(armeAttaque, armeDefense) == 'sign'
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
getDiffDefense(rollData) {
|
||||
const current = this.getCurrent(rollData)
|
||||
const refs = this.getRefs(rollData)
|
||||
if (refs.isDistance) {
|
||||
// Déterminer la difficulté de parade
|
||||
return { diff: 0, mode: DIFF_MODE.LIBRE }
|
||||
}
|
||||
else {
|
||||
return { diff: rollData.attaque.diff, mode: DIFF_MODE.DEFENSE }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -50,6 +50,12 @@ export class RollPartDiff extends RollPart {
|
||||
)
|
||||
}
|
||||
|
||||
setDiff(rollData, diffDefense) {
|
||||
const current = this.getCurrent(rollData)
|
||||
current.value = diffDefense.diff
|
||||
current.mode = diffDefense.mode
|
||||
}
|
||||
|
||||
getAjustements(rollData) {
|
||||
const current = this.getCurrent(rollData)
|
||||
return [{
|
||||
@@ -67,4 +73,5 @@ export class RollPartDiff extends RollPart {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -91,12 +91,12 @@ export class RollPartJeu extends RollPartSelect {
|
||||
})
|
||||
}
|
||||
|
||||
getExternalPartsFilter(partCode, rollData) {
|
||||
impactOtherPart(part, rollData) {
|
||||
if (this.visible(rollData)) {
|
||||
const current = this.getCurrent(rollData)
|
||||
switch (partCode) {
|
||||
case PART_CARAC: return p => current.caracs?.includes(Grammar.toLowerCaseNoAccent(p.key))
|
||||
case PART_COMP: return p => p.label == current.comp?.name
|
||||
switch (part.code) {
|
||||
case PART_CARAC: return part.filterCaracs(rollData, current.caracs)
|
||||
case PART_COMP: return part.filterComps(rollData,[current.comp?.name])
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { ITEM_TYPES } from "../constants.js"
|
||||
import { Grammar } from "../grammar.js"
|
||||
import { RdDCarac } from "../rdd-carac.js"
|
||||
import { CARACS, RdDCarac } from "../rdd-carac.js"
|
||||
import { RdDTimestamp } from "../time/rdd-timestamp.js"
|
||||
import { TMRUtility } from "../tmr-utility.js"
|
||||
import { ROLL_MODE_MEDITATION } from "./roll-constants.mjs"
|
||||
@@ -104,12 +104,12 @@ export class RollPartMeditation extends RollPartSelect {
|
||||
})
|
||||
}
|
||||
|
||||
getExternalPartsFilter(partCode, rollData) {
|
||||
impactOtherPart(part, rollData) {
|
||||
if (this.visible(rollData)) {
|
||||
const current = this.getCurrent(rollData)
|
||||
switch (partCode) {
|
||||
case PART_CARAC: return p => RdDCarac.isIntellect(p.key)
|
||||
case PART_COMP: return p => p.label == current.comp?.name
|
||||
switch (part.code) {
|
||||
case PART_CARAC: return part.filterCaracs(rollData, [CARACS.INTELLECT])
|
||||
case PART_COMP: return part.filterComps(rollData,[current.comp?.name])
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
|
@@ -85,12 +85,12 @@ export class RollPartOeuvre extends RollPartSelect {
|
||||
})
|
||||
}
|
||||
|
||||
getExternalPartsFilter(partCode, rollData) {
|
||||
impactOtherPart(part, rollData) {
|
||||
if (this.visible(rollData)) {
|
||||
const current = this.getCurrent(rollData)
|
||||
switch (partCode) {
|
||||
case PART_CARAC: return p => current.caracs?.includes(Grammar.toLowerCaseNoAccent(p.key))
|
||||
case PART_COMP: return p => p.label == current.comp?.name
|
||||
switch (part.code) {
|
||||
case PART_CARAC: return part.filterCaracs(rollData, current.caracs)
|
||||
case PART_COMP: return part.filterComps(rollData,[current.comp?.name])
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
|
@@ -27,7 +27,7 @@ export class RollPartSelect extends RollPart {
|
||||
const current = this.getCurrent(rollData)
|
||||
const newChoice = (choices.length == 0)
|
||||
? { key: '', value: defValue }
|
||||
: this.$getSelectedChoice(choices, key ?? current?.key ?? refs.key ?? '')
|
||||
: this.$getSelectedChoice(choices, key ?? current?.key ?? refs?.key ?? '')
|
||||
this.setCurrent(rollData, newChoice)
|
||||
return newChoice
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { Misc } from "../misc.js"
|
||||
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"
|
||||
import { StatusEffects } from "../settings/status-effects.js"
|
||||
import { ROLL_MODE_ATTAQUE, ROLL_MODE_DEFENSE } from "./roll-constants.mjs"
|
||||
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
|
||||
@@ -22,11 +23,6 @@ export class RollPartSign extends RollPart {
|
||||
this.setSaved(targetData, this.getCurrent(rollData))
|
||||
}
|
||||
|
||||
// visible(rollData) {
|
||||
// const current = this.getCurrent(rollData)
|
||||
// return current.surprise != ''
|
||||
// }
|
||||
|
||||
isCombat(rollData) {
|
||||
return [ROLL_MODE_ATTAQUE, ROLL_MODE_DEFENSE].includes(rollData.mode.current) || rollData.mode.isCombat
|
||||
}
|
||||
@@ -42,41 +38,61 @@ export class RollPartSign extends RollPart {
|
||||
const actor = rollData.active.actor;
|
||||
const isCombat = this.isCombat(rollData)
|
||||
const current = this.getCurrent(rollData)
|
||||
current.armeDisparate = isCombat && current.armeDisparate
|
||||
current.forceRequise = current.forceRequise ?? 0
|
||||
current.surprise = actor.getSurprise(isCombat)
|
||||
current.reasons = actor.getEffects(it => StatusEffects.niveauSurprise(it) > 0).map(it => it.name)
|
||||
current.diviseur = 1
|
||||
if (isCombat && actor.isDemiReve()) {
|
||||
current.reasons.push('Demi-rêve en combat')
|
||||
}
|
||||
if (current.surprise == 'demi') {
|
||||
current.diviseur *= 2
|
||||
}
|
||||
|
||||
if (this.isAttaqueFinesse(rollData)) {
|
||||
current.diviseur *= 2
|
||||
current.reasons.push('Attaque en finesse')
|
||||
if (isCombat && actor.isDemiReve()) {
|
||||
current.reasons.push('Demi-rêve en combat')
|
||||
}
|
||||
if (this.isForceInsuffisante(rollData)) {
|
||||
if (this.isParadeArmeDisparate(current)) {
|
||||
current.diviseur *= 2
|
||||
current.reasons.push('Armes disparates')
|
||||
}
|
||||
if (this.isForceInsuffisante(actor, current)) {
|
||||
current.diviseur *= 2
|
||||
current.reasons.push('Force insuffisante')
|
||||
}
|
||||
if (this.isAttaqueFinesse(rollData)) {
|
||||
current.diviseur *= 2
|
||||
current.reasons.push('Particulière en finesse')
|
||||
}
|
||||
|
||||
if (!ReglesOptionnelles.isUsing('tripleSignificative')) {
|
||||
current.diviseur = Math.min(current.diviseur, 4);
|
||||
}
|
||||
|
||||
current.reason = current.reasons.join(', ')
|
||||
}
|
||||
|
||||
isForceInsuffisante(rollData) {
|
||||
//this.isCombat(rollData) && ... arme avec force min
|
||||
return this.isCombat(rollData) && true
|
||||
isAttaqueFinesse(rollData) {
|
||||
return ROLL_MODE_DEFENSE == rollData.mode.current && rollData.attaque.particuliere == 'finesse'
|
||||
}
|
||||
|
||||
isAttaqueFinesse(rollData) {
|
||||
// this.rollData.selected[PART_DEFENSE] && attaquant avec particulière en finesse
|
||||
return ROLL_MODE_DEFENSE == rollData.mode.current && true
|
||||
isForceInsuffisante(actor, current) {
|
||||
if (actor?.isPersonnage()) {
|
||||
const requise = current.forceRequise
|
||||
const force = parseInt(actor.system.carac.force.value)
|
||||
return requise > force
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
isParadeArmeDisparate(current) {
|
||||
return current.armeDisparate
|
||||
}
|
||||
|
||||
getAjustements(rollData) {
|
||||
const current = this.getCurrent(rollData)
|
||||
if (current.surprise == 'demi') {
|
||||
return [{ label: 'Significative requise ' + Misc.getFractionOneN(current.diviseur), diff: undefined }]
|
||||
return [
|
||||
{ label: 'Significative requise ' + Misc.getFractionOneN(current.diviseur), diff: undefined },
|
||||
...current.reasons.map(it => { return { label: '<i class="fa-solid fa-triangle-exclamation"></i> ' + it, diff: undefined } })
|
||||
]
|
||||
}
|
||||
return []
|
||||
}
|
||||
@@ -90,4 +106,9 @@ export class RollPartSign extends RollPart {
|
||||
})
|
||||
}
|
||||
|
||||
setArme(rollData, forceRequise, armeDisparate) {
|
||||
const current = this.getCurrent(rollData)
|
||||
current.armeDisparate = armeDisparate
|
||||
current.forceRequise = forceRequise
|
||||
}
|
||||
}
|
@@ -6,6 +6,7 @@ import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
|
||||
import { TMRUtility } from "../tmr-utility.js"
|
||||
import { RdDItemSort } from "../item-sort.js"
|
||||
import { RollPartSelect } from "./roll-part-select.mjs"
|
||||
import { CARACS } from "../rdd-carac.js"
|
||||
|
||||
export const PART_SORT = "sort"
|
||||
|
||||
@@ -115,12 +116,12 @@ export class RollPartSort extends RollPartSelect {
|
||||
})
|
||||
}
|
||||
|
||||
getExternalPartsFilter(partCode, rollData) {
|
||||
impactOtherPart(part, rollData) {
|
||||
if (this.visible(rollData)) {
|
||||
const current = this.getCurrent(rollData)
|
||||
switch (partCode) {
|
||||
case PART_CARAC: return p => p.key == 'reve'
|
||||
case PART_COMP: return p => current.draconics?.includes(p.label)
|
||||
switch (part.code) {
|
||||
case PART_CARAC: return part.filterCaracs(rollData, [CARACS.REVE])
|
||||
case PART_COMP: return part.filterComps(rollData,current.draconics ?? [])
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
|
@@ -53,12 +53,12 @@ export class RollPartTache extends RollPartSelect {
|
||||
})
|
||||
}
|
||||
|
||||
getExternalPartsFilter(partCode, rollData) {
|
||||
impactOtherPart(part, rollData) {
|
||||
if (this.visible(rollData)) {
|
||||
const current = this.getCurrent(rollData)
|
||||
switch (partCode) {
|
||||
case PART_CARAC: return p => Grammar.equalsInsensitive(p.key, current?.tache.system.carac)
|
||||
case PART_COMP: return p => p.label == current?.comp.name
|
||||
switch (part.code) {
|
||||
case PART_CARAC: return part.filterCaracs(rollData, [current?.tache.system.carac])
|
||||
case PART_COMP: return part.filterComps(rollData, [current.comp?.name])
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
|
@@ -72,16 +72,14 @@ export class RollPart {
|
||||
prepareContext(rollData) { }
|
||||
|
||||
/** ---- cross roll-part filtering ---- */
|
||||
setFilter(rollData, filter) { }
|
||||
applyImpact(rollData, filter) { }
|
||||
getSpecialComp(rollData) { return [] }
|
||||
setSpecialComp(comps) { }
|
||||
|
||||
getExternalPartsFilter(partCode, rollData) { return undefined }
|
||||
setExternalFilter(visibleRollParts, rollData) {
|
||||
const predicate = Misc.and(
|
||||
visibleRollParts.map(p => p.getExternalPartsFilter(this.code, rollData)).filter(f => f != undefined)
|
||||
)
|
||||
this.setFilter(rollData, predicate);
|
||||
impactOtherPart(partCode, rollData) { }
|
||||
|
||||
applyExternalImpacts(rollParts, rollData) {
|
||||
rollParts.forEach(part => part.impactOtherPart(this, rollData))
|
||||
}
|
||||
|
||||
toTemplateData() {
|
||||
|
@@ -121,7 +121,7 @@ export const referenceAjustements = {
|
||||
},
|
||||
tactique: {
|
||||
isUsed: (rollData, actor) => rollData.tactique,
|
||||
getLabel: (rollData, actor) => RdDBonus.find(rollData.tactique).descr,
|
||||
getLabel: (rollData, actor) => RdDBonus.find(rollData.tactique).label,
|
||||
getValue: (rollData, actor) => RdDBonus.find(rollData.tactique).attaque,
|
||||
},
|
||||
finesse: {
|
||||
@@ -130,11 +130,11 @@ export const referenceAjustements = {
|
||||
},
|
||||
surprise: {
|
||||
isUsed: (rollData, actor) => actor.getSurprise(rollData.passeArme),
|
||||
getDescr: (rollData, actor) => RdDBonus.find(actor.getSurprise()).descr
|
||||
getDescr: (rollData, actor) => RdDBonus.find(actor.getSurprise()).label
|
||||
},
|
||||
attaqueDefenseurSurpris: {
|
||||
isUsed: (rollData, actor) => rollData.surpriseDefenseur,
|
||||
getLabel: (rollData, actor) => RdDBonus.find(rollData.surpriseDefenseur).descr + (rollData.attackerRoll ? '' : ' défenseur'),
|
||||
getLabel: (rollData, actor) => RdDBonus.find(rollData.surpriseDefenseur).label + (rollData.attackerRoll ? '' : ' défenseur'),
|
||||
getValue: (rollData, actor) => RdDBonus.find(rollData.surpriseDefenseur).attaque,
|
||||
},
|
||||
armeParade: {
|
||||
|
@@ -2,7 +2,7 @@ import { SYSTEM_RDD } from "../constants.js"
|
||||
import { Misc } from "../misc.js"
|
||||
|
||||
export const EXPORT_CSV_SCRIPTARIUM = 'export-csv-scriptarium'
|
||||
export const ROLL_DIALOG_V2 = 'roll-drialog-v2'
|
||||
export const ROLL_DIALOG_V2 = 'roll-dialog-v2'
|
||||
|
||||
const OPTIONS_AVANCEES = [
|
||||
{ group: 'Fenêtres', name: ROLL_DIALOG_V2, descr: "Utiliser les nouvelles fenêtres de jet", default: false },
|
||||
|
@@ -1,4 +1,6 @@
|
||||
import { SYSTEM_RDD } from "../constants.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { RdDBonus } from "../rdd-bonus.js";
|
||||
|
||||
export const STATUSES = {
|
||||
StatusGrappling: 'grappling',
|
||||
@@ -12,9 +14,11 @@ export const STATUSES = {
|
||||
StatusBleeding: 'bleeding',
|
||||
StatusDead: 'dead',
|
||||
StatusDemiReve: 'demi-reve',
|
||||
StatusForceWeak: 'force insuffisante',
|
||||
}
|
||||
|
||||
const demiReveStatusEffect = { rdd: true, id: STATUSES.StatusDemiReve, name: 'EFFECT.StatusDemiReve', img: 'systems/foundryvtt-reve-de-dragon/icons/heures/hd12.svg' };
|
||||
const forceWeakStatusEffect = { rdd: true, id: STATUSES.StatusForceWeak, name: 'EFFECT.StatusForceWeak', img: 'systems/foundryvtt-reve-de-dragon/assets/actions/weak.svg' };
|
||||
const demiReveStatusEffect = { rdd: true, id: STATUSES.StatusDemiReve, name: 'EFFECT.StatusDemiReve', img: 'systems/foundryvtt-reve-de-dragon/assets/actions/sort.svg' };
|
||||
const rddStatusEffects = [
|
||||
{ rdd: true, id: STATUSES.StatusGrappling, tint: '#33cc33', name: 'EFFECT.StatusGrappling', img: 'systems/foundryvtt-reve-de-dragon/icons/empoignade.webp' },
|
||||
{ rdd: true, id: STATUSES.StatusGrappled, tint: '#ff9900', name: 'EFFECT.StatusGrappled', img: 'systems/foundryvtt-reve-de-dragon/icons/empoignade.webp' },
|
||||
@@ -29,15 +33,15 @@ const rddStatusEffects = [
|
||||
|
||||
{ rdd: true, id: STATUSES.StatusBleeding, name: 'EFFECT.StatusBleeding', img: 'icons/svg/blood.svg' },
|
||||
{ rdd: true, id: STATUSES.StatusDead, name: 'EFFECT.StatusDead', img: 'icons/svg/skull.svg' },
|
||||
demiReveStatusEffect
|
||||
demiReveStatusEffect,
|
||||
forceWeakStatusEffect
|
||||
];
|
||||
|
||||
const statusDemiSurprise = new Set([STATUSES.StatusStunned, STATUSES.StatusProne, STATUSES.StatusRestrained])
|
||||
const statusDemiSurprise = new Set([STATUSES.StatusStunned, STATUSES.StatusProne, STATUSES.StatusRestrained, STATUSES.StatusForceWeak])
|
||||
const statusSurpriseTotale = new Set([STATUSES.StatusUnconscious, STATUSES.StatusBlind, STATUSES.StatusComma])
|
||||
|
||||
export class StatusEffects extends FormApplication {
|
||||
|
||||
|
||||
static onReady() {
|
||||
const rddEffectIds = rddStatusEffects.map(it => it.id);
|
||||
rddStatusEffects.forEach(it => {
|
||||
@@ -67,6 +71,27 @@ export class StatusEffects extends FormApplication {
|
||||
console.log('statusEffects', CONFIG.statusEffects);
|
||||
}
|
||||
|
||||
static isSurprise(effect) {
|
||||
return StatusEffects.niveauSurprise(effect, true) > 0
|
||||
}
|
||||
|
||||
static getSurprise(effects, isCombat = undefined) {
|
||||
return StatusEffects.typeSurprise(
|
||||
effects.map(it => StatusEffects.niveauSurprise(it, isCombat))
|
||||
.reduce(Misc.sum(), 0)
|
||||
)
|
||||
}
|
||||
|
||||
static getActorEffetSurprise(actor, forceRequise) {
|
||||
const effets = actor?.getEffects(StatusEffects.isSurprise, forceRequise) ?? []
|
||||
return {
|
||||
effets: effets,
|
||||
surprise: effets.length > 0
|
||||
? RdDBonus.find(StatusEffects.getSurprise(effets, true))
|
||||
: undefined
|
||||
}
|
||||
}
|
||||
|
||||
static niveauSurprise(effect, isCombat) {
|
||||
if (statusSurpriseTotale.intersects(effect.statuses)) {
|
||||
return 2
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<div>
|
||||
{{#if effects}}
|
||||
{{#each effects as |effect key|}}
|
||||
{{#each effects as |effect|}}
|
||||
<span class="active-effect" data-effect="{{effect.id}}">
|
||||
<img class="button-effect-img {{#if @root.options.isGM}}delete-active-effect{{/if}}" src="{{effect.img}}" data-tooltip="{{localize effect.name}}" width="24" height="24" />
|
||||
</span>
|
||||
|
@@ -22,19 +22,34 @@
|
||||
{{#if (eq defender.type 'personnage')}}
|
||||
<a class='chat-card-button appel-chance-defense'
|
||||
data-attackerId='{{attackerId}}' data-defenderTokenId='{{defenderToken.id}}' data-attackerTokenId='{{attackerToken.id}}'>
|
||||
Faire appel à la chance</a>
|
||||
Faire appel à la chance
|
||||
</a>
|
||||
<br>
|
||||
{{/if}}
|
||||
{{#if (and (eq defender.type 'personnage') (gt defender.system.compteurs.destinee.value 0))}}
|
||||
<a class='chat-card-button appel-destinee-defense'
|
||||
data-attackerId='{{attackerId}}' data-attackerTokenId='{{attackerToken.id}}' data-defenderTokenId='{{defenderToken.id}}'>
|
||||
Utiliser la destinée</a>
|
||||
Utiliser la destinée
|
||||
</a>
|
||||
<br>
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
{{else}}
|
||||
{{#if (settings-get 'rdd-advanced-roll-dialog-v2')}}
|
||||
<a class='chat-card-button defense-button'
|
||||
data-attackerId='{{attackerId}}'
|
||||
data-attackerTokenId='{{attackerToken.id}}'
|
||||
data-defenderTokenId='{{defenderToken.id}}'
|
||||
>
|
||||
Se défendre
|
||||
{{#if (or (eq attaqueCategorie 'tir') (eq attaqueCategorie 'lancer'))}}
|
||||
(difficulté à déterminer)
|
||||
{{else}}
|
||||
à {{diffLibre }}
|
||||
{{/if}}
|
||||
</a>
|
||||
<br>
|
||||
{{/if}}
|
||||
{{#each armes as |arme key|}}
|
||||
<a class='chat-card-button parer-button'
|
||||
data-attackerId='{{../attackerId}}' data-defenderTokenId='{{../defenderToken.id}}' data-attackerTokenId='{{../attackerToken.id}}'
|
||||
|
@@ -2,13 +2,13 @@
|
||||
<span {{#if ajustements}}class="tooltip-overflow tooltip-dotted" {{/if}}>
|
||||
<span>
|
||||
<span>{{rolled.caracValue}} à {{plusMoins rolled.finalLevel}}</span>
|
||||
{{#if ajustements}}
|
||||
{{/if}}
|
||||
{{log this}}
|
||||
{{#if rolled.factorHtml}}<span class="rdd-diviseur">×{{{rolled.factorHtml}}}</span>{{/if}}
|
||||
<span>= {{rolled.score}}%</span>
|
||||
{{#if rolled.factorHtml}}
|
||||
{{log rolled}}
|
||||
{{#if (and rolled.factorHtml (gt rolled.factorHtml 1))}}
|
||||
<span class="rdd-diviseur">×{{{rolled.factorHtml}}}</span>
|
||||
<span>= {{rolled.score}}%</span>
|
||||
<span class="rdd-diviseur">×{{{rolled.factorHtml}}}</span>
|
||||
{{else}}
|
||||
<span>= {{rolled.score}}%</span>
|
||||
{{/if}}
|
||||
</span>
|
||||
<div class="tooltiptext ttt-ajustements">
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<div class="table-ajustement">
|
||||
<span class="tooltip tooltip-dotted">
|
||||
<span class="roll-part-resolution">Ajustements: {{rollData.current.carac.value}} à {{plusMoins rollData.current.totaldiff}}</span>
|
||||
<span class="roll-part-resolution">Jet: {{rollData.current.carac.value}} à {{plusMoins rollData.current.totaldiff}}</span>
|
||||
<div class="tooltiptext ttt-ajustements">
|
||||
{{#each rollData.ajustements as |ajust|}}
|
||||
{{#if ajust}}
|
||||
|
@@ -1,14 +1,56 @@
|
||||
{{log 'roll-part-attaque.current' current}}
|
||||
{{log 'roll-part-attaque.refs' refs}}
|
||||
<subline>
|
||||
<select name="select-attaque" {{#if rollData.mode.retry}}disabled{{/if}}>
|
||||
{{selectOptions refs.attaques selected=current.key valueAttr="key" labelAttr="label"}}
|
||||
</select>
|
||||
</subline>
|
||||
<roll-part-img>
|
||||
{{#if current.attaque}}
|
||||
{{#if current.attaque.arme}}
|
||||
<img src="{{current.attaque.arme.img}}" data-tooltip="{{current.attaque.arme.name}}" />
|
||||
{{/if}}
|
||||
</roll-part-img>
|
||||
<roll-part-detail>
|
||||
<subline>
|
||||
<select name="select-attaque" {{#if rollData.mode.retry}}disabled{{/if}}>
|
||||
{{selectOptions refs.attaques selected=current.key valueAttr="key" labelAttr="label"}}
|
||||
<label for="select-tactique">Tactique:</label>
|
||||
<select name="select-tactique" {{#if rollData.mode.retry}}disabled{{/if}}>
|
||||
{{selectOptions refs.tactiques selected=current.tactique.key valueAttr="key" labelAttr="label"}}
|
||||
</select>
|
||||
</subline>
|
||||
<subline>
|
||||
{{#if (eq current.attaque.arme.system.mortalite 'empoignade')}}
|
||||
Empoignade, pas de dommages directs
|
||||
{{else}}
|
||||
{{#if (and (ne current.attaque.arme.system.mortalite 'non-mortel') (eq current.dmg.penetration 0))}}
|
||||
<input name="check-mortalite" type="checkbox" {{#if (eq current.dmg.mortalite 'mortel')}}checked{{/if}} />
|
||||
{{/if}}
|
||||
<label for="check-mortalite">
|
||||
Dommages: {{plusMoins current.dmg.total}} ({{current.dmg.mortalite}})
|
||||
{{~#if current.dmg.penetration}}, pénétration {{current.dmg.penetration}}{{/if}}
|
||||
</label>
|
||||
{{/if}}
|
||||
</subline>
|
||||
{{#if current.attaquant.effets}}
|
||||
<subline>
|
||||
<span class="status-surprise">
|
||||
Attaquant en <strong>{{lowerFirst current.attaquant.surprise.label}}</strong>:
|
||||
{{#each current.attaquant.effets as |effect|}}
|
||||
{{localize effect.name}}
|
||||
<img class="button-effect-img" src="{{effect.img}}" data-tooltip="{{localize effect.name}}" data-effect="{{effect.id}}"/>
|
||||
{{/each}}
|
||||
</span>
|
||||
</subline>
|
||||
{{/if}}
|
||||
{{#if current.defenseur.surprise}}
|
||||
<subline>
|
||||
<span class="status-surprise">
|
||||
Defenseur en <strong>{{lowerFirst current.defenseur.surprise.label}}</strong>:
|
||||
{{#each current.defenseur.effets as |effect|}}
|
||||
{{localize effect.name}}
|
||||
<img class="button-effect-img" src="{{effect.img}}" data-tooltip="{{localize effect.name}}" data-effect="{{effect.id}}"/>
|
||||
{{/each}}
|
||||
</span>
|
||||
</subline>
|
||||
{{/if}}
|
||||
<subline>
|
||||
|
||||
</subline>
|
||||
</roll-part-detail>
|
@@ -1,3 +1,3 @@
|
||||
<input name="{{code}}" type="checkbox" {{#if current.checked}}checked{{/if}}/>
|
||||
{{#if current.icon}}{{{current.icon}}}{{/if}}
|
||||
<label for="{{code}}">{{current.label}} : {{plusMoins current.value}}</label>
|
||||
<label for="{{code}}">{{either current.label refs.label}} : {{plusMoins current.value}}</label>
|
||||
|
@@ -1,12 +1,21 @@
|
||||
<roll-part-img>
|
||||
{{#if current.defense}}
|
||||
<img src="{{current.defense.arme.img}}" data-tooltip="{{current.defense.arme.name}}" />
|
||||
{{/if}}
|
||||
<img src="{{current.img}}" data-tooltip="{{current.name}}" />
|
||||
</roll-part-img>
|
||||
<roll-part-detail>
|
||||
<subline>
|
||||
<select name="select-arme" {{#if rollData.mode.retry}}disabled{{/if}}>
|
||||
<select name="select-defense" {{#if rollData.mode.retry}}disabled{{/if}}>
|
||||
{{selectOptions refs.defenses selected=current.key valueAttr="key" labelAttr="label"}}
|
||||
</select>
|
||||
</subline>
|
||||
{{#if current.defenseur.effets}}
|
||||
<subline>
|
||||
<span class="status-surprise">
|
||||
Defense en <strong>{{lowerFirst current.defenseur.surprise.label}}</strong>:
|
||||
{{#each current.defenseur.effets as |effect|}}
|
||||
{{localize effect.name}}
|
||||
<img class="button-effect-img" src="{{effect.img}}" data-tooltip="{{localize effect.name}}" data-effect="{{effect.id}}"/>
|
||||
{{/each}}
|
||||
</span>
|
||||
</subline>
|
||||
{{/if}}
|
||||
</roll-part-detail>
|
Reference in New Issue
Block a user