Vincent Vandemeulebrouck
3b06bd382b
Dans les messages d'automatisation de combat, le nom des tokens est utilisé au lieu d'utiliser le nom de l'acteur. Ceci permet de ne pas dévoiler un nom générique (Villageois) si le token a un nom personnalisé.
397 lines
18 KiB
JavaScript
397 lines
18 KiB
JavaScript
import { RdDUtility } from "./rdd-utility.js";
|
|
import { HtmlUtility } from "./html-utility.js";
|
|
import { RdDItemArme } from "./item-arme.js";
|
|
import { RdDItemCompetence } from "./item-competence.js";
|
|
import { RdDBonus } from "./rdd-bonus.js";
|
|
import { Misc } from "./misc.js";
|
|
import { RdDCombatManager } from "./rdd-combat.js";
|
|
import { RdDCarac } from "./rdd-carac.js";
|
|
import { DialogSplitItem } from "./dialog-split-item.js";
|
|
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
|
|
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
|
|
import { STATUSES } from "./settings/status-effects.js";
|
|
import { MAINS_DIRECTRICES } from "./actor.js";
|
|
import { RdDBaseActorReveSheet } from "./actor/base-actor-reve-sheet.js";
|
|
import { RdDItem } from "./item.js";
|
|
import { RdDItemBlessure } from "./item/blessure.js";
|
|
import { RdDEmpoignade } from "./rdd-empoignade.js";
|
|
import { RdDBaseActorSangSheet } from "./actor/base-actor-sang-sheet.js";
|
|
import { RdDCoeur } from "./coeur/rdd-coeur.js";
|
|
import { AppPersonnageAleatoire } from "./actor/random/app-personnage-aleatoire.js";
|
|
|
|
/* -------------------------------------------- */
|
|
/**
|
|
* Extend the basic ActorSheet with some very simple modifications
|
|
* @extends {ActorSheet}
|
|
*/
|
|
export class RdDActorSheet extends RdDBaseActorSangSheet {
|
|
|
|
/** @override */
|
|
static get defaultOptions() {
|
|
return foundry.utils.mergeObject(RdDBaseActorReveSheet.defaultOptions, {
|
|
template: "systems/foundryvtt-reve-de-dragon/templates/actor-sheet.html",
|
|
width: 550,
|
|
showCompNiveauBase: false,
|
|
vueArchetype: false,
|
|
}, { inplace: false });
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async getData() {
|
|
let formData = await super.getData();
|
|
foundry.utils.mergeObject(formData, {
|
|
editable: this.isEditable,
|
|
cssClass: this.isEditable ? "editable" : "locked",
|
|
limited: this.actor.limited,
|
|
owner: this.actor.isOwner,
|
|
biographie: await TextEditor.enrichHTML(this.actor.system.biographie, { async: true }),
|
|
notes: await TextEditor.enrichHTML(this.actor.system.notes, { async: true }),
|
|
});
|
|
foundry.utils.mergeObject(formData.calc, {
|
|
surenc: this.actor.computeMalusSurEncombrement(),
|
|
surprise: RdDBonus.find(this.actor.getSurprise(false)).descr,
|
|
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!" : "",
|
|
malusArmure: this.actor.getMalusArmure()
|
|
})
|
|
|
|
this.timerRecherche = undefined;
|
|
|
|
if (formData.type == 'personnage') {
|
|
formData.options.mainsDirectrices = MAINS_DIRECTRICES;
|
|
formData.byCateg = Misc.classify(formData.competences, it => it.system.categorie)
|
|
formData.calc.comptageArchetype = RdDItemCompetence.computeResumeArchetype(formData.competences);
|
|
formData.calc.competenceXPTotal = RdDItemCompetence.computeTotalXP(formData.competences);
|
|
formData.calc.fatigue = RdDUtility.calculFatigueHtml(formData.system.sante.fatigue.value, formData.system.sante.endurance.max);
|
|
|
|
formData.competences.forEach(item => {
|
|
item.system.isHidden = this.options.recherche
|
|
? !item.isNomLike(this.options.recherche.text)
|
|
: (this.options.showCompNiveauBase && RdDItemCompetence.isNiveauBase(item));
|
|
RdDItemCompetence.levelUp(item, formData.system.compteurs.experience.value);
|
|
});
|
|
|
|
Object.values(formData.system.carac).forEach(c => {
|
|
RdDCarac.levelUp(c);
|
|
});
|
|
|
|
// toujours avoir une liste d'armes (pour mettre esquive et corps à corps)
|
|
const actor = this.actor;
|
|
formData.combat = foundry.utils.duplicate(formData.armes);
|
|
RdDItemArme.computeNiveauArmes(formData.combat, formData.competences);
|
|
formData.combat.push(RdDItemArme.mainsNues(actor));
|
|
formData.combat.push(RdDItemArme.empoignade(actor));
|
|
|
|
formData.esquives = this.actor.getCompetences("Esquive");
|
|
formData.combat = RdDCombatManager.listActionsArmes(formData.combat, formData.competences, formData.system.carac);
|
|
formData.empoignades = this.actor.getEmpoignades();
|
|
|
|
this.armesList = formData.combat;
|
|
|
|
// Common data
|
|
formData.ajustementsConditions = CONFIG.RDD.ajustementsConditions;
|
|
formData.difficultesLibres = CONFIG.RDD.difficultesLibres;
|
|
|
|
formData.hautreve = {
|
|
isDemiReve: this.actor.getEffect(STATUSES.StatusDemiReve),
|
|
cacheTMR: this.actor.isTMRCache()
|
|
}
|
|
|
|
formData.subacteurs = {
|
|
vehicules: this.actor.listeVehicules(),
|
|
montures: this.actor.listeMontures(),
|
|
suivants: this.actor.listeSuivants()
|
|
}
|
|
if (this.actor.getBestDraconic().system.niveau > -11 && !this.actor.isHautRevant()) {
|
|
ui.notifications.error(`${this.actor.name} a des compétences draconiques, mais pas le don de Haut-Rêve!
|
|
<br>Ajoutez-lui la tête "Don de Haut-Rêve" pour lui permettre d'utiliser ses compétences et d'accéder aux terres médianes du rêve`);
|
|
}
|
|
}
|
|
return formData;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
/** @override */
|
|
activateListeners(html) {
|
|
super.activateListeners(html);
|
|
|
|
HtmlUtility.showControlWhen(this.html.find(".appliquerFatigue"), ReglesOptionnelles.isUsing("appliquer-fatigue"));
|
|
|
|
this.html.find('.subacteur-open').click(async event => {
|
|
const subActorId = RdDSheetUtility.getEventItemData(event, 'subactor-id');
|
|
this.openSubActeur(subActorId);
|
|
})
|
|
|
|
this.html.find('.show-hide-competences').click(async event => {
|
|
this.options.showCompNiveauBase = !this.options.showCompNiveauBase;
|
|
this.render(true);
|
|
});
|
|
|
|
this.html.find('.button-tmr-visu').click(async event => this.actor.displayTMR("visu"))
|
|
|
|
// Everything below here is only needed if the sheet is editable
|
|
if (!this.options.editable) return;
|
|
|
|
this.html.find('.sheet-possession-attack').click(async event => {
|
|
const poss = RdDSheetUtility.getItem(event, this.actor)
|
|
this.actor.conjurerPossession(poss)
|
|
})
|
|
|
|
this.html.find('.subacteur-coeur-toggle a').click(async event => {
|
|
const subActorIdactorId = RdDSheetUtility.getEventItemData(event, 'subactor-id')
|
|
const coeurNombre = $(event.currentTarget).data('numero-coeur')
|
|
RdDCoeur.toggleSubActeurCoeur(this.actor.id, subActorIdactorId, coeurNombre)
|
|
})
|
|
this.html.find('.subacteur-tendre-moment').click(async event => {
|
|
const subActorId = RdDSheetUtility.getEventItemData(event, 'subactor-id')
|
|
RdDCoeur.startSubActeurTendreMoment(this.actor.id, subActorId)
|
|
})
|
|
this.html.find('.subacteur-delete').click(async event => {
|
|
const li = RdDSheetUtility.getEventElement(event);
|
|
const subActorId = li.data("subactor-id");
|
|
this.deleteSubActeur(subActorId, li);
|
|
})
|
|
this.html.find("input.derivee-value[name='system.compteurs.stress.value']").change(async event => {
|
|
this.actor.updateCompteurValue("stress", parseInt(event.target.value));
|
|
});
|
|
this.html.find("input.derivee-value[name='system.compteurs.experience.value']").change(async event => {
|
|
this.actor.updateCompteurValue("experience", parseInt(event.target.value));
|
|
});
|
|
|
|
this.html.find('.creer-tache').click(async event => this.createEmptyTache());
|
|
this.html.find('.creer-une-oeuvre').click(async event => this.selectTypeOeuvreToCreate());
|
|
this.html.find('.creer-tache-blessure-legere').click(async event => RdDItemBlessure.createTacheSoinBlessure(this.actor, 2));
|
|
this.html.find('.creer-tache-blessure-grave').click(async event => RdDItemBlessure.createTacheSoinBlessure(this.actor, 4));
|
|
this.html.find('.creer-tache-blessure-critique').click(async event => RdDItemBlessure.createTacheSoinBlessure(this.actor, 6));
|
|
|
|
this.html.find('.blessure-premierssoins-done').change(async event => {
|
|
const blessure = this.getBlessure(event);
|
|
await blessure?.setSoinsBlessure({ premierssoins: { done: event.currentTarget.checked } });
|
|
});
|
|
this.html.find('.blessure-soinscomplets-done').change(async event => {
|
|
const blessure = this.getBlessure(event);
|
|
await blessure?.setSoinsBlessure({ soinscomplets: { done: event.currentTarget.checked } })
|
|
});
|
|
this.html.find('.blessure-premierssoins-bonus').change(async event => {
|
|
const blessure = this.getBlessure(event);
|
|
await blessure?.setSoinsBlessure({ premierssoins: { bonus: Number(event.currentTarget.value) } })
|
|
});
|
|
this.html.find('.blessure-soinscomplets-bonus').change(async event => {
|
|
const blessure = this.getBlessure(event);
|
|
await blessure?.setSoinsBlessure({ soinscomplets: { bonus: Number(event.currentTarget.value) } })
|
|
});
|
|
|
|
// Equip Inventory Item
|
|
this.html.find('.item-equip').click(async event => this.actor.equiperObjet(RdDSheetUtility.getItemId(event)))
|
|
this.html.find('.chance-actuelle').click(async event => this.actor.rollCarac('chance-actuelle'))
|
|
|
|
this.html.find('.button-appel-chance').click(async event => this.actor.rollAppelChance())
|
|
|
|
this.html.find('[name="jet-astrologie"]').click(async event => this.actor.astrologieNombresAstraux())
|
|
this.html.find('.tache-label a').click(async event => this.actor.rollTache(RdDSheetUtility.getItemId(event)))
|
|
this.html.find('.meditation-label a').click(async event => this.actor.rollMeditation(RdDSheetUtility.getItemId(event)))
|
|
|
|
this.html.find('.chant-label a').click(async event => this.actor.rollChant(RdDSheetUtility.getItemId(event)))
|
|
this.html.find('.danse-label a').click(async event => this.actor.rollDanse(RdDSheetUtility.getItemId(event)))
|
|
this.html.find('.musique-label a').click(async event => this.actor.rollMusique(RdDSheetUtility.getItemId(event)))
|
|
this.html.find('.oeuvre-label a').click(async event => this.actor.rollOeuvre(RdDSheetUtility.getItemId(event)))
|
|
this.html.find('.jeu-label a').click(async event => this.actor.rollJeu(RdDSheetUtility.getItemId(event)))
|
|
this.html.find('.recettecuisine-label a').click(async event => this.actor.rollRecetteCuisine(RdDSheetUtility.getItemId(event)))
|
|
|
|
this.html.find('.description-aleatoire').click(async event => new AppPersonnageAleatoire(this.actor).render(true))
|
|
if (game.user.isGM) {
|
|
// experience log
|
|
this.html.find('.experiencelog-delete').click(async event => {
|
|
const li = this.html.find(event.currentTarget)?.parents(".experiencelog");
|
|
const key = Number(li.data("key") ?? -1);
|
|
await this.actor.deleteExperienceLog(key, 1);
|
|
});
|
|
this.html.find('.experiencelog-delete-previous').click(async event => {
|
|
const li = this.html.find(event.currentTarget)?.parents(".experiencelog");
|
|
const key = Number(li.data("key") ?? -1);
|
|
await this.actor.deleteExperienceLog(0, key + 1);
|
|
});
|
|
// Boutons spéciaux MJs
|
|
this.html.find('.forcer-tmr-aleatoire').click(async event => this.actor.reinsertionAleatoire("Action MJ"))
|
|
this.html.find('.afficher-tmr').click(async event => this.actor.changeTMRVisible())
|
|
}
|
|
|
|
// Points de reve actuel
|
|
this.html.find('.roll-reve-actuel').click(async event => this.actor.rollCarac('reve-actuel', true))
|
|
this.html.find('.empoignade-label a').click(async event => RdDEmpoignade.onAttaqueEmpoignadeFromItem(RdDSheetUtility.getItem(event, this.actor)))
|
|
|
|
this.html.find('.roll-arme').click(async event => this.actor.rollArme(foundry.utils.duplicate(this._getEventArmeCombat(event)), 'competence'))
|
|
|
|
// Initiative pour l'arme
|
|
this.html.find('.arme-initiative a').click(async event => {
|
|
let combatant = game.combat.combatants.find(c => c.actor.id == this.actor.id)
|
|
if (combatant) {
|
|
RdDCombatManager.rollInitiativeAction(combatant._id, this._getEventArmeCombat(event));
|
|
} else {
|
|
ui.notifications.info("Impossible de lancer l'initiative sans être dans un combat.");
|
|
}
|
|
})
|
|
// Display TMR
|
|
|
|
this.html.find('.button-tmr').click(async event => this.actor.displayTMR("normal"))
|
|
this.html.find('.button-tmr-rapide').click(async event => this.actor.displayTMR("rapide"))
|
|
|
|
this.html.find('.button-repos').click(async event => await this.actor.repos())
|
|
|
|
this.html.find('.carac-xp-augmenter').click(async event => this.actor.updateCaracXPAuto(event.currentTarget.name.replace("augmenter.", "")))
|
|
this.html.find('.competence-xp-augmenter').click(async event => this.actor.updateCompetenceXPAuto(RdDSheetUtility.getItemId(event)))
|
|
this.html.find('.competence-stress-augmenter').click(async event => this.actor.updateCompetenceStress(RdDSheetUtility.getItemId(event)))
|
|
|
|
if (this.options.vueDetaillee) {
|
|
// On carac change
|
|
this.html.find('input.carac-xp').change(async event => {
|
|
let caracName = event.currentTarget.name.replace(".xp", "").replace("system.carac.", "");
|
|
this.actor.updateCaracXP(caracName, parseInt(event.target.value));
|
|
});
|
|
// On competence xp change
|
|
this.html.find('input.competence-xp').change(async event => {
|
|
let compName = event.currentTarget.attributes.compname.value;
|
|
this.actor.updateCompetenceXP(compName, parseInt(event.target.value));
|
|
});
|
|
this.html.find('input.competence-xp-sort').change(async event => {
|
|
let compName = event.currentTarget.attributes.compname.value;
|
|
this.actor.updateCompetenceXPSort(compName, parseInt(event.target.value));
|
|
});
|
|
|
|
this.html.find('.toggle-archetype').click(async event => {
|
|
this.options.vueArchetype = !this.options.vueArchetype;
|
|
this.render(true);
|
|
});
|
|
// On competence archetype change
|
|
this.html.find('.competence-archetype').change(async event => {
|
|
let compName = event.currentTarget.attributes.compname.value;
|
|
this.actor.updateCompetenceArchetype(compName, parseInt(event.target.value));
|
|
});
|
|
this.html.find('.nouvelle-incarnation').click(async event => this.actor.nouvelleIncarnation())
|
|
}
|
|
|
|
// On pts de reve change
|
|
this.html.find('.pointsreve-value').change(async event => this.actor.update({ "system.reve.reve.value": event.currentTarget.value }))
|
|
this.html.find('.seuil-reve-value').change(async event => this.actor.setPointsDeSeuil(event.currentTarget.value))
|
|
|
|
this.html.find('.stress-test').click(async event => this.actor.transformerStress())
|
|
this.html.find('.moral-malheureux').click(async event => this.actor.jetDeMoral('malheureuse'))
|
|
this.html.find('.moral-neutre').click(async event => this.actor.jetDeMoral('neutre'))
|
|
this.html.find('.moral-heureux').click(async event => this.actor.jetDeMoral('heureuse'))
|
|
this.html.find('.button-ethylisme').click(async event => this.actor.jetEthylisme())
|
|
|
|
this.html.find('.ptreve-actuel-plus').click(async event => this.actor.reveActuelIncDec(1))
|
|
this.html.find('.ptreve-actuel-moins').click(async event => this.actor.reveActuelIncDec(-1))
|
|
this.html.find('.fatigue-plus').click(async event => this.actor.santeIncDec("fatigue", 1))
|
|
this.html.find('.fatigue-moins').click(async event => this.actor.santeIncDec("fatigue", -1))
|
|
}
|
|
|
|
getBlessure(event) {
|
|
const blessureId = this.html.find(event.currentTarget).parents(".item-blessure").data('item-id');
|
|
return this.actor.getItem(blessureId, 'blessure');
|
|
}
|
|
|
|
isCompetenceAffichable(competence) {
|
|
return !this.options.showCompNiveauBase || !RdDItemCompetence.isNiveauBase(competence);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async _onDropActor(event, dragData) {
|
|
const dropActor = fromUuidSync(dragData.uuid);
|
|
this.actor.addSubActeur(dropActor);
|
|
super._onDropActor(event, dragData);
|
|
}
|
|
|
|
openSubActeur(actorId) {
|
|
game.actors.get(actorId)?.sheet.render(true)
|
|
}
|
|
|
|
deleteSubActeur(actorId, li) {
|
|
if (actorId) {
|
|
const subActor = game.actors.get(actorId);
|
|
RdDUtility.confirmSubActeurDelete(this, subActor, li, () => {
|
|
console.log('Delete : ', subActor.id);
|
|
this.actor.deleteSubActeur(subActor.id);
|
|
RdDUtility.slideOnDelete(this, li);
|
|
});
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async selectTypeOeuvreToCreate() {
|
|
let types = RdDItem.getTypesOeuvres();
|
|
let content = `<span class="competence-label">Selectionnez le type d'oeuvre</span><select class="item-type">`;
|
|
for (let typeName of types) {
|
|
content += `<option value="${typeName}">${Misc.typeName('Item', typeName)}</option>`
|
|
}
|
|
content += '</select>';
|
|
let dialog = new Dialog({
|
|
title: "Créer une oeuvre",
|
|
content: content,
|
|
buttons: {
|
|
create: {
|
|
icon: '<i class="fas fa-check"></i>',
|
|
label: "Créer l'oeuvre",
|
|
callback: () => this.actor.createItem($(".item-type").val())
|
|
}
|
|
}
|
|
});
|
|
dialog.render(true);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async createEmptyTache() {
|
|
await this.actor.createItem('tache', 'Nouvelle tache');
|
|
}
|
|
|
|
_getEventArmeCombat(event) {
|
|
const li = this.html.find(event.currentTarget)?.parents(".item");
|
|
let armeName = li.data("arme-name");
|
|
let compName = li.data('competence-name');
|
|
const arme = this.armesList.find(a => a.name == armeName && a.system.competence == compName);
|
|
if (!arme) {
|
|
return { name: armeName, system: { competence: compName } };
|
|
}
|
|
return arme;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
/** @override */
|
|
setPosition(options = {}) {
|
|
const position = super.setPosition(options);
|
|
const sheetHeader = this.element.find(".sheet-header");
|
|
const sheetTabs = this.element.find(".sheet-tabs");
|
|
const sheetBody = this.element.find(".sheet-body");
|
|
let bodyHeight = position.height - sheetHeader[0].clientHeight;
|
|
if (sheetTabs.length > 0) {
|
|
bodyHeight -= sheetTabs[0].clientHeight;
|
|
}
|
|
sheetBody.css("height", bodyHeight);
|
|
return position;
|
|
}
|
|
|
|
|
|
/* -------------------------------------------- */
|
|
/** @override */
|
|
_updateObject(event, formData) {
|
|
// Update the Actor
|
|
return this.actor.update(formData);
|
|
}
|
|
|
|
async splitItem(item) {
|
|
const dialog = await DialogSplitItem.create(item, (item, split) => this._onSplitItem(item, split));
|
|
dialog.render(true);
|
|
}
|
|
|
|
async _onSplitItem(item, split) {
|
|
if (split >= 1 && split < item.system.quantite) {
|
|
await item.diminuerQuantite(split);
|
|
const splitItem = foundry.utils.duplicate(item);
|
|
splitItem.system.quantite = split;
|
|
await this.actor.createEmbeddedDocuments('Item', [splitItem])
|
|
}
|
|
}
|
|
|
|
}
|