Vincent Vandemeulebrouck
2fa0ce5f15
L'item "race" permet de paramétrer des ajustements de caracs, des min/max de taille, et une limite de force. Ajouter une race à un acteur enlève la/les races précédentes et ajoute les modificateurs de caracs de la nouvelle race. Enlever une race enlève les modificateurs de caracs de la race aux caractéristiques
402 lines
19 KiB
JavaScript
402 lines
19 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 { ITEM_TYPES, 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";
|
|
import { RdDItemRace } from "./item/race.js";
|
|
|
|
/* -------------------------------------------- */
|
|
/**
|
|
* 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.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.corpsACorps(actor));
|
|
formData.combat.push(RdDItemArme.empoignade(actor));
|
|
|
|
formData.esquives = this.actor.getCompetencesEsquive()
|
|
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.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 => 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('.roll-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('.don-de-haut-reve').click(async event => this.actor.addDonDeHautReve())
|
|
this.html.find('.sortreserve-add').click(async event => this.actor.addSortReserve(RdDSheetUtility.getItemId(event)))
|
|
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('.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._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('.chance-actuelle-plus').click(async event => this.actor.chanceActuelleIncDec(1))
|
|
this.html.find('.chance-actuelle-moins').click(async event => this.actor.chanceActuelleIncDec(-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])
|
|
}
|
|
}
|
|
|
|
}
|