import { ITEM_TYPES } from "../constants.js" import { Grammar } from "../grammar.js" import { ATTAQUE_TYPE } from "../item/arme.js" import { Misc } from "../misc.js" export class Distance { static typeAttaqueDistance(attaque) { function mapTypeAttaque(value) { switch (value) { case ATTAQUE_TYPE.LANCER: case 'lancer': return ATTAQUE_TYPE.LANCER case ATTAQUE_TYPE.TIR: case 'tir': return ATTAQUE_TYPE.TIR } return undefined } switch (attaque.comp?.type) { case ITEM_TYPES.competence: return mapTypeAttaque(attaque.main) case ITEM_TYPES.competencecreature: return mapTypeAttaque(attaque.arme.system.categorie) } return undefined } static ajustements(token, defenderToken, attaque) { const typeAttaque = Distance.typeAttaqueDistance(attaque) if (typeAttaque) { const distance = Distance.distance(token, defenderToken) const isVisible = Distance.isVisible(token, defenderToken) const portee = Distance.ajustementPortee(distance, attaque.arme) const taille = Distance.ajustementTaille(defenderToken?.actor) const activite = Distance.ajustementMouvement(defenderToken) const total = Distance.diff(portee, taille, activite) const diffDefense = Distance.ajustementDefense(attaque) return { typeAttaque, isVisible, distance, portee, taille, activite, total, diffDefense } } return undefined } static distance(token, defenderToken) { if (Distance.$isToken(token) && Distance.$isToken(defenderToken)) { const source = token.getCenterPoint() const target = defenderToken.getCenterPoint() const measure = canvas.grid.measurePath([ source, target]) return measure.distance } return -1 /* distance indéterminée */ } static isVisible(token, defenderToken) { // TODO: regarder les StatusEffect aveuglé? if (Distance.$isToken(token) && Distance.$isToken(defenderToken)) { return canvas.effects.visibility.testVisibility(defenderToken.getCenterPoint(), { object: token }) } return true } static ajustementPortee(distance, arme) { if (distance < 0 || !arme) { return { msg: "non déterminée", diff: 0 }; } if (arme.system.portee_courte && distance <= arme.system.portee_courte) return { msg: "courte", diff: 0 }; if (arme.system.portee_moyenne && distance <= arme.system.portee_moyenne) return { msg: "moyenne", diff: -3 }; if (arme.system.portee_extreme && distance <= arme.system.portee_extreme) return { msg: "extrême", diff: -5 }; return { msg: "inatteignable", diff: -10 }; } static ajustementTaille(actor) { if (!actor) { return { msg: "non déterminée", diff: 0 }; } if (actor.isVehicule()) return { msg: "véhicule", diff: 0 } const taille = actor.getCaracByName('TAILLE')?.value ?? 1; if (taille <= 1) return { msg: "souris", diff: -8 }; if (taille <= 3) return { msg: "chat", diff: -4 }; if (taille <= 5) return { msg: "chien", diff: -2 }; if (taille <= 15) return { msg: "humanoïde", diff: 0 }; if (taille <= 20) return { msg: "ogre", diff: 2 }; return { msg: "gigantesque", diff: 4 }; } static ajustementMouvement(defenderToken) { if (Distance.$isToken(defenderToken)) { if (defenderToken.actor?.getSurprise(true) != '') return { msg: "immobile (surprise)", diff: 0 }; if (defenderToken.inCombat) return { msg: "en combat", diff: -4 }; } return { msg: "à déterminer", diff: -3 }; } static diff(...ajustements) { return ajustements.map(it => it.diff).filter(d => !Number.isNaN(d)).reduce(Misc.sum(), 0) } static ajustementDefense(attaque) { switch (Grammar.toLowerCaseNoAccentNoSpace(attaque.comp.name)) { case 'arbalete': return { label: 'Parade carreau', value: -5 } case 'arc': return { label: 'Parade flêche', value: -5 } case 'fronde': return { label: 'Parade bille de fronde', value: -4 } case 'daguedejet': return { label: 'Parade/Esquive dague lancée', value: -2 } case 'javelot': return { label: 'Parade/Esquive javelot lancé', value: -2 } case 'fouet': return { label: 'Parade/Esquive fouet', value: 0 } } return { label: 'Parade/esquive projectile', value: 0 } } static ajustementBouclier(bouclier) { if (bouclier?.system.categorie_parade == 'boucliers') { if (bouclier.system.force < 10) { return { label: 'Bouclier léger', value: -3 } } if (bouclier.system.force < 12) { return { label: 'Bouclier moyen', value: 0 } } return { label: 'Bouclier lourd', value: 3 } } /* esquive */ return undefined } static $isToken(token) { return token instanceof Token || token instanceof TokenDocument } }