diff --git a/lang/de.json b/lang/de.json index 56d02d2..49ab45f 100644 --- a/lang/de.json +++ b/lang/de.json @@ -17,6 +17,11 @@ "midgard5.phase-movement": "Bewegungsphase", "midgard5.no-encounter": "Kein Kampf", "midgard5.encounter-not-started": "Kein aktiver Kampf", + "midgard5.initiative": "Handlungsrang", + + "midgard5.combat-join": "Kampf Beitreten/Handlungsrang zurücksetzen", + "midgard5.combat-ranged": "Fernangriff", + "midgard5.combat-spell": "Zaubern (10 Sec)", "midgard5.time-duration": "Dauer", "midgard5.time-round": "Runde(n)", @@ -92,7 +97,6 @@ "midgard5.kampfkuenste": "Kampfkünste", "midgard5.combat": "Kampf", - "midgard5.actor-name": "Figur", "midgard5.level": "Grad", "midgard5.class": "Typ", @@ -262,6 +266,10 @@ "midgard5.active": "Aktiv", "midgard5.rangedWeapon": "Schusswaffe", "midgard5.assignItemToCharacter": "Füge Gegenstand einem Charakter hinzu, um hier etwas auswählen zu können", + "midgard5.showAll": "Alle anzeigen", + "midgard5.wealthAndContainers": "Vermögen und Aufbewahrung", + "midgard5.itemsInContainers": "Gegenstände in Aufbewahrung", + "midgard5.allItems": "Alle Gegenstände", "midgard5.pw": "Prüfwurf", "midgard5.attack": "Angriff", diff --git a/source/index.ts b/source/index.ts index 42b83d9..e11f94a 100644 --- a/source/index.ts +++ b/source/index.ts @@ -90,6 +90,16 @@ Hooks.once("init", async () => { return label.toLowerCase().includes(contains.toLowerCase()); }); + Handlebars.registerHelper("count", (object: any) => { + var length = 0; + for (var key in object) { + if (object.hasOwnProperty(key)) { + ++length; + } + } + return length; + }); + // Default Sheet für Items definieren und das Standardsheet deaktivieren Items.unregisterSheet("core", ItemSheet); Items.registerSheet("midgard5", M5ItemSheet, { makeDefault: true }); @@ -114,12 +124,10 @@ Hooks.on("getChatLogEntryContext", function (html, options) { name: "LP & AP Schaden", icon: '', condition: (li) => { - // Only show this context menu if there are re-rollable dice in the message - const damageRolls = li.find(".apply-damage").length; + const damageRolls = li.find(".damage").length; // All must be true to show the reroll dialogue - // The button doesn't work for the GM right now, so we don't need to show it - return game["user"].character && damageRolls > 0; + return (game["user"].character || game["canvas"].tokens.controlled) && damageRolls > 0; }, callback: (li) => applyDamage(li, 2), }, @@ -127,12 +135,10 @@ Hooks.on("getChatLogEntryContext", function (html, options) { name: "AP Schaden", icon: '', condition: (li) => { - // Only show this context menu if there are re-rollable dice in the message - const damageRolls = li.find(".apply-damage").length; + const damageRolls = li.find(".damage").length; // All must be true to show the reroll dialogue - // The button doesn't work for the GM right now, so we don't need to show it - return game["user"].character && damageRolls > 0; + return (game["user"].character || game["canvas"].tokens.controlled) && damageRolls > 0; }, callback: (li) => applyDamage(li, 1), }, @@ -140,12 +146,10 @@ Hooks.on("getChatLogEntryContext", function (html, options) { name: "LP & AP Heilen", icon: '', condition: (li) => { - // Only show this context menu if there are re-rollable dice in the message - const damageRolls = li.find(".apply-damage").length; + const damageRolls = li.find(".heal").length; // All must be true to show the reroll dialogue - // The button doesn't work for the GM right now, so we don't need to show it - return game["user"].character && damageRolls > 0; + return (game["user"].character || game["canvas"].tokens.controlled) && damageRolls > 0; }, callback: (li) => applyDamage(li, -1), }, @@ -153,12 +157,10 @@ Hooks.on("getChatLogEntryContext", function (html, options) { name: "AP Heilen", icon: '', condition: (li) => { - // Only show this context menu if there are re-rollable dice in the message - const damageRolls = li.find(".apply-damage").length; + const damageRolls = li.find(".heal").length; // All must be true to show the reroll dialogue - // The button doesn't work for the GM right now, so we don't need to show it - return game["user"].character && damageRolls > 0; + return (game["user"].character || game["canvas"].tokens.controlled) && damageRolls > 0; }, callback: (li) => applyDamage(li, -2), } @@ -209,15 +211,6 @@ Hooks.on("updateCombat", function (combat: Combat, updateData: { round: number; } }); -function limitHeal(heal: number, current: number, max: number): number { - if (current === max) { - return 0; - } else if (heal + current > max) { - return max - current; - } - return heal; -} - Hooks.on("renderCombatTracker", (combatTracker, html, context) => { if (context.combat === null) { html.find("h3.encounter-title")[0].innerHTML = game["i18n"].localize("midgard5.no-encounter"); @@ -234,27 +227,29 @@ Hooks.once("ready", () => { }); async function applyDamage(roll, direction) { - const damageValue = Array.from(roll.find(".apply-damage") as HTMLElement[]) + console.log(roll, direction); + const damageValue = Array.from(roll.find(".apply") as HTMLElement[]) .map((x) => Math.max(0, Number(x.innerText))) .reduce((prev, curr) => prev + curr, 0); - const userId = game["user"].character.id; - const viewedSceneId = game["user"].viewedScene; - const token = game["actors"].get(userId).getDependentTokens(viewedSceneId)[0]?.delta.syntheticActor; + const controlledTokens = game["canvas"].tokens.controlled; const actor = game["user"].character; - if (token) { - switch (direction) { - case 2: - token["system"].lp.value -= Math.max(0, damageValue - token["system"].calc.stats.lpProtection.value); - case 1: - token["system"].ap.value -= Math.max(0, damageValue - token["system"].calc.stats.apProtection.value); - break; - case -1: - token["system"].lp.value += limitHeal(damageValue, token["system"].lp.value, token["system"].lp.max); - case -2: - token["system"].ap.value += limitHeal(damageValue, token["system"].ap.value, token["system"].ap.max); - } - token.render(); + if (controlledTokens) { + controlledTokens.forEach((controlledToken) => { + let token = controlledToken.document.delta.syntheticActor; + switch (direction) { + case 2: + token["system"].lp.value -= Math.max(0, damageValue - token["system"].calc.stats.lpProtection.value); + case 1: + token["system"].ap.value -= Math.max(0, damageValue - token["system"].calc.stats.apProtection.value); + break; + case -1: + token["system"].lp.value += limitHeal(damageValue, token["system"].lp.value, token["system"].lp.max); + case -2: + token["system"].ap.value += limitHeal(damageValue, token["system"].ap.value, token["system"].ap.max); + } + token.render(); + }); } else { switch (direction) { case 2: @@ -263,10 +258,19 @@ async function applyDamage(roll, direction) { actor["system"].ap.value -= Math.max(0, damageValue - actor["system"].calc.stats.apProtection.value); break; case -1: - actor["system"].lp.value += limitHeal(damageValue, token["system"].lp.value, token["system"].lp.max); + actor["system"].lp.value += limitHeal(damageValue, actor["system"].lp.value, actor["system"].lp.max); case -2: - actor["system"].ap.value += limitHeal(damageValue, token["system"].ap.value, token["system"].ap.max); + actor["system"].ap.value += limitHeal(damageValue, actor["system"].ap.value, actor["system"].ap.max); } actor.render(); } } + +function limitHeal(heal: number, current: number, max: number): number { + if (current === max) { + return 0; + } else if (heal + current > max) { + return max - current; + } + return heal; +} diff --git a/source/module/M5Base.ts b/source/module/M5Base.ts index 7f7f7bc..586b84f 100644 --- a/source/module/M5Base.ts +++ b/source/module/M5Base.ts @@ -61,6 +61,13 @@ export enum M5ItemType { EFFECT = "effect", } +export enum M5SkillType { + INNATE = "innate", + GENERAL = "general", + LANGUAGE = "language", + COMBAT = "combat", +} + export enum M5EwResult { TBD = "", FUMBLE = "roll-ew-result-fumble", diff --git a/source/module/actors/M5Character.ts b/source/module/actors/M5Character.ts index f88da16..b691ef3 100644 --- a/source/module/actors/M5Character.ts +++ b/source/module/actors/M5Character.ts @@ -1,5 +1,5 @@ import { M5Item } from "../items/M5Item"; -import { M5Attribute, M5CharacterCalculatedData, M5ItemMod, M5ItemType, M5ModOperation, M5ModResult, M5ModType, M5RollData, M5Skill, M5SkillCalculated } from "../M5Base"; +import { M5Attribute, M5CharacterCalculatedData, M5ItemMod, M5ItemType, M5ModOperation, M5ModResult, M5ModType, M5RollData, M5Skill, M5SkillCalculated, M5SkillLearned, M5SkillType } from "../M5Base"; import M5ModAggregate from "./M5ModAggregate"; export class M5Character extends Actor { // constructor( @@ -666,10 +666,11 @@ export class M5Character extends Actor { }); } - async createItem(itemName: string, itemType: M5ItemType): Promise { + createItem(itemName: string, itemType: M5ItemType, options?: any): Promise { const itemData = { name: itemName, type: itemType, + data: options, }; return (this as any).createEmbeddedDocuments("Item", [itemData]).then((docs) => { diff --git a/source/module/rolls/M5Roll.ts b/source/module/rolls/M5Roll.ts index f0b2565..9a5f316 100644 --- a/source/module/rolls/M5Roll.ts +++ b/source/module/rolls/M5Roll.ts @@ -269,27 +269,6 @@ export class M5Roll { return new M5Roll(rollData, actor, (game as Game).i18n.localize("midgard5.resistanceMind")); } - static async initativeRoll(actor: any) { - let newInitiative; // the initiative value for the combatant - - // ... - // The intnitiative value is calculated here - // ... - - let combatant = game["combat"].getCombatantByActor(actor._id); - if (!combatant) { - await game["combat"].createEmbeddedDocuments("Combatant", [{ actorId: actor._id }]); - combatant = game["combat"].getCombatantByActor(actor._id); - } - - const initiatives = { - _id: combatant._id, - initiative: actor.system.calc.attributes.gw.value, - }; - - await game["combat"].updateEmbeddedDocuments("Combatant", [initiatives]); - } - static resistanceBody(actor: any) { const rollData = actor.getRollData() as M5RollData; rollData.i = { diff --git a/source/module/sheets/M5CharacterSheet.ts b/source/module/sheets/M5CharacterSheet.ts index b98f039..1e9af95 100644 --- a/source/module/sheets/M5CharacterSheet.ts +++ b/source/module/sheets/M5CharacterSheet.ts @@ -1,7 +1,7 @@ import Logger from "../../utils/Logger"; import { M5Character } from "../actors/M5Character"; import { M5Item } from "../items/M5Item"; -import { M5ItemType, M5SkillLearned, M5SkillUnlearned } from "../M5Base"; +import { M5ItemType, M5SkillLearned, M5SkillType, M5SkillUnlearned } from "../M5Base"; import { M5Roll } from "../rolls/M5Roll"; export default class M5CharacterSheet extends ActorSheet { @@ -282,14 +282,7 @@ export default class M5CharacterSheet extends ActorSheet { const data = this.actor.system; const character = this.actor as M5Character; - character.createItem((game as Game).i18n.localize("TYPES.Item.item"), M5ItemType.ITEM).then((i) => { - const item = i as any; - item.update({ - data: { - quantity: 1, - }, - }); - }); + character.createItem((game as Game).i18n.localize("TYPES.Item.item"), M5ItemType.ITEM, { quantity: 1 }); }); html.find(".add-weapon").on("click", async (event) => { @@ -317,42 +310,51 @@ export default class M5CharacterSheet extends ActorSheet { const data = this.actor.system; const character = this.actor as M5Character; - character.createItem((game as Game).i18n.localize("TYPES.Item.container"), M5ItemType.CONTAINER).then((i) => { - const item = i as any; - item.update({ - data: { - quantity: 1, - }, - }); - }); + character.createItem((game as Game).i18n.localize("TYPES.Item.container"), M5ItemType.CONTAINER, { quantity: 1 }); + }); + + html.find(".add-innate-skill").on("click", async (event) => { + const data = this.actor.system; + + const character = this.actor as M5Character; + character.createItem((game as Game).i18n.localize("TYPES.Item.innate-ability"), M5ItemType.SKILL, { type: M5SkillType.INNATE }); + }); + + html.find(".add-general-skill").on("click", async (event) => { + const data = this.actor.system; + + const character = this.actor as M5Character; + character.createItem((game as Game).i18n.localize("TYPES.Item.skill"), M5ItemType.SKILL, { type: M5SkillType.GENERAL }); + }); + + html.find(".add-combat-skill").on("click", async (event) => { + const data = this.actor.system; + + const character = this.actor as M5Character; + character.createItem((game as Game).i18n.localize("TYPES.Item.weapon-skill"), M5ItemType.SKILL, { type: M5SkillType.COMBAT }); + }); + + html.find(".add-language-skill").on("click", async (event) => { + const data = this.actor.system; + + const character = this.actor as M5Character; + character.createItem((game as Game).i18n.localize("TYPES.Item.language"), M5ItemType.SKILL, { type: M5SkillType.LANGUAGE }); }); html.find(".add-spell").on("click", async (event) => { const data = this.actor.system; const character = this.actor as M5Character; - character.createItem((game as Game).i18n.localize("TYPES.Item.spell"), M5ItemType.SPELL).then((i) => { - const item = i as any; - item.update({ - data: { - process: "none", - }, - }); - }); + character.createItem((game as Game).i18n.localize("TYPES.Item.spell"), M5ItemType.SPELL, { process: "none" }); }); html.find(".add-kampfkunst").on("click", async (event) => { const data = this.actor.system; const character = this.actor as M5Character; - character.createItem((game as Game).i18n.localize("TYPES.Item.kampfkunst"), M5ItemType.KAMPFKUNST).then((i) => { - const item = i as any; - item.update({ - data: { - type: "angriff", - variante: "anstuermen", - }, - }); + character.createItem((game as Game).i18n.localize("TYPES.Item.kampfkunst"), M5ItemType.KAMPFKUNST, { + type: "angriff", + variante: "anstuermen", }); }); @@ -363,6 +365,57 @@ export default class M5CharacterSheet extends ActorSheet { character.createItem((game as Game).i18n.localize("TYPES.Item.effect"), M5ItemType.EFFECT); }); + html.find(".join-combat").on("click", async (event) => { + if (!!game["combat"]) { + let combatant = game["combat"].getCombatantByActor(this.actor._id); + if (!combatant) { + await game["combat"].createEmbeddedDocuments("Combatant", [{ actorId: this.actor._id }]); + combatant = game["combat"].getCombatantByActor(this.actor._id); + } + + const initiatives = { + _id: combatant._id, + initiative: this.actor.system.calc.attributes.gw.value, + }; + + await game["combat"].updateEmbeddedDocuments("Combatant", [initiatives]); + } + }); + + html.find(".ranged-combat").on("click", async (event) => { + if (!!game["combat"]) { + let combatant = game["combat"].getCombatantByActor(this.actor._id); + if (!combatant) { + await game["combat"].createEmbeddedDocuments("Combatant", [{ actorId: this.actor._id }]); + combatant = game["combat"].getCombatantByActor(this.actor._id); + } + + const initiatives = { + _id: combatant._id, + initiative: 0.01 * this.actor.system.calc.attributes.gw.value, + }; + + await game["combat"].updateEmbeddedDocuments("Combatant", [initiatives]); + } + }); + + html.find(".spell-combat").on("click", async (event) => { + if (!!game["combat"]) { + let combatant = game["combat"].getCombatantByActor(this.actor._id); + if (!combatant) { + await game["combat"].createEmbeddedDocuments("Combatant", [{ actorId: this.actor._id }]); + combatant = game["combat"].getCombatantByActor(this.actor._id); + } + + const initiatives = { + _id: combatant._id, + initiative: 0.001 * this.actor.system.calc.attributes.gw.value, + }; + + await game["combat"].updateEmbeddedDocuments("Combatant", [initiatives]); + } + }); + // Drag & Drop const dragDrop = new DragDrop({ dragSelector: ".items-list .item", diff --git a/source/style/Character-sheet.less b/source/style/Character-sheet.less index 75a86bb..dd4dda2 100644 --- a/source/style/Character-sheet.less +++ b/source/style/Character-sheet.less @@ -217,6 +217,10 @@ height: 1rem; } + .wide-button { + margin: 0.25rem 0; + } + .learn-button { padding: 0; margin: 0; diff --git a/templates/chat/roll-m5.hbs b/templates/chat/roll-m5.hbs index 856e72b..0a10a2c 100644 --- a/templates/chat/roll-m5.hbs +++ b/templates/chat/roll-m5.hbs @@ -82,7 +82,7 @@ {{roll.label}} - {{roll.totalStr}} + {{roll.totalStr}} {{roll.result}} diff --git a/templates/sheets/character/combat.hbs b/templates/sheets/character/combat.hbs index e26b12a..a6705fb 100644 --- a/templates/sheets/character/combat.hbs +++ b/templates/sheets/character/combat.hbs @@ -1,5 +1,41 @@
-
+ +
+
+
{{localize "midgard5.calculated-values"}}
+ + + + + + + + + + + + + + + + + + + +
{{localize "midgard5.movementRange"}}{{data.calc.stats.movement.value}}{{localize "midgard5.initiative"}}{{data.calc.attributes.gw.value}}
{{localize "midgard5.defense"}}{{data.calc.stats.defense.value}}{{localize "midgard5.defenseBonus"}}{{data.calc.stats.defenseBonus.value}}
{{localize "midgard5.attackBonus"}}{{data.calc.stats.attackBonus.value}}{{localize "midgard5.damageBonus"}}{{data.calc.stats.damageBonus.value}}
+
+
+ +
+
+
{{localize "midgard5.initiative"}}
+ + + +
+
+ +
{{localize "midgard5.attack"}}
@@ -48,7 +84,7 @@ - + diff --git a/templates/sheets/character/effects.hbs b/templates/sheets/character/effects.hbs index 7af454d..d87114f 100644 --- a/templates/sheets/character/effects.hbs +++ b/templates/sheets/character/effects.hbs @@ -2,7 +2,7 @@ - + diff --git a/templates/sheets/character/gear.hbs b/templates/sheets/character/gear.hbs index 1e984ca..ea6cfac 100644 --- a/templates/sheets/character/gear.hbs +++ b/templates/sheets/character/gear.hbs @@ -31,11 +31,181 @@
-
- - {{localize "midgard5.gear"}} - (alle ) -
+
{{localize "TYPES.Item.container"}}
+
{{localize "midgard5.kampfkunst-variante-short"}} {{localize "midgard5.ew"}}
{{localize "TYPES.Item.effect"}}
+ + + + + + + + + + + {{#each data.calc.gear.containers as |item itemId|}} + + + + + + + + {{/each}} + +
{{localize "TYPES.Item.container"}}{{localize "midgard5.item-value"}} +
+ {{item.label}} + + {{#unless (or (eq item.value 0) (eq item.currency ""))}} + {{item.value}} {{localize (m5concat "midgard5.currency-" item.currency)}} + {{/unless}} + + {{#if item.equipped}} + + {{else}} + + {{/if}} + {{#if item.rollExist}}{{/if}}
+
+
+
+ +

{{localize "midgard5.itemsInContainers"}}

+
+ {{#each data.calc.gear.containers as |container containerId|}} +
+
+
{{container.label}}
+ + + + + + + + + + + + + + {{#each ../data.calc.gear.items as |item itemId|}} + {{#if (eq item.containerId containerId)}} + + + + + + + + + {{/if}} + {{/each}} + {{#each ../data.calc.gear.weapons as |item itemId|}} + {{#if (eq item.containerId containerId)}} + + + + + + + + + {{/if}} + {{/each}} + {{#each ../data.calc.gear.defensiveWeapons as |item itemId|}} + {{#if (eq item.containerId containerId)}} + + + + + + + + + {{/if}} + {{/each}} + {{#each ../data.calc.gear.armor as |item itemId|}} + {{#if (eq item.containerId containerId)}} + + + + + + + + + {{/if}} + {{/each}} + +
{{localize "TYPES.Item.item"}}{{localize "midgard5.item-quantity"}}{{localize "midgard5.item-value"}} 
+ {{item.label}} + + + {{item.quantity}} + + + {{#unless (or (eq item.value 0) (eq item.currency ""))}} + {{item.value}} {{localize (m5concat "midgard5.currency-" item.currency)}} + {{/unless}} + + {{#if item.equipped}} + + {{else}} + + {{/if}} + {{#if item.rollExist}}{{/if}}
+ {{item.label}} + + {{#unless (or (eq item.value 0) (eq item.currency ""))}} + {{item.value}} {{localize (m5concat "midgard5.currency-" item.currency)}} + {{/unless}} + + {{#if item.equipped}} + + {{else}} + + {{/if}} + {{#if item.rollExist}}{{/if}}
+ {{item.label}} + + {{#unless (or (eq item.value 0) (eq item.currency ""))}} + {{item.value}} {{localize (m5concat "midgard5.currency-" item.currency)}} + {{/unless}} + + {{#if item.equipped}} + + {{else}} + + {{/if}} + {{#if item.rollExist}}{{/if}}
+ {{item.label}} + + {{#unless (or (eq item.value 0) (eq item.currency ""))}} + {{item.value}} {{localize (m5concat "midgard5.currency-" item.currency)}} + {{/unless}} + + {{#if item.equipped}} + + {{else}} + + {{/if}} + {{#if item.rollExist}}{{/if}}
+
+
+ {{/each}} +
+ +

+ {{localize "midgard5.allItems"}} + + +

+
+
+
+
{{localize "midgard5.gear"}}
@@ -45,7 +215,7 @@ - + @@ -87,7 +257,9 @@
{{localize "midgard5.item-weight"}}
+
+
{{localize "midgard5.weapons"}}
@@ -97,7 +269,7 @@ - + @@ -128,7 +300,9 @@
{{localize "midgard5.item-value"}} {{localize "midgard5.item-weight"}}
+
+
{{localize "midgard5.defensive-weapons"}}
@@ -138,7 +312,7 @@ - + @@ -168,7 +342,9 @@
{{localize "midgard5.item-value"}} {{localize "midgard5.item-weight"}}
+
+
{{localize "midgard5.armor"}}
@@ -178,7 +354,7 @@ - + diff --git a/templates/sheets/character/skills.hbs b/templates/sheets/character/skills.hbs index b666208..15f9c72 100644 --- a/templates/sheets/character/skills.hbs +++ b/templates/sheets/character/skills.hbs @@ -11,7 +11,7 @@ - + @@ -56,7 +56,7 @@ - + @@ -66,7 +66,7 @@ - + @@ -86,7 +86,7 @@ - + @@ -116,7 +116,7 @@ - + diff --git a/templates/sheets/character/spells.hbs b/templates/sheets/character/spells.hbs index ff5db64..aef25db 100644 --- a/templates/sheets/character/spells.hbs +++ b/templates/sheets/character/spells.hbs @@ -4,7 +4,7 @@ - +
{{localize "midgard5.item-value"}} {{localize "midgard5.item-weight"}}
{{localize "midgard5.bonus"}} {{localize "midgard5.ew"}}
{{localize "midgard5.ew"}} {{localize "midgard5.pp-short"}}
{{skill.fw}} {{skill.calc.bonus}} {{skill.calc.ew}}{{skill.pp}}
{{localize "midgard5.ew"}} {{localize "midgard5.pp-short"}}
{{localize "midgard5.ew"}} {{localize "midgard5.pp-short"}}
{{localize "TYPES.Item.spell"}} {{localize "midgard5.ew"}}