Skip to content

Commit

Permalink
feat: traits are now active effects
Browse files Browse the repository at this point in the history
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 xdy#272
  • Loading branch information
jonepatr committed Jan 3, 2022
1 parent 59fe505 commit c735dc4
Show file tree
Hide file tree
Showing 20 changed files with 272 additions and 59 deletions.
21 changes: 21 additions & 0 deletions src/migrations/2022_01_03_05_08_25_active-effects-for-traits.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
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) {
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<void> {
const tokenActor = game.scenes?.reduce((memo: TokenDocument[], scene: Scene) => memo.concat(scene.tokens.contents), [])
.filter((token: TokenDocument) => token.actor?.type === "traveller" && !token.data.actorLink)
.map((token: TokenDocument) => token.actor);
await game.actors?.filter(actor => actor.type === "traveller").reduce(applyActiveEffects, Promise.resolve());
await tokenActor?.reduce(applyActiveEffects, Promise.resolve());
}
13 changes: 12 additions & 1 deletion src/module/entities/TwodsixActor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Weapon = dataTwodsix.Weapon;
import Gear = dataTwodsix.Gear;
import Traveller = dataTwodsix.Traveller;
import Skills = dataTwodsix.Skills;
import Trait = dataTwodsix.Trait;
import Characteristic = dataTwodsix.Characteristic;

export default class TwodsixActor extends Actor {
Expand Down Expand Up @@ -73,7 +74,17 @@ export default class TwodsixActor extends Actor {
data.skills = new Proxy(Object.fromEntries(actorSkills), handler);
}

protected async _onCreate() {
_onUpdateEmbeddedDocuments(embeddedName:string, documents): void {
if (embeddedName === "ActiveEffect") {
(<ActiveEffect[]>documents).forEach((element:ActiveEffect) => {
const item = <TwodsixItem>(<TwodsixActor>element.parent)?.items.find((itm:TwodsixItem) => (<Trait>itm.data.data).effectId === element.id);
item?.update({"data.changes": element.data.changes});
});
}
this.render();
}

protected async _onCreate(): Promise<void> {
switch (this.data.type) {
case "traveller":
await this.createUntrainedSkill();
Expand Down
5 changes: 5 additions & 0 deletions src/module/entities/TwodsixItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,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(gear: Gear = <Gear>this.data.data): void {
Expand Down
12 changes: 6 additions & 6 deletions src/module/handlebars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,20 +179,20 @@ 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:string, array:TwodsixItem[], options) => {
let sortedArray: TwodsixItem[] = [];
const slice: TwodsixItem[] = <TwodsixItem[]>array?.slice(0);
const slice = array?.slice(0);
if (slice) {
sortedArray = slice.sort((a, b) => {
if (a.name == null) {
if (a[property] == null) {
return 1;
} else {
if (b.name == null) {
if (b[property] == null) {
return -1;
} else if (a.name === b.name) {
} else if (a[property] === b[property]) {
return 0;
} else {
return a.name?.toLocaleLowerCase().localeCompare(b.name?.toLocaleLowerCase());
return a[property]?.toLocaleLowerCase().localeCompare(b[property]?.toLocaleLowerCase());
}
}
});
Expand Down
31 changes: 23 additions & 8 deletions src/module/sheets/AbstractTwodsixActorSheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import TwodsixItem from "../entities/TwodsixItem";
import { getDataFromDropEvent, getItemDataFromDropData } from "../utils/sheetUtils";
import Armor = dataTwodsix.Armor;
import Skills = dataTwodsix.Skills;
import Trait = dataTwodsix.Trait;
import UsesConsumables = dataTwodsix.UsesConsumables;
import TwodsixActor from "../entities/TwodsixActor";

Expand Down Expand Up @@ -45,7 +46,7 @@ export abstract class AbstractTwodsixActorSheet extends ActorSheet {
title: title,
content: template,
yes: async () => {
// somehow on hooks isn't wokring when a consumable is deleted - force the issue
// somehow on hooks isn't working when a consumable is deleted - force the issue
if (ownedItem.type === "consumable") {
this.actor.items.filter(i => i.type !== "skills").forEach(i => {
const usesConsumables:UsesConsumables = <UsesConsumables>i.data.data;
Expand Down Expand Up @@ -140,13 +141,19 @@ 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, <string>type);

// Finally, create the item!
await this.actor.createEmbeddedDocuments("Item", [itemData]);
const items = <TwodsixItem[]>await this.actor.createEmbeddedDocuments("Item", [itemData]);

if (type === "trait") {
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});
}
}


Expand Down Expand Up @@ -243,10 +250,18 @@ export abstract class AbstractTwodsixActorSheet extends ActorSheet {
itemData.data.skill = actor.items.getName(itemData.data.associatedSkillName)?.data._id;
}

// 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 = <TwodsixItem[]>await this._onDropItemCreate(itemData);

if (items[0].type === "trait") {
const effects = await actor.createEmbeddedDocuments("ActiveEffect", [{
origin: items[0].uuid,
icon: "systems/twodsix/assets/icons/science.svg",
changes: (<Trait>items[0].data.data).changes
}]);
await items[0].update({"data.effectId": effects[0].id});
actor.render();
}
return items;
}

private static _getWeight(item): number{
Expand Down
12 changes: 12 additions & 0 deletions src/module/sheets/TwodsixActorSheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,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;
Expand Down Expand Up @@ -95,8 +101,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): TwodsixItem {
const itemId = $(event.currentTarget).parents('.item').data('item-id');
Expand Down
64 changes: 58 additions & 6 deletions src/module/sheets/TwodsixItemSheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { AbstractTwodsixItemSheet } from "./AbstractTwodsixItemSheet";
import { TWODSIX } from "../config";
import TwodsixItem from "../entities/TwodsixItem";
import { getDataFromDropEvent, getItemDataFromDropData } from "../utils/sheetUtils";
import Trait = dataTwodsix.Trait;

/**
* Extend the basic ItemSheet with some very simple modifications
Expand Down Expand Up @@ -31,7 +32,7 @@ export class TwodsixItemSheet extends AbstractTwodsixItemSheet {
/** @override */
getData(): ItemSheet {
const data = super.getData();
data.actor = data.data;
data.actor = this.item.actor;

(<TwodsixItem>this.item).prepareConsumable();
// Add relevant data from system settings
Expand All @@ -46,6 +47,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;
}

Expand Down Expand Up @@ -75,19 +82,64 @@ 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 getConsumable(event) {
const li = $(event.currentTarget).parents(".consumable");
return this.item.actor?.items.get(li.data("consumableId"));
private _onEditEffect(event:Event): void {
if (event.currentTarget) {
const effect = (<TwodsixActor>this.actor).effects.get($(event.currentTarget).data('effectId'));
effect?.sheet.render(true);
}
}

private _onDeleteChange(event:Event): void {
if (event.currentTarget) {
const idx = parseInt($(event.currentTarget).data("index"), 10);
const changes = (<Trait>this.item.data.data).changes.filter((_, i) => i !== idx);
this.item.update({"data.changes": changes});
}
}

private _onEditChange(event:Event) : void{
if (event.currentTarget) {
const idx = parseInt($(event.currentTarget).parents(".change-row").data("change-index"), 10);
const changes = (<Trait>this.item.data.data).changes;
const type:string = $(event.currentTarget).data("type");
if (!isNaN(idx) && type) {
const val = $(event.currentTarget).val() as string;
changes[idx][type] = type === "mode" ? parseInt(val, 10) : val;
this.item.update({"data.changes": changes});
}
}
}

private _onCreateChange(): void {
const changes = (<Trait>this.item.data.data).changes ?? [];
this.item.update({"data.changes": changes.concat({key: "", value: "", mode: 0})});
}

private getConsumable(event:Event):TwodsixItem | undefined {
if (event.currentTarget) {
const li = $(event.currentTarget).parents(".consumable");
return <TwodsixItem>(this.item).actor?.items.get(li.data("consumableId"));
} else {
return undefined;
}
}

private _onEditConsumable(event): void {
private _onEditConsumable(event:Event): void {
this.getConsumable(event)?.sheet?.render(true);
}

private async _onDeleteConsumable(event): Promise<void> {
private async _onDeleteConsumable(event:Event): Promise<void> {
const consumable = this.getConsumable(event);
if (!consumable) {
(<TwodsixItem>this.item).removeConsumable(""); //TODO Should have await?
Expand Down
2 changes: 1 addition & 1 deletion src/scripts/create-migration.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ const date = (new Date(temporaryDate.toUTCString())).toISOString().replace(/[:_t
const templateString = 'export async function migrate():Promise<void> {\n\n}';

fs.writeFileSync(`src/migrations/${date}-${migrationName}.ts`, templateString);
console.log(`Succesfully created migration: src/migrations/${date}-${migrationName}.ts`);
console.log(`Successfully created migration: src/migrations/${date}-${migrationName}.ts`);
8 changes: 8 additions & 0 deletions src/types/template.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,12 @@ declare namespace dataTwodsix {
weight: number;
}

export interface TraitChange {
mode: number;
key: string;
value: string;
}

export interface Trait {
templates: string[];
value: number;
Expand All @@ -397,6 +403,8 @@ declare namespace dataTwodsix {
subtype: string;
reference: string;
key: string;
changes: TraitChange[];
effectId: string;
}

export interface Weapon extends GearTemplate {
Expand Down
12 changes: 11 additions & 1 deletion static/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,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"
Expand Down
13 changes: 11 additions & 2 deletions static/styles/twodsix.css
Original file line number Diff line number Diff line change
Expand Up @@ -765,9 +765,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 {
Expand Down
14 changes: 12 additions & 2 deletions static/styles/twodsix_basic.css
Original file line number Diff line number Diff line change
Expand Up @@ -516,9 +516,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 {
Expand Down Expand Up @@ -1458,6 +1467,7 @@ button.flexrow.flex-group-center.toggle-skills {
text-shadow: 0 0 5px /*var(--default-color);
}*/


.item-type {
position: relative;
float: right;
Expand Down
3 changes: 2 additions & 1 deletion static/template.json
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,8 @@
"shortdescr": "",
"subtype": "",
"reference": "",
"key": "key"
"effectId": "",
"changes": []
},
"consumable": {
"templates": ["gearTemplate"],
Expand Down
Loading

0 comments on commit c735dc4

Please sign in to comment.