Cas rencontré une fois, un jet de chance d'un autre joueur, pouvait être tenté. Cas plus étrange, un jet de chance alors que le jet sauvegardé n'avait pas d'actorId
395 lines
18 KiB
JavaScript
395 lines
18 KiB
JavaScript
import { RdDUtility } from "./rdd-utility.js";
|
|
import { HtmlUtility } from "./html-utility.js";
|
|
import { RdDBonus } from "./rdd-bonus.js";
|
|
import { Misc } from "./misc.js";
|
|
import { RdDCombatManager } from "./rdd-combat.js";
|
|
import { CARACS, 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 { MAINS_DIRECTRICES } from "./actor.js";
|
|
import { RdDBaseActorReveSheet } from "./actor/base-actor-reve-sheet.js";
|
|
import { ACTOR_TYPES, ITEM_TYPES } from "./constants.js";
|
|
import { RdDItem } from "./item.js";
|
|
import { RdDItemCompetence } from "./item-competence.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";
|
|
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
|
|
import { MORAL } from "./moral/apprecier.mjs";
|
|
|
|
/* -------------------------------------------- */
|
|
/**
|
|
* Extend the basic ActorSheet with some very simple modifications
|
|
*/
|
|
export class RdDActorSheet extends RdDBaseActorSangSheet {
|
|
|
|
/** @override */
|
|
static get defaultOptions() {
|
|
return foundry.utils.mergeObject(RdDBaseActorReveSheet.defaultOptions, {
|
|
template: "systems/foundryvtt-reve-de-dragon/templates/actor-sheet.hbs",
|
|
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 RdDTextEditor.enrichHTML(this.actor.system.biographie, this.actor),
|
|
notes: await RdDTextEditor.enrichHTML(this.actor.system.notes, this.actor),
|
|
});
|
|
foundry.utils.mergeObject(formData.calc, {
|
|
surenc: this.actor.computeMalusSurEncombrement(),
|
|
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!" : "",
|
|
malusArmure: this.actor.getMalusArmure()
|
|
})
|
|
|
|
this.timerRecherche = undefined;
|
|
|
|
if (formData.type == ACTOR_TYPES.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.esquives = this.actor.getCompetencesEsquive()
|
|
formData.combat = actor.listActionsAttaque()
|
|
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.isDemiReve(),
|
|
cacheTMR: this.actor.isTMRCache()
|
|
}
|
|
|
|
formData.race = actor.itemTypes[ITEM_TYPES.race].find(it => true)
|
|
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 => await 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)
|
|
await 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')
|
|
await RdDCoeur.toggleSubActeurCoeur(this.actor.id, subActorIdactorId, coeurNombre)
|
|
})
|
|
this.html.find('.subacteur-tendre-moment').click(async event => {
|
|
const subActorId = RdDSheetUtility.getEventItemData(event, 'subactor-id')
|
|
await 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 =>
|
|
await this.actor.updateCompteurValue("stress", parseInt(event.target.value))
|
|
);
|
|
this.html.find("input.derivee-value[name='system.compteurs.experience.value']").change(async event =>
|
|
await this.actor.updateCompteurValue("experience", parseInt(event.target.value))
|
|
);
|
|
|
|
this.html.find('.creer-tache').click(async event => await this.createEmptyTache());
|
|
this.html.find('.creer-une-oeuvre').click(async event => await this.selectTypeOeuvreToCreate());
|
|
this.html.find('.creer-tache-blessure-legere').click(async event => await RdDItemBlessure.createTacheSoinBlessure(this.actor, 2));
|
|
this.html.find('.creer-tache-blessure-grave').click(async event => await RdDItemBlessure.createTacheSoinBlessure(this.actor, 4));
|
|
this.html.find('.creer-tache-blessure-critique').click(async event => await RdDItemBlessure.createTacheSoinBlessure(this.actor, 6));
|
|
|
|
this.html.find('.blessure-premierssoins-done').change(async event => {
|
|
await this.getBlessure(event)?.setSoinsBlessure({ premierssoins: { done: event.currentTarget.checked } });
|
|
});
|
|
this.html.find('.blessure-soinscomplets-done').change(async event => {
|
|
await this.getBlessure(event)?.setSoinsBlessure({ soinscomplets: { done: event.currentTarget.checked } })
|
|
});
|
|
this.html.find('.blessure-premierssoins-bonus').change(async event => {
|
|
await this.getBlessure(event)?.setSoinsBlessure({ premierssoins: { bonus: Number(event.currentTarget.value) } })
|
|
});
|
|
this.html.find('.blessure-soinscomplets-bonus').change(async event => {
|
|
await this.getBlessure(event)?.setSoinsBlessure({ soinscomplets: { bonus: Number(event.currentTarget.value) } })
|
|
});
|
|
|
|
this.html.find('.roll-chance-actuelle').click(async event => await this.actor.rollCarac(CARACS.CHANCE_ACTUELLE))
|
|
this.html.find('.button-appel-chance').click(async event => await this.actor.rollAppelChance())
|
|
|
|
this.html.find('[name="jet-astrologie"]').click(async event => await this.actor.astrologieNombresAstraux())
|
|
this.html.find('.action-tache').click(async event => await this.actor.rollTache(RdDSheetUtility.getItemId(event)))
|
|
this.html.find('.meditation-label a').click(async event => await this.actor.rollMeditation(RdDSheetUtility.getItemId(event)))
|
|
|
|
this.html.find('.action-chant').click(async event => await this.actor.rollChant(RdDSheetUtility.getItemId(event)))
|
|
this.html.find('.action-danse').click(async event => await this.actor.rollDanse(RdDSheetUtility.getItemId(event)))
|
|
this.html.find('.action-musique').click(async event => await this.actor.rollMusique(RdDSheetUtility.getItemId(event)))
|
|
this.html.find('.action-oeuvre').click(async event => await this.actor.rollOeuvre(RdDSheetUtility.getItemId(event)))
|
|
this.html.find('.action-jeu').click(async event => await this.actor.rollJeu(RdDSheetUtility.getItemId(event)))
|
|
this.html.find('.action-recettecuisine').click(async event => await 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 => await this.actor.reinsertionAleatoire("Action MJ"))
|
|
this.html.find('.don-de-haut-reve').click(async event => await this.actor.addDonDeHautReve())
|
|
this.html.find('.afficher-tmr').click(async event => await this.actor.changeTMRVisible())
|
|
}
|
|
|
|
// Points de reve actuel
|
|
this.html.find('.roll-reve-actuel').click(async event => await this.actor.rollReveActuel({ resistance: false }))
|
|
this.html.find('.button-reve-resistance').click(async event => await this.actor.rollReveActuel({ diff: -8, resistance: true }))
|
|
this.html.find('.action-empoignade').click(async event => await RdDEmpoignade.onAttaqueEmpoignadeFromItem(RdDSheetUtility.getItem(event, this.actor)))
|
|
|
|
this.html.find('.roll-arme').click(async event => {
|
|
const action = this._getActionCombat(event);
|
|
await this.actor.rollArme(action.arme, action.main)
|
|
|
|
})
|
|
|
|
// Initiative pour l'arme
|
|
this.html.find('.roll-init-arme').click(async event => {
|
|
let combatant = game.combat.combatants.find(c => c.actor.id == this.actor.id)
|
|
if (combatant) {
|
|
RdDCombatManager.rollInitiativeAction(combatant._id, this._getActionCombat(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 => await this.actor.displayTMR("normal"))
|
|
this.html.find('.button-tmr-rapide').click(async event => await 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 => await this.actor.updateCaracXPAuto(event.currentTarget.name.replace("augmenter.", "")))
|
|
this.html.find('.competence-xp-augmenter').click(async event => await this.actor.updateCompetenceXPAuto(RdDSheetUtility.getItemId(event)))
|
|
this.html.find('.competence-stress-augmenter').click(async event => {
|
|
await this.actor.updateCompetenceStress(RdDSheetUtility.getItemId(event))
|
|
this.render(true)
|
|
}
|
|
)
|
|
|
|
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.", "")
|
|
await 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
|
|
await 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
|
|
await 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;
|
|
await this.actor.updateCompetenceArchetype(compName, parseInt(event.target.value));
|
|
});
|
|
this.html.find('.nouvelle-incarnation').click(async event => await this.actor.nouvelleIncarnation())
|
|
}
|
|
|
|
// On pts de reve change
|
|
this.html.find('.pointsreve-value').change(async event => await this.actor.update({ "system.reve.reve.value": event.currentTarget.value }))
|
|
this.html.find('.seuil-reve-value').change(async event => await this.actor.setPointsDeSeuil(event.currentTarget.value))
|
|
|
|
this.html.find('.stress-test').click(async event => await this.actor.transformerStress())
|
|
this.html.find('.moral-malheureux').click(async event => await this.actor.jetDeMoral(MORAL.MALHEUREUX))
|
|
this.html.find('.moral-neutre').click(async event => await this.actor.jetDeMoral(MORAL.NEUTRE))
|
|
this.html.find('.moral-heureux').click(async event => await this.actor.jetDeMoral(MORAL.HEUREUX))
|
|
this.html.find('.button-ethylisme').click(async event => await this.actor.jetEthylisme())
|
|
|
|
this.html.find('.ptreve-actuel-plus').click(async event => await this.actor.reveActuelIncDec(1))
|
|
this.html.find('.ptreve-actuel-moins').click(async event => await this.actor.reveActuelIncDec(-1))
|
|
this.html.find('.chance-actuelle-plus').click(async event => await this.actor.chanceActuelleIncDec(1))
|
|
this.html.find('.chance-actuelle-moins').click(async event => await this.actor.chanceActuelleIncDec(-1))
|
|
this.html.find('.fatigue-plus').click(async event => await this.actor.santeIncDec("fatigue", 1))
|
|
this.html.find('.fatigue-moins').click(async event => await 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="generic-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(ITEM_TYPES.tache, 'Nouvelle tache')
|
|
}
|
|
|
|
_getActionCombat(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.arme.name == armeName && a.comp.name == compName);
|
|
if (!arme) {
|
|
return {
|
|
name: armeName,
|
|
arme: { name: armeName },
|
|
comp: { name: 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;
|
|
}
|
|
|
|
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])
|
|
}
|
|
}
|
|
|
|
}
|