diff --git a/changelog.md b/changelog.md index 178fd550..0c92edaf 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,7 @@ # v11.0 +## v11.0.24 - les couleurs de Khrachtchoum +- nouvelle carte des TMRs + ## v11.0.23 - la lumière de Khrachtchoum - ajustement automatique de la luminosité selon l'heure pour les scènes: - avec une vision des tokens (sinon: ce n'est pas une scène de carte pour tokens) diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js index f9a47ba0..c0c937d7 100644 --- a/module/rdd-tmr-dialog.js +++ b/module/rdd-tmr-dialog.js @@ -46,7 +46,7 @@ export class RdDTMRDialog extends Dialog { const dialogOptions = { classes: ["tmrdialog"], - width: 920, height: 980, + width: 920, maxheight: 1024, height: 'fit-content', 'z-index': 40 } super(dialogConf, dialogOptions); @@ -62,7 +62,6 @@ export class RdDTMRDialog extends Dialog { this.allTokens = []; this.rencontreState = 'aucune'; this.pixiApp = new PIXI.Application({ width: 720, height: 860 }); - this.pixiTMR = new PixiTMR(this, this.pixiApp); this.callbacksOnAnimate = []; @@ -906,15 +905,12 @@ export class RdDTMRDialog extends Dialog { if (this.viewOnly) { return; } - let clickOddq = RdDTMRDialog._computeEventOddq(event.nativeEvent); - await this._onClickTMRPos(clickOddq); // Vérifier l'état des compteurs reve/fatigue/vie - } - - /* -------------------------------------------- */ - async _onClickTMRPos(clickOddq) { + let clickOddq = TMRUtility.computeEventOddq(event); let currentOddq = TMRUtility.coordTMRToOddq(this._getActorCoord()); + let targetCoord = TMRUtility.oddqToCoordTMR(clickOddq); let currentCoord = TMRUtility.oddqToCoordTMR(currentOddq); + // Validation de la case de destination (gestion du cas des rencontres qui peuvent téléporter) let deplacementType = this._calculDeplacement(targetCoord, currentCoord, currentOddq, clickOddq); @@ -946,7 +942,7 @@ export class RdDTMRDialog extends Dialog { await this._messagerDemiReve(targetCoord); break; default: - ui.notifications.error("Vous ne pouvez pas vous déplacer que sur des cases adjacentes à votre position ou valides dans le cas d'une rencontre"); + ui.notifications.error("Vous ne pouvez vous déplacer que sur des cases adjacentes à votre position ou valides dans le cas d'une rencontre"); console.log("STATUS :", this.rencontreState, this.currentRencontre); } @@ -1049,19 +1045,6 @@ export class RdDTMRDialog extends Dialog { await this.postRencontre(tmr); return tmr; } - - /* -------------------------------------------- */ - static _computeEventOddq(origEvent) { - console.log("EVENT", origEvent) - let canvasRect = origEvent.target.getBoundingClientRect(); - let x = origEvent.clientX - canvasRect.left; - let y = origEvent.clientY - canvasRect.top; - let col = Math.floor(x / tmrConstants.cellw); // [From 0 -> 12] - y -= col % 2 == 0 ? tmrConstants.col1_y : tmrConstants.col2_y; - let row = Math.floor(y / tmrConstants.cellh); // [From 0 -> 14] - return { col: col, row: row }; - } - /* -------------------------------------------- */ /** Retourne les coordonnées x, h, w, h du rectangle d'une case donnée */ _getCaseRectangleCoord(coord) { diff --git a/module/tmr-utility.js b/module/tmr-utility.js index f74e4194..f0e60be1 100644 --- a/module/tmr-utility.js +++ b/module/tmr-utility.js @@ -1,6 +1,7 @@ import { Misc } from "./misc.js"; import { Grammar } from "./grammar.js"; import { RdDDice } from "./rdd-dice.js"; +import { tmrConstants } from "./tmr-constants.js"; /* -------------------------------------------- */ const TMRMapping = { @@ -199,7 +200,7 @@ const TMRMapping = { K14: { type: "necropole", label: "Nécropole d’Antinéar" }, L14: { type: "plaines", label: "Plaines de Jislith" }, M14: { type: "desolation", label: "Désolation d’Après" }, - + A15: { type: "cite", label: "Cité de Mielh" }, C15: { type: "plaines", label: "Plaines de Toué" }, E15: { type: "foret", label: "Forêt des Furies" }, @@ -274,11 +275,11 @@ export class TMRUtility { const tmr = TMRUtility.getTMR(coord); return Grammar.articleDetermine(tmr.type) + ' ' + tmr.label; } - - static findTMRLike(type, options = {inclusMauvaise:true}) { + + static findTMRLike(type, options = { inclusMauvaise: true }) { const choix = [...Object.values(TMRType)] - if (options.inclusMauvaise){ - choix.push({name: 'Mauvaise'}); + if (options.inclusMauvaise) { + choix.push({ name: 'Mauvaise' }); } const selection = Misc.findAllLike(type, choix).map(it => it.name); if (selection.length == 0) { @@ -297,7 +298,7 @@ export class TMRUtility { } static buildSelectionTypesTMR(typesTMR) { - typesTMR = typesTMR?? []; + typesTMR = typesTMR ?? []; return Object.values(TMRType).map(value => Misc.upperFirst(value.name)) .sort() .map(name => { return { name: name, selected: typesTMR.includes(name) } }); @@ -375,6 +376,33 @@ export class TMRUtility { return caseList; } + // /* -------------------------------------------- */ + static computeEventPosition(event) { + const canvasRect = event.nativeEvent.target.getBoundingClientRect(); + return { + x: event.nativeEvent.clientX - canvasRect.left, + y: event.nativeEvent.clientY - canvasRect.top + }; + } + + /* -------------------------------------------- */ + static computeEventOddq(event) { + var { x, y } = TMRUtility.computeEventPosition(event); + return TMRUtility.computeOddq(x, y); + } + + static computeOddq(x, y) { + const col = Math.floor(x / tmrConstants.cellw); // [From 0 -> 12] + const decallageColonne = col % 2 == 0 ? tmrConstants.col1_y : tmrConstants.col2_y; + const row = Math.floor((y - decallageColonne) / tmrConstants.cellh); // [From 0 -> 14] + return { col, row }; + } + + static computeEventCoord(event) { + const oddq = TMRUtility.computeEventOddq(event); + return TMRUtility.oddqToCoordTMR(oddq); + } + /* -------------------------------------------- */ // https://www.redblobgames.com/grids/hexagons/#distances // TMR Letter-row correspond to "odd-q" grid (letter => col, numeric => row ) @@ -400,7 +428,7 @@ export class TMRUtility { col >= 0 && col < 13 && row >= 0 && (row + col % 2 <= 14) - ); + ); // if (x >= 0 && x < 13 && y >= 0 && y < 14) return true; // if (x >= 0 && x < 13 && x % 2 == 0 && y == 14) return true; // return false; @@ -444,7 +472,7 @@ export class TMRUtility { static axial_subtract(a, b) { return { - q: a.q- b.q, + q: a.q - b.q, r: a.r - b.r }; } @@ -456,7 +484,7 @@ export class TMRUtility { // return Cube(q, r, s) // } - + // /* -------------------------------------------- */ // static computeRealPictureCoordinates(coordOddq) { // let decallagePairImpair = (coordOddq.col % 2 == 0) ? tmrConstants.col1_y : tmrConstants.col2_y; diff --git a/module/tmr/carte-tmr.js b/module/tmr/carte-tmr.js index 43b08064..b1e61053 100644 --- a/module/tmr/carte-tmr.js +++ b/module/tmr/carte-tmr.js @@ -4,7 +4,6 @@ import { PixiTMR } from "./pixi-tmr.js"; export class CarteTmr extends Draconique { constructor() { - console.log("Sprite create 1!!!!") super(); } @@ -14,9 +13,25 @@ export class CarteTmr extends Draconique { async onActorCreateOwned(actor, item) { } code() { return 'tmr' } - img() { return 'systems/foundryvtt-reve-de-dragon/styles/img/ui/tmp_main_r1.webp' } + img() { return 'systems/foundryvtt-reve-de-dragon/styles/img/ui/tmr.webp' } createSprite(pixiTMR) { - return pixiTMR.carteTmr(this.code()); + + const img = PixiTMR.getImgFromCode(this.code()) + const sprite = new PIXI.Sprite(PIXI.utils.TextureCache[img]); + // Setup the position of the TMR + sprite.x = 0; + sprite.y = 0; + sprite.width = 722; + sprite.height = 860; + // Rotate around the center + sprite.anchor.set(0); + sprite.buttonMode = true; + sprite.tmrObject = pixiTMR; + + pixiTMR.addTooltip(sprite, (e,s) => this.computeTooltip(e,s)); + pixiTMR.pixiApp.stage.addChild(sprite); + return sprite; } + } diff --git a/module/tmr/draconique.js b/module/tmr/draconique.js index 70c3352b..dea066dd 100644 --- a/module/tmr/draconique.js +++ b/module/tmr/draconique.js @@ -11,7 +11,7 @@ const registeredEffects = [ export class Draconique { static isCaseTMR(item) { return item.type == TYPES.casetmr; } static isQueueDragon(item) { return item.isQueueDragon(); } - static isSouffleDragon(item) {return item.type == TYPES.souffle; } + static isSouffleDragon(item) { return item.type == TYPES.souffle; } static isTeteDragon(item) { return item.type == TYPES.tete; } static isQueueSouffle(item) { return Draconique.isQueueDragon(item) || Draconique.isSouffleDragon(item); } @@ -78,25 +78,45 @@ export class Draconique { /** * @param {*} img l'url du fichier image à utiliser pour le token. Si indéfini (et si createSprite n'est pas surchargé), * un disque est utilisé. - */ + */ img() { return undefined } /** - * factory d'élément graphique PIXI correpsondant à l'objet draconique + * factory d'élément graphique PIXI correspondant à l'objet draconique * @param {*} pixiTMR instance de PixiTMR qui gère les tooltips, les méthodes de création de sprite standard, les clicks. - */ + */ token(pixiTMR, linkData, coordTMR, type = undefined) { const token = { sprite: this.createSprite(pixiTMR), coordTMR: coordTMR }; token[type ?? this.code()] = linkData; - console.log("SPRITE: ", token.sprite) - //PixiTMR.getImgFromCode() - pixiTMR.addTooltip(token.sprite, this.tooltip(linkData)); + this.linkData = linkData; + if (this.tooltip(linkData)) { + pixiTMR.addTooltip(token.sprite, (e, s) => this.computeTooltip(e, s)); + } return token; } + /** + * methode en charge de recalculer le tooltip lorsque la souris bouge + * @param {*} event evenement contenant les coordonnées + * @param {*} sprite sprite pour laquelle calculer le tooltip + */ + computeTooltip(event, sprite) { + if (sprite.isOver) { + const oddq = TMRUtility.computeEventOddq(event); + const coord = TMRUtility.oddqToCoordTMR(oddq); + const tmr = TMRUtility.getTMR(coord) + if (tmr){ + const label = TMRUtility.getTMRLabel(coord); + const text = this.tooltip(this.linkData); + return text ? `${coord}: ${label}\n${text}` : `${coord}: ${label}` + } + } + return ''; + } + /** * factory d'élément graphique PIXI correpsondant à l'objet draconique * @param {*} pixiTMR instance de PixiTMR qui gère les tooltips, les méthodes de création de sprite standard, les clicks. @@ -118,11 +138,11 @@ export class Draconique { isCase(item, coord = undefined) { return Draconique.isCaseTMR(item) && item.system.specific == this.code() && (coord ? item.system.coord == coord : true); } - + find(list, coord = undefined) { return list.find(c => this.isCase(c, coord)); } - + async createCaseTmr(actor, label, tmr, sourceId = undefined) { const casetmrData = { name: label, type: 'casetmr', img: this.img(), @@ -130,12 +150,12 @@ export class Draconique { }; await actor.createEmbeddedDocuments('Item', [casetmrData]); } - + async deleteCasesTmr(actor, draconique) { let caseTmrs = actor.items.filter(it => this.isCaseForSource(it, draconique)); await actor.deleteEmbeddedDocuments('Item', caseTmrs.map(it => it.id)); } - + isCaseForSource(item, draconique) { return Draconique.isCaseTMR(item) && item.system.specific == this.code() && item.system.sourceid == draconique.id; } diff --git a/module/tmr/pixi-tmr.js b/module/tmr/pixi-tmr.js index 8ac89e6b..9dfe79c2 100644 --- a/module/tmr/pixi-tmr.js +++ b/module/tmr/pixi-tmr.js @@ -1,6 +1,8 @@ +import { RdDTMRDialog } from "../rdd-tmr-dialog.js"; import { tmrConstants, tmrTokenZIndex } from "../tmr-constants.js"; +import { TMRUtility } from "../tmr-utility.js"; -const tooltipStyle = new PIXI.TextStyle({ +export const tooltipStyle = new PIXI.TextStyle({ fontFamily: 'CaslonAntique', fontSize: 18, fill: '#FFFFFF', @@ -20,7 +22,7 @@ export class PixiTMR { this.callbacksOnAnimate = []; } - async load( onLoad = (loader, resources) => {} ) { + async load(onLoad = (loader, resources) => { }) { // WIP - Deprecated since v7 : let loader = new PIXI.Loader(); for (const [name, img] of Object.entries(PixiTMR.textures)) { const texture = await PIXI.Assets.load(img); @@ -40,40 +42,17 @@ export class PixiTMR { PixiTMR.textures[name] = img; } - animate(animation = pixiApp=>{}) - { + animate(animation = pixiApp => { }) { this.callbacksOnAnimate.push(() => animation(this.pixiApp)); } - carteTmr(code) { - let img = PixiTMR.getImgFromCode(code) - const carteTmr = new PIXI.Sprite(PIXI.utils.TextureCache[img]); - console.log(code, carteTmr) - // Setup the position of the TMR - carteTmr.x = 0; - carteTmr.y = 0; - carteTmr.width = 720; - carteTmr.height = 860; - // Rotate around the center - carteTmr.anchor.set(0); - carteTmr.eventMode = 'dynamic'; // PIXI 7 : Not sure .. - // This one is deprecated ; carteTmr.interactive = true; - carteTmr.buttonMode = true; - carteTmr.tmrObject = this; - if (!this.tmrObject.viewOnly) { - carteTmr.on('pointerdown', event => this.onClickBackground(event)); - } - this.pixiApp.stage.addChild(carteTmr); - return carteTmr; - } - sprite(code, options = {}) { let img = PixiTMR.getImgFromCode(code) const texture = PIXI.utils.TextureCache[img]; if (!texture) { console.error("Texture manquante", code, PIXI.utils.TextureCache) return; - } + } let sprite = new PIXI.Sprite(texture); sprite.width = options.taille ?? tmrConstants.half; sprite.height = options.taille ?? tmrConstants.half; @@ -81,13 +60,13 @@ export class PixiTMR { if (options.color) { sprite.tint = options.color; } - sprite.zIndex = options.zIndex ?? tmrTokenZIndex.casehumide+1; + sprite.zIndex = options.zIndex ?? tmrTokenZIndex.casehumide + 1; sprite.alpha = options.alpha ?? 0.75; sprite.decallage = options.decallage ?? tmrConstants.center; this.pixiApp.stage.addChild(sprite); return sprite; - } - + } + circle(name, options = {}) { let sprite = new PIXI.Graphics(); sprite.beginFill(options.color, options.opacity); @@ -98,27 +77,37 @@ export class PixiTMR { return sprite; } - addTooltip(sprite, text) { - if (text) { - sprite.tooltip = new PIXI.Text(text, tooltipStyle); - sprite.tooltip.zIndex = tmrTokenZIndex.tooltip; - sprite.isOver = false; - // Deprecated : sprite.interactive = true; - sprite.eventMode = 'dynamic'; // PIXI 7 To be checked - sprite.on('pointerdown', event => this.onClickBackground(event)) - .on('pointerover', () => this.onShowTooltip(sprite)) - .on('pointerout', () => this.onHideTooltip(sprite)); - } + addTooltip(sprite, computeTooltip) { + sprite.tooltip = new PIXI.Text('', tooltipStyle); + sprite.tooltip.zIndex = tmrTokenZIndex.tooltip; + sprite.isOver = false; + sprite.eventMode = 'dynamic'; // PIXI 7 To be checked + sprite + .on('pointermove', event => this.onPointerMove(event, sprite, computeTooltip)) + .on('pointerdown', event => this.onClickBackground(event)) + .on('pointerover', event => this.onShowTooltip(event, sprite)) + .on('pointerout', event => this.onHideTooltip(event, sprite)); } - onClickBackground(event) { - this.tmrObject.onClickTMR(event) + if (!this.viewOnly) { + this.tmrObject.onClickTMR(event) + } } - onShowTooltip(sprite) { - if (sprite.tooltip) { + onPointerMove(event, sprite, computeTooltip) { + if (sprite.isOver && sprite.tooltip) { + var { x, y } = TMRUtility.computeEventPosition(event); + const oddq = TMRUtility.computeOddq(x, y); + sprite.tooltip.x = x + (oddq.col > 8 ? - 3 * tmrConstants.full : tmrConstants.half) + sprite.tooltip.y = y + (oddq.row > 10 ? - tmrConstants.half : tmrConstants.half) + sprite.tooltip.text = computeTooltip(event, sprite); + } + } + + onShowTooltip(event, sprite) { + if (sprite.tooltip) { if (!sprite.isOver) { sprite.tooltip.x = sprite.x; sprite.tooltip.y = sprite.y; @@ -128,7 +117,7 @@ export class PixiTMR { } } - onHideTooltip(sprite) { + onHideTooltip(event, sprite) { if (sprite.tooltip) { if (sprite.isOver) { this.pixiApp.stage.removeChild(sprite.tooltip); @@ -137,7 +126,7 @@ export class PixiTMR { } } - setPosition( sprite, oddq) { + setPosition(sprite, oddq) { let decallagePairImpair = (oddq.col % 2 == 0) ? tmrConstants.col1_y : tmrConstants.col2_y; let dx = (sprite.decallage == undefined) ? 0 : sprite.decallage.x; let dy = (sprite.decallage == undefined) ? 0 : sprite.decallage.y; diff --git a/styles/img/ui/tmp_main_r1.webp b/styles/img/ui/tmp_main_r1.webp deleted file mode 100644 index a7bb19c4..00000000 Binary files a/styles/img/ui/tmp_main_r1.webp and /dev/null differ diff --git a/styles/img/ui/tmr.webp b/styles/img/ui/tmr.webp new file mode 100644 index 00000000..84f1483a Binary files /dev/null and b/styles/img/ui/tmr.webp differ diff --git a/styles/simple.css b/styles/simple.css index 03760217..9f942770 100644 --- a/styles/simple.css +++ b/styles/simple.css @@ -171,6 +171,9 @@ i:is(.fas, .far) { width: fit-content; } +.tmr-dialog table { + border: none; +} .system-foundryvtt-reve-de-dragon .sheet-header div.tmr-buttons { padding: 0; margin: 0; diff --git a/templates/dialog-tmr.html b/templates/dialog-tmr.html index 85dc9212..d11e003e 100644 --- a/templates/dialog-tmr.html +++ b/templates/dialog-tmr.html @@ -1,7 +1,5 @@