Working on Skills and some fixes
- Added Skills to character sheet - Added migration to old skills - Added icon on skills - Added actor.isNpc - Money out of system
This commit is contained in:
@@ -16,66 +16,96 @@ export class ActorL5r5e extends Actor {
|
||||
docData.img = `${CONFIG.l5r5e.paths.assets}icons/actors/${docData.type}.svg`;
|
||||
}
|
||||
|
||||
// Some tweak on actors prototypeToken
|
||||
docData.prototypeToken = docData.prototypeToken || {};
|
||||
switch (docData.type) {
|
||||
case "character":
|
||||
foundry.utils.mergeObject(
|
||||
docData.prototypeToken,
|
||||
{
|
||||
// vision: true,
|
||||
// dimSight: 30,
|
||||
// brightSight: 0,
|
||||
actorLink: true,
|
||||
disposition: 1, // friendly
|
||||
bar1: {
|
||||
attribute: "fatigue",
|
||||
},
|
||||
bar2: {
|
||||
attribute: "strife",
|
||||
},
|
||||
},
|
||||
{ overwrite: false }
|
||||
);
|
||||
break;
|
||||
// Only for new actors (New actor has no items, duplicates does)
|
||||
if (!docData.items) {
|
||||
// Some tweak on actors prototypeToken
|
||||
docData.prototypeToken = docData.prototypeToken || {};
|
||||
switch (docData.type) {
|
||||
case "character":
|
||||
// Load skills from core compendiums (only for pc character)
|
||||
docData.items = [];
|
||||
await ActorL5r5e.addSkillsFromCompendiums(docData);
|
||||
|
||||
case "npc":
|
||||
foundry.utils.mergeObject(
|
||||
docData.prototypeToken,
|
||||
{
|
||||
actorLink: true,
|
||||
disposition: 0, // neutral
|
||||
bar1: {
|
||||
attribute: "fatigue",
|
||||
// Set token properties
|
||||
foundry.utils.mergeObject(
|
||||
docData.prototypeToken,
|
||||
{
|
||||
// vision: true,
|
||||
// dimSight: 30,
|
||||
// brightSight: 0,
|
||||
actorLink: true,
|
||||
disposition: 1, // friendly
|
||||
bar1: {
|
||||
attribute: "fatigue",
|
||||
},
|
||||
bar2: {
|
||||
attribute: "strife",
|
||||
},
|
||||
},
|
||||
bar2: {
|
||||
attribute: "strife",
|
||||
},
|
||||
},
|
||||
{ overwrite: false }
|
||||
);
|
||||
break;
|
||||
{ overwrite: false }
|
||||
);
|
||||
break;
|
||||
|
||||
case "army":
|
||||
foundry.utils.mergeObject(
|
||||
docData.prototypeToken,
|
||||
{
|
||||
actorLink: true,
|
||||
disposition: 0, // neutral
|
||||
bar1: {
|
||||
attribute: "battle_readiness.casualties_strength",
|
||||
case "npc":
|
||||
foundry.utils.mergeObject(
|
||||
docData.prototypeToken,
|
||||
{
|
||||
actorLink: true,
|
||||
disposition: 0, // neutral
|
||||
bar1: {
|
||||
attribute: "fatigue",
|
||||
},
|
||||
bar2: {
|
||||
attribute: "strife",
|
||||
},
|
||||
},
|
||||
bar2: {
|
||||
attribute: "battle_readiness.panic_discipline",
|
||||
{ overwrite: false }
|
||||
);
|
||||
break;
|
||||
|
||||
case "army":
|
||||
foundry.utils.mergeObject(
|
||||
docData.prototypeToken,
|
||||
{
|
||||
actorLink: true,
|
||||
disposition: 0, // neutral
|
||||
bar1: {
|
||||
attribute: "battle_readiness.casualties_strength",
|
||||
},
|
||||
bar2: {
|
||||
attribute: "battle_readiness.panic_discipline",
|
||||
},
|
||||
},
|
||||
},
|
||||
{ overwrite: false }
|
||||
);
|
||||
break;
|
||||
{ overwrite: false }
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
await super.create(docData, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all the skills from compendiums to "items"
|
||||
*/
|
||||
static async addSkillsFromCompendiums(docData) {
|
||||
console.log(`L5R5E | Adding skills to ${docData.name}`);
|
||||
|
||||
const packName = CONFIG.l5r5e.systemName + ".core-skills";
|
||||
const skills = await game.l5r5e.HelpersL5r5e.loadCompendium(packName);
|
||||
if (skills.length < 1) {
|
||||
console.log(`L5R5E | No items found in Pack [${packName}]`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the json data and replace the object id
|
||||
skills.forEach(item => {
|
||||
const tmpData = item.toObject();
|
||||
tmpData._id = foundry.utils.randomID();
|
||||
docData.items.push(tmpData);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Entity-specific actions that should occur when the Entity is updated
|
||||
* @override
|
||||
@@ -94,7 +124,7 @@ export class ActorL5r5e extends Actor {
|
||||
context.pack = this.pack;
|
||||
|
||||
// NPC switch between types : Linked actor for Adversary, unlinked for Minion
|
||||
if (!!docData["system.type"] && this.type === "npc" && docData["system.type"] !== this.system.type) {
|
||||
if (!!docData["system.type"] && this.isNpc && docData["system.type"] !== this.system.type) {
|
||||
docData["prototypeToken.actorLink"] = docData["system.type"] === "adversary";
|
||||
}
|
||||
|
||||
@@ -254,12 +284,20 @@ export class ActorL5r5e extends Actor {
|
||||
return this.type === "character";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this actor is a NPC
|
||||
* @return {boolean}
|
||||
*/
|
||||
get isNpc() {
|
||||
return this.type === "npc";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this actor is an Adversary
|
||||
* @return {boolean}
|
||||
*/
|
||||
get isAdversary() {
|
||||
return this.type === "npc" && this.system.type === "adversary";
|
||||
return this.isNpc && this.system.type === "adversary";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -267,7 +305,7 @@ export class ActorL5r5e extends Actor {
|
||||
* @return {boolean}
|
||||
*/
|
||||
get isMinion() {
|
||||
return this.type === "npc" && this.system.type === "minion";
|
||||
return this.isNpc && this.system.type === "minion";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -363,7 +401,7 @@ export class ActorL5r5e extends Actor {
|
||||
if (!this.isCharacterType) {
|
||||
return null;
|
||||
}
|
||||
return this.type === "npc" ? this.system.conflict_rank.social : this.system.identity.school_rank;
|
||||
return this.isNpc ? this.system.conflict_rank.social : this.system.identity.school_rank;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -374,6 +412,6 @@ export class ActorL5r5e extends Actor {
|
||||
if (!this.isCharacterType) {
|
||||
return null;
|
||||
}
|
||||
return this.type === "npc" ? this.system.conflict_rank.martial : this.system.identity.school_rank;
|
||||
return this.isNpc ? this.system.conflict_rank.martial : this.system.identity.school_rank;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,6 +230,10 @@ export class BaseCharacterSheetL5r5e extends BaseSheetL5r5e {
|
||||
itemData = item.toObject(true);
|
||||
break;
|
||||
|
||||
case "skill":
|
||||
itemData.system.rank = 0;
|
||||
break;
|
||||
|
||||
case "technique":
|
||||
// School_ability and mastery_ability, allow only 1 per type
|
||||
if (CONFIG.l5r5e.techniques.get(itemData.system.technique_type)?.type === "school") {
|
||||
|
||||
@@ -98,7 +98,7 @@ export class CharacterGeneratorDialog extends FormApplication {
|
||||
}));
|
||||
return {
|
||||
...(await super.getData(options)),
|
||||
isNpc: this.actor.type === "npc",
|
||||
isNpc: this.actor.isNpc,
|
||||
clanList: [{ id: "random", label: game.i18n.localize("l5r5e.global.random") }, ...clans],
|
||||
genderList: [
|
||||
{ id: "random", label: game.i18n.localize("l5r5e.global.random") },
|
||||
|
||||
@@ -292,7 +292,7 @@ export class CharacterGenerator {
|
||||
}
|
||||
) {
|
||||
const actorDatas = actor.system;
|
||||
const isNpc = actor.type === "npc";
|
||||
const isNpc = actor.isNpc;
|
||||
|
||||
// Need to set some required values
|
||||
this.data.age = actorDatas.identity.age || CharacterGenerator.genAge(this.data.avgRingsValue);
|
||||
|
||||
@@ -47,8 +47,11 @@ export class CharacterSheetL5r5e extends BaseCharacterSheetL5r5e {
|
||||
// Min rank = 1
|
||||
this.actor.system.identity.school_rank = Math.max(1, this.actor.system.identity.school_rank);
|
||||
|
||||
// Split Skills
|
||||
sheetData.data.skillCategories = this._splitSkills(sheetData);
|
||||
|
||||
// Split Money
|
||||
sheetData.data.system.money = this._zeniToMoney(this.actor.system.zeni);
|
||||
sheetData.data.money = this._zeniToMoney(this.actor.system.zeni);
|
||||
|
||||
// Split school advancements by rank, and calculate xp spent and add it to total
|
||||
this._prepareSchoolAdvancement(sheetData);
|
||||
@@ -64,6 +67,28 @@ export class CharacterSheetL5r5e extends BaseCharacterSheetL5r5e {
|
||||
return sheetData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split Skills item by categories
|
||||
* @private
|
||||
*/
|
||||
_splitSkills(sheetData) {
|
||||
const skill = CONFIG.l5r5e.skillCategories.reduce((acc,curr) => (acc[curr] = [], acc), {});
|
||||
|
||||
sheetData.items.forEach((item) => {
|
||||
if (item.type === "skill") {
|
||||
const cat = item.system.category ?? "artisan";
|
||||
skill[cat].push(item);
|
||||
}
|
||||
});
|
||||
|
||||
// Sort Items by name
|
||||
Object.values(skill).forEach(section => {
|
||||
section.sort((a, b) => a.name.localeCompare(b.name));
|
||||
});
|
||||
|
||||
return skill;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to events from the sheet.
|
||||
* @param {jQuery} html HTML content of the sheet.
|
||||
@@ -180,6 +205,12 @@ export class CharacterSheetL5r5e extends BaseCharacterSheetL5r5e {
|
||||
* @param formData
|
||||
*/
|
||||
_updateObject(event, formData) {
|
||||
// Update items ranks
|
||||
const formDataObj = foundry.utils.expandObject(formData);
|
||||
if (formDataObj.skillsValues) {
|
||||
this._updateItemsRank(foundry.utils.expandObject(formDataObj.skillsValues));
|
||||
}
|
||||
|
||||
// Clan tag trim if autocomplete in school name
|
||||
if (
|
||||
formData["autoCompleteListName"] === "system.identity.school" &&
|
||||
@@ -194,16 +225,12 @@ export class CharacterSheetL5r5e extends BaseCharacterSheetL5r5e {
|
||||
}
|
||||
|
||||
// Store money in Zeni
|
||||
if (formData["system.money.koku"] || formData["system.money.bu"] || formData["system.money.zeni"]) {
|
||||
if (formData["money.koku"] || formData["money.bu"] || formData["money.zeni"]) {
|
||||
formData["system.zeni"] = this._moneyToZeni(
|
||||
formData["system.money.koku"] || 0,
|
||||
formData["system.money.bu"] || 0,
|
||||
formData["system.money.zeni"] || 0
|
||||
formData["money.koku"] || 0,
|
||||
formData["money.bu"] || 0,
|
||||
formData["money.zeni"] || 0
|
||||
);
|
||||
// Remove fake money object
|
||||
delete formData["system.money.koku"];
|
||||
delete formData["system.money.bu"];
|
||||
delete formData["system.money.zeni"];
|
||||
}
|
||||
|
||||
// Save computed values
|
||||
@@ -219,6 +246,20 @@ export class CharacterSheetL5r5e extends BaseCharacterSheetL5r5e {
|
||||
return super._updateObject(event, formData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update embedded items ranks
|
||||
* @param {Object<String:String>} itemsValues items new values "ids: rank"
|
||||
*/
|
||||
_updateItemsRank(itemsValues) {
|
||||
Object.entries(itemsValues).forEach(([key, rank]) => {
|
||||
const item = this.actor.items.get(key);
|
||||
if (!item || item.system.rank === rank) {
|
||||
return;
|
||||
}
|
||||
item.update({ "system.rank": rank });
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a sum in Zeni to Zeni, Bu and Koku
|
||||
* @param {number} zeni
|
||||
|
||||
@@ -199,6 +199,6 @@ export class CombatL5r5e extends Combat {
|
||||
* @private
|
||||
*/
|
||||
static _getWeightByActorType(actor) {
|
||||
return actor.type === "npc" ? (actor.type === "minion" ? 3 : 2) : 1;
|
||||
return actor.isNpc ? (actor.type === "minion" ? 3 : 2) : 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,7 +385,7 @@ export class DicePickerDialog extends FormApplication {
|
||||
* @return {boolean}
|
||||
*/
|
||||
get useCategory() {
|
||||
return !!this._actor && this._actor.type === "npc";
|
||||
return !!this._actor && this._actor.isNpc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -91,7 +91,7 @@ export class GmMonitor extends FormApplication {
|
||||
actors = game.actors.filter((e) => ids.includes(e.id));
|
||||
} else {
|
||||
// If empty add pc with owner
|
||||
actors = game.actors.filter((actor) => actor.type === "character" && actor.hasPlayerOwnerActive);
|
||||
actors = game.actors.filter((actor) => actor.isCharacter && actor.hasPlayerOwnerActive);
|
||||
this._saveActorsIds();
|
||||
}
|
||||
|
||||
|
||||
@@ -745,7 +745,7 @@ export class HelpersL5r5e {
|
||||
* @return {Promise<{RollTableDraw}>} The drawn results
|
||||
*/
|
||||
static async drawManyFromPack(pack, tableName, retrieve = 5, opt = { rollMode: "selfroll" }) {
|
||||
const comp = await game.packs.get(pack);
|
||||
const comp = game.packs.get(pack);
|
||||
if (!comp) {
|
||||
console.log(`L5R5E | Pack not found[${pack}]`);
|
||||
return;
|
||||
@@ -760,6 +760,23 @@ export class HelpersL5r5e {
|
||||
return await table.drawMany(retrieve, opt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all compendium data from his id
|
||||
*
|
||||
* @param {String} compendium
|
||||
* @param {Function} filter
|
||||
* @returns {Promise<Item[]>}
|
||||
*/
|
||||
static async loadCompendium(compendium, filter = item => true) {
|
||||
const pack = game.packs.get(compendium);
|
||||
if (!pack) {
|
||||
console.log(`L5R5E | Pack not found[${compendium}]`);
|
||||
return;
|
||||
}
|
||||
const data = (await pack.getDocuments()) ?? [];
|
||||
return data.filter(filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the string simplified for comparaison
|
||||
* @param {string} str
|
||||
|
||||
@@ -6,7 +6,7 @@ export class MigrationL5r5e {
|
||||
* Minimum Version needed for migration stuff to trigger
|
||||
* @type {string}
|
||||
*/
|
||||
static NEEDED_VERSION = "1.3.0";
|
||||
static NEEDED_VERSION = "2.0.0";
|
||||
|
||||
/**
|
||||
* Return true if the version need some updates
|
||||
@@ -28,6 +28,11 @@ export class MigrationL5r5e {
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for translation to load
|
||||
if (!options.force && typeof Babele !== "undefined") {
|
||||
await new Promise((r) => setTimeout(r, 5000));
|
||||
}
|
||||
|
||||
// if (MigrationL5r5e.needUpdate("1.3.0")) {
|
||||
// ChatMessage.create({"content": "<strong>L5R5E v1.3.0 :</strong><br>"});
|
||||
// }
|
||||
@@ -42,7 +47,7 @@ export class MigrationL5r5e {
|
||||
// Migrate World Actors
|
||||
for (let actor of game.actors.contents) {
|
||||
try {
|
||||
const updateData = MigrationL5r5e._migrateActorData(actor, options);
|
||||
const updateData = await MigrationL5r5e._migrateActorData(actor, options);
|
||||
if (!foundry.utils.isEmpty(updateData)) {
|
||||
console.log(`L5R5E | Migrating Actor document ${actor.name}[${actor._id}]`);
|
||||
await actor.update(updateData);
|
||||
@@ -227,7 +232,7 @@ export class MigrationL5r5e {
|
||||
* @param options
|
||||
* @return {Object} The updateData to apply
|
||||
*/
|
||||
static _migrateActorData(actor, options = { force: false }) {
|
||||
static async _migrateActorData(actor, options = { force: false }) {
|
||||
const updateData = {};
|
||||
const system = actor.system;
|
||||
|
||||
@@ -245,7 +250,7 @@ export class MigrationL5r5e {
|
||||
}
|
||||
|
||||
// NPC are now without autostats, we need to save the value
|
||||
if (actor.type === "npc") {
|
||||
if (actor.isNpc) {
|
||||
if (system.endurance < 1) {
|
||||
updateData["system.endurance"] = (Number(system.rings.earth) + Number(system.rings.fire)) * 2;
|
||||
updateData["system.composure"] = (Number(system.rings.earth) + Number(system.rings.water)) * 2;
|
||||
@@ -266,7 +271,7 @@ export class MigrationL5r5e {
|
||||
}
|
||||
|
||||
// NPC have now more than a Strength and a Weakness
|
||||
if (actor.type === "npc" && system.rings_affinities?.strength) {
|
||||
if (actor.isNpc && system.rings_affinities?.strength) {
|
||||
const aff = system.rings_affinities;
|
||||
updateData["system.rings_affinities." + aff.strength.ring] = aff.strength.value;
|
||||
updateData["system.rings_affinities." + aff.weakness.ring] = aff.weakness.value;
|
||||
@@ -278,6 +283,28 @@ export class MigrationL5r5e {
|
||||
}
|
||||
// ***** End of 1.3.0 *****
|
||||
|
||||
// ***** Start of 2.0.0 *****
|
||||
if (options?.force || MigrationL5r5e.needUpdate("2.0.0")) {
|
||||
// Only PC : Convert fixed skills to items list
|
||||
if (actor.isCharacter && Array.from(actor.items).every(i => i.type !== "skill")) {
|
||||
// Add skills items
|
||||
const update = {items: [], name: actor.name};
|
||||
await game.l5r5e.ActorL5r5e.addSkillsFromCompendiums(update);
|
||||
|
||||
// Set actor value
|
||||
update.items.forEach(item => {
|
||||
const skillId = item.flags?.l5r5e?.skillCoreId;
|
||||
const skillCatId = CONFIG.l5r5e.skills.get(skillId);
|
||||
if (skillCatId && system.skills[skillCatId][skillId]) {
|
||||
item.system.rank = system.skills[skillCatId][skillId];
|
||||
}
|
||||
});
|
||||
|
||||
updateData.items = update.items;
|
||||
}
|
||||
}
|
||||
// ***** End of 2.0.0 *****
|
||||
|
||||
return updateData;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ export const PreloadTemplates = async function () {
|
||||
`${tpl}actors/character/inventory.html`,
|
||||
`${tpl}actors/character/narrative.html`,
|
||||
`${tpl}actors/character/rings.html`,
|
||||
`${tpl}actors/character/skill.html`,
|
||||
`${tpl}actors/character/social.html`,
|
||||
`${tpl}actors/character/stance.html`,
|
||||
`${tpl}actors/character/techniques.html`,
|
||||
|
||||
Reference in New Issue
Block a user