Améliorations des tmr

* fermeture des cités
* utilisations d'icônes pour les cases spéciales, rencontres, sorts
en réserve
* séparation pixi/actions TMR / définition des cases spéciales

fixes divers:
* #153 lancer de sort si draconic utilise compétence autre que rêve
* #152: table de résolution doublée sur cht points de rêve
* /table n'affichait plus les résultats suite à chgt sur souffles/queues
This commit is contained in:
Vincent Vandemeulebrouck
2021-02-11 02:48:27 +01:00
parent d25e25e6fd
commit b226e5c09a
36 changed files with 1631 additions and 774 deletions

20
module/tmr/carte-tmr.js Normal file
View File

@ -0,0 +1,20 @@
import { Draconique } from "./draconique.js";
export class CarteTmr extends Draconique {
constructor() {
super();
}
type() { return '' }
match(item) { return false; }
manualMessage() { return false }
async onActorCreateOwned(actor, item) { }
code() { return 'tmr' }
img() { return 'systems/foundryvtt-reve-de-dragon/styles/img/ui/tmp_main_r1.webp' }
_createSprite(pixiTMR) {
return pixiTMR.carteTmr(this.code());
}
}

31
module/tmr/debordement.js Normal file
View File

@ -0,0 +1,31 @@
import { tmrColors, tmrConstants, TMRUtility } from "../tmr-utility.js";
import { Draconique } from "./draconique.js";
export class Debordement extends Draconique {
constructor() {
super();
}
type() { return 'souffle' }
match(item) { return Draconique.isSouffleDragon(item) && item.name.toLowerCase().includes('trou noir'); }
manualMessage() { return false }
async onActorCreateOwned(actor, item) { await this._creerCaseTmr(actor); }
code() { return 'debordement' }
tooltip(linkData) { return `Débordement en ${TMRUtility.getTMR(linkData.data.coord).label}` }
img() { return 'systems/foundryvtt-reve-de-dragon/icons/svg/wave.svg' }
_createSprite(pixiTMR) {
return pixiTMR.sprite(this.code(),
{
color: tmrColors.casehumide, alpha: 0.5, taille: tmrConstants.twoThird, decallage: tmrConstants.bottom
});
}
async _creerCaseTmr(actor) {
const existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord);
const tmr = TMRUtility.getTMRAleatoire(it => !(TMRUtility.isCaseHumide(it) || existants.includes(it.coord)));
await this.createCaseTmr(actor, 'Debordement: ' + tmr.label, tmr);
}
}

27
module/tmr/demi-reve.js Normal file
View File

@ -0,0 +1,27 @@
import { tmrColors, tmrConstants } from "../tmr-utility.js";
import { Draconique } from "./draconique.js";
export class DemiReve extends Draconique {
constructor() {
super();
}
type() { return '' }
match(item) { return false; }
manualMessage() { return false }
async onActorCreateOwned(actor, item) { }
code() { return 'demi-reve' }
tooltip(linkData) { return `Demi-rêve` }
img() { return 'icons/svg/sun.svg' }
_createSprite(pixiTMR) {
const sprite = pixiTMR.sprite(this.code(), {
color: tmrColors.demireve,
taille: (tmrConstants.full * 0.7)
});
pixiTMR.animate(pixiApp => pixiApp.ticker.add((delta) => sprite.rotation -= 0.01 * delta));
return sprite;
}
}

118
module/tmr/draconique.js Normal file
View File

@ -0,0 +1,118 @@
import { PixiTMR } from "./pixi-tmr.js";
const registeredEffects = [
]
/**
* Définition des informations d'une "draconique" (queue, ombre, tête, souffle) qui influence les TMR
*/
export class Draconique
{
static isCaseTMR(element) { return element.type == 'casetmr'; }
static isQueueDragon(element) { return element.type == 'queue' || element.type == 'ombre'; }
static isSouffleDragon(element) { return element.type == 'souffle'; }
static isTeteDragon(element) { return element.type == 'tete'; }
static isQueueSouffle(it) { return Draconique.isQueueDragon(it) || Draconique.isSouffleDragon(it); }
static register(draconique) {
registeredEffects[draconique.code()] = draconique;
if (draconique.img()) {
PixiTMR.register(draconique.code(), draconique.img())
}
return draconique;
}
static all() {
return Object.values(registeredEffects);
}
static get(code) {
return registeredEffects[code];
}
/**
* @param item un Item quelconque
* @returns true si l'item correspond
*/
match(item) {
return Draconique.isQueueDragon(item) || Draconique.isSouffleDragon(item) || Draconique.isTeteDragon(item);
}
/**
* @returns un message à afficher si la draconique doit être gérée manuellement.
*/
manualMessage() {
return false;
}
/**
* Méthode responsable de gérer une draconique (par exemple, ajouter des casetmr pour la fermeture des cités).
* @param actor auquel la draconique est ajoutée
*/
async onActorCreateOwned(actor) {
return false;
}
async onActorDeleteOwned(actor) {
return false;
}
/**
* @return le code interne utilisé pour les casetmr correpondant
*/
code() { return undefined }
/**
* @param {*} linkData données associées au token pixi (une casetmr, un sort en réserve, une rencontre en attente)
* @returns un tooltip à afficher au dessus du token
*/
tooltip(linkData) { return undefined }
/**
* @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
* @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;
pixiTMR.addTooltip(token.sprite, this.tooltip(linkData));
return token;
return sprite;
}
/**
* 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.
*/
_createSprite(pixiTMR) {
if (this.img()) {
return pixiTMR.sprite(this.code());
}
else{
return pixiTMR.circle()
}
}
/**
*
* @param {*} it un item à tester
* @param {*} coord les coordonnées d'une case. Si undefined toute case du type correspondra,
*/
isCase(it, coord = undefined) {
return Draconique.isCaseTMR(it) && it.data.specific == this.code() && (coord ? it.data.coord == coord : true);
}
async createCaseTmr(actor, label, tmr) {
await actor.createOwnedItem({
name: label, type: 'casetmr', img: this.img(), _id: randomID(16),
data: { coord: tmr.coord, specific: this.code() }
});
}
}

View File

@ -0,0 +1,152 @@
import { Debordement } from "./debordement.js";
import { FermetureCites } from "./fermeture-cites.js";
import { QueteEaux } from "./quete-eaux.js";
import { TerreAttache } from "./terre-attache.js";
import { ReserveExtensible } from "./reserve-extensible.js";
import { DemiReve } from "./demi-reve.js";
import { TrouNoir } from "./trou-noir.js";
import { Rencontre } from "./rencontre.js";
import { SortReserve } from "./sort-reserve.js";
import { CarteTmr } from "./carte-tmr.js";
import { PontImpraticable } from "./pont-impraticable.js";
import { Draconique } from "./draconique.js";
import { PresentCites } from "./present-cites.js";
export class EffetsDraconiques {
static carteTmr = new CarteTmr();
static demiReve = new DemiReve();
static rencontre = new Rencontre();
static sortReserve = new SortReserve();
static debordement = new Debordement();
static presentCites = new PresentCites();
static fermetureCites = new FermetureCites();
static queteEaux = new QueteEaux();
static reserveExtensible = new ReserveExtensible();
static terreAttache = new TerreAttache();
static trouNoir = new TrouNoir();
static pontImpraticable = new PontImpraticable();
static init() {
Draconique.register(EffetsDraconiques.carteTmr);
Draconique.register(EffetsDraconiques.demiReve);
Draconique.register(EffetsDraconiques.rencontre);
Draconique.register(EffetsDraconiques.sortReserve);
Draconique.register(EffetsDraconiques.debordement);
Draconique.register(EffetsDraconiques.fermetureCites);
Draconique.register(EffetsDraconiques.queteEaux);
Draconique.register(EffetsDraconiques.reserveExtensible);
Draconique.register(EffetsDraconiques.terreAttache);
Draconique.register(EffetsDraconiques.trouNoir);
Draconique.register(EffetsDraconiques.pontImpraticable);
Draconique.register(EffetsDraconiques.presentCites);
}
/* -------------------------------------------- */
static isCaseInondee(caseTMR, coord) {
return EffetsDraconiques.debordement.isCase(caseTMR, coord) || EffetsDraconiques.pontImpraticable.isCase(caseTMR, coord);
}
static isCaseTrouNoir(caseTMR, coord) {
return EffetsDraconiques.trouNoir.isCase(caseTMR, coord);
}
static isReserveExtensible(caseTMR, coord) {
return EffetsDraconiques.reserveExtensible.isCase(caseTMR, coord);
}
static isTerreAttache(caseTMR, coord) {
return EffetsDraconiques.terreAttache.isCase(caseTMR, coord);
}
static isCiteFermee(caseTMR, coord) {
return EffetsDraconiques.fermetureCites.isCase(caseTMR, coord);
}
static isPresentCite(caseTMR, coord) {
return EffetsDraconiques.presentCites.isCase(caseTMR, coord);
}
/* -------------------------------------------- */
static isMauvaiseRencontre(element) {
return EffetsDraconiques.isMatching(element, it => Draconique.isQueueSouffle(it) && it.name.toLowerCase().includes('mauvaise rencontre'));
}
static isMonteeLaborieuse(element) {
return EffetsDraconiques.isMatching(element, it => Draconique.isQueueSouffle(it) && it.name.toLowerCase().includes('montée laborieuse'));
}
static isFermetureCite(element) {
/* -------------------------------------------- */
return EffetsDraconiques.isMatching(element, it => EffetsDraconiques.fermetureCites.match(it));
}
static isPontImpraticable(element) {
return EffetsDraconiques.isMatching(element, it => EffetsDraconiques.pontImpraticable.match(it));
}
static isDoubleResistanceFleuve(element) {
return EffetsDraconiques.isMatching(element, it => Draconique.isSouffleDragon(it) && it.name.toLowerCase().includes('résistance du fleuve'));
}
static isPeage(element) {
return EffetsDraconiques.isMatching(element, it => Draconique.isSouffleDragon(it) && it.name.toLowerCase().includes('péage'));
}
static isPeriple(element) {
// TODO
return EffetsDraconiques.isMatching(element, it => Draconique.isSouffleDragon(it) && ir.name.toLowerCase() == 'périple');
}
static isDesorientation(element) {
// TODO
return EffetsDraconiques.isMatching(element, it => Draconique.isSouffleDragon(it) && it.name.toLowerCase() == 'désorientation');
}
/* -------------------------------------------- */
static isConquete(element) {
// TODO
return EffetsDraconiques.isMatching(element, it => Draconique.isQueueDragon(it) && it.name.toLowerCase() == 'conquête');
}
static isPelerinage(element) {
return EffetsDraconiques.isMatching(element, it => Draconique.isQueueDragon(it) && it.name.toLowerCase() == 'pélerinage');
}
static countInertieDraconique(element) {
return EffetsDraconiques.count(element, it => Draconique.isQueueDragon(it) && it.name.toLowerCase().includes('inertie draconique'));
}
static isUrgenceDraconique(element) {
return EffetsDraconiques.isMatching(element, it => Draconique.isQueueDragon(it) && it.name.toLowerCase() == 'urgence draconique');
}
/* -------------------------------------------- */
static isDonDoubleReve(element) {
return EffetsDraconiques.isMatching(element, it => Draconique.isTeteDragon(it) && it.name == 'Don de double-rêve');
}
static isConnaissanceFleuve(element) {
return EffetsDraconiques.isMatching(element, it => Draconique.isTeteDragon(it) && it.name.toLowerCase().includes('connaissance du fleuve'));
}
static isReserveEnSecurite(element) {
return EffetsDraconiques.isMatching(element, it => Draconique.isTeteDragon(it) && it.name.toLowerCase().includes(' en sécurité'));
}
static isDeplacementAccelere(element) {
return EffetsDraconiques.isMatching(element, it => Draconique.isTeteDragon(it) && it.name.toLowerCase().includes(' déplacement accéléré'));
}
static isMatching(element, matcher) {
return EffetsDraconiques.toItems(element).find(matcher);
}
static count(element, matcher) {
return EffetsDraconiques.toItems(element).filter(matcher).length;
}
static toItems(element) {
return (element?.entity === 'Actor') ? element.data.items : (element?.entity === 'Item') ? [element] : [];
}
}

View File

@ -0,0 +1,33 @@
import { tmrColors, tmrConstants, TMRUtility } from "../tmr-utility.js";
import { Draconique } from "./draconique.js";
export class FermetureCites extends Draconique {
constructor() {
super();
}
type() { return 'souffle' }
match(item) { return Draconique.isSouffleDragon(item) && item.name.toLowerCase() == 'fermeture des cités'; }
manualMessage() { return false }
async onActorCreateOwned(actor, item) { await this._fermerLesCites(actor); }
code() { return 'fermeture' }
tooltip(linkData) { return `La ${TMRUtility.getTMR(linkData.data.coord).label} est fermée` }
img() { return 'icons/svg/door-closed.svg' }
_createSprite(pixiTMR) {
return pixiTMR.sprite(this.code(),
{
color: tmrColors.souffle, alpha: 0.9, taille: tmrConstants.full, decallage: { x: 2, y: 0 }
});
}
async _fermerLesCites(actor) {
let existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord);
let ouvertes = TMRUtility.filterTMR(it => it.type == 'cite' && !existants.includes(it.coord));
for (let tmr of ouvertes) {
await this.createCaseTmr(actor, 'Fermeture: ' + tmr.label, tmr);
}
}
}

148
module/tmr/pixi-tmr.js Normal file
View File

@ -0,0 +1,148 @@
import { tmrConstants } from "../tmr-utility.js";
const tooltipStyle = new PIXI.TextStyle({
fontFamily: 'CaslonAntique',
fontSize: 18,
fill: '#FFFFFF',
stroke: '#000000',
strokeThickness: 3
});
export class PixiTMR {
static textures = []
constructor(tmrObject, pixiApp) {
this.tmrObject = tmrObject;
this.pixiApp = pixiApp ?? tmrObject.pixiApp;
this.callbacksOnAnimate = [];
}
load(onLoad = (loader, resources) => {}) {
let loader = this.pixiApp.loader;
for (const [name, img] of Object.entries(PixiTMR.textures)) {
loader = loader.add(name, img);
}
loader.load((loader, resources) => {
onLoad(loader, resources);
for (let onAnimate of this.callbacksOnAnimate) {
onAnimate();
}
});
}
static register(name, img) {
PixiTMR.textures[name] = img;
}
animate(animation = pixiApp=>{})
{
this.callbacksOnAnimate.push(() => animation(this.pixiApp));
}
carteTmr(code) {
const carteTmr = new PIXI.Sprite(PIXI.utils.TextureCache[code]);
// 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.interactive = true;
carteTmr.buttonMode = true;
carteTmr.tmrObject = this;
// atténue les couleurs des TMRs
const tmrColorFilter = new PIXI.filters.ColorMatrixFilter();
tmrColorFilter.contrast(1);
tmrColorFilter.brightness(0.2);
tmrColorFilter.saturate(-0.5);
carteTmr.filters = [tmrColorFilter];
if (!this.tmrObject.viewOnly) {
carteTmr.on('pointerdown', event => this.onClickBackground(event));
}
this.pixiApp.stage.addChild(carteTmr);
return carteTmr;
}
sprite(code, options = {}) {
const texture = PIXI.utils.TextureCache[code];
if (!texture) {
console.error("Texture manquante", code)
return;
}
let sprite = new PIXI.Sprite(texture);
sprite.width = options.taille ?? tmrConstants.half;
sprite.height = options.taille ?? tmrConstants.half;
sprite.anchor.set(0.5);
sprite.tint = options.color ?? 0x000000;
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);
sprite.drawCircle(0, 0, (options.taille ?? 12) / 2);
sprite.endFill();
sprite.decallage = options.decallage ?? tmrConstants.topLeft;
this.pixiApp.stage.addChild(sprite);
return sprite;
}
addTooltip(sprite, text) {
if (text) {
sprite.tooltip = new PIXI.Text(text, tooltipStyle);
sprite.isOver = false;
sprite.interactive = true;
sprite.on('pointerdown', event => this.onClickBackground(event))
.on('pointerover', () => this.onShowTooltip(sprite))
.on('pointerout', () => this.onHideTooltip(sprite));
}
}
onClickBackground(event) {
this.tmrObject.onClickTMR(event)
}
onShowTooltip(sprite) {
if (sprite.tooltip) {
if (!sprite.isOver) {
sprite.tooltip.x = sprite.x;
sprite.tooltip.y = sprite.y;
this.pixiApp.stage.addChild(sprite.tooltip);
}
sprite.isOver = true;
}
}
onHideTooltip(sprite) {
if (sprite.tooltip) {
if (sprite.isOver) {
this.pixiApp.stage.removeChild(sprite.tooltip);
}
sprite.isOver = false;
}
}
setPosition( sprite, pos) {
let decallagePairImpair = (pos.x % 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;
sprite.x = tmrConstants.gridx + (pos.x * tmrConstants.cellw) + dx;
sprite.y = tmrConstants.gridy + (pos.y * tmrConstants.cellh) + dy + decallagePairImpair;
}
getCaseRectangle(pos) {
let decallagePairImpair = (pos.x % 2 == 0) ? tmrConstants.col1_y : tmrConstants.col2_y;
let x = tmrConstants.gridx + (pos.x * tmrConstants.cellw) - (tmrConstants.cellw / 2);
let y = tmrConstants.gridy + (pos.y * tmrConstants.cellh) - (tmrConstants.cellh / 2) + decallagePairImpair;
return { x: x, y: y, w: tmrConstants.cellw, h: tmrConstants.cellh };
}
}

View File

@ -0,0 +1,40 @@
import { tmrColors, tmrConstants, TMRUtility } from "../tmr-utility.js";
import { Draconique } from "./draconique.js";
export class PontImpraticable extends Draconique {
constructor() {
super();
}
type() { return 'souffle' }
match(item) { return Draconique.isSouffleDragon(item) && item.name.toLowerCase().includes('impraticabilité des ponts'); }
async onActorCreateOwned(actor, item) { await this._creerCaseTmr(actor); }
async onActorDeleteOwned(actor, item) { await this._supprimerCaseTmr(actor); }
code() { return 'pont-impraticable' }
tooltip(linkData) { return `${TMRUtility.getTMR(linkData.data.coord).label} impraticable` }
img() { return 'systems/foundryvtt-reve-de-dragon/icons/svg/wave.svg' }
_createSprite(pixiTMR) {
return pixiTMR.sprite(this.code(),
{
color: tmrColors.casehumide, alpha: 0.5, taille: tmrConstants.twoThird, decallage: tmrConstants.bottom
});
}
async _creerCaseTmr(actor) {
const ponts = TMRUtility.getListTMR('pont');
for (let tmr of ponts) {
await this.createCaseTmr(actor, 'Pont impraticable: ' + tmr.label, tmr);
}
}
async _supprimerCaseTmr(actor) {
const existants = actor.data.items.filter(it => this.isCase(it));
for (let caseTMR of existants) {
await actor.deleteOwnedItem(caseTMR._id);
}
}
}

View File

@ -0,0 +1,42 @@
import { ChatUtility } from "../chat-utility.js";
import { tmrColors, tmrConstants, TMRUtility } from "../tmr-utility.js";
import { Draconique } from "./draconique.js";
export class PresentCites extends Draconique {
constructor() {
super();
}
type() { return 'tete' }
match(item) { return Draconique.isTeteDragon(item) && item.name.toLowerCase() == 'présent des cités'; }
manualMessage() { return false }
async onActorCreateOwned(actor, item) { await this._ajouterPresents(actor); }
code() { return 'present-cites' }
tooltip(linkData) { return `La ${TMRUtility.getTMR(linkData.data.coord).label} a un présent` }
img() { return 'systems/foundryvtt-reve-de-dragon/icons/svg/gift.svg' }
_createSprite(pixiTMR) {
return pixiTMR.sprite(this.code(),
{
color: tmrColors.tetes, alpha: 0.7, taille: tmrConstants.third, decallage:tmrConstants.topRight
});
}
async _ajouterPresents(actor) {
let existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord);
if (existants.length >0 ) {
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user),
content: "Vous avez encore des présents dans des cités, vous devrez tirer une autre tête pour remplacer celle ci!"
})
}
else{
let cites = TMRUtility.filterTMR(it => it.type == 'cite');
for (let tmr of cites) {
await this.createCaseTmr(actor, 'Présent: ' + tmr.label, tmr);
}
}
}
}

25
module/tmr/quete-eaux.js Normal file
View File

@ -0,0 +1,25 @@
import { tmrColors, tmrConstants, TMRUtility } from "../tmr-utility.js";
import { Draconique } from "./draconique.js";
export class QueteEaux extends Draconique {
constructor() {
super();
}
type() { return 'tete' }
match(item) { return Draconique.isTeteDragon(item) && item.name.toLowerCase().includes("quête des eaux"); }
manualMessage() { return "Vous devrez re-configurer votre Quête des Eaux une fois un lac ou marais vaincu" }
async onActorCreateOwned(actor, item) { await this._creerCaseTmr(actor); }
code() { return 'maitrisee' }
tooltip(linkData) { return `Quête des eaux, le ${TMRUtility.getTMR(linkData.data.coord).label} est maîtrisé` }
img() { return 'icons/svg/bridge.svg' }
_createSprite(pixiTMR) {
return pixiTMR.sprite(this.code(), { color: tmrColors.tetes, decallage: tmrConstants.topRight });
}
async _creerCaseTmr(actor) {
await this.createCaseTmr(actor, "Quête des eaux à déterminer", {coord:'A0'});
}
}

22
module/tmr/rencontre.js Normal file
View File

@ -0,0 +1,22 @@
import { tmrColors, tmrConstants } from "../tmr-utility.js";
import { Draconique } from "./draconique.js";
export class Rencontre extends Draconique {
constructor() {
super();
}
type() { return '' }
match(item) { return false; }
manualMessage() { return false }
async onActorCreateOwned(actor, item) { }
code() { return 'rencontre' }
tooltip(linkData) { return `${linkData.name} de force ${linkData.force}` }
img() { return 'systems/foundryvtt-reve-de-dragon/icons/heures/hd06.svg' }
_createSprite(pixiTMR) {
return pixiTMR.sprite(this.code(), { color: tmrColors.rencontre, taille: tmrConstants.full, decallage: { x: 2, y: 2 } });
}
}

View File

@ -0,0 +1,28 @@
import { tmrColors, tmrConstants, TMRUtility } from "../tmr-utility.js";
import { Draconique } from "./draconique.js";
export class ReserveExtensible extends Draconique {
constructor() {
super();
}
type() { return 'tete' }
match(item) { return Draconique.isTeteDragon(item) && item.name.toLowerCase().includes("réserve extensible"); }
manualMessage() { return "Vous pouvez re-configurer votre Réserve extensible" }
async onActorCreateOwned(actor, item) { await this._creerCaseTmr(actor); }
code() { return 'reserve_extensible' }
tooltip(linkData) { return `Réserve extensible en ${TMRUtility.getTMR(linkData.data.coord).label} !` }
img() { return 'icons/svg/chest.svg' }
_createSprite(pixiTMR) {
return pixiTMR.sprite(this.code(), { color: tmrColors.tetes, decallage: tmrConstants.left});
}
async _creerCaseTmr(actor) {
const existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord);
const tmr = TMRUtility.getTMRAleatoire(it => !(it.type == 'fleuve' || existants.includes(it.coord)));
await this.createCaseTmr(actor, "Nouvelle Réserve extensible", tmr);
}
}

View File

@ -0,0 +1,22 @@
import { tmrColors, tmrConstants } from "../tmr-utility.js";
import { Draconique } from "./draconique.js";
export class SortReserve extends Draconique {
constructor() {
super();
}
type() { return '' }
match(item) { return false; }
manualMessage() { return false }
async onActorCreateOwned(actor, item) { }
code() { return 'sort' }
tooltip(linkData) { return `${linkData.name}, r${linkData.data.ptreve_reel}` }
img() { return 'icons/svg/book.svg' }
_createSprite(pixiTMR) {
return pixiTMR.sprite(this.code(), { color: tmrColors.sort, decallage: tmrConstants.right });
}
}

View File

@ -0,0 +1,25 @@
import { tmrColors, tmrConstants, TMRUtility } from "../tmr-utility.js";
import { Draconique } from "./draconique.js";
export class TerreAttache extends Draconique {
constructor() {
super();
}
type() { return 'tete' }
match(item) { return Draconique.isTeteDragon(item) && item.name.toLowerCase().includes("terre d'attache"); }
manualMessage() { return "Vous pouvez re-configurer votre Terre d'Attache" }
async onActorCreateOwned(actor, item) { await this._creerCaseTmr(actor); }
code() { return 'attache' }
tooltip(linkData) { return `Terre d'attache en ${TMRUtility.getTMR(linkData.data.coord).label} !` }
img() { return 'icons/svg/anchor.svg' }
_createSprite(pixiTMR) {
return pixiTMR.sprite(this.code(), { color: tmrColors.tetes, decallage: tmrConstants.topLeft });
}
async _creerCaseTmr(actor) {
await this.createCaseTmr(actor, "Terre d'attache à déterminer", {coord:'A0'});
}
}

30
module/tmr/trou-noir.js Normal file
View File

@ -0,0 +1,30 @@
import { tmrColors, tmrConstants, TMRUtility } from "../tmr-utility.js";
import { Draconique } from "./draconique.js";
export class TrouNoir extends Draconique {
constructor() {
super();
}
type() { return 'souffle' }
match(item) { return Draconique.isSouffleDragon(item) && item.name.toLowerCase().includes('trou noir'); }
manualMessage() { return false }
async onActorCreateOwned(actor, item) { await this._creerCaseTmr(actor); }
code() { return 'trounoir' }
tooltip(linkData) { return `Trou noir en ${TMRUtility.getTMR(linkData.data.coord).label} !` }
img() { return 'icons/svg/explosion.svg' }
_createSprite(pixiTMR) {
return pixiTMR.sprite(this.code(),
{
color: tmrColors.trounoir, alpha: 1, taille: tmrConstants.full, decallage: { x: 2, y: 2 },
});
}
async _creerCaseTmr(actor) {
const existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord);
const tmr = TMRUtility.getTMRAleatoire(it => !(TMRUtility.isCaseHumide(it) || existants.includes(it.coord)));
await this.createCaseTmr(actor, 'Trou noir: ' + tmr.label, tmr);
}
}