From 22dacad1204c162b0faf9f468b6363c3f745d91f Mon Sep 17 00:00:00 2001 From: mclemente Date: Sat, 21 Aug 2021 23:38:30 -0300 Subject: [PATCH] PF1 and Starfinder support --- module/SystemProvider.js | 208 ++++++++++++++++++++++++++++++++- module/api.js | 8 +- module/logic.js | 2 +- party-overview.js | 2 +- style/party-overview.css | 5 - templates/generic.hbs | 28 +++++ templates/parts/Languages.html | 4 +- templates/parts/PF2e-Lore.html | 4 +- templates/pf1.hbs | 89 ++++++++++++++ templates/pf2e.hbs | 32 ++--- templates/sfrpg.hbs | 80 +++++++++++++ templates/wfrp4e.hbs | 2 +- 12 files changed, 434 insertions(+), 30 deletions(-) create mode 100644 templates/generic.hbs create mode 100644 templates/pf1.hbs create mode 100644 templates/sfrpg.hbs diff --git a/module/SystemProvider.js b/module/SystemProvider.js index 42dc036..8ed02a4 100644 --- a/module/SystemProvider.js +++ b/module/SystemProvider.js @@ -7,18 +7,31 @@ export class SystemProvider { this.id = id } + get customCSS() { + return []; + } + get loadTemplates() { return []; } get template() { - throw new Error("A SystemProvider must implement the template function"); + return "/modules/party-overview/templates/generic.hbs" } get width() { return 500; } + getActorDetails(actor) { + const data = actor.data.data; + return { + id: actor.id, + name: actor.name, + hp: data.attributes?.hp || data.hp + } + } + getUpdate(actors) { return [actors, {}] } @@ -144,6 +157,102 @@ export class dnd5eProvider extends SystemProvider { } } +export class pf1Provider extends SystemProvider { + get loadTemplates() { + return [ + "modules/party-overview/templates/parts/PF2e-Lore.html", + "modules/party-overview/templates/parts/PF2e-Bulk.html" + ]; + } + + get template() { + return "/modules/party-overview/templates/pf1.hbs" + } + + getLore(data) { + let result = []; + for (let key in data) { + result.push(data[key].name); + } + + return result; + } + + getTotalGP(currency) { + return currency.cp / 100 + currency.sp / 10 + currency.gp + currency.pp * 10; + } + + getActorDetails(actor) { + const data = actor.data.data; + return { + id: actor.id, + name: actor.name, + hp: { + value: data.attributes.hp.value, + max: data.attributes.hp.max + }, + armor: data.armor.total ? data.armor.total : 10, + shieldAC: data.shield && data.shield.total ? `(+${data.shield.total})` : "", + perception: data.skills.per.mod, + stealth: data.skills.ste.mod, + speed: data.attributes.speed.land.total, + + saves: { + fortitude: data.attributes.savingThrows.fort.total, + reflex: data.attributes.savingThrows.ref.total, + will: data.attributes.savingThrows.will.total, + }, + languages: data.traits.languages ? data.traits.languages.value.map(code => game.i18n.localize(CONFIG.PF1.languages[code])) : [], + currency: data.currency, + + lore: this.getLore(actor.data.data.skills.lor.subSkills), + totalGP: this.getTotalGP(data.currency).toFixed(2) + } + } + + getUpdate(actors) { + let languages = actors + .reduce((languages, actor) => [...new Set(languages.concat(actor.languages))], []) + .filter(language => language !== undefined) + .sort(); + let totalCurrency = actors.reduce( + (currency, actor) => { + for (let prop in actor.currency) { + currency[prop] += actor.currency[prop]; + } + return currency; + }, + { + cp: 0, + sp: 0, + gp: 0, + pp: 0, + } + ); + let totalPartyGP = actors.reduce((totalGP, actor) => totalGP + parseFloat(actor.totalGP), 0).toFixed(2); + let lores = actors + .reduce((lore, actor) => [...new Set(lore.concat(actor.lore))], []) + .filter(lore => lore !== undefined) + .sort(); + actors = actors.map(actor => { + return { + ...actor, + languages: languages.map(language => actor.languages && actor.languages.includes(language)), + lore: lores.map(lore => actor.lore && actor.lore.includes(lore)), + } + }) + return [ + actors, + { + languages: languages, + totalCurrency: totalCurrency, + totalPartyGP: totalPartyGP, + lore: lores + } + ] + } +} + export class pf2eProvider extends SystemProvider { get loadTemplates() { return [ @@ -254,6 +363,99 @@ export class pf2eProvider extends SystemProvider { } } +export class sfrpgProvider extends SystemProvider { + get loadTemplates() { + return [ + "modules/party-overview/templates/parts/PF2e-Lore.html", + "modules/party-overview/templates/parts/PF2e-Bulk.html" + ]; + } + + get template() { + return "/modules/party-overview/templates/sfrpg.hbs" + } + + getLore(data) { + let result = []; + for (let key in data) { + if (key.startsWith("pro") && Number(key.slice(key.length-1))) { + result.push(data[key].subname); + } + } + return result; + } + + getActorDetails(actor) { + const data = actor.data.data; + return { + id: actor.id, + name: actor.name, + hp: { + value: data.attributes.hp.value, + max: data.attributes.hp.max + }, + armor: data.attributes.eac.value ? data.attributes.eac.value : 10, + perception: data.skills.per.mod, + stealth: data.skills.ste.mod, + speed: data.attributes.speed.land.value, + + saves: { + fortitude: data.attributes.fort.value, + reflex: data.attributes.reflex.value, + will: data.attributes.will.value, + }, + languages: data.traits.languages ? data.traits.languages.value.map(code => game.i18n.localize(CONFIG.SFRPG.languages[code])) : [], + currency: data.currency, + + lore: this.getLore(actor.data.data.skills) + } + } + + getUpdate(actors) { + let languages = actors + .reduce((languages, actor) => [...new Set(languages.concat(actor.languages))], []) + .filter(language => language !== undefined) + .sort(); + let totalCurrency = actors.reduce( + (currency, actor) => { + for (let prop in actor.currency) { + currency[prop] += actor.currency[prop]; + } + return currency; + }, + { + cp: 0, + sp: 0, + gp: 0, + pp: 0, + } + ); + let totalPartyCredits = actors.reduce((total, actor) => total + parseFloat(actor.currency.credit), 0); + let totalPartyUPB = actors.reduce((total, actor) => total + parseFloat(actor.currency.upb), 0); + let lores = actors + .reduce((lore, actor) => [...new Set(lore.concat(actor.lore))], []) + .filter(lore => lore !== undefined) + .sort(); + actors = actors.map(actor => { + return { + ...actor, + languages: languages.map(language => actor.languages && actor.languages.includes(language)), + lore: lores.map(lore => actor.lore && actor.lore.includes(lore)), + } + }) + return [ + actors, + { + languages: languages, + totalCurrency: totalCurrency, + totalPartyCredits: totalPartyCredits, + totalPartyUPB: totalPartyUPB, + lore: lores + } + ] + } +} + export class swadeProvider extends SystemProvider { get template() { return "/modules/party-overview/templates/swade.hbs" @@ -276,6 +478,10 @@ export class swadeProvider extends SystemProvider { } export class wfrp4eProvider extends SystemProvider { + get customCSS() { + return ["wfrp4e"]; + } + get template() { return "/modules/party-overview/templates/wfrp4e.hbs" } diff --git a/module/api.js b/module/api.js index 4e65458..4f4bc23 100644 --- a/module/api.js +++ b/module/api.js @@ -1,4 +1,4 @@ -import {SystemProvider, dnd5eProvider, pf2eProvider, swadeProvider, wfrp4eProvider +import {SystemProvider, dnd5eProvider, pf1Provider, pf2eProvider, sfrpgProvider, swadeProvider, wfrp4eProvider } from "./SystemProvider.js" export const availableSystemProviders = {} @@ -47,9 +47,15 @@ export function initApi() { case "dnd5e": systemProviders.push(new dnd5eProvider("native.dnd5e")); break; + case "pf1": + systemProviders.push(new pf1Provider("native.pf1")); + break; case "pf2e": systemProviders.push(new pf2eProvider("native.pf2e")); break; + case "sfrpg": + systemProviders.push(new sfrpgProvider("native.swade")); + break; case "swade": systemProviders.push(new swadeProvider("native.swade")); break; diff --git a/module/logic.js b/module/logic.js index 7ed526e..b8d3aa5 100644 --- a/module/logic.js +++ b/module/logic.js @@ -69,7 +69,7 @@ class PartyOverviewApp extends Application { resizable: true, title: "Party Overview", template: currentSystemProvider.template, - classes: ["party-overview", game.system.id], + classes: ["party-overview", ...currentSystemProvider.customCSS], tabs: [ { navSelector: ".tabs", diff --git a/party-overview.js b/party-overview.js index e064900..1ea9b1b 100644 --- a/party-overview.js +++ b/party-overview.js @@ -29,7 +29,7 @@ Hooks.on("renderActorDirectory", (app, html, data) => { if (!game.user.isGM && !game.settings.get("party-overview", "EnablePlayerAccess")) return; let div = $( - `
` + `
` ); $(html).find("header.directory-header").prepend(div); diff --git a/style/party-overview.css b/style/party-overview.css index c4db51e..3bdef98 100644 --- a/style/party-overview.css +++ b/style/party-overview.css @@ -126,8 +126,3 @@ div.party-overview.wfrp4e .table-row .button button { div.party-overview.wfrp4e .table-row:nth-child(2n) { background-color: rgba(228, 228, 228, 0.34); } - -.dnd5e button.party-overview { - background: rgba(255, 255, 240, 0.8); - border: 1px solid #b5b3a4; -} diff --git a/templates/generic.hbs b/templates/generic.hbs new file mode 100644 index 0000000..199a523 --- /dev/null +++ b/templates/generic.hbs @@ -0,0 +1,28 @@ +
+ +
+
+
+ {{> "modules/party-overview/templates/parts/FilterButton.html"}} +
Name
+
+
+ + {{#each actors as | actor | }} +
+
+ +
+
{{ actor.shortestName }}
+ +
{{ actor.hp.value }}/{{ actor.hp.max }}
+
+ {{/each}} +
+
+
diff --git a/templates/parts/Languages.html b/templates/parts/Languages.html index b66fbce..426ed06 100644 --- a/templates/parts/Languages.html +++ b/templates/parts/Languages.html @@ -3,7 +3,7 @@ {{> "modules/party-overview/templates/parts/FilterButton.html"}}
{{localize "party-overview.NAME"}}
{{#each languages as | language | }} -
{{language}}
+
{{language}}
{{/each}} @@ -17,7 +17,7 @@
{{ actor.shortestName }}
{{#each actor.languages as | language | }} -
{{#if language}}{{else}}{{#if language}}{{else}}{{/if}}
{{/each}} diff --git a/templates/parts/PF2e-Lore.html b/templates/parts/PF2e-Lore.html index e3ea035..07b3c84 100644 --- a/templates/parts/PF2e-Lore.html +++ b/templates/parts/PF2e-Lore.html @@ -3,7 +3,7 @@ {{> "modules/party-overview/templates/parts/FilterButton.html"}}
{{localize "party-overview.NAME"}}
{{#each lore as | l | }} -
{{l}}
+
{{l}}
{{/each}} @@ -17,7 +17,7 @@
{{ actor.shortestName }}
{{#each actor.lore as | lore | }} -
{{#if lore}}{{else}}{{#if lore}}{{else}}{{/if}}
{{/each}} diff --git a/templates/pf1.hbs b/templates/pf1.hbs new file mode 100644 index 0000000..3168786 --- /dev/null +++ b/templates/pf1.hbs @@ -0,0 +1,89 @@ +
+ +
+
+
+ {{> "modules/party-overview/templates/parts/FilterButton.html"}} +
{{localize "party-overview.NAME"}}
+
+
+
+
+
+
+
+ + {{#each actors as | actor | }} +
+
+ +
+
{{ actor.shortestName }}
+
{{ actor.hp.value }}/{{ actor.hp.max }}
+
{{ actor.armor }} {{#if actor.shieldAC}}{{ actor.shieldAC }}{{/if}}
+
{{ actor.perception }}
+
{{ actor.saves.fortitude }}
+
{{ actor.saves.reflex }}
+
{{ actor.saves.will }}
+
+ {{/each}} +
+ + {{> "modules/party-overview/templates/parts/Languages.html"}} + + + {{> "modules/party-overview/templates/parts/PF2e-Lore.html"}} + + +
+
+ {{> "modules/party-overview/templates/parts/FilterButton.html"}} +
Name
+
{{localize "PF1.CurrencyPP"}}
+
{{localize "PF1.CurrencyGP"}}
+
{{localize "PF1.CurrencySP"}}
+
{{localize "PF1.CurrencyCP"}}
+
{{localize "PF1.CurrencyGP"}} ({{localize "party-overview.TOTAL"}})
+
+ + {{#each actors as | actor | }} +
+
+ +
+
{{ actor.shortestName }}
+
{{currency.pp}}
+
{{currency.gp}}
+
{{currency.sp}}
+
{{currency.cp}}
+
{{actor.totalGP}}
+
+ {{/each}} +
+
+ +
+
{{localize "party-overview.TOTAL"}}
+
{{totalCurrency.pp}}
+
{{totalCurrency.gp}}
+
{{totalCurrency.sp}}
+
{{totalCurrency.cp}}
+
{{totalPartyGP}}
+
+
+ + + {{> "modules/party-overview/templates/parts/PF2e-Bulk.html"}} +
+
\ No newline at end of file diff --git a/templates/pf2e.hbs b/templates/pf2e.hbs index 714859d..1125299 100644 --- a/templates/pf2e.hbs +++ b/templates/pf2e.hbs @@ -1,7 +1,7 @@
{{ actor.shortestName }}
-
{{currency.pp}}
-
{{currency.gp}}
-
{{currency.sp}}
-
{{currency.cp}}
-
{{actor.totalGP}}
+
{{currency.pp}}
+
{{currency.gp}}
+
{{currency.sp}}
+
{{currency.cp}}
+
{{actor.totalGP}}
{{/each}}
@@ -76,11 +76,11 @@
{{localize "party-overview.TOTAL"}}
-
{{totalCurrency.pp}}
-
{{totalCurrency.gp}}
-
{{totalCurrency.sp}}
-
{{totalCurrency.cp}}
-
{{totalPartyGP}}
+
{{totalCurrency.pp}}
+
{{totalCurrency.gp}}
+
{{totalCurrency.sp}}
+
{{totalCurrency.cp}}
+
{{totalPartyGP}}
diff --git a/templates/sfrpg.hbs b/templates/sfrpg.hbs new file mode 100644 index 0000000..d3038f7 --- /dev/null +++ b/templates/sfrpg.hbs @@ -0,0 +1,80 @@ +
+ +
+
+
+ {{> "modules/party-overview/templates/parts/FilterButton.html"}} +
{{localize "party-overview.NAME"}}
+
+
+
+
+
+
+
+ + {{#each actors as | actor | }} +
+
+ +
+
{{ actor.shortestName }}
+
{{ actor.hp.value }}/{{ actor.hp.max }}
+
{{ actor.armor }}
+
{{ actor.perception }}
+
{{ actor.saves.fortitude }}
+
{{ actor.saves.reflex }}
+
{{ actor.saves.will }}
+
+ {{/each}} +
+ + {{> "modules/party-overview/templates/parts/Languages.html"}} + + + {{> "modules/party-overview/templates/parts/PF2e-Lore.html"}} + + +
+
+ {{> "modules/party-overview/templates/parts/FilterButton.html"}} +
Name
+
{{localize "SFRPG.Currencies.Credits"}}
+
{{localize "SFRPG.Currencies.UPBs"}}
+
+ + {{#each actors as | actor | }} +
+
+ +
+
{{ actor.shortestName }}
+
{{currency.credit}}
+
{{currency.upb}}
+
+ {{/each}} +
+
+ +
+
{{localize "party-overview.TOTAL"}}
+
{{totalPartyCredits}}
+
{{totalPartyUPB}}
+
+
+ + + {{> "modules/party-overview/templates/parts/PF2e-Bulk.html"}} +
+
\ No newline at end of file diff --git a/templates/wfrp4e.hbs b/templates/wfrp4e.hbs index 9dcc79e..2eca8f2 100644 --- a/templates/wfrp4e.hbs +++ b/templates/wfrp4e.hbs @@ -2,7 +2,7 @@ -
+
{{> "modules/party-overview/templates/parts/FilterButton.html"}}