foundryvtt-reve-de-dragon/module/rdd-tmr-dialog.js

853 lines
33 KiB
JavaScript
Raw Normal View History

2020-07-05 21:45:25 +02:00
/**
* Extend the base Dialog entity by defining a custom window to perform spell.
* @extends {Dialog}
*/
2020-07-06 09:03:21 +02:00
import { RdDUtility } from "./rdd-utility.js";
2020-07-17 22:04:35 +02:00
import { TMRUtility } from "./tmr-utility.js";
import { RdDRollTables } from "./rdd-rolltables.js";
2020-11-12 16:35:51 +01:00
import { RdDResolutionTable } from "./rdd-resolution-table.js";
2020-11-29 18:21:34 +01:00
import { RdDTMRRencontreDialog } from "./rdd-tmr-rencontre-dialog.js";
2020-07-05 21:45:25 +02:00
2020-11-18 23:49:05 +01:00
/* -------------------------------------------- */
const tmrConstants = {
col1_y: 30,
col2_y: 55,
cellw: 55,
cellh: 55,
gridx: 28,
gridy: 28
}
2020-11-18 23:49:05 +01:00
/* -------------------------------------------- */
2020-07-05 21:45:25 +02:00
export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */
constructor(html, actor, tmrData, mode) {
const dialogConf = {
title: "Terres Médianes de Rêve",
2020-07-05 21:45:25 +02:00
content: html,
buttons: {
closeButton: { label: "Fermer", callback: html => this.close(html) }
},
default: "closeButton"
}
const dialogOptions = {
classes: ["tmrdialog"],
width: 920, height: 980,
'z-index': 20
}
2020-07-05 21:45:25 +02:00
super(dialogConf, dialogOptions);
this.tmrdata = duplicate(tmrData);
2020-07-14 22:19:29 +02:00
this.actor = actor;
2020-11-17 18:08:19 +01:00
this.actor.tmrApp = this; // reference this app in the actor structure
this.viewOnly = mode == "visu"
2020-11-14 20:46:39 +01:00
this.nbFatigue = this.viewOnly ? 0 : 1; // 1 premier point de fatigue du à la montée
2020-07-21 23:51:24 +02:00
this.rencontresExistantes = duplicate(this.actor.data.data.reve.rencontre.list);
2020-07-26 18:44:03 +02:00
this.sortReserves = duplicate(this.actor.data.data.reve.reserve.list);
this.casesSpeciales = this.actor.data.items.filter( item => item.type == 'casetmr');
2020-11-17 18:08:19 +01:00
this.allTokens = [];
2020-11-20 13:46:43 +01:00
this.rencontreState = 'aucune';
this.pixiApp = new PIXI.Application({ width: 720, height: 860 });
if (!this.viewOnly){
this._tellToGM(this.actor.name + " monte dans les terres médianes (" + mode + ")");
}
2020-07-14 22:19:29 +02:00
}
/* -------------------------------------------- */
2020-07-25 10:29:28 +02:00
close() {
this.actor.santeIncDec("fatigue", this.nbFatigue).then(super.close()); // moving 1 cell costs 1 fatigue
2020-11-17 18:08:19 +01:00
this.actor.tmrApp = undefined; // Cleanup reference
this._tellToGM(this.actor.name + " a quitté les terres médianes")
2020-07-25 10:29:28 +02:00
}
/* -------------------------------------------- */
2020-07-26 18:44:03 +02:00
displaySortReserve() {
console.debug("displaySortReserve", this.sortReserves);
for (let sort of this.sortReserves) {
this._trackToken(this._tokenSortEnReserve(sort));
2020-07-26 18:44:03 +02:00
}
}
/* -------------------------------------------- */
displaySpecificCase() {
for (let caseTMR of this.casesSpeciales) {
console.log("SPEC CASE ", caseTMR);
if ( caseTMR.data.specific == 'trounoir') {
this._trackToken(this._tokenTrouNoir( caseTMR.data.coord ));
} else if ( caseTMR.data.specific == 'attache') {
this._trackToken(this._tokenTerreAttache( caseTMR.data.coord ));
2020-12-30 19:27:35 +01:00
} else if ( caseTMR.data.specific == 'debordement') {
this._trackToken(this._tokenDebordement( caseTMR.data.coord ));
} else if ( caseTMR.data.specific == 'maitrisee') {
this._trackToken(this._tokenMaitrisee( caseTMR.data.coord ));
}
}
}
/* -------------------------------------------- */
2020-07-21 23:51:24 +02:00
displayPreviousRencontres() {
console.debug("displayPreviousRencontres", this.rencontresExistantes);
2020-07-21 23:51:24 +02:00
for (let rencontre of this.rencontresExistantes) {
this._trackToken(this._tokenRencontre(rencontre));
2020-07-21 23:51:24 +02:00
}
}
/* -------------------------------------------- */
2020-07-21 23:51:24 +02:00
updatePreviousRencontres() {
this._removeTokens(t => t.rencontre != undefined);
this.rencontresExistantes = duplicate(this.actor.data.data.reve.rencontre.list);
this.displayPreviousRencontres();
2020-07-21 23:51:24 +02:00
}
2020-07-26 18:44:03 +02:00
/* -------------------------------------------- */
2020-07-26 18:44:03 +02:00
updateSortReserve() {
this._removeTokens(t => t.sort != undefined);
this.sortReserves = duplicate(this.actor.data.data.reve.reserve.list);
2020-07-26 18:44:03 +02:00
this.displaySortReserve();
}
/* -------------------------------------------- */
2020-07-17 22:04:35 +02:00
async derober() {
await this.actor.addTMRRencontre(this.currentRencontre);
2020-07-17 22:04:35 +02:00
console.log("-> derober", this.currentRencontre);
this._tellToGM(this.actor.name + " s'est dérobé et quitte les TMR.");
2020-07-21 23:51:24 +02:00
this.close();
2020-07-14 22:19:29 +02:00
}
/* -------------------------------------------- */
2020-07-14 22:19:29 +02:00
async refouler(data) {
this._tellToGM(this.actor.name + " a refoulé : " + this.currentRencontre.name );
await this.actor.deleteTMRRencontreAtPosition(); // Remove the stored rencontre if necessary
let result = await this.actor.ajouterRefoulement( this.currentRencontre.data.refoulement );
2020-07-21 23:51:24 +02:00
this.updatePreviousRencontres();
2020-07-14 22:19:29 +02:00
console.log("-> refouler", this.currentRencontre)
2020-07-17 22:04:35 +02:00
this.updateValuesDisplay();
2020-11-20 13:46:43 +01:00
this.nettoyerRencontre();
2020-07-14 22:19:29 +02:00
}
2020-11-20 12:06:54 +01:00
/* -------------------------------------------- */
2020-11-20 13:46:43 +01:00
colorierZoneRencontre( locList) {
2020-11-20 12:06:54 +01:00
this.currentRencontre.graphics = []; // Keep track of rectangles to delete it
this.currentRencontre.locList = duplicate(locList); // And track of allowed location
for (let loc of locList) {
let rect = this._getCaseRectangleCoord( loc);
var rectDraw = new PIXI.Graphics();
rectDraw.beginFill(0xFFFF00, 0.3);
// set the line style to have a width of 5 and set the color to red
rectDraw.lineStyle(5, 0xFF0000);
// draw a rectangle
rectDraw.drawRect(rect.x, rect.y, rect.w, rect.h);
this.pixiApp.stage.addChild(rectDraw);
this.currentRencontre.graphics.push(rectDraw); // garder les objets pour gestion post-click
}
}
2020-11-21 14:30:00 +01:00
/* -------------------------------------------- */
async gererTourbillon( value ) {
this.nbFatigue += value;
await this.actor.reveActuelIncDec( -value );
2020-11-21 14:30:00 +01:00
if ( !this.currentRencontre.tourbillonDirection ) {
this.currentRencontre.tourbillonDirection = TMRUtility.getDirectionPattern();
}
2020-11-21 18:16:18 +01:00
let tmrPos = this.actor.data.data.reve.tmrpos;
tmrPos.coord = TMRUtility.deplaceTMRSelonPattern( tmrPos.coord, this.currentRencontre.tourbillonDirection, value );
await this.actor.update({ "data.reve.tmrpos": tmrPos });
console.log("NEWPOS", tmrPos);
2020-11-21 14:30:00 +01:00
}
/* -------------------------------------------- */
async gererTourbillonRouge( ) {
this.nbFatigue += 4; // 4 cases -> 4 pts de fatigue
await this.actor.reveActuelIncDec( -2 ); // -2 pts de Reve a chaque itération
if ( !this.currentRencontre.tourbillonDirection ) {
this.currentRencontre.tourbillonDirection = TMRUtility.getDirectionPattern();
}
let tmrPos = this.actor.data.data.reve.tmrpos;
tmrPos.coord = TMRUtility.deplaceTMRSelonPattern( tmrPos.coord, this.currentRencontre.tourbillonDirection, 4 ); // Depl. 4 cases.
await this.actor.update({ "data.reve.tmrpos": tmrPos });
await this.actor.santeIncDec( "vie", -1); // Et -1 PV
console.log("TOURBILLON ROUGE", tmrPos);
}
2020-11-20 12:06:54 +01:00
/* -------------------------------------------- */
/** Gère les rencontres avec du post-processing graphique (passeur, messagers, tourbillons, ...) */
2020-11-21 08:27:28 +01:00
async rencontrePostProcess( rencontreData) {
2020-11-20 12:06:54 +01:00
if (!rencontreData) return; // Sanity check
this.rencontreState = rencontreData.state; // garder la trace de l'état en cours
2020-11-20 13:46:43 +01:00
2020-11-21 08:27:28 +01:00
let locList
if ( this.rencontreState == 'passeur' || this.rencontreState == 'messager' ) {
2020-11-20 12:06:54 +01:00
// Récupère la liste des cases à portées
2020-11-21 08:27:28 +01:00
locList = TMRUtility.getTMRArea(this.actor.data.data.reve.tmrpos.coord, this.currentRencontre.force, tmrConstants );
} else if ( this.rencontreState == 'passeurfou' ) { // Cas spécial du passeur fou
let sortReserve = this.actor.data.data.reve.reserve[0];
let tmrPos
if ( sortReserve ) {
tmrPos = sortReserve.coord; // Passeur fou positionne sur la case d'un ort en réserve (TODO : Choisir le plus loin)
} else {
let direction = TMRUtility.getDirectionPattern(); // Déplacement aléatoire de la force du Passeur Fou
tmrPos = TMRUtility.deplaceTMRSelonPattern(this.actor.data.data.reve.tmrpos.coord, direction, this.currentRencontre.force );
}
await this.actor.update({ "data.reve.tmrpos": tmrPos });
2020-11-21 08:27:28 +01:00
} else if ( this.rencontreState == 'changeur' ) {
// Liste des cases de même type
locList = TMRUtility.getLocationTypeList( this.actor.data.data.reve.tmrpos.coord );
} else if ( this.rencontreState == 'reflet' ) {
this.nbFatigue += 1;
2020-11-21 14:30:00 +01:00
} else if ( this.rencontreState == 'tourbillonblanc' ) {
2020-11-21 18:16:18 +01:00
await this.gererTourbillon(1);
2020-11-21 14:30:00 +01:00
} else if ( this.rencontreState == 'tourbillonnoir' ) {
2020-11-21 18:16:18 +01:00
await this.gererTourbillon(2);
2020-11-21 14:30:00 +01:00
} else if ( this.rencontreState == 'tourbillonrouge' ) {
await this.gererTourbillonRouge();
2020-11-20 12:06:54 +01:00
} else {
this.currentRencontre = undefined; // Cleanup, not used anymore
}
2020-11-21 08:27:28 +01:00
if ( locList )
this.colorierZoneRencontre( locList );
}
/* -------------------------------------------- */
2020-11-21 23:24:00 +01:00
checkQuitterTMR() {
2020-11-21 08:27:28 +01:00
if ( this.actor.data.data.reve.reve.value == 0) {
this._tellToGM("Vos Points de Rêve sont à 0 : vous quittez les Terres médianes !");
2020-11-21 08:27:28 +01:00
this.close();
}
if ( this.nbFatigue == this.actor.data.data.sante.fatigue.max ) {
this._tellToGM("Vous vous écroulez de fatigue : vous quittez les Terres médianes !");
2020-11-21 08:27:28 +01:00
this.close();
}
if ( this.actor.data.data.sante.vie.value == 0 ) {
this._tellToGM("Vous n'avez plus de Points de Vie : vous quittez les Terres médianes !");
2020-11-21 08:27:28 +01:00
this.close();
}
2020-11-20 12:06:54 +01:00
}
/* -------------------------------------------- */
async maitriser(data) {
this.actor.deleteTMRRencontreAtPosition(); // Remove the stored rencontre if necessary
2020-07-21 23:51:24 +02:00
this.updatePreviousRencontres();
2020-11-12 16:35:51 +01:00
const draconic = this.actor.getBestDraconic();
2020-11-16 04:01:36 +01:00
const carac = this.actor.getReveActuel();
2020-11-21 08:27:28 +01:00
const etatGeneral = this.actor.data.data.compteurs.etat.value;
const difficulte = draconic.data.niveau - this.currentRencontre.force + etatGeneral;
console.log("Maitriser", carac, draconic.data.niveau, this.currentRencontre.force, etatGeneral);
2020-11-12 16:35:51 +01:00
2020-11-21 09:54:21 +01:00
let rolled = await RdDResolutionTable.roll(carac, difficulte);
let message = "<br><strong>Test : Rêve actuel / " + draconic.name + " / " + this.currentRencontre.name + "</strong>" + "<br>"
+ RdDResolutionTable.explain(rolled);
2020-11-20 12:06:54 +01:00
let rencontreData
if (rolled.isEchec) {
2020-11-20 12:06:54 +01:00
rencontreData = await TMRUtility.processRencontreEchec(this.actor, this.currentRencontre, rolled, this);
message += rencontreData.message;
this._tellToGM("Vous avez <strong>échoué</strong> à maîtriser un " + this.currentRencontre.name + " de force " + this.currentRencontre.force + message);
if (this.currentRencontre.data.quitterTMR) { // Selon les rencontres, quitter TMR ou pas
2020-11-18 18:11:01 +01:00
this.close();
}
2020-07-17 22:04:35 +02:00
} else {
2020-11-20 12:06:54 +01:00
rencontreData = await TMRUtility.processRencontreReussite(this.actor, this.currentRencontre, rolled);
message += rencontreData.message;
this._tellToGM("Vous avez <strong>réussi</strong> à maîtriser un " + this.currentRencontre.name + " de force " + this.currentRencontre.force + message);
2020-07-17 22:04:35 +02:00
}
2020-11-20 12:06:54 +01:00
2020-11-21 08:27:28 +01:00
await this.rencontrePostProcess( rencontreData );
2020-11-20 12:06:54 +01:00
2020-07-17 22:04:35 +02:00
console.log("-> matriser", this.currentRencontre);
this.updateValuesDisplay();
2020-11-21 08:27:28 +01:00
this.checkQuitterTMR();
2020-11-21 14:30:00 +01:00
if ( this.rencontreState == 'reflet' || this.rencontreState == 'tourbillonblanc' || this.rencontreState == 'tourbillonnoir' )
2020-11-21 08:27:28 +01:00
this.maitriser();
2020-07-14 22:19:29 +02:00
}
2020-11-12 23:35:29 +01:00
2020-11-17 16:30:03 +01:00
/* -------------------------------------------- */
_tellToUser(message) {
ChatMessage.create({ content: message, user: game.user._id, whisper: [game.user._id] });
}
2020-11-18 23:49:05 +01:00
/* -------------------------------------------- */
_tellToGM(message) {
ChatMessage.create({ content: message, user: game.user._id, whisper: ChatMessage.getWhisperRecipients("GM") });
2020-11-18 23:49:05 +01:00
}
/* -------------------------------------------- */
async manageRencontre(coordTMR, cellDescr) {
2020-11-14 20:46:39 +01:00
if (this.viewOnly) {
return;
}
this.currentRencontre = undefined;
let rencontre = await this._jetDeRencontre(coordTMR, cellDescr);
2020-11-18 18:11:01 +01:00
2020-07-14 22:19:29 +02:00
if (rencontre) { // Manages it
2020-11-18 18:11:01 +01:00
if (rencontre.rencontre) rencontre = rencontre.rencontre; // Manage stored rencontres
console.log("manageRencontre", rencontre);
2020-07-21 23:51:24 +02:00
this.currentRencontre = duplicate(rencontre);
2020-11-16 04:01:36 +01:00
2020-11-29 18:21:34 +01:00
let dialog = new RdDTMRRencontreDialog("", this, this.currentRencontre);
2020-11-12 23:35:29 +01:00
dialog.render(true);
2020-07-14 22:19:29 +02:00
}
}
/* -------------------------------------------- */
async _jetDeRencontre(coordTMR, cellDescr) {
let rencontre = this.rencontresExistantes.find(prev => prev.coord == coordTMR);
if (rencontre == undefined) {
2020-12-04 20:52:04 +01:00
let myRoll = new Roll("1d7").roll();
if (myRoll.total == 7) {
let isSpecial = this.actor.isRencontreSpeciale();
rencontre = await TMRUtility.rencontreTMRRoll(coordTMR, cellDescr, isSpecial );
} else {
this._tellToUser(myRoll.total + ": Pas de rencontre en " + cellDescr.label + " (" + coordTMR + ")");
}
}
if (TMRUtility.isForceRencontre()) {
return await TMRUtility.rencontreTMRRoll(coordTMR, cellDescr);
}
return rencontre;
}
/* -------------------------------------------- */
2020-07-17 22:04:35 +02:00
updateValuesDisplay() {
2020-11-20 16:45:20 +01:00
let ptsreve = document.getElementById("tmr-pointsreve-value");
2020-07-17 22:04:35 +02:00
ptsreve.innerHTML = this.actor.data.data.reve.reve.value;
2020-07-17 22:04:35 +02:00
let tmrpos = document.getElementById("tmr-pos");
let tmr = TMRUtility.getTMRDescription(this.actor.data.data.reve.tmrpos.coord);
tmrpos.innerHTML = this.actor.data.data.reve.tmrpos.coord + " (" + tmr.label + ")";
2020-11-20 16:45:20 +01:00
let etat = document.getElementById("tmr-etatgeneral-value");
2020-07-17 22:04:35 +02:00
etat.innerHTML = this.actor.data.data.compteurs.etat.value;
2020-11-20 16:45:20 +01:00
let refoulement = document.getElementById("tmr-refoulement-value");
2020-07-17 22:04:35 +02:00
refoulement.innerHTML = this.actor.data.data.reve.refoulement.value;
2020-11-20 16:45:20 +01:00
let fatigueItem = document.getElementById("tmr-fatigue-table");
2020-12-30 19:27:35 +01:00
//console.log("Refresh : ", this.actor.data.data.sante.fatigue.value);
fatigueItem.innerHTML = "<table class='table-fatigue'>" + RdDUtility.makeHTMLfatigueMatrix(this.actor.data.data.sante.fatigue.value, this.actor.data.data.sante.endurance.max).html() + "</table>";
2020-07-17 22:04:35 +02:00
}
/* -------------------------------------------- */
async manageCaseSpeciale( cellDescr, coordTMR ) {
for( let caseTMR of this.casesSpeciales) {
if (caseTMR.data.coord == coordTMR) { // Match !
if (caseTMR.data.specific == 'trounoir') {
let newTMR = TMRUtility.getTMRAleatoire();
let tmrPos = duplicate(this.actor.data.data.reve.tmrpos);
tmrPos.coord = newTMR;
await this.actor.update( { "data.reve.tmrpos": tmrPos } );
ChatMessage.create( {
content: "Vous êtes rentré sur un Trou Noir : ré-insertion aléatoire.",
whisper: ChatMessage.getWhisperRecipients(game.user.name) } );
}
}
}
}
/* -------------------------------------------- */
isCaseMaitrisee( coordTMR) {
for( let caseTMR of this.casesSpeciales) {
if (caseTMR.data.coord == coordTMR && caseTMR.data.specific == 'maitrisee') {
return true;
}
}
return false;
}
/* -------------------------------------------- */
2020-07-17 22:04:35 +02:00
manageCaseHumideResult() {
if (this.toclose)
2020-07-17 22:04:35 +02:00
this.close();
}
2020-11-12 16:35:51 +01:00
/* -------------------------------------------- */
2020-12-30 19:27:35 +01:00
async manageCaseHumide(cellDescr, coordTMR) {
2020-11-14 20:46:39 +01:00
if (this.viewOnly) {
return;
}
2020-12-30 19:27:35 +01:00
let isHumide = this.actor.checkIsAdditionnalHumide(cellDescr, coordTMR);
if (cellDescr.type == "lac" || cellDescr.type == "fleuve" || cellDescr.type == "marais" || isHumide) {
if ( this.isCaseMaitrisee( coordTMR ) ) {
ChatMessage.create( {
content: "Cette case humide est déja maitrisée grâce à votre Tête <strong>Quête des Eaux</strong>",
whisper: ChatMessage.getWhisperRecipients(game.user.name) } );
return;
}
// TODO: permettre de choisir la voie de draconic?
2020-07-17 22:04:35 +02:00
let draconic = this.actor.getBestDraconic();
2020-11-16 04:01:36 +01:00
let carac = this.actor.getReveActuel();
const etatGeneral = this.actor.data.data.compteurs.etat.value
let difficulte = draconic.data.niveau - 7;
2020-11-29 18:21:34 +01:00
let rolled = await RdDResolutionTable.roll(carac, difficulte);
// Gestion du souffle Double Résistance du Fleuve
if ( this.actor.isDoubleResistanceFleuve() ) {
let rolled2 = await RdDResolutionTable.roll(carac, difficulte);
if (rolled2.isEchec)
rolled = rolled;
}
console.log("manageCaseHumide >>", rolled);
2020-11-12 16:35:51 +01:00
let explication = "";
2020-11-29 18:21:34 +01:00
let msg2MJ = "";
this.toclose = rolled.isEchec;
if (rolled.isEchec) {
explication += "Vous êtes entré sur une case humide, et vous avez <strong>raté</strong> votre maîtrise ! Vous <strong>quittez les Terres Médianes</strong> !"
2020-11-29 18:21:34 +01:00
msg2MJ += game.user.name + " est rentré sur une case humides : Echec !";
2020-11-12 16:35:51 +01:00
}
else {
explication += "Vous êtes entré sur une case humide, et vous avez <strong>réussi</strong> votre maîtrise !"
2020-11-29 18:21:34 +01:00
msg2MJ += game.user.name + " est rentré sur une case humides : Réussite !";
2020-11-12 16:35:51 +01:00
}
explication += "<br><strong>Test : Rêve actuel / " + draconic.name + " / " + cellDescr.type + "</strong>"
2020-11-16 04:32:42 +01:00
+ RdDResolutionTable.explain(rolled);
2020-11-12 16:35:51 +01:00
if (rolled.isETotal) {
let souffle = await this.actor.ajouterSouffle({chat: false});
explication += "<br>Vous avez fait un Echec Total. Vous subissez un Souffle de Dragon : " + souffle.name;
2020-11-29 18:21:34 +01:00
msg2MJ += "<br>Et a reçu un Souffle de Dragon : " + souffle.name;
2020-11-12 16:35:51 +01:00
}
if (rolled.isPart) {
explication += "<br>Vous avez fait une Réussite Particulière";
2020-12-30 11:50:18 +01:00
this.actor._appliquerAjoutExperience({ rolled: rolled, seletedCarac: { label: 'reve'}, competence: draconic.name })
2020-11-29 18:21:34 +01:00
msg2MJ += "<br>Et a fait une réussite particulière";
2020-11-12 16:35:51 +01:00
}
2020-11-29 18:21:34 +01:00
// Notification au MJ
ChatMessage.create( { content: msg2MJ, whisper: ChatMessage.getWhisperRecipients("GM") } );
// Et au joueur (ca pourrait être un message de tchat d'ailleurs)
2020-11-12 16:35:51 +01:00
let humideDiag = new Dialog({
title: "Case humide",
content: explication,
2020-11-12 16:35:51 +01:00
buttons: {
choice: { icon: '<i class="fas fa-check"></i>', label: "Fermer", callback: () => this.manageCaseHumideResult() }
2020-07-25 10:29:28 +02:00
}
2020-07-17 22:04:35 +02:00
}
2020-11-12 16:35:51 +01:00
);
2020-07-17 22:04:35 +02:00
humideDiag.render(true);
}
}
/* -------------------------------------------- */
isReserveExtensible( coordTMR) {
for( let caseTMR of this.casesSpeciales) {
if (caseTMR.data.specific == 'reserve_extensible' && caseTMR.data.coord == coordTMR )
return true;
}
return false;
}
/* -------------------------------------------- */
async declencheSortEnReserve(coordTMR) {
2020-11-14 20:46:39 +01:00
if (this.viewOnly) {
return;
}
2020-12-30 11:50:18 +01:00
let sortReserveList = TMRUtility.getSortReserveList( this.sortReserves, coordTMR );
if (sortReserveList.length > 0 ) {
if ( this.actor.isReserveEnSecurite() || this.isReserveExtensible(coordTMR) ) {
let msg = "Vous êtes sur une case avec un Sort en Réserve. Grâce à votre Tête <strong>Reserve en Sécurité</strong> ou <strong>Réserve Exensible</strong>, vous pouvez contrôler le déclenchement. Cliquez si vous souhaitez le déclencher : <ul>";
for (let sortReserve of sortReserveList) {
msg += "<li><a class='chat-card-button' id='sort-reserve' data-actor-id='"+this.actor._id+"' data-tmr-coord='"+coordTMR+"' data-sort-id='"+sortReserve.sort._id+"'>"+sortReserve.sort.name+"</a></li>";
}
msg += "</ol>";
ChatMessage.create( {
content: msg,
whisper: ChatMessage.getWhisperRecipients(game.user.name) } );
} else {
await this.processSortReserve( sortReserveList[0] );
}
}
}
/* -------------------------------------------- */
lancerSortEnReserve( coordTMR, sortId ) {
let sortReserveList = TMRUtility.getSortReserveList( this.sortReserves, coordTMR );
let sortReserve = sortReserveList.find( sortReserve => sortReserve.sort._id == sortId);
//console.log("SORT RESA", sortReserveList, coordTMR, sortId, sortReserve);
if ( sortReserve) {
this.processSortReserve( sortReserve );
} else {
ChatMessage.create( {
content: "Une erreur est survenue : impossible de récupérer le sort en réserve demandé.",
whisper: ChatMessage.getWhisperRecipients(game.user.name) } );
2020-07-26 18:44:03 +02:00
}
}
/* -------------------------------------------- */
async processSortReserve( sortReserve ) {
await this.actor.deleteSortReserve(sortReserve);
this.updateSortReserve();
console.log("declencheSortEnReserve", sortReserve)
const declenchementSort = "Vous avez déclenché le sort <strong>" + sortReserve.sort.name
+ "</strong> en réserve en " + sortReserve.coord + " (" + TMRUtility.getTMRDescription(sortReserve.coord).label
+ ") avec " + sortReserve.sort.data.ptreve_reel + " points de Rêve";
this._tellToGM(declenchementSort);
this.close();
}
2020-11-20 13:46:43 +01:00
/* -------------------------------------------- */
nettoyerRencontre( ) {
if ( !this.currentRencontre) return; // Sanity check
if ( this.currentRencontre.graphics) {
for (let drawRect of this.currentRencontre.graphics) { // Suppression des dessins des zones possibles
this.pixiApp.stage.removeChild( drawRect );
}
}
this.currentRencontre = undefined; // Nettoyage de la structure
this.rencontreState = 'aucune'; // Et de l'état
}
2020-11-20 12:06:54 +01:00
/* -------------------------------------------- */
processClickPostRencontre( coord ) {
let deplacementType = "erreur";
2020-11-21 08:27:28 +01:00
if (this.rencontreState == 'passeur' || this.rencontreState == 'messager' || this.rencontreState == 'changeur') {
2020-11-20 13:46:43 +01:00
console.log("Searching", this.currentRencontre.locList, coord);
2020-11-20 12:06:54 +01:00
let isInArea = this.currentRencontre.locList.find(locCoord => locCoord == coord );
if ( isInArea ) { // OK !
2020-11-20 13:46:43 +01:00
deplacementType = (this.rencontreState == 'messager') ? 'messager' : 'saut';
}
2020-11-21 08:27:28 +01:00
}
2020-11-20 13:46:43 +01:00
return deplacementType;
2020-11-20 12:06:54 +01:00
}
/* -------------------------------------------- */
isTerreAttache( coordTMR ) {
for( let caseTMR of this.casesSpeciales) {
if (caseTMR.data.specific == 'attache' && caseTMR.data.coord == coordTMR) { // Match !
return true;
}
}
return false;
}
/* -------------------------------------------- */
checkConnaissanceFleuve( currentTMR, nextTMR ) {
if ( this.actor.isConnaissanceFleuve() ) {
//console.log(currentTMR, nextTMR );
if ( TMRUtility.getTMRDescription(currentTMR).type == 'fleuve' && TMRUtility.getTMRDescription(nextTMR).type == 'fleuve') {
return true;
}
}
return false;
}
/* -------------------------------------------- */
async deplacerDemiReve(event) {
2020-11-14 20:46:39 +01:00
if (this.viewOnly) {
return;
}
2020-11-21 23:24:00 +01:00
2020-07-14 22:19:29 +02:00
let origEvent = event.data.originalEvent;
let myself = event.target.tmrObject;
let eventCoord = RdDTMRDialog._computeEventCoord(origEvent);
let cellx = eventCoord.cellx;
let celly = eventCoord.celly;
console.log("deplacerDemiReve >>>>", cellx, celly);
2020-07-17 22:04:35 +02:00
let currentPos = TMRUtility.convertToCellCoord(myself.actor.data.data.reve.tmrpos.coord);
2020-11-20 13:46:43 +01:00
let coordTMR = TMRUtility.convertToTMRCoord(cellx, celly);
let currentTMR = TMRUtility.convertToTMRCoord( currentPos.x, currentPos.y);
2020-11-20 12:06:54 +01:00
// Validation de la case de destination (gestion du cas des rencontres qui peuvent téléporter)
2020-11-20 13:46:43 +01:00
let deplacementType = 'erreur';
if ( myself.rencontreState == 'aucune') { // Pas de recontre en post-processing, donc deplacement normal
if ( !RdDTMRDialog._horsDePortee(currentPos, cellx, celly) || myself.isTerreAttache(coordTMR) || myself.checkConnaissanceFleuve(currentTMR,coordTMR ) ) {
2020-11-20 13:46:43 +01:00
deplacementType = 'normal';
2020-11-20 12:06:54 +01:00
}
2020-07-14 22:19:29 +02:00
} else {
2020-11-20 13:46:43 +01:00
deplacementType = myself.processClickPostRencontre( coordTMR );
2020-11-20 12:06:54 +01:00
}
// Si le deplacement est valide
2020-11-20 13:46:43 +01:00
if ( deplacementType == 'normal' || deplacementType == 'saut') {
if ( myself.currentRencontre != 'normal' )
2020-11-20 13:46:43 +01:00
myself.nettoyerRencontre();
let cellDescr = TMRUtility.getTMRDescription(coordTMR);
await myself.manageCaseSpeciale(cellDescr, coordTMR); // Gestion cases spéciales type Trou noir, etc
console.log("deplacerDemiReve: TMR column is", coordTMR, cellx, celly, cellDescr, this);
2020-07-14 22:19:29 +02:00
let tmrPos = duplicate(myself.actor.data.data.reve.tmrpos);
tmrPos.coord = coordTMR;
await myself.actor.update({ "data.reve.tmrpos": tmrPos });
myself._updateDemiReve(myself);
2020-07-25 10:29:28 +02:00
myself.nbFatigue += 1;
myself.updateValuesDisplay();
2020-11-20 13:46:43 +01:00
if ( deplacementType == 'normal') { // Pas de rencontres après un saut de type passeur/changeur/...
2020-11-21 09:54:21 +01:00
await myself.manageRencontre(coordTMR, cellDescr);
2020-11-20 12:06:54 +01:00
}
2020-12-30 19:27:35 +01:00
await myself.manageCaseHumide(cellDescr, coordTMR);
await myself.declencheSortEnReserve(coordTMR);
2020-12-30 16:57:47 +01:00
await myself.actor.checkSoufflePeage(cellDescr);
2020-11-20 13:46:43 +01:00
} else if (deplacementType == 'messager') { // Dans ce cas, ouverture du lancement de sort sur la case visée
/*
TODO: si la case a un sort en réserve, lancer ce sort.
Si la case est le demi-rêve, ne pas lancer de sort.
Si un lancement de sort est en cours, trouver un moyen de réafficher cette fenêtre si on essaie de lancer un sort (ou bloquer le lancer de sort)
*/
await myself.actor.rollUnSort( coordTMR );
2020-11-20 13:46:43 +01:00
myself.nettoyerRencontre();
2020-11-20 12:06:54 +01:00
} else {
ui.notifications.error("Vous ne pouvez vous déplacer que sur des cases adjacentes à votre position ou valides dans le cas d'une rencontre");
2020-11-20 13:46:43 +01:00
console.log("STATUS :", myself.rencontreState, myself.currentRencontre);
2020-07-14 22:19:29 +02:00
}
2020-11-21 08:27:28 +01:00
2020-11-21 09:54:21 +01:00
myself.checkQuitterTMR(); // Vérifier l'état des compteurs reve/fatigue/vie
2020-07-05 22:35:18 +02:00
}
2020-11-17 18:08:19 +01:00
/* -------------------------------------------- */
async forceDemiRevePosition( coordTMR ) {
2020-11-18 18:11:01 +01:00
await this.actor.updateCoordTMR(coordTMR);
2020-11-17 18:08:19 +01:00
this._updateDemiReve(this);
2020-11-18 18:11:01 +01:00
let cellDescr = TMRUtility.getTMRDescription(coordTMR);
2020-11-21 09:54:21 +01:00
await this.manageRencontre(coordTMR, cellDescr);
2020-12-30 19:27:35 +01:00
this.manageCaseHumide(cellDescr, coordTMR);
2020-11-18 18:11:01 +01:00
await this.declencheSortEnReserve(coordTMR);
2020-11-17 18:08:19 +01:00
}
/* -------------------------------------------- */
async activateListeners(html) {
2020-07-05 21:45:25 +02:00
super.activateListeners(html);
2020-07-14 22:19:29 +02:00
var row = document.getElementById("tmrrow1");
var cell1 = row.insertCell(1);
cell1.append(this.pixiApp.view);
2020-11-14 20:46:39 +01:00
if (this.viewOnly) {
html.find('#lancer-sort').remove();
}
else {
// Roll Sort
html.find('#lancer-sort').click((event) => {
this.actor.rollUnSort(this.actor.data.data.reve.tmrpos.coord);
});
}
2020-07-14 22:19:29 +02:00
// load the texture we need
await this.pixiApp.loader
2020-11-17 18:10:54 +01:00
.add('tmr', 'systems/foundryvtt-reve-de-dragon/styles/img/ui/tmp_main_r1.webp')
.add('demi-reve', "icons/svg/sun.svg")
.load((loader, resources) => {
// This creates a texture from a TMR image
const mytmr = new PIXI.Sprite(resources.tmr.texture);
// Setup the position of the TMR
mytmr.x = 0;
mytmr.y = 0;
mytmr.width = 720;
mytmr.height = 860;
// Rotate around the center
mytmr.anchor.x = 0;
mytmr.anchor.y = 0;
mytmr.interactive = true;
mytmr.buttonMode = true;
mytmr.tmrObject = this;
2020-11-14 20:46:39 +01:00
if (!this.viewOnly) {
mytmr.on('pointerdown', this.deplacerDemiReve);
}
this.pixiApp.stage.addChild(mytmr);
this._addDemiReve();
this.displayPreviousRencontres();
this.displaySortReserve();
this.displaySpecificCase();
});
2020-11-14 20:46:39 +01:00
if (this.viewOnly) {
return;
}
// Gestion du cout de montée en points de rêve
let reveCout = -1;
if ( this.actor.checkTeteDeplacementAccelere() ) {
reveCout = -1;
} else {
reveCout = (this.tmrdata.isRapide) ? -2 : -1;
}
reveCout -= this.actor.checkMonteeLaborieuse();
await this.actor.reveActuelIncDec( reveCout );
// Le reste...
2020-07-17 22:04:35 +02:00
this.updateValuesDisplay();
2020-12-30 19:27:35 +01:00
let coordTMR = this.actor.data.data.reve.tmrpos.coord;
let cellDescr = TMRUtility.getTMRDescription(coordTMR);
await this.manageRencontre(coordTMR, cellDescr);
this.manageCaseHumide(cellDescr, coordTMR);
2020-12-30 15:31:43 +01:00
// Mise à jour du nb de cases de Fatigue
this.nbFatigue = this.actor.getTMRFatigue();
this.actor.displayTMRQueueSouffleInformation();
}
/* -------------------------------------------- */
static _computeEventCoord(origEvent) {
let canvasRect = origEvent.target.getBoundingClientRect();
let x = origEvent.clientX - canvasRect.left;
let y = origEvent.clientY - canvasRect.top;
let cellx = Math.floor(x / tmrConstants.cellw); // [From 0 -> 12]
y -= (cellx % 2 == 0) ? tmrConstants.col1_y : tmrConstants.col2_y;
let celly = Math.floor(y / tmrConstants.cellh); // [From 0 -> 14]
return { cellx, celly };
}
2020-11-17 18:08:19 +01:00
/* -------------------------------------------- */
static _horsDePortee(pos, cellx, celly) {
return Math.abs(cellx - pos.x) > 1
|| Math.abs(celly - pos.y) > 1
|| (pos.y == 0 && celly > pos.y && cellx != pos.x && pos.x % 2 == 0)
|| (celly == 0 && celly < pos.y && cellx != pos.x && pos.x % 2 == 1);
}
2020-11-17 18:08:19 +01:00
/* -------------------------------------------- */
_tokenRencontre(rencontre) {
let sprite = new PIXI.Graphics();
sprite.beginFill(0x767610, 0.6);
sprite.drawCircle(0, 0, 6);
sprite.endFill();
sprite.decallage = {
x: (tmrConstants.cellw / 2) - 16,
y: 16 - (tmrConstants.cellh / 2)
};
return { sprite: sprite, rencontre: rencontre, coordTMR: () => rencontre.coord };
}
/* -------------------------------------------- */
_tokenTrouNoir( coord ) {
let sprite = new PIXI.Graphics();
sprite.beginFill(0x050505, 0.8);
sprite.drawCircle(0, 0, (tmrConstants.cellw / 2) - 2);
sprite.endFill();
sprite.decallage = {
x: 0,
y: 2
}
return { sprite: sprite, coordTMR: () => coord }
}
2020-12-30 19:27:35 +01:00
/* -------------------------------------------- */
_tokenDebordement( coord ) {
let sprite = new PIXI.Graphics();
sprite.beginFill(0x0101FE, 0.3);
sprite.drawCircle(0, 0, (tmrConstants.cellw / 2) - 2);
sprite.endFill();
sprite.decallage = {
x: 0,
y: 2
}
return { sprite: sprite, coordTMR: () => coord }
}
/* -------------------------------------------- */
_tokenMaitrisee(coord) {
let sprite = new PIXI.Graphics();
sprite.beginFill(0x1010F0, 0.8);
sprite.drawCircle(0, 0, 6);
sprite.endFill();
sprite.decallage = {
x: 16 - (tmrConstants.cellw / 2),
y: 16 - (tmrConstants.cellh / 2)
}
return { sprite: sprite, coordTMR: () => coord }
}
/* -------------------------------------------- */
_tokenTerreAttache(coord) {
let sprite = new PIXI.Graphics();
sprite.beginFill(0x10F010, 0.8);
sprite.drawCircle(0, 0, 6);
sprite.endFill();
sprite.decallage = {
x: 16 - (tmrConstants.cellw / 2),
y: 16 - (tmrConstants.cellh / 2)
}
return { sprite: sprite, coordTMR: () => coord }
}
2020-11-17 18:08:19 +01:00
/* -------------------------------------------- */
_tokenSortEnReserve(sort) {
let sprite = new PIXI.Graphics();
sprite.beginFill(0x101010, 0.8);
sprite.drawCircle(0, 0, 6);
sprite.endFill();
sprite.decallage = {
x: 16 - (tmrConstants.cellw / 2),
y: 16 - (tmrConstants.cellh / 2)
}
2020-11-14 20:46:39 +01:00
return { sprite: sprite, sort: sort, coordTMR: () => sort.coord }
}
2020-11-17 18:08:19 +01:00
/* -------------------------------------------- */
_tokenDemiReve() {
let texture = PIXI.utils.TextureCache['demi-reve'];
let sprite = new PIXI.Sprite(texture);
sprite.width = tmrConstants.cellw * 0.7;
sprite.height = tmrConstants.cellh * 0.7;
sprite.anchor.set(0.5);
sprite.tint = 0x00FFEE;
return { sprite: sprite, actor: this.actor, coordTMR: () => this.actor.data.data.reve.tmrpos.coord }
}
/* -------------------------------------------- */
_addDemiReve() {
this.demiReve = this._tokenDemiReve();
this._setTokenPosition(this.demiReve);
this.pixiApp.stage.addChild(this.demiReve.sprite);
}
2020-11-17 18:08:19 +01:00
/* -------------------------------------------- */
_updateDemiReve(myself) {
myself._setTokenPosition(myself.demiReve);
}
2020-11-17 18:08:19 +01:00
/* -------------------------------------------- */
2020-11-20 12:06:54 +01:00
/** Retourne les coordonnées x, h, w, h du rectangle d'une case donnée */
_getCaseRectangleCoord( coord ) {
let coordXY = TMRUtility.convertToCellCoord( coord );
let decallagePairImpair = (coordXY.x % 2 == 0) ? tmrConstants.col1_y : tmrConstants.col2_y;
let x = tmrConstants.gridx + (coordXY.x * tmrConstants.cellw) - (tmrConstants.cellw /2);
let y = tmrConstants.gridy + (coordXY.y * tmrConstants.cellh) - (tmrConstants.cellh /2) + decallagePairImpair;
return {x: x, y: y, w: tmrConstants.cellw, h: tmrConstants.cellh}
}
/* -------------------------------------------- */
_setTokenPosition(token) {
let coordXY = TMRUtility.convertToCellCoord(token.coordTMR());
let decallagePairImpair = (coordXY.x % 2 == 0) ? tmrConstants.col1_y : tmrConstants.col2_y;
let dx = (token.sprite.decallage == undefined) ? 0 : token.sprite.decallage.x;
let dy = (token.sprite.decallage == undefined) ? 0 : token.sprite.decallage.y;
token.sprite.x = tmrConstants.gridx + (coordXY.x * tmrConstants.cellw) + dx;
token.sprite.y = tmrConstants.gridy + (coordXY.y * tmrConstants.cellh) + dy + decallagePairImpair;
}
2020-11-17 18:08:19 +01:00
/* -------------------------------------------- */
_removeTokens(filter) {
const tokensToRemove = this.allTokens.filter(filter);
for (let token of tokensToRemove) {
this.pixiApp.stage.removeChild(token.sprite);
}
}
2020-11-17 18:08:19 +01:00
/* -------------------------------------------- */
_trackToken(token) {
this.allTokens.push(token)
this._setTokenPosition(token);
this.pixiApp.stage.addChild(token.sprite);
2020-07-05 21:45:25 +02:00
}
2020-11-18 23:49:05 +01:00
2020-07-05 21:45:25 +02:00
}