diff --git a/lang/fr.json b/lang/fr.json index ee3e67cb..3201992b 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -41,7 +41,8 @@ "TypeOmbre": "Ombre de Thanatos", "TypeSouffle": "Souffle de Dragon", "TypeTete": "Tête de Dragon", - "TypePossession": "Possession" + "TypePossession": "Possession", + "TypeSortreserve": "Sort en réserve" }, "EFFECT": { "StatusStunned": "Sonné", diff --git a/module/actor-sheet.js b/module/actor-sheet.js index b823162a..69224370 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -101,7 +101,6 @@ export class RdDActorSheet extends ActorSheet { formData.hautreve = { isDemiReve: this.actor.getEffectByLabel("Demi-rêve"), - sortsReserve: formData.system.reve.reserve.list, rencontres: duplicate(formData.system.reve.rencontre.list), casesTmr: formData.itemsByType.casetmr, cacheTMR: this.actor.isTMRCache() @@ -184,19 +183,6 @@ export class RdDActorSheet extends ActorSheet { const item = this.actor.getObjet(li.data("item-id")); RdDUtility.confirmerSuppressionItem(this, item, li); }); - html.find('.sort-reserve-delete').click(async event => { - const li = RdDSheetUtility.getEventElement(event); - const index = li.data('index'); - const sortReserve = this.actor.system.reve.reserve.list[index]; - RdDUtility.confirmerSuppression(this, li, { - supprimer: `le sort en réserve ${sortReserve.sort.name} en ${TMRUtility.getTMR(sortReserve.coord).label}`, - deleteLabel: "Supprimer le sort en réserve", - onDelete: () => { - console.log("Delete : ", sortReserve.name); - this.actor.deleteSortReserveKey(index); - } - }); - }); html.find('.item-vendre').click(async event => { const item = RdDSheetUtility.getItem(event, this.actor); item?.proposerVente(); diff --git a/module/actor.js b/module/actor.js index ee9307a8..8ef268f7 100644 --- a/module/actor.js +++ b/module/actor.js @@ -418,28 +418,6 @@ export class RdDActor extends Actor { } } - /* -------------------------------------------- */ - async deleteSortReserve(sortReserve) { - let reserve = duplicate(this.system.reve.reserve); - let tmr = TMRUtility.getTMR(sortReserve.coord); - let index = reserve.list.findIndex(tmr.type == 'fleuve' - ? sort => (TMRUtility.getTMR(sort.coord).type == 'fleuve' && sort.sort.name == sortReserve.sort.name) - : sort => (sort.coord == sortReserve.coord && sort.sort.name == sortReserve.sort.name) - ); - if (index >= 0) { - reserve.list.splice(index, 1); - await this.update({ "system.reve.reserve": reserve }); - } - } - - async deleteSortReserveKey(index) { - let reserve = duplicate(this.system.reve.reserve); - if (index >= 0) { - reserve.list.splice(index, 1); - await this.update({ "system.reve.reserve": reserve }, { renderSheet: false }); - } - } - /* -------------------------------------------- */ getSurprise(isCombat = undefined) { let niveauSurprise = this.getActiveEffects() @@ -856,10 +834,13 @@ export class RdDActor extends Actor { } /* -------------------------------------------- */ - async sortMisEnReserve(rollData, sort) { - let reserve = duplicate(this.system.reve.reserve.list); - reserve.push({ coord: rollData.tmr.coord, sort: sort, draconic: duplicate(rollData.competence) }); - await this.update({ "system.reve.reserve.list": reserve }); + async sortMisEnReserve(sort, draconic, coord, ptreve) { + await this.createEmbeddedDocuments("Item", [{ + type: 'sortreserve', + name: sort.name, + img: sort.img, + system: { sortid: sort.id, draconic: (draconic ?? sort.system.draconic), ptreve: ptreve, coord: coord, heurecible: 'Vaisseau' } }], + { renderSheet: false}); this.currentTMR.updateTokens(); } @@ -1140,11 +1121,11 @@ export class RdDActor extends Actor { } /* -------------------------------------------- */ - async deleteAllConteneur(itemId) { + async deleteAllConteneur(itemId, options) { let list = []; list.push({ id: itemId, conteneurId: undefined }); // Init list this.buildSubConteneurObjetList(itemId, list); - await this.deleteEmbeddedDocuments('Item', list.map(it => it.id)); + await this.deleteEmbeddedDocuments('Item', list.map(it => it.id), options); } /* -------------------------------------------- */ @@ -2453,7 +2434,7 @@ export class RdDActor extends Actor { RdDItemSort.incrementBonusCase(this, selectedSort, rollData.tmr.coord); if (rollData.isSortReserve) { - await this.sortMisEnReserve(rollData, selectedSort); + await this.sortMisEnReserve(selectedSort, rollData.competence, rollData.tmr.coord, Number(selectedSort.system.ptreve_reel)); } } else { @@ -2465,6 +2446,7 @@ export class RdDActor extends Actor { if (rolled.isETotal) { // Echec total ! rollData.depenseReve = Math.min(reveActuel, Math.floor(rollData.depenseReve * 1.5)) // TODO: mise en réserve d'un échec total... + // await dialog mse en réserve, pour traitement échec total } else { rollData.depenseReve = 0 } diff --git a/module/constants.js b/module/constants.js index 675749ed..2861889b 100644 --- a/module/constants.js +++ b/module/constants.js @@ -1,5 +1,6 @@ export const SYSTEM_RDD = 'foundryvtt-reve-de-dragon'; export const SYSTEM_SOCKET_ID = 'system.foundryvtt-reve-de-dragon'; +export const LOG_HEAD = 'RdD | '; export const HIDE_DICE = 'hide'; export const SHOW_DICE = 'show'; diff --git a/module/item-sheet.js b/module/item-sheet.js index 933b4642..ee2abc4a 100644 --- a/module/item-sheet.js +++ b/module/item-sheet.js @@ -84,32 +84,36 @@ export class RdDItemSheet extends ItemSheet { } formData.categorieCompetences = RdDItemCompetence.getCategorieCompetences() - if (formData.type == 'tache' || formData.type == 'livre' || formData.type == 'meditation' || formData.type == 'oeuvre') { + if (this.item.type == 'tache' || this.item.type == 'livre' || this.item.type == 'meditation' || this.item.type == 'oeuvre') { formData.caracList = duplicate(game.system.model.Actor.personnage.carac) formData.caracList["reve-actuel"] = duplicate(game.system.model.Actor.personnage.reve.reve) formData.competences = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.competences') } - if (formData.type == 'arme') { + if (this.item.type == 'arme') { formData.competences = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.competences', it => RdDItemCompetence.isCompetenceArme(it)); console.log(formData.competences) } - if (formData.type == 'recettealchimique') { + if (this.item.type == 'recettealchimique') { RdDAlchimie.processManipulation(this.item, this.actor && this.actor.id); } - if (formData.type == 'gemme') { + if (this.item.type == 'gemme') { formData.gemmeTypeList = RdDGemme.getGemmeTypeOptionList(); RdDGemme.calculDataDerivees(this.item); } - if (formData.type == 'potion') { + if (this.item.type == 'potion') { if (this.dateUpdated) { formData.system.prdate = this.dateUpdated; this.dateUpdated = undefined; } RdDHerbes.updatePotionData(formData); } - if (formData.isOwned && formData.type == 'herbe' && (formData.system.categorie == 'Soin' || formData.system.categorie == 'Repos')) { + if (formData.isOwned && this.item.type == 'herbe' && (formData.system.categorie == 'Soin' || formData.system.categorie == 'Repos')) { formData.isIngredientPotionBase = true; } + if (this.item.type == 'sortreserve') { + const sortId = this.item.system.sortid; + formData.sort = formData.isOwned ? this.item.actor.items.get(sortId) : game.items.get(sortId); + } formData.bonusCaseList = RdDItemSort.getBonusCaseList(formData, true); return formData; diff --git a/module/item.js b/module/item.js index 7f9003d8..3e8a8cd9 100644 --- a/module/item.js +++ b/module/item.js @@ -36,7 +36,8 @@ export const defaultItemImg = { nourritureboisson: "systems/foundryvtt-reve-de-dragon/icons/objets/provision_crue.webp", signedraconique: "systems/foundryvtt-reve-de-dragon/icons/tmr/signe_draconique.webp", gemme: "systems/foundryvtt-reve-de-dragon/icons/gemmes/almaze.webp", - possession: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp" + possession: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp", + sortreserve: "systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp", } /* -------------------------------------------- */ diff --git a/module/migrations.js b/module/migrations.js new file mode 100644 index 00000000..9bd75d62 --- /dev/null +++ b/module/migrations.js @@ -0,0 +1,103 @@ +import { LOG_HEAD, SYSTEM_RDD } from "./constants.js"; + +class Migration { + get code() { return "sample"; } + get version() { return "0.0.0"; } + async migrate() { } +} + +class _10_0_16_MigrationSortsReserve extends Migration { + get code() { return "creation-item-sort-reserve"; } + get version() { return "10.0.16"; } + + async migrate() { + await game.actors + .filter((actor) => actor.type == "personnage") + .filter((actor) => actor.system.reve?.reserve?.list?.length ?? 0 > 0) + .forEach(async (actor) => { + const sortsReserve = actor.system.reve.reserve.list.map(this.conversionSortReserve); + console.log(LOG_HEAD + "Migration des sorts ", sortsReserve); + await actor.createEmbeddedDocuments("Item", sortsReserve, { + renderSheet: false, + }); + await actor.update({'system.reve.reserve.list':[]}) + }); + } + + conversionSortReserve(it) { + return { + type: 'sortreserve', + name: it.sort.name, + img: it.sort.img, + system: { + // ATTENTION, utilisation de data / _id possibles, encore présents pour les anciens sorts en réserve + sortid: it.sort._id, + draconic: it.sort.draconic, + ptreve: (it.sort.system ?? it.sort.data).ptreve_reel, + coord: it.coord, + heurecible: 'Vaisseau', + }, + }; + } +} + +export class Migrations { + static getMigrations() { + return [ + new _10_0_16_MigrationSortsReserve() + ]; + } + + constructor() { + game.settings.register(SYSTEM_RDD, "systemMigrationVersion", { + name: "System Migration Version", + scope: "world", + config: false, + type: String, + default: "0.0.0", + }); + } + + migrate() { + const currentVersion = game.settings.get( + SYSTEM_RDD, + "systemMigrationVersion" + ); + if (isNewerVersion(game.system.version, currentVersion)) { + const migrations = Migrations.getMigrations().filter(m => isNewerVersion(m.version, currentVersion)); + // if (true) { + // const migrations = Migrations.getMigrations(); + if (migrations.length > 0) { + migrations.sort((a, b) => + isNewerVersion(a.version, b.version) + ? 1 + : isNewerVersion(b.version, a.version) + ? -1 + : 0 + ); + migrations.forEach(async (m) => { + ui.notifications.info( + `Executing migration ${m.code}: version ${currentVersion} is lower than ${m.version}` + ); + await m.migrate(); + }); + ui.notifications.info( + `Migrations done, version will change to ${game.system.version}` + ); + } else { + console.log( + LOG_HEAD + + `No migration needeed, version will change to ${game.system.version}` + ); + } + + game.settings.set( + SYSTEM_RDD, + "systemMigrationVersion", + game.system.version + ); + } else { + console.log(LOG_HEAD + `No system version changed`); + } + } +} diff --git a/module/rdd-main.js b/module/rdd-main.js index a01bc08c..cfb87b59 100644 --- a/module/rdd-main.js +++ b/module/rdd-main.js @@ -35,6 +35,7 @@ import { RdDDice } from "./rdd-dice.js"; import { RdDPossession } from "./rdd-possession.js"; import { RdDSigneDraconiqueItemSheet } from "./item-signedraconique-sheet.js"; import { Misc } from "./misc.js"; +import { Migrations } from './migrations.js'; /* -------------------------------------------- */ /* Foundry VTT Initialization */ @@ -183,7 +184,7 @@ Hooks.once("init", async function () { Items.registerSheet(SYSTEM_RDD, RdDItemSheet, { types: ["arme", "armure", "objet", "arme", "armure", "conteneur", "competence", "sort", "herbe", "ingredient", "livre", "potion", "munition", "rencontresTMR", "queue", "ombre", "souffle", "tete", "competencecreature", "tarot", "monnaie", "nombreastral", "tache", "meditation", "casetmr", "recettealchimique", "gemme", - "musique", "chant", "danse", "jeu", "recettecuisine", "maladie", "poison", "oeuvre", "nourritureboisson", "possession"], makeDefault: true + "musique", "chant", "danse", "jeu", "recettecuisine", "maladie", "poison", "oeuvre", "nourritureboisson", "possession", "sortreserve"], makeDefault: true }); CONFIG.Combat.documentClass = RdDCombatManager; @@ -245,6 +246,9 @@ function registerUsageCount( registerKey ) { /* -------------------------------------------- */ Hooks.once("ready", async function () { await migrationPngWebp_1_5_34() + if (Misc.isUniqueConnectedGM()) { + new Migrations().migrate(); + } StatusEffects.onReady(); RdDHerbes.initializeHerbes(); diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js index fce54383..f7e07f83 100644 --- a/module/rdd-tmr-dialog.js +++ b/module/rdd-tmr-dialog.js @@ -55,7 +55,6 @@ export class RdDTMRDialog extends Dialog { this.fatigueParCase = this.viewOnly || !ReglesOptionelles.isUsing("appliquer-fatigue") ? 0 : this.actor.getTMRFatigue(); this.cumulFatigue = 0; this.loadRencontres(); - this.loadSortsReserve(); this.loadCasesSpeciales(); this.allTokens = []; this.rencontreState = 'aucune'; @@ -81,9 +80,16 @@ export class RdDTMRDialog extends Dialog { this.casesSpeciales = this.actor.items.filter(item => Draconique.isCaseTMR(item)); } - /* -------------------------------------------- */ - loadSortsReserve() { - this.sortsReserves = this.actor.system.reve.reserve.list; + get sortsReserve() { + return this.actor.itemTypes['sortreserve']; + } + + getSortsReserve(coord) { + return this.actor.itemTypes['sortreserve'].filter(// Reserve sur une case fleuve ou normale + TMRUtility.getTMR(coord).type == 'fleuve' + ? it => TMRUtility.getTMR(it.system.coord).type == 'fleuve' + : it => it.system.coord == coord + ); } /* -------------------------------------------- */ @@ -97,10 +103,10 @@ export class RdDTMRDialog extends Dialog { this.updateTokens(); this.forceDemiRevePositionView(); } - + /* -------------------------------------------- */ _createTokens() { - if (!this.isDemiReveCache()){ + if (!this.isDemiReveCache()) { this.demiReve = this._tokenDemiReve(); this._trackToken(this.demiReve); } @@ -117,7 +123,6 @@ export class RdDTMRDialog extends Dialog { updateTokens() { this._removeTokens(t => true); this.loadRencontres(); - this.loadSortsReserve(); this.loadCasesSpeciales(); this._createTokens(); } @@ -136,7 +141,7 @@ export class RdDTMRDialog extends Dialog { return this.rencontresExistantes.map(it => this._tokenRencontre(it)); } _getTokensSortsReserve() { - return this.sortsReserves.map(it => this._tokenSortEnReserve(it)); + return this.actor.itemTypes['sortreserve'].map(it => this._tokenSortEnReserve(it)); } /* -------------------------------------------- */ @@ -148,8 +153,8 @@ export class RdDTMRDialog extends Dialog { const draconique = Draconique.get(caseData.system.specific); return draconique?.token(this.pixiTMR, caseData, () => caseData.system.coord); } - _tokenSortEnReserve(sortEnReserve) { - return EffetsDraconiques.sortReserve.token(this.pixiTMR, sortEnReserve.sort, () => sortEnReserve.coord); + _tokenSortEnReserve(sortReserve) { + return EffetsDraconiques.sortReserve.token(this.pixiTMR, sortReserve, () => sortReserve.system.coord); } _tokenDemiReve() { @@ -254,9 +259,9 @@ export class RdDTMRDialog extends Dialog { let tmrpos = document.getElementById("tmr-pos"); if (this.isDemiReveCache()) { - tmrpos.innerHTML = '?? (' + TMRUtility.getTMRType(coord) + ')'; + tmrpos.innerHTML = `?? ( ${ TMRUtility.getTMRType(coord)})`; } else { - tmrpos.innerHTML = coord + " (" + TMRUtility.getTMRLabel(coord) + ")"; + tmrpos.innerHTML = `${coord} ( ${TMRUtility.getTMRLabel(coord)})`; } let etat = document.getElementById("tmr-etatgeneral-value"); @@ -318,9 +323,9 @@ export class RdDTMRDialog extends Dialog { for (let coordTMR of listCoordTMR) { let rect = this._getCaseRectangleCoord(coordTMR); var rectDraw = new PIXI.Graphics(); - rectDraw.beginFill(0xFFFF00, 0.3); + 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); + rectDraw.lineStyle(5, 0xff0000); // draw a rectangle rectDraw.drawRect(rect.x, rect.y, rect.w, rect.h); this.pixiApp.stage.addChild(rectDraw); @@ -336,8 +341,7 @@ export class RdDTMRDialog extends Dialog { /* -------------------------------------------- */ async choisirCasePortee(coord, portee) { - if (this.actor.isTMRCache()) - { + if (this.actor.isTMRCache()) { return; } // Récupère la liste des cases à portées @@ -774,9 +778,8 @@ export class RdDTMRDialog extends Dialog { /* -------------------------------------------- */ async declencheSortEnReserve(coord) { - - let sortsEnCoord = TMRUtility.getSortsReserve(this.sortsReserves, coord); - if (sortsEnCoord.length > 0) { + let sorts = this.getSortsReserve(coord); + if (sorts.length > 0) { if (EffetsDraconiques.isSortReserveImpossible(this.actor)) { ui.notifications.error("Une queue ou un souffle vous empèche de déclencher de sort!"); return; @@ -784,8 +787,8 @@ export class RdDTMRDialog extends Dialog { if (!EffetsDraconiques.isUrgenceDraconique(this.actor) && (EffetsDraconiques.isReserveEnSecurite(this.actor) || this.isReserveExtensible(coord))) { let msg = "Vous êtes sur une case avec un Sort en Réserve. Grâce à votre Tête Reserve en Sécurité ou Réserve Exensible, vous pouvez contrôler le déclenchement. Cliquez si vous souhaitez le déclencher :