Ajout: Information de distance
This commit is contained in:
@@ -5,9 +5,12 @@
|
||||
- Corrections diverses
|
||||
- l'encombrement total est affiché avec deux décimales
|
||||
- le poids des monnaies est de nouveau décimal
|
||||
- Fenêtre de jets V2
|
||||
- affichage des ajustements dans la fenêtre d'attaque avec arme à distance
|
||||
- Corrections liées à Foundry v12/v13
|
||||
- Fix ajout de notes dans le journal par un joueur (/chrono, ou clic sur le libelé de l'heure dans l'horloge)
|
||||
|
||||
|
||||
## 13.0.21 - La folie d'Illysis
|
||||
|
||||
- Jets d'appréciation et de moral
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import { Misc } from "../misc.js"
|
||||
|
||||
export class Distance {
|
||||
|
||||
static ajustements(token, defenderToken, arme){
|
||||
const distance = Distance.distance(token, defenderToken)
|
||||
const isVisible = Distance.isVisible(token, defenderToken)
|
||||
const portee = Distance.ajustementPortee(distance, arme)
|
||||
const taille = Distance.ajustementTaille(defenderToken.actor)
|
||||
const activite = Distance.ajustementMouvement(defenderToken)
|
||||
const total = Distance.diff(portee, taille, activite)
|
||||
return {
|
||||
isVisible: isVisible,
|
||||
distance: distance,
|
||||
portee: portee,
|
||||
taille: taille,
|
||||
activite: activite,
|
||||
total: total
|
||||
}
|
||||
}
|
||||
|
||||
static distance(token, defenderToken) {
|
||||
const ray = new foundry.canvas.geometry.Ray(
|
||||
token.getCenterPoint(),
|
||||
defenderToken.getCenterPoint()
|
||||
)
|
||||
return Number(canvas.grid.measureDistances([{ ray }], { gridSpaces: false }))
|
||||
}
|
||||
|
||||
static isVisible(token, defenderToken) {
|
||||
// TODO: regarder les StatusEffect aveuglé?
|
||||
return canvas.effects.visibility.testVisibility(defenderToken.getCenterPoint(), { object: token })
|
||||
}
|
||||
|
||||
static ajustementPortee(distance, arme) {
|
||||
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.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 (defenderToken.actor?.getSurprise(true) != '') return { msg: "immobile (surprise)", diff: 0 };
|
||||
if (defenderToken.inCombat) return { msg: "en mouvement (combat)", diff: -4 };
|
||||
return { msg: "à déterminer (0 immobile, -3 actif, -4 en mouvement, -5 en zig-zag)", diff: -3 };
|
||||
}
|
||||
|
||||
static diff(...ajustements){
|
||||
return ajustements.map(it => it.diff).filter(d => !Number.isNaN(d)).reduce(Misc.sum(), 0)
|
||||
}
|
||||
|
||||
}
|
||||
+9
-50
@@ -19,6 +19,7 @@ import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll/roll-constants.mjs"
|
||||
import { OptionsAvancees, ROLL_DIALOG_V2 } from "./settings/options-avancees.js";
|
||||
import { MappingCreatureArme } from "./item/mapping-creature-arme.mjs";
|
||||
import { RollBasicParts } from "./roll/roll-basic-parts.mjs";
|
||||
import { Distance } from "./combat/distance.mjs";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
const premierRoundInit = [
|
||||
@@ -625,63 +626,22 @@ export class RdDCombat {
|
||||
}
|
||||
else {
|
||||
const defenderToken = canvas.tokens.get(this.defenderTokenId)
|
||||
const dist = this.distance(_token, defenderToken)
|
||||
const isVisible = this.isVisible(_token, defenderToken)
|
||||
const portee = this._ajustementPortee(dist, rollData.arme)
|
||||
const taille = this._ajustementTaille(this.defender)
|
||||
const activite = this._ajustementMouvement(this.defender)
|
||||
const total = [portee, taille, activite].map(it => it.diff).filter(d => !Number.isNaN(d)).reduce(Misc.sum(), 0)
|
||||
ChatMessage.create({
|
||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-info-distance.hbs', {
|
||||
const info = foundry.utils.mergeObject(
|
||||
{
|
||||
rollData: rollData,
|
||||
attacker: _token,
|
||||
isVisible: isVisible,
|
||||
defender: defenderToken,
|
||||
distance: dist,
|
||||
portee: portee,
|
||||
taille: taille,
|
||||
activite: activite,
|
||||
total: total
|
||||
}),
|
||||
},
|
||||
Distance.ajustements(_token, defenderToken, rollData.arme)
|
||||
)
|
||||
ChatMessage.create({
|
||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-info-distance.hbs', info),
|
||||
whisper: ChatUtility.getGMs()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isVisible(token, defenderToken) {
|
||||
return canvas.effects.visibility.testVisibility(defenderToken.center, { object: token })
|
||||
}
|
||||
|
||||
distance(token, defenderToken) {
|
||||
return Number(canvas.grid.measureDistances([{ ray: new Ray(token.center, defenderToken.center) }], { gridSpaces: false })).toFixed(1);
|
||||
}
|
||||
|
||||
_ajustementPortee(dist, arme) {
|
||||
if (dist <= arme.system.portee_courte) return { msg: "courte", diff: 0 };
|
||||
if (dist <= arme.system.portee_moyenne) return { msg: "moyenne", diff: -3 };
|
||||
if (dist <= arme.system.portee_extreme) return { msg: "extrême", diff: -5 };
|
||||
return { msg: "inatteignable", diff: -10 };
|
||||
}
|
||||
|
||||
_ajustementTaille(actor) {
|
||||
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 };
|
||||
}
|
||||
|
||||
_ajustementMouvement(defender) {
|
||||
if (defender.getSurprise(true) != '') return { msg: "immobile (surprise)", diff: 0 };
|
||||
if (game.combat?.combatants.find(it => it.actorId == defender.id)) return { msg: "en mouvement (combat)", diff: -4 };
|
||||
return { msg: "à déterminer (0 immobile, -3 actif, -4 en mouvement, -5 en zig-zag)", diff: -3 };
|
||||
}
|
||||
|
||||
|
||||
async attaqueV2() {
|
||||
if (!await this.attacker.accorder(this.defender, 'avant-attaque')) {
|
||||
return
|
||||
@@ -699,7 +659,6 @@ export class RdDCombat {
|
||||
}
|
||||
|
||||
async doRollAttaque(rollData, callbacks = []) {
|
||||
// TODO V2 await this.proposerAjustementTirLancer(rollData)
|
||||
return await RollDialog.create(rollData, {
|
||||
onRollDone: RollDialog.onRollDoneClose,
|
||||
callbacks: [
|
||||
@@ -740,7 +699,7 @@ export class RdDCombat {
|
||||
}
|
||||
|
||||
_socketSendMessageDefenseV2(paramChatDefense) {
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_defense_v2", data: {paramChatDefense} })
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_defense_v2", data: { paramChatDefense } })
|
||||
}
|
||||
|
||||
static async onMsgDefenseV2(msg) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Distance } from "../combat/distance.mjs"
|
||||
import { RDD_CONFIG } from "../constants.js"
|
||||
import { ATTAQUE_TYPE_MELEE } from "../item/arme.js"
|
||||
import { RdDBonus } from "../rdd-bonus.js"
|
||||
@@ -30,7 +31,7 @@ export class RollPartAttaque extends RollPartSelect {
|
||||
loadRefs(rollData) {
|
||||
const refs = this.getRefs(rollData)
|
||||
const attaques = rollData.active.actor.listAttaques()
|
||||
refs.all = attaques.map(it => RollPartAttaque.$extractAttaque(it, rollData.active.actor))
|
||||
refs.all = attaques.map(it => RollPartAttaque.$extractAttaque(it, rollData))
|
||||
this.filterAttaquesEmpoignade(rollData)
|
||||
refs.tactiques = TACTIQUES
|
||||
if (refs.attaques.length > 0) {
|
||||
@@ -64,13 +65,22 @@ export class RollPartAttaque extends RollPartSelect {
|
||||
|
||||
choices(refs) { return refs.attaques }
|
||||
|
||||
static $extractAttaque(attaque, actor) {
|
||||
static $extractAttaque(attaque, rollData) {
|
||||
attaque.key = `${attaque.action}::${attaque.label}`
|
||||
attaque.tactique = TACTIQUES[0]
|
||||
attaque.initialDiff = attaque.comp?.system.default_diffLibre ?? 0
|
||||
if (RollPartAttaque.isAttaqueDistance(attaque)) {
|
||||
attaque.distance = Distance.ajustements(rollData.active.token,
|
||||
rollData.opponent.token,
|
||||
attaque.arme)
|
||||
}
|
||||
return attaque
|
||||
}
|
||||
|
||||
static isAttaqueDistance(attaque) {
|
||||
return ['(lancer)', '(tir)'].includes(attaque.main)
|
||||
}
|
||||
|
||||
prepareContext(rollData) {
|
||||
this.filterAttaquesEmpoignade(rollData)
|
||||
const current = this.getCurrent(rollData)
|
||||
@@ -102,20 +112,22 @@ export class RollPartAttaque extends RollPartSelect {
|
||||
}
|
||||
|
||||
async _onRender(rollDialog, context, options) {
|
||||
const inputDiff = rollDialog.element.querySelector(`roll-section[name="diff"] input[name="diff"]`)
|
||||
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 utiliserDagueEmpoignade = rollDialog.element.querySelector(`roll-section[name="${this.code}"] a.utiliser-dague-empoignade`)
|
||||
const current = this.getCurrent(rollDialog.rollData)
|
||||
const rollData = rollDialog.rollData
|
||||
const current = this.getCurrent(rollData)
|
||||
|
||||
selectAttaque.addEventListener("change", e => {
|
||||
selectAttaque?.addEventListener("change", e => {
|
||||
const selectOptions = e.currentTarget.options
|
||||
const index = selectOptions.selectedIndex
|
||||
this.$selectAttaque(rollDialog.rollData, selectOptions[index]?.value)
|
||||
this.$selectAttaque(rollData, selectOptions[index]?.value)
|
||||
rollDialog.render()
|
||||
})
|
||||
|
||||
selectTactique.addEventListener("change", e => {
|
||||
selectTactique?.addEventListener("change", e => {
|
||||
const selectOptions = e.currentTarget.options
|
||||
const index = selectOptions.selectedIndex
|
||||
current.tactique = RdDBonus.find(selectOptions[index]?.value)
|
||||
@@ -128,9 +140,11 @@ export class RollPartAttaque extends RollPartSelect {
|
||||
})
|
||||
utiliserDagueEmpoignade?.addEventListener("click", e => {
|
||||
e.preventDefault()
|
||||
const rollData = rollDialog.rollData
|
||||
this.utiliserDagueEmpoignade(rollData)
|
||||
})
|
||||
inputDiff?.addEventListener("input", e => {
|
||||
this.getRefs(rollData).all.forEach(attaque => attaque.initialDiff = undefined)
|
||||
})
|
||||
}
|
||||
|
||||
utiliserDagueEmpoignade(rollData) {
|
||||
@@ -153,8 +167,11 @@ export class RollPartAttaque extends RollPartSelect {
|
||||
case PART_CARAC: return part.filterCaracs(rollData, [current.carac.key])
|
||||
case PART_COMP: return part.filterComps(rollData, [current.comp.name])
|
||||
case PART_DIFF: {
|
||||
if (current.initialDiff) {
|
||||
part.setDiff(rollData, { type: DIFF.ATTAQUE, value: current.initialDiff })
|
||||
if (RollPartAttaque.isAttaqueDistance(current)) {
|
||||
part.setDiff(rollData, { type: DIFF.DEFAUT })
|
||||
}
|
||||
else {
|
||||
part.setDiff(rollData, { type: DIFF.ATTAQUE, diff: current.initialDiff })
|
||||
current.initialDiff = undefined
|
||||
}
|
||||
break
|
||||
|
||||
@@ -63,7 +63,22 @@
|
||||
</span>
|
||||
</subline>
|
||||
{{/if}}
|
||||
{{#if current.distance}}
|
||||
<subline>
|
||||
|
||||
<span>
|
||||
<strong>Attaque à distance</strong> {{current.main}} proposé de <strong>{{current.distance.total}}</strong> à valider par le Gardien
|
||||
</span>
|
||||
</subline>
|
||||
<subline>
|
||||
<ul>
|
||||
<li>La cible est à une distance indicative de {{numberFormat current.distance.distance decimals=1}} mètres.</li>
|
||||
<li>Avec les murs et la lumière, la cible
|
||||
{{#if current.distance.isVisible}}est{{else}}n'est pas{{/if}} visible.
|
||||
</li>
|
||||
<li>Portée {{current.distance.portee.msg}} : {{current.distance.portee.diff}}</li>
|
||||
<li>De taille {{current.distance.taille.msg}}: {{current.distance.taille.diff}}</li>
|
||||
<li>Mouvement {{current.distance.activite.msg}}: {{current.distance.activite.diff}}</li>
|
||||
</ul>
|
||||
</subline>
|
||||
{{/if}}
|
||||
</roll-part-detail>
|
||||
Reference in New Issue
Block a user