From 745c3ae8b4fd3063ae53347814a585b66bc20b8e Mon Sep 17 00:00:00 2001 From: Patrik Jonell Date: Sun, 26 Dec 2021 09:39:27 -0500 Subject: [PATCH] feature: traits are now active effects Previsouly adding a trait did not affect the actor. This change makes it so that a trait is an active effect and can change the actor. Fix #272 --- rollup.config.js | 2 +- ...2_29_05_08_25_active-effects-for-traits.ts | 25 ++++++++++ src/module/entities/TwodsixActor.ts | 10 ++++ src/module/entities/TwodsixItem.ts | 5 ++ src/module/handlebars.ts | 4 +- .../sheets/AbstractTwodsixActorSheet.ts | 27 +++++++++-- src/module/sheets/TwodsixActorSheet.ts | 12 +++++ src/module/sheets/TwodsixItemSheet.ts | 40 +++++++++++++++- src/scripts/create_migration.ts | 5 +- static/lang/en.json | 12 ++++- static/styles/twodsix.css | 13 ++++- static/styles/twodsix_basic.css | 14 +++++- static/template.json | 3 +- .../actors/parts/actor/actor-info.html | 41 ++++++++++------ .../actors/parts/actor/actor-items.html | 16 +++---- .../actors/parts/actor/actor-skills.html | 4 +- .../parts/ship/ship-components-double.html | 4 +- .../parts/ship/ship-components-single.html | 4 +- .../actors/parts/ship/ship-storage.html | 4 +- static/templates/items/trait-sheet.html | 48 +++++++++++++++++++ 20 files changed, 245 insertions(+), 48 deletions(-) create mode 100644 src/migrations/2021_12_29_05_08_25_active-effects-for-traits.ts diff --git a/rollup.config.js b/rollup.config.js index 923e52baa..4b88eda7f 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -13,7 +13,7 @@ module.exports = { plugins: [ nodeResolve(), commonjs(), - esbuild({ + esbuild.default({ include: /\.[jt]sx?$/, // TODO Might have to include d.ts here sourceMap: true, minify: process.env.NODE_ENV === 'production', diff --git a/src/migrations/2021_12_29_05_08_25_active-effects-for-traits.ts b/src/migrations/2021_12_29_05_08_25_active-effects-for-traits.ts new file mode 100644 index 000000000..e68ffae7d --- /dev/null +++ b/src/migrations/2021_12_29_05_08_25_active-effects-for-traits.ts @@ -0,0 +1,25 @@ +async function applyActiveEffects(p, actor) { + await p; + return Promise.all(actor.items.filter(item => item.type === "trait").map(async item => { + if (!item.data.data.effectId) { + //@ts-ignore + const effects = await actor.createEmbeddedDocuments("ActiveEffect", [{ + origin: item.uuid, + icon: "systems/twodsix/assets/icons/science.svg" + }]); + await item.update({ "data.effectId": effects[0].id }); + } + return Promise.resolve(); + })); +} + +export async function migrate(): Promise { + const tokenActor = game.scenes + //@ts-ignore + .reduce((memo, scene) => memo.concat(scene.tokens.contents), []) + .filter(s => s.actor.type === "traveller" && !s.data.actorLink) + .map(token => token._actor); + //@ts-ignore + await game.actors.filter(actor => actor.type === "traveller").reduce(applyActiveEffects, Promise.resolve()); + await tokenActor.reduce(applyActiveEffects, Promise.resolve()); +} diff --git a/src/module/entities/TwodsixActor.ts b/src/module/entities/TwodsixActor.ts index d61613b13..1871dee1c 100644 --- a/src/module/entities/TwodsixActor.ts +++ b/src/module/entities/TwodsixActor.ts @@ -47,6 +47,16 @@ export default class TwodsixActor extends Actor { } } + _onUpdateEmbeddedDocuments(embeddedName, documents, result, options, userId) { + if (embeddedName === "ActiveEffect") { + documents.forEach(element => { + const item = element.parent.items.find(itm => itm.data.data.effectId === element.id); + item.update({"data.changes": element.data.changes}); + }); + } + this.render(); + } + protected async _onCreate(data, options, user) { switch (this.data.type) { case "traveller": diff --git a/src/module/entities/TwodsixItem.ts b/src/module/entities/TwodsixItem.ts index 0e0535ebd..d142bf721 100644 --- a/src/module/entities/TwodsixItem.ts +++ b/src/module/entities/TwodsixItem.ts @@ -25,6 +25,11 @@ export default class TwodsixItem extends Item { if (this.getFlag("twodsix", "untrainedSkill")) { this.data.name = game.i18n.localize("TWODSIX.Actor.Skills.Untrained"); } + + if (this.data.data.effectId && this.actor?.data) { + const effect = this.actor.effects.get(this.data.data.effectId); + this.data.data.effect = effect; + } } prepareConsumable(): void { diff --git a/src/module/handlebars.ts b/src/module/handlebars.ts index 656239d14..a11162dfe 100644 --- a/src/module/handlebars.ts +++ b/src/module/handlebars.ts @@ -182,9 +182,9 @@ export default function registerHandlebarsHelpers():void { Handlebars.registerHelper("concat", (...args) => args.slice(0, args.length - 1).join('')); - Handlebars.registerHelper('each_sort_by_name', (array, options) => { + Handlebars.registerHelper('each_sort_by_property', (property, array, options) => { const sortedArray = array?.slice(0).sort((a:TwodsixItem, b:TwodsixItem) => { - const aName = a.name.toLowerCase(), bName = b.name.toLowerCase(); + const aName = a[property].toLowerCase(), bName = b[property].toLowerCase(); return (aName > bName) ? 1 : ((bName > aName) ? -1 : 0); }); return Handlebars.helpers.each(sortedArray, options); diff --git a/src/module/sheets/AbstractTwodsixActorSheet.ts b/src/module/sheets/AbstractTwodsixActorSheet.ts index 61add2ff8..15ab381a2 100644 --- a/src/module/sheets/AbstractTwodsixActorSheet.ts +++ b/src/module/sheets/AbstractTwodsixActorSheet.ts @@ -140,14 +140,21 @@ export abstract class AbstractTwodsixActorSheet extends ActorSheet { type, data }; - // Remove the type from the dataset since it's in the itemData.type prop. // delete itemData.data.type; this.updateWithItemSpecificValues(itemData, type); - // Finally, create the item! // @ts-ignore - await this.actor.createEmbeddedDocuments("Item", [itemData]); + const items = await this.actor.createEmbeddedDocuments("Item", [itemData]); + + if (type === "trait") { + // @ts-ignore + const effects = await this.actor.createEmbeddedDocuments("ActiveEffect", [{ + origin: items[0].uuid, + icon: "systems/twodsix/assets/icons/science.svg" + }]); + items[0].update({"data.effectId": effects[0].id}); + } } @@ -258,7 +265,19 @@ export abstract class AbstractTwodsixActorSheet extends ActorSheet { // Create the owned item (TODO Add to type and remove the two lines below...) // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - return this._onDropItemCreate(itemData); + const items = await this._onDropItemCreate(itemData); + + if (items[0].type === "trait") { + // @ts-ignore + const effects = await actor.createEmbeddedDocuments("ActiveEffect", [{ + origin: items[0].uuid, + icon: "systems/twodsix/assets/icons/science.svg", + changes: items[0].data.data.changes + }]); + await items[0].update({"data.effectId": effects[0].id}); + actor.render(); + } + return items; } private static _getWeight(item): number{ diff --git a/src/module/sheets/TwodsixActorSheet.ts b/src/module/sheets/TwodsixActorSheet.ts index 32a31aba2..674b88e38 100644 --- a/src/module/sheets/TwodsixActorSheet.ts +++ b/src/module/sheets/TwodsixActorSheet.ts @@ -43,6 +43,12 @@ export class TwodsixActorSheet extends AbstractTwodsixActorSheet { showLifebloodStamina: game.settings.get("twodsix", "showLifebloodStamina"), showHeroPoints: game.settings.get("twodsix", "showHeroPoints") }; + + data.ACTIVE_EFFECT_MODES = Object.entries(CONST.ACTIVE_EFFECT_MODES).reduce((ret, entry) => { + const [ key, value ] = entry; + ret[ value ] = key; + return ret; + }, {}); data.config = TWODSIX; return data; @@ -93,8 +99,14 @@ export class TwodsixActorSheet extends AbstractTwodsixActorSheet { html.find(".item-value-edit").on("click", (event) => { $(event.currentTarget).trigger("select"); }); + + html.find(".effect-edit").on("click", this._onTraitEdit.bind(this)); } + private _onTraitEdit(event) { + const effect = this.actor.effects.get($(event.currentTarget).data('effectId')); + effect.sheet.render(true); + } private getItem(event:Event):TwodsixItem { const itemId = $(event.currentTarget).parents('.item').data('item-id'); diff --git a/src/module/sheets/TwodsixItemSheet.ts b/src/module/sheets/TwodsixItemSheet.ts index 110e94232..2fb33466d 100644 --- a/src/module/sheets/TwodsixItemSheet.ts +++ b/src/module/sheets/TwodsixItemSheet.ts @@ -34,8 +34,7 @@ export class TwodsixItemSheet extends AbstractTwodsixItemSheet { // @ts-ignore getData():ItemSheetData { const data = super.getData(); - const actorData = data.data; - data.actor = actorData; + data.actor = this.item.actor; // @ts-ignore this.item.prepareConsumable(); @@ -51,6 +50,12 @@ export class TwodsixItemSheet extends AbstractTwodsixItemSheet { }; data.data.config = TWODSIX; data.data.isOwned = this.item.isOwned; + + data.ACTIVE_EFFECT_MODES = Object.entries(CONST.ACTIVE_EFFECT_MODES).reduce((ret, entry) => { + const [ key, value ] = entry; + ret[ value ] = key; + return ret; + }, {}); return data; } @@ -81,9 +86,40 @@ export class TwodsixItemSheet extends AbstractTwodsixItemSheet { html.find('.consumable-edit').on('click', this._onEditConsumable.bind(this)); html.find('.consumable-delete').on('click', this._onDeleteConsumable.bind(this)); html.find('.consumable-use-consumable-for-attack').on('change', this._onChangeUseConsumableForAttack.bind(this)); + + //change-row + html.find('.change-row input, .change-row select').on('change', this._onEditChange.bind(this)); + html.find('.change-create').on('click', this._onCreateChange.bind(this)); + html.find('.change-delete').on('click', this._onDeleteChange.bind(this)); + + html.find(".effect-edit").on("click", this._onEditEffect.bind(this)); + this.handleContentEditable(html); } + private _onEditEffect(event) { + const effect = this.actor.effects.get($(event.currentTarget).data('effectId')); + effect.sheet.render(true); + } + + private _onDeleteChange(event:Event) { + const idx = parseInt($(event.currentTarget).data("index"), 10); + const changes = this.item.data.data.changes.filter((_, i) => i !== idx); + this.item.update({"data.changes": changes}); + } + + private _onEditChange(event:Event) { + const idx = $(event.currentTarget).parents(".change-row").data("change-index"); + const changes = this.item.data.data.changes; + changes[parseInt(idx, 10)][$(event.currentTarget).data("type")] = $(event.currentTarget).val(); + this.item.update({"data.changes": changes}); + } + + private _onCreateChange(event:Event) { + const changes = this.item.data.data.changes ?? []; + this.item.update({"data.changes": changes.concat({key: "", value: "", mode: 0})}); + } + private getConsumable(event:Event):TwodsixItem { const li = $(event.currentTarget).parents(".consumable"); // @ts-ignore diff --git a/src/scripts/create_migration.ts b/src/scripts/create_migration.ts index af89a7061..d1bb72e08 100644 --- a/src/scripts/create_migration.ts +++ b/src/scripts/create_migration.ts @@ -1,4 +1,5 @@ -import fs from 'fs'; +/* eslint-disable @typescript-eslint/no-var-requires */ +const fs = require("fs"); const migrationName = process.argv[2]; if (!migrationName) { @@ -7,7 +8,7 @@ if (!migrationName) { } const tmpDate = new Date(); -const date = (new Date(tmpDate.toUTCString())).toISOString().replaceAll(/-|:|T/ig, "_").split(".")[0]; +const date = (new Date(tmpDate.toUTCString())).toISOString().replace(/-|:|T/ig, "_").split(".")[0]; const templateString = "export async function migrate():Promise {\n\n}"; diff --git a/static/lang/en.json b/static/lang/en.json index 47d2e4a8f..9f78ad483 100644 --- a/static/lang/en.json +++ b/static/lang/en.json @@ -230,7 +230,17 @@ }, "Traits": { "Prerequisite": "Prerequisite", - "TraitName": "Trait Name" + "TraitName": "Trait Name", + "AttributeKey": "Attribute Key", + "ChangeMode": "Change Mode", + "EffectValue": "Effect Value", + "CreateEffect": "Create Effect", + "DeleteEffect": "Delete Effect", + "EditEffects": "Edit Effects", + "EditEffect": "Edit Effect", + "Effects": "Effects", + "CreateTrait": "Create Trait", + "DeleteTrait": "Delete Trait" }, "Tool": { "Bonus": "Bonus" diff --git a/static/styles/twodsix.css b/static/styles/twodsix.css index 4e1e4ff50..29a6adbb5 100644 --- a/static/styles/twodsix.css +++ b/static/styles/twodsix.css @@ -757,9 +757,18 @@ a.notes-tab.active { .items-traits { display: grid; - grid-template-columns: 14em 2em 14em 3em; + grid-template-columns: 7em 22em 4em; gap: 1px 1px; - grid-template-areas: '. . . .'; + grid-template-areas: '. . .'; +} + +.trait-name { + display: inline-flex; + align-items: center; +} + +.effect-edit { + width: 150%; } .items-consumable { diff --git a/static/styles/twodsix_basic.css b/static/styles/twodsix_basic.css index f97a2bcf8..9660db2cf 100644 --- a/static/styles/twodsix_basic.css +++ b/static/styles/twodsix_basic.css @@ -512,9 +512,18 @@ a.skill-tab.active, a.item-tab.active, a.finances-tab.active, a.info-tab.active, .items-traits { display: grid; - grid-template-columns: 14em 2em 14em 3em; + grid-template-columns: 7em 22em 4em; gap: 1px 1px; - grid-template-areas: '. . . .'; + grid-template-areas: '. . .'; +} + +.trait-name { + display: inline-flex; + align-items: center; +} + +.effect-edit { + width: 150%; } .items-consumable { @@ -1453,6 +1462,7 @@ button.flexrow.flex-group-center.toggle-skills { text-shadow: 0 0 5px /*var(--default-color); }*/ + .item-type { position: relative; float: right; diff --git a/static/template.json b/static/template.json index da05f4464..6ba4abecf 100644 --- a/static/template.json +++ b/static/template.json @@ -411,7 +411,8 @@ "shortdescr": "", "subtype": "", "reference": "", - "key": "key" + "effectId": "", + "changes": [] }, "consumable": { "templates": ["gearTemplate"], diff --git a/static/templates/actors/parts/actor/actor-info.html b/static/templates/actors/parts/actor/actor-info.html index de8ce408e..dc1e56f33 100644 --- a/static/templates/actors/parts/actor/actor-info.html +++ b/static/templates/actors/parts/actor/actor-info.html @@ -2,32 +2,43 @@
{{localize "TWODSIX.Actor.Items.TRAITS"}}
- {{localize "TWODSIX.Actor.Items.Name"}} - {{localize "TWODSIX.Actor.Skills.Level"}} - {{localize "TWODSIX.Actor.Items.ShortDescr"}} - + {{localize "TWODSIX.Items.Traits.TraitName"}} + {{localize "TWODSIX.Items.Traits.Effects"}} + + + + +
- - {{#each_sort_by_name data.traits as |item id|}} + {{#each_sort_by_property "name" data.traits as |item|}}
  1. - {{item.name}} - {{item.data.data.value}} - {{item.data.data.shortdescr}} + {{item.name}} + +
      + {{#each item.data.data.effect.data.changes as |change|}} +
    • {{change.key}} {{lookup @root.ACTIVE_EFFECT_MODES change.mode}} {{change.value}}
    • + {{/each}} +
    +
    - - + + + + + + + + +
- {{/each_sort_by_name}} + {{/each_sort_by_property}}
diff --git a/static/templates/actors/parts/actor/actor-items.html b/static/templates/actors/parts/actor/actor-items.html index 24bb97c94..ba3b98cde 100644 --- a/static/templates/actors/parts/actor/actor-items.html +++ b/static/templates/actors/parts/actor/actor-items.html @@ -15,7 +15,7 @@
- {{#each_sort_by_name data.weapon as |item id|}} + {{#each_sort_by_property "name" data.weapon as |item id|}}
  1. @@ -60,7 +60,7 @@ {{> "systems/twodsix/templates/actors/parts/actor/actor-consumable.html" consumableData}} {{/each}}
- {{/each_sort_by_name}} + {{/each_sort_by_property}} @@ -78,7 +78,7 @@ - {{#each_sort_by_name data.armor as |item id|}} + {{#each_sort_by_property "name" data.armor as |item id|}}
  1. @@ -101,7 +101,7 @@ {{> "systems/twodsix/templates/actors/parts/actor/actor-consumable.html" consumableData}} {{/each}}
- {{/each_sort_by_name}} + {{/each_sort_by_property}} @@ -118,7 +118,7 @@ class="fas fa-plus"> - {{#each_sort_by_name data.augment as |item id|}} + {{#each_sort_by_property "name" data.augment as |item id|}}
  1. @@ -140,7 +140,7 @@ {{> "systems/twodsix/templates/actors/parts/actor/actor-consumable.html" consumableData}} {{/each}}
- {{/each_sort_by_name}} + {{/each_sort_by_property}} @@ -156,7 +156,7 @@ class="fas fa-plus"> - {{#each_sort_by_name data.equipment as |item id|}} + {{#each_sort_by_property "name" data.equipment as |item id|}}
  1. @@ -178,7 +178,7 @@ {{> "systems/twodsix/templates/actors/parts/actor/actor-consumable.html" consumableData}} {{/each}}
- {{/each_sort_by_name}} + {{/each_sort_by_property}} diff --git a/static/templates/actors/parts/actor/actor-skills.html b/static/templates/actors/parts/actor/actor-skills.html index 77f4bdfc3..54a333171 100644 --- a/static/templates/actors/parts/actor/actor-skills.html +++ b/static/templates/actors/parts/actor/actor-skills.html @@ -29,7 +29,7 @@ -{{#each_sort_by_name data.skills as |item id|}} +{{#each_sort_by_property "name" data.skills as |item id|}} {{#if (twodsix_hideUntrainedSkills item.data.data.value)}} {{else}} @@ -57,7 +57,7 @@ {{/if}} {{/if}} -{{/each_sort_by_name}} +{{/each_sort_by_property}} {{#if (twodsix_hideUntrainedSkills -1)}}
diff --git a/static/templates/actors/parts/ship/ship-components-double.html b/static/templates/actors/parts/ship/ship-components-double.html index 9c0f11924..192037b6e 100644 --- a/static/templates/actors/parts/ship/ship-components-double.html +++ b/static/templates/actors/parts/ship/ship-components-double.html @@ -21,7 +21,7 @@
- {{#each_sort_by_name data.component as |item id|}} + {{#each_sort_by_property "name" data.component as |item id|}}
  1. @@ -50,6 +50,6 @@
- {{/each_sort_by_name}} + {{/each_sort_by_property}}
diff --git a/static/templates/actors/parts/ship/ship-components-single.html b/static/templates/actors/parts/ship/ship-components-single.html index b2a953d62..2116b9c2e 100644 --- a/static/templates/actors/parts/ship/ship-components-single.html +++ b/static/templates/actors/parts/ship/ship-components-single.html @@ -17,7 +17,7 @@
- {{#each_sort_by_name data.component as |item id|}} + {{#each_sort_by_property "name" data.component as |item id|}}
  1. @@ -51,6 +51,6 @@
- {{/each_sort_by_name}} + {{/each_sort_by_property}}
diff --git a/static/templates/actors/parts/ship/ship-storage.html b/static/templates/actors/parts/ship/ship-storage.html index a12d5c5e0..77759030f 100644 --- a/static/templates/actors/parts/ship/ship-storage.html +++ b/static/templates/actors/parts/ship/ship-storage.html @@ -21,7 +21,7 @@
- {{#each_sort_by_name data.storage as |item id|}} + {{#each_sort_by_property "name" data.storage as |item id|}}
  1. @@ -39,6 +39,6 @@
- {{/each_sort_by_name}} + {{/each_sort_by_property}}
diff --git a/static/templates/items/trait-sheet.html b/static/templates/items/trait-sheet.html index 2fe59424f..9d062ed1b 100644 --- a/static/templates/items/trait-sheet.html +++ b/static/templates/items/trait-sheet.html @@ -17,6 +17,54 @@ + + + + + + + + + + + {{#each data.changes as |change|}} + + {{#if ../actor}} + + + + + {{else}} + + + + + {{/if}} + + {{/each}} + +
{{localize "TWODSIX.Items.Traits.AttributeKey"}}{{localize "TWODSIX.Items.Traits.Mode"}}{{localize "TWODSIX.Items.Traits.EffectValue"}} + {{#unless actor}} + + + {{/unless}} +
{{change.key}}{{lookup @root.ACTIVE_EFFECT_MODES change.mode}}{{change.value}} + + + + +
+ {{#if actor}} + + {{/if}}