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:
Vlyan
2023-01-08 15:12:22 +01:00
parent 1ec9e65ca5
commit 710afd9804
22 changed files with 302 additions and 145 deletions

View File

@@ -96,7 +96,7 @@
"void": "Vide"
},
"sheets": {
"narrative": "Mode Narratif",
"narrative": "Narratif",
"experience": "Expérience",
"family": "Famille",
"region": "Région",

View File

@@ -1,24 +1,24 @@
{"_id":"L5RCoreSkl000001","name":"Composition","permission":{"default":0},"type":"skill","data":{"category":"artisan","description":"","book_reference":"Core Rulebook p.146","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000002","name":"Aesthetics","permission":{"default":0},"type":"skill","data":{"category":"artisan","description":"","book_reference":"Core Rulebook p.146","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000003","name":"Smithing","permission":{"default":0},"type":"skill","data":{"category":"artisan","description":"","book_reference":"Core Rulebook p.149","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000004","name":"Design","permission":{"default":0},"type":"skill","data":{"category":"artisan","description":"","book_reference":"Core Rulebook p.147","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000005","name":"Martial Arts [Melee]","permission":{"default":0},"type":"skill","data":{"category":"martial","description":"","book_reference":"Core Rulebook p.162","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000006","name":"Martial Arts [Ranged]","permission":{"default":0},"type":"skill","data":{"category":"martial","description":"","book_reference":"Core Rulebook p.163","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000007","name":"Martial Arts [Unarmed]","permission":{"default":0},"type":"skill","data":{"category":"martial","description":"","book_reference":"Core Rulebook p.164","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000008","name":"Fitness","permission":{"default":0},"type":"skill","data":{"category":"martial","description":"","book_reference":"Core Rulebook p.162","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000009","name":"Meditation","permission":{"default":0},"type":"skill","data":{"category":"martial","description":"","book_reference":"Core Rulebook p.164","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000010","name":"Tactics","permission":{"default":0},"type":"skill","data":{"category":"martial","description":"","book_reference":"Core Rulebook p.165","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000011","name":"Commerce","permission":{"default":0},"type":"skill","data":{"category":"trade","description":"","book_reference":"Core Rulebook p.167","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000012","name":"Skulduggery","permission":{"default":0},"type":"skill","data":{"category":"trade","description":"","book_reference":"Core Rulebook p.168","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000013","name":"Seafaring","permission":{"default":0},"type":"skill","data":{"category":"trade","description":"","book_reference":"Core Rulebook p.168","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000014","name":"Survival","permission":{"default":0},"type":"skill","data":{"category":"trade","description":"","book_reference":"Core Rulebook p.169","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000015","name":"Labor","permission":{"default":0},"type":"skill","data":{"category":"trade","description":"","book_reference":"Core Rulebook p.167","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000016","name":"Culture","permission":{"default":0},"type":"skill","data":{"category":"scholar","description":"","book_reference":"Core Rulebook p.156","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000017","name":"Government","permission":{"default":0},"type":"skill","data":{"category":"scholar","description":"","book_reference":"Core Rulebook p.156","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000018","name":"Medicine","permission":{"default":0},"type":"skill","data":{"category":"scholar","description":"","book_reference":"Core Rulebook p.157","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000019","name":"Sentiment","permission":{"default":0},"type":"skill","data":{"category":"scholar","description":"","book_reference":"Core Rulebook p.158","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000020","name":"Theology","permission":{"default":0},"type":"skill","data":{"category":"scholar","description":"","book_reference":"Core Rulebook p.158","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000021","name":"Command","permission":{"default":0},"type":"skill","data":{"category":"social","description":"","book_reference":"Core Rulebook p.151","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000022","name":"Courtesy","permission":{"default":0},"type":"skill","data":{"category":"social","description":"","book_reference":"Core Rulebook p.152","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000023","name":"Games","permission":{"default":0},"type":"skill","data":{"category":"social","description":"","book_reference":"Core Rulebook p.153","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000024","name":"Performance","permission":{"default":0},"type":"skill","data":{"category":"social","description":"","book_reference":"Core Rulebook p.154","rank":0},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/skill.svg","effects":[]}
{"_id":"L5RCoreSkl000001","name":"Composition","permission":{"default":0},"type":"skill","data":{"category":"artisan","description":"","book_reference":"Core Rulebook p.146","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"composition"}},"img":"icons/sundries/scrolls/scroll-symbol-circle-white.webp","effects":[]}
{"_id":"L5RCoreSkl000002","name":"Aesthetics","permission":{"default":0},"type":"skill","data":{"category":"artisan","description":"","book_reference":"Core Rulebook p.146","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"aesthetics"}},"img":"systems/l5r5e/assets/icons/techs/kiho.svg","effects":[]}
{"_id":"L5RCoreSkl000003","name":"Smithing","permission":{"default":0},"type":"skill","data":{"category":"artisan","description":"","book_reference":"Core Rulebook p.149","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"smithing"}},"img":"systems/l5r5e/assets/icons/items/item_pattern.svg","effects":[]}
{"_id":"L5RCoreSkl000004","name":"Design","permission":{"default":0},"type":"skill","data":{"category":"artisan","description":"","book_reference":"Core Rulebook p.147","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"design"}},"img":"systems/l5r5e/assets/icons/items/keikogi.svg","effects":[]}
{"_id":"L5RCoreSkl000005","name":"Martial Arts [Melee]","permission":{"default":0},"type":"skill","data":{"category":"martial","description":"","book_reference":"Core Rulebook p.162","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"melee"}},"img":"systems/l5r5e/assets/icons/weapons/katana.svg","effects":[]}
{"_id":"L5RCoreSkl000006","name":"Martial Arts [Ranged]","permission":{"default":0},"type":"skill","data":{"category":"martial","description":"","book_reference":"Core Rulebook p.163","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"ranged"}},"img":"systems/l5r5e/assets/icons/weapons/crossbow.svg","effects":[]}
{"_id":"L5RCoreSkl000007","name":"Martial Arts [Unarmed]","permission":{"default":0},"type":"skill","data":{"category":"martial","description":"","book_reference":"Core Rulebook p.164","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"unarmed"}},"img":"systems/l5r5e/assets/icons/weapons/unarmed.svg","effects":[]}
{"_id":"L5RCoreSkl000008","name":"Fitness","permission":{"default":0},"type":"skill","data":{"category":"martial","description":"","book_reference":"Core Rulebook p.162","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"fitness"}},"img":"icons/skills/melee/maneuver-daggers-paired-orange.webp","effects":[]}
{"_id":"L5RCoreSkl000009","name":"Meditation","permission":{"default":0},"type":"skill","data":{"category":"martial","description":"","book_reference":"Core Rulebook p.164","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"meditation"}},"img":"systems/l5r5e/assets/icons/techs/ritual.svg","effects":[]}
{"_id":"L5RCoreSkl000010","name":"Tactics","permission":{"default":0},"type":"skill","data":{"category":"martial","description":"","book_reference":"Core Rulebook p.165","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"tactics"}},"img":"systems/l5r5e/assets/icons/items/armor.svg","effects":[]}
{"_id":"L5RCoreSkl000011","name":"Commerce","permission":{"default":0},"type":"skill","data":{"category":"trade","description":"","book_reference":"Core Rulebook p.167","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"commerce"}},"img":"icons/skills/trades/baking-bread-rolls-green.webp","effects":[]}
{"_id":"L5RCoreSkl000012","name":"Skulduggery","permission":{"default":0},"type":"skill","data":{"category":"trade","description":"","book_reference":"Core Rulebook p.168","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"skulduggery"}},"img":"icons/skills/social/intimidation-impressing.webp","effects":[]}
{"_id":"L5RCoreSkl000013","name":"Seafaring","permission":{"default":0},"type":"skill","data":{"category":"trade","description":"","book_reference":"Core Rulebook p.168","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"seafaring"}},"img":"icons/skills/trades/profession-sailing-ship.webp","effects":[]}
{"_id":"L5RCoreSkl000014","name":"Survival","permission":{"default":0},"type":"skill","data":{"category":"trade","description":"","book_reference":"Core Rulebook p.169","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"survival"}},"img":"icons/environment/wilderness/camp-improvised.webp","effects":[]}
{"_id":"L5RCoreSkl000015","name":"Labor","permission":{"default":0},"type":"skill","data":{"category":"trade","description":"","book_reference":"Core Rulebook p.167","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"labor"}},"img":"icons/tools/hand/hammer-and-nail.webp","effects":[]}
{"_id":"L5RCoreSkl000016","name":"Culture","permission":{"default":0},"type":"skill","data":{"category":"scholar","description":"","book_reference":"Core Rulebook p.156","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"culture"}},"img":"icons/sundries/documents/document-sealed-signatures-red.webp","effects":[]}
{"_id":"L5RCoreSkl000017","name":"Government","permission":{"default":0},"type":"skill","data":{"category":"scholar","description":"","book_reference":"Core Rulebook p.156","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"government"}},"img":"systems/l5r5e/assets/icons/items/army_fortification.svg","effects":[]}
{"_id":"L5RCoreSkl000018","name":"Medicine","permission":{"default":0},"type":"skill","data":{"category":"scholar","description":"","book_reference":"Core Rulebook p.157","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"medicine"}},"img":"icons/tools/laboratory/bowl-liquid-pink-yellow-green.webp","effects":[]}
{"_id":"L5RCoreSkl000019","name":"Sentiment","permission":{"default":0},"type":"skill","data":{"category":"scholar","description":"","book_reference":"Core Rulebook p.158","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"sentiment"}},"img":"systems/l5r5e/assets/icons/actors/traditional-japanese-woman.svg","effects":[]}
{"_id":"L5RCoreSkl000020","name":"Theology","permission":{"default":0},"type":"skill","data":{"category":"scholar","description":"","book_reference":"Core Rulebook p.158","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"theology"}},"img":"systems/l5r5e/assets/icons/items/blessed.svg","effects":[]}
{"_id":"L5RCoreSkl000021","name":"Command","permission":{"default":0},"type":"skill","data":{"category":"social","description":"","book_reference":"Core Rulebook p.151","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"command"}},"img":"systems/l5r5e/assets/icons/items/army_cohort.svg","effects":[]}
{"_id":"L5RCoreSkl000022","name":"Courtesy","permission":{"default":0},"type":"skill","data":{"category":"social","description":"","book_reference":"Core Rulebook p.152","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"courtesy"}},"img":"systems/l5r5e/assets/icons/social.svg","effects":[]}
{"_id":"L5RCoreSkl000023","name":"Games","permission":{"default":0},"type":"skill","data":{"category":"social","description":"","book_reference":"Core Rulebook p.153","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"games"}},"img":"icons/sundries/gaming/dice-runed-tan.webp","effects":[]}
{"_id":"L5RCoreSkl000024","name":"Performance","permission":{"default":0},"type":"skill","data":{"category":"social","description":"","book_reference":"Core Rulebook p.154","rank":0},"sort":100001,"flags":{"l5r5e":{"skillCoreId":"performance"}},"img":"icons/environment/people/group.webp","effects":[]}

View File

@@ -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;
}
}

View File

@@ -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") {

View File

@@ -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") },

View File

@@ -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);

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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;
}
/**

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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`,

File diff suppressed because one or more lines are too long

View File

@@ -7,6 +7,8 @@
.item {
.item-header {
display: flex;
align-items: center;
.item-img {
flex: 0 0 32px;
padding-right: 0.25rem;

View File

@@ -41,29 +41,63 @@
);
}
ul {
flex: 50%;
padding: 0.25rem 0.5rem 0.25rem 0;
flex: 100%;
padding: 0 0.15rem;
li {
text-align: left;
line-height: 2rem;
margin: 0.25rem 0;
&.skill {
text-align: right;
span {
color: $l5r5e-black;
&[data-skill="melee"],
&[data-skill="ranged"],
&[data-skill="unarmed"] {
float: left;
line-height: 1rem;
width: calc(100% - 2rem);
}
}
&.skill-category-skills-list {
img {
width: 32px;
height: 32px;
object-fit: contain;
object-position: 50% 0;
border: none;
padding: 2px 0;
}
input {
text-align: center;
}
.item-header {
flex: 4;
align-items: center;
h4 {
margin: 0;
}
.item-img {
height: 32px;
margin: 0;
flex: 0 0 32px;
}
.item-rank {
flex: 0 0 32px;
text-align: center;
}
.item-edit,
.item-delete {
text-align: center;
line-height: 1rem;
font-size: 0.75rem;
flex: 0 0 1rem;
padding: 0 0.1rem;
color: $black-light;
}
}
}
&.skill-category-ring-actions {
padding: 0.25rem 0 0.25rem 0.5rem;
border-top: 1px dashed $l5r5e-title;
border-left: 1px solid $l5r5e-title;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-content: center;
justify-content: space-evenly;
}
}
input {

View File

@@ -127,7 +127,7 @@
{{!-- items list --}}
<h2>{{localize 'l5r5e.sheets.equipment'}}</h2>
<ul>
<li>{{localize 'l5r5e.money.title'}} : {{data.system.money.koku}} {{localize 'l5r5e.money.koku'}} / {{data.system.money.bu}} {{localize 'l5r5e.money.bu'}} / {{data.system.money.zeni}} {{localize 'l5r5e.money.zeni'}}</li>
<li>{{localize 'l5r5e.money.title'}} : {{data.money.koku}} {{localize 'l5r5e.money.koku'}} / {{data.money.bu}} {{localize 'l5r5e.money.bu'}} / {{data.money.zeni}} {{localize 'l5r5e.money.zeni'}}</li>
{{#each data.splitItemsList as |cat type|}}
<li>
<strong>{{localize (localize 'l5r5e.{type}s.title' type=type)}} ({{cat.length}})</strong>

View File

@@ -34,8 +34,8 @@
{{!-- Skills Tab --}}
<article class="tab skills" data-group="primary" data-tab="skills">
<ul class="skills-wrapper">
{{#each data.system.skills as |category id|}}
{{> 'systems/l5r5e/templates/actors/character/category.html' category=category categoryId=id data=../data}}
{{#each data.skillCategories as |itemsInCategory id|}}
{{> 'systems/l5r5e/templates/actors/character/category.html' itemsInCategory=itemsInCategory categoryId=id data=../data}}
{{/each}}
</ul>
{{> 'systems/l5r5e/templates/actors/character/techniques.html'}}

View File

@@ -1,8 +1,8 @@
<li class="skill-category-wrapper skill-category-content">
<h4 class="section-header toggle-on-click" data-toggle="toggle-skill-category-{{categoryId}}">{{localizeSkill categoryId 'title'}}</h4>
<ul class="skill-category-skills-list toggle-skill-category-{{categoryId}} {{#ifCond data.storeInfos 'includes' (concat 'toggle-skill-category-' categoryId)}}toggle-hidden{{/ifCond}}">
{{#each category as |skill id|}}
{{> 'systems/l5r5e/templates/actors/character/skill.html' categoryId=../categoryId skill=skill skillId=id data=../data}}
{{#each itemsInCategory as |skill|}}
{{> 'systems/l5r5e/templates/items/skill/skill-entry.html' skill=skill data=../data}}
{{/each}}
</ul>
<ul class="skill-category-ring-actions toggle-skill-category-{{categoryId}} {{#ifCond data.storeInfos 'includes' (concat 'toggle-skill-category-' categoryId)}}toggle-hidden{{/ifCond}}">

View File

@@ -2,7 +2,7 @@
<legend class="section-header">{{localize 'l5r5e.money.title'}}</legend>
<label>
{{localize 'l5r5e.money.koku'}}
<input name="system.money.koku" type="number" value="{{data.system.money.koku}}" data-dtype="Number" min="0" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
<input name="money.koku" type="number" value="{{data.money.koku}}" data-dtype="Number" min="0" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
<span class="money-buttons">
<i class="money-control pointer-choice fa fa-plus-square" data-type="koku" data-value="1"></i>
<i class="money-control pointer-choice fa fa-minus-square" data-type="koku" data-value="-1"></i>
@@ -10,7 +10,7 @@
</label>
<label>
{{localize 'l5r5e.money.bu'}}
<input name="system.money.bu" type="number" value="{{data.system.money.bu}}" data-dtype="Number" min="0" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
<input name="money.bu" type="number" value="{{data.money.bu}}" data-dtype="Number" min="0" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
<span class="money-buttons">
<i class="money-control pointer-choice fa fa-plus-square" data-type="bu" data-value="1"></i>
<i class="money-control pointer-choice fa fa-minus-square" data-type="bu" data-value="-1"></i>
@@ -18,7 +18,7 @@
</label>
<label>
{{localize 'l5r5e.money.zeni'}}
<input name="system.money.zeni" type="number" value="{{data.system.money.zeni}}" data-dtype="Number" min="0" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
<input name="money.zeni" type="number" value="{{data.money.zeni}}" data-dtype="Number" min="0" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
<span class="money-buttons">
<i class="money-control pointer-choice fa fa-plus-square" data-type="zeni" data-value="1"></i>
<i class="money-control pointer-choice fa fa-minus-square" data-type="zeni" data-value="-1"></i>

View File

@@ -1,16 +0,0 @@
<li class="skill skill-wrapper">
<label class="skill-content">
<span class="dice-picker attribute-label rollable" data-skill="{{skillId}}">{{localizeSkill categoryId skillId}}</span>
<input
class="centered-input select-on-focus"
type="number"
name="system.skills.{{categoryId}}.{{skillId}}"
value="{{skill}}"
data-dtype="Number"
min="0"
max="9"
placeholder="0"
{{^if data.editable_not_soft_locked}}disabled{{/if}}
/>
</label>
</li>

View File

@@ -1,10 +1,21 @@
<li class="item skill flexcol" data-item-id="{{skill.id}}">
<ul class="item-header skill-controls">
<ul class="item-header skill-controls flexrow">
<li class="item-img"><img src="{{skill.img}}" title="{{skill.name}}" width="32px" height="32px"/></li>
<li class="item-name l5r5e-tooltip" data-item-id="{{skill.id}}">{{skill.name}}</li>
{{#if editable}}
<li data-item-id="{{skill.id}}" class="item-control item-edit" title="{{localize 'l5r5e.global.edit'}}"><i class="fas fa-edit"></i></li>
<li data-item-id="{{skill.id}}" class="item-control item-delete" title="{{localize 'Delete'}}"><i class="fas fa-trash"></i></li>
<li class="item-name dice-picker attribute-label rollable l5r5e-tooltip" data-item-id="{{skill._id}}" data-skill="{{skill._id}}">{{skill.name}}</li>
<li class="item-rank"><input
class="centered-input select-on-focus"
type="number"
name="skillsValues.{{skill._id}}"
value="{{skill.system.rank}}"
data-dtype="Number"
min="0"
max="9"
placeholder="0"
{{^if data.editable_not_soft_locked}}disabled{{/if}}
/></li>
{{#if data.editable_not_soft_locked}}
<li data-item-id="{{skill._id}}" class="item-control item-edit" title="{{localize 'l5r5e.global.edit'}}"><i class="fas fa-edit"></i></li>
<li data-item-id="{{skill._id}}" class="item-control item-delete" title="{{localize 'Delete'}}"><i class="fas fa-trash"></i></li>
{{/if}}
</ul>
</li>