From 53a65a66914610b36af554d4f09a09891a85b812 Mon Sep 17 00:00:00 2001 From: Andrea Costantini Date: Fri, 4 Mar 2022 08:38:07 +0100 Subject: [PATCH 1/3] Adds multiclassing and races to the character sheet --- src/lang/en.json | 9 ++- src/lang/es.json | 7 +++ src/lang/fr.json | 7 +++ src/lang/it.json | 9 ++- src/lang/pt-BR.json | 7 +++ src/module/actor/character-sheet.js | 2 +- src/scss/character.scss | 11 ++++ src/templates/actors/character-sheet.html | 2 +- .../actors/dialogs/tweaks-dialog.html | 58 +++++++++++++++++++ .../partials/character-attributes-tab.html | 11 ++++ .../actors/partials/character-header.html | 46 ++++++++++++++- template.json | 23 ++++++++ 12 files changed, 187 insertions(+), 5 deletions(-) diff --git a/src/lang/en.json b/src/lang/en.json index 6ca2aa35..50658a79 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -10,7 +10,8 @@ "OSE.Roll": "Roll", "OSE.Success": "Success", "OSE.Failure": "Failure", - + "OSE.Multiclass": "Multiclass Character", + "OSE.dialog.tweaks": "Tweaks", "OSE.dialog.partysheet": "Party Overview", "OSE.dialog.partyselect": "Select PCs", @@ -52,6 +53,7 @@ "OSE.details.name": "Name", "OSE.details.class": "Class", + "OSE.details.race": "Race", "OSE.details.title": "Title", "OSE.details.alignment": "Alignment", "OSE.details.level": "Level", @@ -66,6 +68,9 @@ "OSE.details.morale": "Morale", "OSE.details.reaction": "Reaction", "OSE.details.appearing": "NA", + "OSE.details.1stClass": "1st Class", + "OSE.details.2ndClass": "2nd Class", + "OSE.details.3rdClass": "3rd Class", "OSE.Attack": "Attack", "OSE.Encumbrance": "Encumbrance", @@ -107,6 +112,8 @@ "OSE.HealthShort": "HP", "OSE.HitDice": "Hit Dice", "OSE.HitDiceShort": "HD", + "OSE.FractionalHpShort": "HPF", + "OSE.FractionalHp": "Remaining HP Fraction", "OSE.movement.base": "Movement Rate", "OSE.movement.short": "MV", diff --git a/src/lang/es.json b/src/lang/es.json index 42041811..ba71848f 100644 --- a/src/lang/es.json +++ b/src/lang/es.json @@ -10,6 +10,7 @@ "OSE.Roll": "Tirar", "OSE.Success": "Éxito", "OSE.Failure": "Fallo", + "OSE.Multiclass": "Multiclass Character", "OSE.dialog.tweaks": "Ajustes", "OSE.dialog.partysheet": "Resumen del grupo", @@ -52,6 +53,7 @@ "OSE.details.name": "Nombre", "OSE.details.class": "Clase", + "OSE.details.race": "Race", "OSE.details.title": "Título", "OSE.details.alignment": "Alineamiento", "OSE.details.level": "Nivel", @@ -66,6 +68,9 @@ "OSE.details.morale": "Moral", "OSE.details.reaction": "Reacción", "OSE.details.appearing": "NA", + "OSE.details.1stClass": "1st Class", + "OSE.details.2ndClass": "2nd Class", + "OSE.details.3rdClass": "3rd Class", "OSE.Attack": "Ataque", "OSE.Encumbrance": "Carga", @@ -107,6 +112,8 @@ "OSE.HealthShort": "PG", "OSE.HitDice": "Dado de Golpe", "OSE.HitDiceShort": "DG", + "OSE.FractionalHpShort": "HPF", + "OSE.FractionalHp": "Remaining HP Fraction", "OSE.movement.base": "Movimiento", "OSE.movement.short": "MV", diff --git a/src/lang/fr.json b/src/lang/fr.json index 56dc4c15..52167f79 100644 --- a/src/lang/fr.json +++ b/src/lang/fr.json @@ -10,6 +10,7 @@ "OSE.Roll": "Lancer", "OSE.Success": "Succès", "OSE.Failure": "Échec", + "OSE.Multiclass": "Multiclass Character", "OSE.dialog.tweaks": "Ajuster", "OSE.dialog.partysheet": "Fiche de Groupe", @@ -52,6 +53,7 @@ "OSE.details.name": "Nom", "OSE.details.class": "Classe", "OSE.details.title": "Titre", + "OSE.details.race": "Race", "OSE.details.alignment": "Alignement", "OSE.details.level": "Niveau", "OSE.details.experience.base": "Expérience", @@ -65,6 +67,9 @@ "OSE.details.morale": "Moral", "OSE.details.reaction": "Réaction", "OSE.details.appearing": "NA", + "OSE.details.1stClass": "1st Class", + "OSE.details.2ndClass": "2nd Class", + "OSE.details.3rdClass": "3rd Class", "OSE.Attack": "Attaque", "OSE.Encumbrance": "Encombrement", @@ -106,6 +111,8 @@ "OSE.HealthShort": "PV", "OSE.HitDice": "Dé de Vie", "OSE.HitDiceShort": "DV", + "OSE.FractionalHpShort": "HPF", + "OSE.FractionalHp": "Remaining HP Fraction", "OSE.movement.base": "Déplacement", "OSE.movement.short": "DP", diff --git a/src/lang/it.json b/src/lang/it.json index a5fca506..86dca27a 100644 --- a/src/lang/it.json +++ b/src/lang/it.json @@ -10,6 +10,7 @@ "OSE.Roll": "Tiro", "OSE.Success": "Successo", "OSE.Failure": "Fallimento", + "OSE.Multiclass": "Multiclass Character", "OSE.dialog.tweaks": "Modifiche", "OSE.dialog.partysheet": "Panoramica del Gruppo", @@ -52,6 +53,7 @@ "OSE.details.name": "Nome", "OSE.details.class": "Classe", "OSE.details.title": "Titolo", + "OSE.details.race": "Race", "OSE.details.alignment": "Allineamento", "OSE.details.level": "Livello", "OSE.details.experience.base": "Esperienza", @@ -65,6 +67,9 @@ "OSE.details.morale": "Morale", "OSE.details.reaction": "Reazione", "OSE.details.appearing": "Nr. Mostri", + "OSE.details.1stClass": "1st Class", + "OSE.details.2ndClass": "2nd Class", + "OSE.details.3rdClass": "3rd Class", "OSE.Attack": "Attacco", "OSE.Encumbrance": "Ingombro", @@ -106,7 +111,9 @@ "OSE.HealthShort": "PF", "OSE.HitDice": "Dadi Vita", "OSE.HitDiceShort": "DV", - + "OSE.FractionalHpShort": "HPF", + "OSE.FractionalHp": "Remaining HP Fraction", + "OSE.movement.base": "Movimento", "OSE.movement.short": "MV", "OSE.movement.details": "Dettagli Movimento", diff --git a/src/lang/pt-BR.json b/src/lang/pt-BR.json index c34d518c..732762a2 100644 --- a/src/lang/pt-BR.json +++ b/src/lang/pt-BR.json @@ -10,6 +10,7 @@ "OSE.Roll": "Rolar", "OSE.Success": "Sucesso", "OSE.Failure": "Falha", + "OSE.Multiclass": "Multiclass Character", "OSE.dialog.tweaks": "Ferramentas", "OSE.dialog.partysheet": "Visão do grupo", @@ -48,6 +49,7 @@ "OSE.details.name": "Nome", "OSE.details.class": "Classe", "OSE.details.title": "Titulo", + "OSE.details.race": "Race", "OSE.details.alignment": "Alinhamento", "OSE.details.level": "Nivel", "OSE.details.experience.base": "Experiência", @@ -61,6 +63,9 @@ "OSE.details.morale": "Moral", "OSE.details.reaction": "Reação", "OSE.details.appearing": "NA", + "OSE.details.1stClass": "1st Class", + "OSE.details.2ndClass": "2nd Class", + "OSE.details.3rdClass": "3rd Class", "OSE.Attack": "Ataca", "OSE.Encumbrance": "Sobrecarga", @@ -101,6 +106,8 @@ "OSE.HealthShort": "PV", "OSE.HitDice": "Dados de Vida", "OSE.HitDiceShort": "DV", + "OSE.FractionalHpShort": "HPF", + "OSE.FractionalHp": "Remaining HP Fraction", "OSE.movement.base": "Taxa de Movimento", "OSE.movement.short": "TM", diff --git a/src/module/actor/character-sheet.js b/src/module/actor/character-sheet.js index e7f68c3e..49b768a7 100644 --- a/src/module/actor/character-sheet.js +++ b/src/module/actor/character-sheet.js @@ -17,7 +17,7 @@ export class OseActorSheetCharacter extends OseActorSheet { * Extend and override the default options used by the 5e Actor Sheet * @returns {Object} */ - static get defaultOptions() { + static get defaultOptions() { return foundry.utils.mergeObject(super.defaultOptions, { classes: ["ose", "sheet", "actor", "character"], template: "systems/ose/dist/templates/actors/character-sheet.html", diff --git a/src/scss/character.scss b/src/scss/character.scss index f4ffc21f..bfecd406 100644 --- a/src/scss/character.scss +++ b/src/scss/character.scss @@ -7,6 +7,7 @@ min-width: 450px; min-height: 550px; + /* ----------------------------------------- */ /* Sheet Header */ /* ----------------------------------------- */ @@ -44,6 +45,10 @@ /* ----------------------------------------- */ /* Sheet Body */ /* ----------------------------------------- */ + .multiclass .sheet-body { + height: calc(100% - 240px); + } + .sheet-body { .tab { height: 100%; @@ -237,3 +242,9 @@ /* Item Controls */ /* ----------------------------------------- */ } + +/* Tweaks Dialog */ + +.additional-classes{ + margin-bottom: 15px; +} \ No newline at end of file diff --git a/src/templates/actors/character-sheet.html b/src/templates/actors/character-sheet.html index f3ce6e1d..e1d28c82 100644 --- a/src/templates/actors/character-sheet.html +++ b/src/templates/actors/character-sheet.html @@ -1,4 +1,4 @@ -
+ {{! Sheet Header }}
{{> "systems/ose/dist/templates/actors/partials/character-header.html"}} diff --git a/src/templates/actors/dialogs/tweaks-dialog.html b/src/templates/actors/dialogs/tweaks-dialog.html index 7612df95..6e40e8b0 100644 --- a/src/templates/actors/dialogs/tweaks-dialog.html +++ b/src/templates/actors/dialogs/tweaks-dialog.html @@ -21,6 +21,18 @@ {{#if (eq this.type 'character')}} +
+ +
+ +
+
+ {{#if data.multiclass.enabled}} +
+ +
+ {{/if}}
@@ -35,6 +47,52 @@ data-dtype="Number" />
+ {{#if data.multiclass.enabled}} +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ {{/if}}
diff --git a/src/templates/actors/partials/character-attributes-tab.html b/src/templates/actors/partials/character-attributes-tab.html index 534e01f3..ce5dc1d3 100644 --- a/src/templates/actors/partials/character-attributes-tab.html +++ b/src/templates/actors/partials/character-attributes-tab.html @@ -109,6 +109,17 @@

data-dtype="String" />

+ {{#if data.multiclass.enabled}} +
  • +

    + {{ localize "OSE.FractionalHpShort" }} +

    +
    + +
    +
  • + {{/if}} {{#if config.initiative}}
  • diff --git a/src/templates/actors/partials/character-header.html b/src/templates/actors/partials/character-header.html index 6dc78de7..29674700 100644 --- a/src/templates/actors/partials/character-header.html +++ b/src/templates/actors/partials/character-header.html @@ -24,8 +24,12 @@

  • -
  • +

  • {{/if}} +
  • + + +
  • @@ -48,4 +52,44 @@

    {{/if}}

  • + {{#if data.multiclass.enabled}} + {{#if data.details.xp2.enabled}} +
      +
    • + + +
    • +
    • + + +
    • +
    • + + + {{#if data.details.xp2.bonus}} + +{{data.details.xp2.bonus}}% + {{/if}} +
    • +
    + {{/if}} + {{#if data.details.xp3.enabled}} +
      +
    • + + +
    • +
    • + + +
    • +
    • + + + {{#if data.details.xp3.bonus}} + +{{data.details.xp3.bonus}}% + {{/if}} +
    • +
    + {{/if}} + {{/if}} \ No newline at end of file diff --git a/template.json b/template.json index 300d2785..9617b70c 100644 --- a/template.json +++ b/template.json @@ -10,6 +10,7 @@ }, "hp": { "hd": "1d8", + "fraction": "", "value": 20, "max": 20 }, @@ -54,6 +55,9 @@ "mod": 0 } }, + "multiclass": { + "enabled": false + }, "spellcaster": { "spells": { "enabled": false, @@ -87,14 +91,33 @@ "biography": "", "notes": "", "class": "", + "class2": "", + "class3": "", + "race": "", "title": "", "alignment": "", "level": 1, + "level2": 0, + "level3": 0, "xp": { "share": 100, "next": 2000, "value": 0, "bonus": 0 + }, + "xp2": { + "enabled": false, + "share": 100, + "next": 2000, + "value": 0, + "bonus": 0 + }, + "xp3": { + "enabled": false, + "share": 100, + "next": 2000, + "value": 0, + "bonus": 0 } }, "exploration": { From 51b5ddce208b9cb5de8bc37c65d9798b936c0d27 Mon Sep 17 00:00:00 2001 From: Andrea Costantini Date: Fri, 4 Mar 2022 21:26:29 +0100 Subject: [PATCH 2/3] Added multi-class party overview xp dispersal --- src/module/actor/entity.js | 89 ++++++++++++++++--- .../actors/dialogs/tweaks-dialog.html | 15 ++++ 2 files changed, 90 insertions(+), 14 deletions(-) diff --git a/src/module/actor/entity.js b/src/module/actor/entity.js index fff1f4c5..8e065c1e 100644 --- a/src/module/actor/entity.js +++ b/src/module/actor/entity.js @@ -63,21 +63,82 @@ export class OseActor extends Actor { if (this.data.type != "character") { return; } - let modified = Math.floor( - value + (this.data.data.details.xp.bonus * value) / 100 - ); - return this.update({ - "data.details.xp.value": modified + this.data.data.details.xp.value, - }).then(() => { - const speaker = ChatMessage.getSpeaker({ actor: this }); - ChatMessage.create({ - content: game.i18n.format("OSE.messages.GetExperience", { - name: this.name, - value: modified, - }), - speaker, + if(!this.data.data.multiclass){ + let modified = Math.floor( + value + (this.data.data.details.xp.bonus * value) / 100 + ); + return this.update({ + "data.details.xp.value": modified + this.data.data.details.xp.value, + }).then(() => { + const speaker = ChatMessage.getSpeaker({ actor: this }); + ChatMessage.create({ + content: game.i18n.format("OSE.messages.GetExperience", { + name: this.name, + value: modified, + }), + speaker, + }); }); - }); + } else { + let xpModified; + let xp2Modified; + let xp3Modified; + let xpForUpdate = value; + let xpsToDisperse = {}; + let total = 0; + const xp2Enabled = this.data.data.details.xp2.enabled; + const xp3Enabled = this.data.data.details.xp3.enabled; + + if(xp2Enabled){ + xpForUpdate = Math.floor(value / 2); + } + + if(xp2Enabled && xp3Enabled){ + xpForUpdate = Math.floor(value / 3); + } + + xpModified = Math.floor( + xpForUpdate + (this.data.data.details.xp.bonus * xpForUpdate) / 100 + ); + + total = xpModified + total; + xpsToDisperse = { + ...xpsToDisperse, + "data.details.xp.value": xpModified + this.data.data.details.xp.value + }; + + if(xp2Enabled){ + xp2Modified = Math.floor( + xpForUpdate + (this.data.data.details.xp2.bonus * xpForUpdate) / 100 + ); + xpsToDisperse = { + ...xpsToDisperse, + "data.details.xp2.value": + xp2Modified + this.data.data.details.xp2.value + }; + total = xp2Modified + total; + } + + if(xp3Enabled){ + xp3Modified = Math.floor( + xpForUpdate + (this.data.data.details.xp3.bonus * xpForUpdate) / 100 + ); + xpsToDisperse = {...xpsToDisperse, "data.details.xp3.value": xp3Modified + this.data.data.details.xp3.value}; + total = xp3Modified + total; + } + + return this.update(xpsToDisperse).then(() => { + const speaker = ChatMessage.getSpeaker({ actor: this }); + ChatMessage.create({ + content: game.i18n.format("OSE.messages.GetExperience", { + name: this.name, + value: total, + }), + speaker, + }); + }); + + } } isNew() { diff --git a/src/templates/actors/dialogs/tweaks-dialog.html b/src/templates/actors/dialogs/tweaks-dialog.html index 6e40e8b0..4cbfd092 100644 --- a/src/templates/actors/dialogs/tweaks-dialog.html +++ b/src/templates/actors/dialogs/tweaks-dialog.html @@ -73,22 +73,37 @@
    + {{#if data.details.xp2.enabled}} + {{else}} + + {{/if}}
    + {{#if data.details.xp2.enabled}} + {{else}} + + {{/if}}
    + {{#if data.details.xp2.enabled}} + {{else}} + + {{/if}}
    From f24e578e43be2f07ce3ff3151b4a7bca604927d4 Mon Sep 17 00:00:00 2001 From: Andrea Costantini Date: Sat, 5 Mar 2022 09:38:30 +0100 Subject: [PATCH 3/3] Better tweak form interactions --- src/module/actor/entity.js | 2 +- src/module/dialog/entity-tweaks.js | 43 +++++++++++++++++++ src/scss/character.scss | 5 ++- .../actors/dialogs/tweaks-dialog.html | 19 ++++---- 4 files changed, 57 insertions(+), 12 deletions(-) diff --git a/src/module/actor/entity.js b/src/module/actor/entity.js index 8e065c1e..d0f8e6bd 100644 --- a/src/module/actor/entity.js +++ b/src/module/actor/entity.js @@ -63,7 +63,7 @@ export class OseActor extends Actor { if (this.data.type != "character") { return; } - if(!this.data.data.multiclass){ + if(!this.data.data.multiclass?.enabled){ let modified = Math.floor( value + (this.data.data.details.xp.bonus * value) / 100 ); diff --git a/src/module/dialog/entity-tweaks.js b/src/module/dialog/entity-tweaks.js index c7d24799..7d810812 100644 --- a/src/module/dialog/entity-tweaks.js +++ b/src/module/dialog/entity-tweaks.js @@ -44,6 +44,38 @@ export class OseEntityTweaks extends FormApplication { /** @override */ activateListeners(html) { + + html.find("#multiclass").change(e => { + const multiClassEnabled = $(e.currentTarget).is(":checked"); + if(!multiClassEnabled){ + html.find("#xp2enabled").val(false); + html.find("#xp3enabled").val(false); + html.find("#experience2").val(0); + html.find("#experience3").val(0); + html.find("#experiencenext2").val(0); + html.find("#experiencenext3").val(0); + html.find(".additional-classes").hide(); + html.find(".first-class-multiclass-label").hide(); + } else { + html.find(".additional-classes").show(); + html.find(".first-class-multiclass-label").show(); + } + }); + + html.find("#xp2enabled").change(e => { + const xp2Enabled = $(e.currentTarget).is(":checked"); + if(!xp2Enabled){ + html.find("#xp3enabled").val(false).attr("disabled", true); + html.find("#experience3").val(0).attr("readonly", true); + html.find("#experiencenext3").val(0).attr("readonly", true); + + } else { + html.find("#xp3enabled").attr("disabled", false); + html.find("#experience3").attr("readonly", false); + html.find("#experiencenext3").attr("readonly", false); + } + }); + super.activateListeners(html); } @@ -56,6 +88,17 @@ export class OseEntityTweaks extends FormApplication { async _updateObject(event, formData) { event.preventDefault(); // Update the actor + const multiClassEnabled = $("#multiclass").is(":checked"); + const xp2Enabled = $("#xp2enabled").is(":checked"); + + if(!multiClassEnabled){ + formData['data.details.xp2.enabled'] = false; + formData['data.details.xp3.enabled'] = false; + } + if(!xp2Enabled){ + formData['data.details.xp3.enabled'] = false; + } + this.object.update(formData); // Re-draw the updated sheet this.object.sheet.render(true); diff --git a/src/scss/character.scss b/src/scss/character.scss index bfecd406..1aa0da72 100644 --- a/src/scss/character.scss +++ b/src/scss/character.scss @@ -247,4 +247,7 @@ .additional-classes{ margin-bottom: 15px; -} \ No newline at end of file + &.hidden { + display: none; + } +} diff --git a/src/templates/actors/dialogs/tweaks-dialog.html b/src/templates/actors/dialogs/tweaks-dialog.html index 4cbfd092..87964b09 100644 --- a/src/templates/actors/dialogs/tweaks-dialog.html +++ b/src/templates/actors/dialogs/tweaks-dialog.html @@ -28,11 +28,10 @@ data-dtype="Boolean" /> - {{#if data.multiclass.enabled}} -
    + +
    - {{/if}}
    @@ -47,8 +46,8 @@ data-dtype="Number" />
    - {{#if data.multiclass.enabled}} -
    + +
    @@ -66,7 +65,7 @@
    -
    @@ -89,7 +88,7 @@ {{else}} - {{/if}}
    @@ -98,16 +97,16 @@
    {{#if data.details.xp2.enabled}} - {{else}} - {{/if}}
    - {{/if}} +