Added System migration stuff
Some reorganisation
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## 1.0.1 - Initiative first !
|
## 1.1.0 - Initiative first !
|
||||||
- Added initiative system :
|
- Added initiative system :
|
||||||
- Now use the score rule (the real one if you prefer)
|
- Now use the score rule (the real one if you prefer)
|
||||||
- Added global modifiers for Characters, Adversary and Minons in the combat tracker : Confrontation types, Prepared
|
- Added global modifiers for Characters, Adversary and Minons in the combat tracker : Confrontation types, Prepared
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
- Xp not in curriculum are now rounded up (down before)
|
- Xp not in curriculum are now rounded up (down before)
|
||||||
- No more automation in stats for Npc (these cheaters !)
|
- No more automation in stats for Npc (these cheaters !)
|
||||||
- 20Q Pushed the step3 item's limit to 20 (10 previous)
|
- 20Q Pushed the step3 item's limit to 20 (10 previous)
|
||||||
|
- Added System migration stuff
|
||||||
|
|
||||||
## 1.0.0 - First public release
|
## 1.0.0 - First public release
|
||||||
- Removed the 0ds if no skill point
|
- Removed the 0ds if no skill point
|
||||||
|
|||||||
@@ -96,12 +96,6 @@ export class ActorL5r5e extends Actor {
|
|||||||
if (data.void_points.value > data.void_points.max) {
|
if (data.void_points.value > data.void_points.max) {
|
||||||
data.void_points.value = data.void_points.max;
|
data.void_points.value = data.void_points.max;
|
||||||
}
|
}
|
||||||
|
|
||||||
// *** Migration stuff ***
|
|
||||||
// TODO remove in patch 1.1+
|
|
||||||
if (data.prepared === undefined) {
|
|
||||||
data.prepared = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ export class TwentyQuestions {
|
|||||||
const actorDatas = actor.data.data;
|
const actorDatas = actor.data.data;
|
||||||
|
|
||||||
// already 20q struct ?
|
// already 20q struct ?
|
||||||
if (actorDatas.twenty_questions?.step1?.clan) {
|
if (!isObjectEmpty(actorDatas.twenty_questions)) {
|
||||||
this.data = {
|
this.data = {
|
||||||
...this.data,
|
...this.data,
|
||||||
...actorDatas.twenty_questions,
|
...actorDatas.twenty_questions,
|
||||||
@@ -216,6 +216,8 @@ export class TwentyQuestions {
|
|||||||
const actorDatas = actor.data.data;
|
const actorDatas = actor.data.data;
|
||||||
const formData = this.data;
|
const formData = this.data;
|
||||||
|
|
||||||
|
this.data.generated = true;
|
||||||
|
|
||||||
const status = parseInt(formData.step1.social_status) + parseInt(formData.step18.heritage_add_status);
|
const status = parseInt(formData.step1.social_status) + parseInt(formData.step18.heritage_add_status);
|
||||||
|
|
||||||
const glory =
|
const glory =
|
||||||
|
|||||||
99
system/scripts/handlebars.js
Normal file
99
system/scripts/handlebars.js
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
/**
|
||||||
|
* Custom Handlebars for L5R5e
|
||||||
|
*/
|
||||||
|
export const RegisterHandlebars = function () {
|
||||||
|
/* ------------------------------------ */
|
||||||
|
/* Localizations */
|
||||||
|
/* ------------------------------------ */
|
||||||
|
Handlebars.registerHelper("localizeSkill", function (categoryId, skillId) {
|
||||||
|
const key = "l5r5e.skills." + categoryId.toLowerCase() + "." + skillId.toLowerCase();
|
||||||
|
return game.i18n.localize(key);
|
||||||
|
});
|
||||||
|
|
||||||
|
Handlebars.registerHelper("localizeSkillId", function (skillId) {
|
||||||
|
const key = "l5r5e.skills." + CONFIG.l5r5e.skills.get(skillId.toLowerCase()) + "." + skillId.toLowerCase();
|
||||||
|
return game.i18n.localize(key);
|
||||||
|
});
|
||||||
|
|
||||||
|
Handlebars.registerHelper("localizeRing", function (ringId) {
|
||||||
|
const key = "l5r5e.rings." + ringId.toLowerCase();
|
||||||
|
return game.i18n.localize(key);
|
||||||
|
});
|
||||||
|
|
||||||
|
Handlebars.registerHelper("localizeStanceTip", function (ringId) {
|
||||||
|
const key = "l5r5e.conflict.stances." + ringId.toLowerCase() + "tip";
|
||||||
|
return game.i18n.localize(key);
|
||||||
|
});
|
||||||
|
|
||||||
|
Handlebars.registerHelper("localizeTechnique", function (techniqueName) {
|
||||||
|
return game.i18n.localize("l5r5e.techniques." + techniqueName.toLowerCase());
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ------------------------------------ */
|
||||||
|
/* Utility */
|
||||||
|
/* ------------------------------------ */
|
||||||
|
/**
|
||||||
|
* Json - Display a object in textarea (for debug)
|
||||||
|
*/
|
||||||
|
Handlebars.registerHelper("json", function (...objects) {
|
||||||
|
objects.pop(); // remove this function call
|
||||||
|
return new Handlebars.SafeString(objects.map((e) => `<textarea>${JSON.stringify(e)}</textarea>`));
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add props "checked" if a and b are equal ({{radioChecked a b}}
|
||||||
|
*/
|
||||||
|
Handlebars.registerHelper("radioChecked", function (a, b) {
|
||||||
|
return a === b ? new Handlebars.SafeString('checked="checked"') : "";
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility conditional, usable in nested expression
|
||||||
|
* {{#ifCond (ifCond advancement.type '==' 'technique') '||' (ifCond item.data.technique_type '==' 'kata')}}
|
||||||
|
* {{#ifCond '["distinction","passion"]' 'includes' item.data.peculiarity_type}}
|
||||||
|
*/
|
||||||
|
Handlebars.registerHelper("ifCond", function (a, operator, b, options) {
|
||||||
|
let result = false;
|
||||||
|
switch (operator) {
|
||||||
|
case "==":
|
||||||
|
result = a == b;
|
||||||
|
break;
|
||||||
|
case "===":
|
||||||
|
result = a === b;
|
||||||
|
break;
|
||||||
|
case "!=":
|
||||||
|
result = a != b;
|
||||||
|
break;
|
||||||
|
case "!==":
|
||||||
|
result = a !== b;
|
||||||
|
break;
|
||||||
|
case "<":
|
||||||
|
result = a < b;
|
||||||
|
break;
|
||||||
|
case "<=":
|
||||||
|
result = a <= b;
|
||||||
|
break;
|
||||||
|
case ">":
|
||||||
|
result = a > b;
|
||||||
|
break;
|
||||||
|
case ">=":
|
||||||
|
result = a >= b;
|
||||||
|
break;
|
||||||
|
case "&&":
|
||||||
|
result = a && b;
|
||||||
|
break;
|
||||||
|
case "||":
|
||||||
|
result = a || b;
|
||||||
|
break;
|
||||||
|
case "includes":
|
||||||
|
result = a && b && a.includes(b);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (typeof options.fn === "function") {
|
||||||
|
return result ? options.fn(this) : options.inverse(this);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -21,6 +21,11 @@ export default class HooksL5r5e {
|
|||||||
* Do anything once the system is ready
|
* Do anything once the system is ready
|
||||||
*/
|
*/
|
||||||
static ready() {
|
static ready() {
|
||||||
|
// Migration stuff
|
||||||
|
if (game.l5r5e.migrations.needUpdate()) {
|
||||||
|
game.l5r5e.migrations.migrateWorld();
|
||||||
|
}
|
||||||
|
|
||||||
// Settings TN and EncounterType
|
// Settings TN and EncounterType
|
||||||
if (game.user.isGM) {
|
if (game.user.isGM) {
|
||||||
new game.l5r5e.GmToolsDialog().render(true);
|
new game.l5r5e.GmToolsDialog().render(true);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { HelpersL5r5e } from "./helpers.js";
|
|||||||
import { SocketHandlerL5r5e } from "./socket-handler.js";
|
import { SocketHandlerL5r5e } from "./socket-handler.js";
|
||||||
import { RegisterSettings } from "./settings.js";
|
import { RegisterSettings } from "./settings.js";
|
||||||
import { PreloadTemplates } from "./preloadTemplates.js";
|
import { PreloadTemplates } from "./preloadTemplates.js";
|
||||||
|
import { RegisterHandlebars } from "./handlebars.js";
|
||||||
import { HelpDialog } from "./help/help-dialog.js";
|
import { HelpDialog } from "./help/help-dialog.js";
|
||||||
import HooksL5r5e from "./hooks.js";
|
import HooksL5r5e from "./hooks.js";
|
||||||
// Actors
|
// Actors
|
||||||
@@ -31,11 +32,13 @@ import { PeculiaritySheetL5r5e } from "./items/peculiarity-sheet.js";
|
|||||||
// JournalEntry
|
// JournalEntry
|
||||||
import { JournalL5r5e } from "./journal.js";
|
import { JournalL5r5e } from "./journal.js";
|
||||||
import { BaseJournalSheetL5r5e } from "./journals/base-journal-sheet.js";
|
import { BaseJournalSheetL5r5e } from "./journals/base-journal-sheet.js";
|
||||||
|
// Specific
|
||||||
|
import { MigrationL5r5e } from "./migration.js";
|
||||||
|
|
||||||
/* ------------------------------------ */
|
/* ------------------------------------ */
|
||||||
/* Initialize system */
|
/* Initialize system */
|
||||||
/* ------------------------------------ */
|
/* ------------------------------------ */
|
||||||
Hooks.once("init", async function () {
|
Hooks.once("init", async () => {
|
||||||
// ***** Initializing l5r5e *****
|
// ***** Initializing l5r5e *****
|
||||||
// Ascii art :p
|
// Ascii art :p
|
||||||
console.log(
|
console.log(
|
||||||
@@ -79,11 +82,15 @@ Hooks.once("init", async function () {
|
|||||||
ActorL5r5e,
|
ActorL5r5e,
|
||||||
HelpDialog,
|
HelpDialog,
|
||||||
sockets: new SocketHandlerL5r5e(),
|
sockets: new SocketHandlerL5r5e(),
|
||||||
|
migrations: MigrationL5r5e,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Register custom system settings
|
// Register custom system settings
|
||||||
RegisterSettings();
|
RegisterSettings();
|
||||||
|
|
||||||
|
// Register custom Handlebars Helpers
|
||||||
|
RegisterHandlebars();
|
||||||
|
|
||||||
// Preload Handlebars templates
|
// Preload Handlebars templates
|
||||||
await PreloadTemplates();
|
await PreloadTemplates();
|
||||||
|
|
||||||
@@ -106,89 +113,6 @@ Hooks.once("init", async function () {
|
|||||||
// Journal
|
// Journal
|
||||||
Items.unregisterSheet("core", JournalSheet);
|
Items.unregisterSheet("core", JournalSheet);
|
||||||
Items.registerSheet("l5r5e", BaseJournalSheetL5r5e, { makeDefault: true });
|
Items.registerSheet("l5r5e", BaseJournalSheetL5r5e, { makeDefault: true });
|
||||||
|
|
||||||
// ***** Handlebars *****
|
|
||||||
// for debug
|
|
||||||
Handlebars.registerHelper("json", function (...objects) {
|
|
||||||
objects.pop(); // remove this function call
|
|
||||||
return new Handlebars.SafeString(objects.map((e) => `<textarea>${JSON.stringify(e)}</textarea>`));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add props "checked" if a and b are equal ({{radioChecked a b}}
|
|
||||||
Handlebars.registerHelper("radioChecked", function (a, b) {
|
|
||||||
return a === b ? new Handlebars.SafeString('checked="checked"') : "";
|
|
||||||
});
|
|
||||||
|
|
||||||
Handlebars.registerHelper("localizeSkill", function (categoryId, skillId) {
|
|
||||||
const key = "l5r5e.skills." + categoryId.toLowerCase() + "." + skillId.toLowerCase();
|
|
||||||
return game.i18n.localize(key);
|
|
||||||
});
|
|
||||||
Handlebars.registerHelper("localizeSkillId", function (skillId) {
|
|
||||||
const key = "l5r5e.skills." + L5R5E.skills.get(skillId.toLowerCase()) + "." + skillId.toLowerCase();
|
|
||||||
return game.i18n.localize(key);
|
|
||||||
});
|
|
||||||
|
|
||||||
Handlebars.registerHelper("localizeRing", function (ringId) {
|
|
||||||
const key = "l5r5e.rings." + ringId.toLowerCase();
|
|
||||||
return game.i18n.localize(key);
|
|
||||||
});
|
|
||||||
|
|
||||||
Handlebars.registerHelper("localizeStanceTip", function (ringId) {
|
|
||||||
const key = "l5r5e.conflict.stances." + ringId.toLowerCase() + "tip";
|
|
||||||
return game.i18n.localize(key);
|
|
||||||
});
|
|
||||||
|
|
||||||
Handlebars.registerHelper("localizeTechnique", function (techniqueName) {
|
|
||||||
return game.i18n.localize("l5r5e.techniques." + techniqueName.toLowerCase());
|
|
||||||
});
|
|
||||||
|
|
||||||
// Utility conditional, usable in nested expression
|
|
||||||
// {{#ifCond (ifCond advancement.type '==' 'technique') '||' (ifCond item.data.technique_type '==' 'kata')}}
|
|
||||||
// {{#ifCond '["distinction","passion"]' 'includes' item.data.peculiarity_type}}
|
|
||||||
Handlebars.registerHelper("ifCond", function (a, operator, b, options) {
|
|
||||||
let result = false;
|
|
||||||
switch (operator) {
|
|
||||||
case "==":
|
|
||||||
result = a == b;
|
|
||||||
break;
|
|
||||||
case "===":
|
|
||||||
result = a === b;
|
|
||||||
break;
|
|
||||||
case "!=":
|
|
||||||
result = a != b;
|
|
||||||
break;
|
|
||||||
case "!==":
|
|
||||||
result = a !== b;
|
|
||||||
break;
|
|
||||||
case "<":
|
|
||||||
result = a < b;
|
|
||||||
break;
|
|
||||||
case "<=":
|
|
||||||
result = a <= b;
|
|
||||||
break;
|
|
||||||
case ">":
|
|
||||||
result = a > b;
|
|
||||||
break;
|
|
||||||
case ">=":
|
|
||||||
result = a >= b;
|
|
||||||
break;
|
|
||||||
case "&&":
|
|
||||||
result = a && b;
|
|
||||||
break;
|
|
||||||
case "||":
|
|
||||||
result = a || b;
|
|
||||||
break;
|
|
||||||
case "includes":
|
|
||||||
result = a && b && a.includes(b);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (typeof options.fn === "function") {
|
|
||||||
return result ? options.fn(this) : options.inverse(this);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/* ------------------------------------ */
|
/* ------------------------------------ */
|
||||||
|
|||||||
227
system/scripts/migration.js
Normal file
227
system/scripts/migration.js
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
/**
|
||||||
|
* L5R Migration class
|
||||||
|
*/
|
||||||
|
export class MigrationL5r5e {
|
||||||
|
/**
|
||||||
|
* Version needed for migration stuff to trigger
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
static NEEDED_VERSION = "1.1.0";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the current world need some updates
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
static needUpdate() {
|
||||||
|
const currentVersion = game.settings.get("l5r5e", "systemMigrationVersion");
|
||||||
|
return currentVersion && isNewerVersion(MigrationL5r5e.NEEDED_VERSION, currentVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a system migration for the entire World, applying migrations for Actors, Items, and Compendium packs
|
||||||
|
* @return {Promise} A Promise which resolves once the migration is completed
|
||||||
|
*/
|
||||||
|
static async migrateWorld() {
|
||||||
|
if (!game.user.isGM) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.notifications.info(
|
||||||
|
`Applying L5R5e System Migration for version ${game.system.data.version}.` +
|
||||||
|
` Please be patient and do not close your game or shut down your server.`,
|
||||||
|
{ permanent: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Migrate World Actors
|
||||||
|
for (let a of game.actors.entities) {
|
||||||
|
try {
|
||||||
|
const updateData = MigrationL5r5e._migrateActorData(a.data);
|
||||||
|
if (!isObjectEmpty(updateData)) {
|
||||||
|
console.log(`Migrating Actor entity ${a.name}`);
|
||||||
|
await a.update(updateData, { enforceTypes: false });
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
err.message = `Failed L5R5e system migration for Actor ${a.name}: ${err.message}`;
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrate World Items
|
||||||
|
for (let i of game.items.entities) {
|
||||||
|
try {
|
||||||
|
const updateData = MigrationL5r5e._migrateItemData(i.data);
|
||||||
|
if (!isObjectEmpty(updateData)) {
|
||||||
|
console.log(`Migrating Item entity ${i.name}`);
|
||||||
|
await i.update(updateData, { enforceTypes: false });
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
err.message = `Failed L5R5e system migration for Item ${i.name}: ${err.message}`;
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrate Actor Override Tokens
|
||||||
|
for (let s of game.scenes.entities) {
|
||||||
|
try {
|
||||||
|
const updateData = MigrationL5r5e._migrateSceneData(s.data);
|
||||||
|
if (!isObjectEmpty(updateData)) {
|
||||||
|
console.log(`Migrating Scene entity ${s.name}`);
|
||||||
|
await s.update(updateData, { enforceTypes: false });
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
err.message = `Failed L5R5e system migration for Scene ${s.name}: ${err.message}`;
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrate World Compendium Packs
|
||||||
|
for (let p of game.packs) {
|
||||||
|
if (p.metadata.package !== "world") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!["Actor", "Item", "Scene"].includes(p.metadata.entity)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
await MigrationL5r5e._migrateCompendium(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the migration as complete
|
||||||
|
await game.settings.set("l5r5e", "systemMigrationVersion", game.system.data.version);
|
||||||
|
ui.notifications.info(`L5R5e System Migration to version ${game.system.data.version} completed!`, {
|
||||||
|
permanent: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply migration rules to all Entities within a single Compendium pack
|
||||||
|
* @param pack
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
|
static async _migrateCompendium(pack) {
|
||||||
|
const entity = pack.metadata.entity;
|
||||||
|
if (!["Actor", "Item", "Scene"].includes(entity)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlock the pack for editing
|
||||||
|
const wasLocked = pack.locked;
|
||||||
|
await pack.configure({ locked: false });
|
||||||
|
|
||||||
|
// Begin by requesting server-side data model migration and get the migrated content
|
||||||
|
await pack.migrate();
|
||||||
|
const content = await pack.getContent();
|
||||||
|
|
||||||
|
// Iterate over compendium entries - applying fine-tuned migration functions
|
||||||
|
for (let ent of content) {
|
||||||
|
let updateData = {};
|
||||||
|
try {
|
||||||
|
switch (entity) {
|
||||||
|
case "Actor":
|
||||||
|
updateData = MigrationL5r5e._migrateActorData(ent.data);
|
||||||
|
break;
|
||||||
|
case "Item":
|
||||||
|
updateData = MigrationL5r5e._migrateItemData(ent.data);
|
||||||
|
break;
|
||||||
|
case "Scene":
|
||||||
|
updateData = MigrationL5r5e._migrateSceneData(ent.data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (isObjectEmpty(updateData)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the entry, if data was changed
|
||||||
|
updateData["_id"] = ent._id;
|
||||||
|
await pack.updateEntity(updateData);
|
||||||
|
console.log(`Migrated ${entity} entity ${ent.name} in Compendium ${pack.collection}`);
|
||||||
|
} catch (err) {
|
||||||
|
// Handle migration failures
|
||||||
|
err.message = `Failed L5R5e system migration for entity ${ent.name} in pack ${pack.collection}: ${err.message}`;
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the original locked status for the pack
|
||||||
|
pack.configure({ locked: wasLocked });
|
||||||
|
console.log(`Migrated all ${entity} entities from Compendium ${pack.collection}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrate a single Scene entity to incorporate changes to the data model of it's actor data overrides
|
||||||
|
* Return an Object of updateData to be applied
|
||||||
|
* @param {Object} scene The Scene data to Update
|
||||||
|
* @return {Object} The updateData to apply
|
||||||
|
*/
|
||||||
|
static _migrateSceneData(scene) {
|
||||||
|
const tokens = duplicate(scene.tokens);
|
||||||
|
return {
|
||||||
|
tokens: tokens.map((t) => {
|
||||||
|
if (!t.actorId || t.actorLink || !t.actorData.data) {
|
||||||
|
t.actorData = {};
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
const token = new Token(t);
|
||||||
|
if (!token.actor) {
|
||||||
|
t.actorId = null;
|
||||||
|
t.actorData = {};
|
||||||
|
} else if (!t.actorLink) {
|
||||||
|
const updateData = MigrationL5r5e._migrateActorData(token.data.actorData);
|
||||||
|
t.actorData = mergeObject(token.data.actorData, updateData);
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrate a single Actor entity to incorporate latest data model changes
|
||||||
|
* Return an Object of updateData to be applied
|
||||||
|
* @param {Actor} actor The actor to Update
|
||||||
|
* @return {Object} The updateData to apply
|
||||||
|
*/
|
||||||
|
static _migrateActorData(actor) {
|
||||||
|
const updateData = {};
|
||||||
|
const actorData = actor.data;
|
||||||
|
|
||||||
|
// ***** Start of 1.1.0 *****
|
||||||
|
// Add "Prepared" in actor
|
||||||
|
if (actorData.prepared === undefined) {
|
||||||
|
updateData["data.prepared"] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NPC are now without autostats, we need to save the value
|
||||||
|
if (actor.type === "npc") {
|
||||||
|
if (actorData.endurance < 1) {
|
||||||
|
updateData["data.endurance"] = (Number(actorData.rings.earth) + Number(actorData.rings.fire)) * 2;
|
||||||
|
updateData["data.composure"] = (Number(actorData.rings.earth) + Number(actorData.rings.water)) * 2;
|
||||||
|
updateData["data.focus"] = Number(actorData.rings.air) + Number(actorData.rings.fire);
|
||||||
|
updateData["data.vigilance"] = Math.ceil(
|
||||||
|
(Number(actorData.rings.air) + Number(actorData.rings.water)) / 2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ***** End of 1.1.0 *****
|
||||||
|
|
||||||
|
return updateData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scrub an Actor's system data, removing all keys which are not explicitly defined in the system template
|
||||||
|
* @param {Object} actorData The data object for an Actor
|
||||||
|
* @return {Object} The scrubbed Actor data
|
||||||
|
*/
|
||||||
|
static cleanActorData(actorData) {
|
||||||
|
const model = game.system.model.Actor[actorData.type];
|
||||||
|
actorData.data = filterObject(actorData.data, model);
|
||||||
|
return actorData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrate a single Item entity to incorporate latest data model changes
|
||||||
|
* @param item
|
||||||
|
*/
|
||||||
|
static _migrateItemData(item) {
|
||||||
|
// Nothing for now
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,9 +2,20 @@
|
|||||||
* Custom system settings register
|
* Custom system settings register
|
||||||
*/
|
*/
|
||||||
export const RegisterSettings = function () {
|
export const RegisterSettings = function () {
|
||||||
/**
|
/* ------------------------------------ */
|
||||||
* Settings set by Initiative Roll Dialog (GM only)
|
/* Update */
|
||||||
*/
|
/* ------------------------------------ */
|
||||||
|
game.settings.register("l5r5e", "systemMigrationVersion", {
|
||||||
|
name: "System Migration Version",
|
||||||
|
scope: "world",
|
||||||
|
config: false,
|
||||||
|
type: String,
|
||||||
|
default: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ------------------------------------ */
|
||||||
|
/* Initiative Roll Dialog (GM only) */
|
||||||
|
/* ------------------------------------ */
|
||||||
game.settings.register("l5r5e", "initiative.difficulty.hidden", {
|
game.settings.register("l5r5e", "initiative.difficulty.hidden", {
|
||||||
name: "Initiative difficulty is hidden",
|
name: "Initiative difficulty is hidden",
|
||||||
scope: "world",
|
scope: "world",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "l5r5e",
|
"name": "l5r5e",
|
||||||
"title": "Legend of the Five Rings (5th Edition)",
|
"title": "Legend of the Five Rings (5th Edition)",
|
||||||
"description": "This is a game system, multilingual in En/FR/ES, for Legend of the Five Rings (5th Edition) by <a href='https://edge-studio.net/'>Edge Studio</a> <p> - Join the official Discord server: <a href='https://discord.gg/foundryvtt'> Official Discord</a></p><p> - Rejoignez la communauté Francophone: <a href='https://discord.gg/pPSDNJk'>Francophone Discord</a></p>",
|
"description": "This is a game system, multilingual in En/FR/ES, for Legend of the Five Rings (5th Edition) by <a href='https://edge-studio.net/'>Edge Studio</a> <p> - Join the official Discord server: <a href='https://discord.gg/foundryvtt'> Official Discord</a></p><p> - Rejoignez la communauté Francophone: <a href='https://discord.gg/pPSDNJk'>Francophone Discord</a></p>",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"minimumCoreVersion": "0.7.9",
|
"minimumCoreVersion": "0.7.9",
|
||||||
"compatibleCoreVersion": "0.7.9",
|
"compatibleCoreVersion": "0.7.9",
|
||||||
"manifestPlusVersion": "1.0.0",
|
"manifestPlusVersion": "1.0.0",
|
||||||
@@ -159,5 +159,5 @@
|
|||||||
],
|
],
|
||||||
"url": "https://gitlab.com/teaml5r/l5r5e",
|
"url": "https://gitlab.com/teaml5r/l5r5e",
|
||||||
"manifest": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/system/system.json",
|
"manifest": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/system/system.json",
|
||||||
"download": "https://gitlab.com/teaml5r/l5r5e/-/jobs/artifacts/v1.0.0/raw/l5r5e.zip?job=build"
|
"download": "https://gitlab.com/teaml5r/l5r5e/-/jobs/artifacts/v1.1.0/raw/l5r5e.zip?job=build"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user