From 7f7e305722f9bbd050e4f73f62d887d885022035 Mon Sep 17 00:00:00 2001 From: mstein Date: Fri, 10 Jun 2022 14:27:28 +0200 Subject: [PATCH] Add weapon item handling --- gulpfile.ts | 20 ++-- lang/de.json | 8 +- source/index.ts | 2 +- source/module/actors/M5Character.ts | 139 +++++++++++++++-------- source/module/items/M5Item.ts | 20 +++- source/module/sheets/M5CharacterSheet.ts | 22 +++- source/module/sheets/M5ItemSheet.ts | 1 + source/template.json | 47 +++++--- templates/sheets/character/gear.hbs | 18 +++ templates/sheets/character/skills.hbs | 12 +- templates/sheets/item/weapon.hbs | 51 ++++++++- 11 files changed, 252 insertions(+), 88 deletions(-) diff --git a/gulpfile.ts b/gulpfile.ts index b2dc842..0d88760 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -157,7 +157,7 @@ function buildTS() { const bundleModule = () => { const debug = argv.dbg || argv.debug const bsfy = browserify(path.join(__dirname, "source/index.ts"), { debug: debug }) - return bsfy.on('error', Logger.Err) + return bsfy.on('error', Logger.err) .plugin(tsify) .bundle() .pipe(source(path.join(distPath, "bundle.js"))) @@ -252,7 +252,7 @@ const copyFiles = async() => { return Promise.resolve() const filter = (src: string, dest: string): boolean => { - Logger.Ok("Copying file: " + dest) + Logger.ok("Copying file: " + dest) return true } @@ -292,7 +292,7 @@ const cleanDist = async () => { if (file.endsWith("bundle.js") || file.endsWith(".css") || file.endsWith("module.json")) continue - Logger.Warn("Cleaning " + path.relative(process.cwd(), file)) + Logger.warn("Cleaning " + path.relative(process.cwd(), file)) await fs.promises.unlink(file) } } @@ -364,12 +364,12 @@ const linkUserData = async () => { } //if (argv.clean || argv.c) { - Logger.Warn(`Removing build in ${linkDir}`) + Logger.warn(`Removing build in ${linkDir}`) fs.rmSync(linkDir, { recursive: true, force: true }) fs.mkdirSync(linkDir) //} - Logger.Ok(`Copying build to ${linkDir}`) + Logger.ok(`Copying build to ${linkDir}`) fs.copySync(path.resolve(distPath), linkDir, { overwrite: true }) return Promise.resolve() @@ -388,7 +388,7 @@ const linkUserData = async () => { async function packageBuild() { const manifest = getManifest() if (manifest === null) { - Logger.Err("Manifest file could not be loaded.") + Logger.err("Manifest file could not be loaded.") throw Error() } @@ -396,7 +396,7 @@ async function packageBuild() { try { // Remove the package dir without doing anything else if (argv.clean || argv.c) { - Logger.Warn("Removing all packaged files") + Logger.warn("Removing all packaged files") fs.rmSync(distPath, { force: true, recursive: true }) return } @@ -411,8 +411,8 @@ async function packageBuild() { const zip = archiver("zip", { zlib: { level: 9 } }) zipFile.on("close", () => { - Logger.Ok(zip.pointer() + " total bytes") - Logger.Ok(`Zip file ${zipName} has been written`) + Logger.ok(zip.pointer() + " total bytes") + Logger.ok(`Zip file ${zipName} has been written`) return resolve(true) }) @@ -492,7 +492,7 @@ const updateManifest = (cb: any) => { return cb(Error("Error: Target version is identical to current version.")) } - Logger.Ok(`Updating version number to '${targetVersion}'`) + Logger.ok(`Updating version number to '${targetVersion}'`) packageJson.version = targetVersion manifest.file.version = targetVersion diff --git a/lang/de.json b/lang/de.json index 12109ab..21f3728 100644 --- a/lang/de.json +++ b/lang/de.json @@ -143,5 +143,11 @@ "midgard5.learned-skill": "Gelernte Fertigkeit", "midgard5.language": "Sprache", "midgard5.weapon-skill": "Waffenfertigkeit", - "midgard5.unlearned-skill": "Ungelernte Fertigkeit" + "midgard5.unlearned-skill": "Ungelernte Fertigkeit", + + "midgard5.base-damage": "Grundschaden", + "midgard5.defensive-weapon": "Verteidigungswaffe", + "midgard5.no-skill": "Keine Fertigkeit", + "midgard5.magic": "magisch", + "midgard5.rangedWeapon": "Schusswaffe" } diff --git a/source/index.ts b/source/index.ts index d6eb4d7..cbb959c 100644 --- a/source/index.ts +++ b/source/index.ts @@ -62,5 +62,5 @@ Hooks.once("setup", () => { }) Hooks.once("ready", () => { - Logger.Ok("Template module is now ready.") + Logger.ok("Template module is now ready.") }) diff --git a/source/module/actors/M5Character.ts b/source/module/actors/M5Character.ts index 15351af..02ddf05 100644 --- a/source/module/actors/M5Character.ts +++ b/source/module/actors/M5Character.ts @@ -30,6 +30,14 @@ export interface M5CharacterCalculatedData { } skills: { general: {} + combat: {} + language: {} + custom: {} + } + gear: { + weapons: {} + armor: {} + items: {} } } @@ -60,10 +68,8 @@ export class M5Character extends Actor { return -2 } - prepareDerivedData() { - const context = (this as any).data - - context.data.calc = { + derivedData(skipSkills: boolean, skipWeapons: boolean): M5CharacterCalculatedData { + let ret: M5CharacterCalculatedData = { level: 0, attributes: { st: { value: 0, bonus: 0 }, @@ -95,56 +101,93 @@ export class M5Character extends Actor { combat: {}, language: {}, custom: {} + }, + gear: { + weapons: {}, + armor: {}, + items: {} } } as M5CharacterCalculatedData + const context = (this as any).data const data = context.data - const calc = context.data.calc as M5CharacterCalculatedData - calc.level = M5Character.levelFromExp(data.es) + ret.level = M5Character.levelFromExp(data.es) - calc.attributes.st.value = M5Character.attributeMinMax(data.attributes.st) // TODO item effects - calc.attributes.gs.value = M5Character.attributeMinMax(data.attributes.gs) - calc.attributes.gw.value = M5Character.attributeMinMax(data.attributes.gw) - calc.attributes.ko.value = M5Character.attributeMinMax(data.attributes.ko) - calc.attributes.in.value = M5Character.attributeMinMax(data.attributes.in) - calc.attributes.zt.value = M5Character.attributeMinMax(data.attributes.zt) - calc.attributes.au.value = M5Character.attributeMinMax(data.attributes.au) - calc.attributes.pa.value = M5Character.attributeMinMax(data.attributes.pa) - calc.attributes.wk.value = M5Character.attributeMinMax(data.attributes.wk) + ret.attributes.st.value = M5Character.attributeMinMax(data.attributes.st) // TODO item effects + ret.attributes.gs.value = M5Character.attributeMinMax(data.attributes.gs) + ret.attributes.gw.value = M5Character.attributeMinMax(data.attributes.gw) + ret.attributes.ko.value = M5Character.attributeMinMax(data.attributes.ko) + ret.attributes.in.value = M5Character.attributeMinMax(data.attributes.in) + ret.attributes.zt.value = M5Character.attributeMinMax(data.attributes.zt) + ret.attributes.au.value = M5Character.attributeMinMax(data.attributes.au) + ret.attributes.pa.value = M5Character.attributeMinMax(data.attributes.pa) + ret.attributes.wk.value = M5Character.attributeMinMax(data.attributes.wk) - calc.attributes.st.bonus = M5Character.attributeBonus(data.attributes.st) - calc.attributes.gs.bonus = M5Character.attributeBonus(data.attributes.gs) - calc.attributes.gw.bonus = M5Character.attributeBonus(data.attributes.gw) - calc.attributes.ko.bonus = M5Character.attributeBonus(data.attributes.ko) - calc.attributes.in.bonus = M5Character.attributeBonus(data.attributes.in) - calc.attributes.zt.bonus = M5Character.attributeBonus(data.attributes.zt) - calc.attributes.au.bonus = M5Character.attributeBonus(data.attributes.au) - calc.attributes.pa.bonus = M5Character.attributeBonus(data.attributes.pa) - calc.attributes.wk.bonus = M5Character.attributeBonus(data.attributes.wk) + ret.attributes.st.bonus = M5Character.attributeBonus(data.attributes.st) + ret.attributes.gs.bonus = M5Character.attributeBonus(data.attributes.gs) + ret.attributes.gw.bonus = M5Character.attributeBonus(data.attributes.gw) + ret.attributes.ko.bonus = M5Character.attributeBonus(data.attributes.ko) + ret.attributes.in.bonus = M5Character.attributeBonus(data.attributes.in) + ret.attributes.zt.bonus = M5Character.attributeBonus(data.attributes.zt) + ret.attributes.au.bonus = M5Character.attributeBonus(data.attributes.au) + ret.attributes.pa.bonus = M5Character.attributeBonus(data.attributes.pa) + ret.attributes.wk.bonus = M5Character.attributeBonus(data.attributes.wk) - calc.stats.armor = 0 - calc.stats.defense = M5Character.defenseFromLevel(calc.level) - calc.stats.damageBonus = Math.floor(calc.attributes.st.value/20) + Math.floor(calc.attributes.gs.value/30) - 3 - calc.stats.attackBonus = calc.attributes.gs.bonus - calc.stats.defenseBonus = calc.attributes.gw.bonus - calc.stats.movementBonus = 0 - calc.stats.resistanceMind = calc.stats.defense - calc.stats.resistanceBody = calc.stats.defense + 1 - calc.stats.spellCasting = (data.info.magicUsing ? M5Character.spellCastingFromLevel(calc.level) : 3) + calc.attributes.zt.bonus - calc.stats.brawl = Math.floor((calc.attributes.st.value + calc.attributes.gw.value) / 20) - calc.stats.poisonResistance = 30 + Math.floor(calc.attributes.ko.value / 2) - calc.stats.enduranceBonus = Math.floor(calc.attributes.ko.value/10) + Math.floor(calc.attributes.st.value/20) + ret.stats.armor = 0 + ret.stats.defense = M5Character.defenseFromLevel(ret.level) + ret.stats.damageBonus = Math.floor(ret.attributes.st.value/20) + Math.floor(ret.attributes.gs.value/30) - 3 + ret.stats.attackBonus = ret.attributes.gs.bonus + ret.stats.defenseBonus = ret.attributes.gw.bonus + ret.stats.movementBonus = 0 + ret.stats.resistanceMind = ret.stats.defense + ret.stats.resistanceBody = ret.stats.defense + 1 + ret.stats.spellCasting = (data.info.magicUsing ? M5Character.spellCastingFromLevel(ret.level) : 3) + ret.attributes.zt.bonus + ret.stats.brawl = Math.floor((ret.attributes.st.value + ret.attributes.gw.value) / 20) + ret.stats.poisonResistance = 30 + Math.floor(ret.attributes.ko.value / 2) + ret.stats.enduranceBonus = Math.floor(ret.attributes.ko.value/10) + Math.floor(ret.attributes.st.value/20) - context.items?.filter(item => item.data.type === "skill").forEach(item => { - item.prepareDerivedData() - const skillMap = calc.skills[item.data.data.type] - skillMap[item.data._id] = { - label: item.data.name, - fw: item.data.data.fw, - attribute: item.data.data.attribute, - calc: item.data.data.calc - } - }) + if (!skipSkills) { + context.items?.filter(item => item.data.type === "skill").forEach(item => { + item.prepareDerivedData() + const skillMap = ret.skills[item.data.data.type] + skillMap[item.data._id] = { + label: item.data.name, + fw: item.data.data.fw, + attribute: item.data.data.attribute, + calc: item.data.data.calc + } + }) + } + + if (!skipWeapons) { + context.items?.filter(item => item.data.type === "weapon").forEach(item => { + item.prepareDerivedData() + + let label = item.data.name + if (item.data.data.magic) { + label += "*(" + + (item.data.data.stats.attackBonus < 0 ? "" : "+") + + item.data.data.stats.attackBonus + "/" + + (item.data.data.stats.damageBonus < 0 ? "" : "+") + + item.data.data.stats.damageBonus + ")" + } + + ret.gear.weapons[item.data._id] = { + label: label, + skillId: item.data.data.skillId, + defensive: item.data.data.defensive, + magic: item.data.data.magic, + calc: item.data.data.calc + } + }) + } + + return ret + } + + prepareDerivedData() { + const context = (this as any).data + context.data.calc = this.derivedData(false, false) } override getRollData(): any { @@ -220,4 +263,8 @@ export class M5Character extends Actor { }) } + getSkill(skillId: string): M5Skill { + return (this as any).getEmbeddedDocument("Item", skillId) as M5Skill + } + } diff --git a/source/module/items/M5Item.ts b/source/module/items/M5Item.ts index f1d5885..f932e98 100644 --- a/source/module/items/M5Item.ts +++ b/source/module/items/M5Item.ts @@ -14,17 +14,33 @@ export class M5Item extends Item { calc.bonus = 0 if (context.data.attribute && context.data.attribute !== "") { - //console.log(context.name, context.data) const attribute = character.attribute(context.data.attribute) calc.bonus += M5Character.attributeBonus(attribute) } - if (context._id === actor.data.data.skills.preferredCombatSkill) { + if (context._id === actor.data?.data?.skills.preferredCombatSkill) { calc.bonus += 2 } calc.ew = context.data.fw + calc.bonus } else if (context.type === "weapon") { + calc.ew = context.data.stats.attackBonus + calc.combatSkills = null + + if (actor) { + const actorCalc = character.derivedData(false, true) + calc.ew += actorCalc.stats.attackBonus + + const skill = character.getSkill(context.data.skillId) as any + //console.log("M5Item.prepareDerivedData:weapon", context.data, skill?.data?.data) + if (skill) { + skill.prepareDerivedData() + const skillData = skill.data.data + calc.ew += skillData.calc.ew + } + + calc.combatSkills = actorCalc.skills.combat + } } } diff --git a/source/module/sheets/M5CharacterSheet.ts b/source/module/sheets/M5CharacterSheet.ts index 44cdc25..c56b34a 100644 --- a/source/module/sheets/M5CharacterSheet.ts +++ b/source/module/sheets/M5CharacterSheet.ts @@ -37,18 +37,18 @@ export default class M5CharacterSheet extends ActorSheet { override activateListeners(html: JQuery) { super.activateListeners(html) - html.find(".edit-skill").on("click", async (event) => { + html.find(".edit-item").on("click", async (event) => { const row = event.target.parentElement - let skillId = row.dataset["skill"] + let itemId = row.dataset["item"] const context = this.actor.data - const item = context.items.get(skillId) + const item = context.items.get(itemId) item.sheet.render(true) }) html.find(".change-special-combat-skill").on("click", async (event) => { const row = event.target.parentElement.parentElement - let skillId = row.dataset["skill"] + let skillId = row.dataset["item"] const actor = this.actor as any actor.update({ @@ -62,7 +62,7 @@ export default class M5CharacterSheet extends ActorSheet { html.find(".roll-learned-button").on("click", async (event) => { const row = event.target.parentElement.parentElement - let skillId = row.dataset["skill"] + let skillId = row.dataset["item"] const actor = this.actor as any const context = this.actor.data @@ -139,6 +139,18 @@ export default class M5CharacterSheet extends ActorSheet { }) }) + html.find(".roll-weapon-button").on("click", async (event) => { + const row = event.target.parentElement.parentElement + let itemId = row.dataset["item"] + + const actor = this.actor as any + const context = this.actor.data + const data = context.data + + const item = context.items.get(itemId) as M5Item + await item.roll() + }) + // Drag & Drop const dragDrop = new DragDrop({ dragSelector: ".items-list .item", diff --git a/source/module/sheets/M5ItemSheet.ts b/source/module/sheets/M5ItemSheet.ts index 1e6322a..d845dcb 100644 --- a/source/module/sheets/M5ItemSheet.ts +++ b/source/module/sheets/M5ItemSheet.ts @@ -30,6 +30,7 @@ export class M5ItemSheet extends ItemSheet { let actor = this.object?.parent ?? null if (actor) { context.rollData = actor.getRollData() + } else { } // Add the actor's data to context.data for easier access, as well as flags. diff --git a/source/template.json b/source/template.json index 212f21e..200ecba 100644 --- a/source/template.json +++ b/source/template.json @@ -116,9 +116,6 @@ "templates": ["characterBars", "attributes", "characterDescription", "characterHeader", "skills"], "calc": {} }, - "npc": { - "templates": ["characterBars", "attributes", "characterDescription"] - }, "vehicle": { "templates": ["characterBars", "attributes"] } @@ -130,13 +127,15 @@ "description": "" }, "stats": { - "damageBonus": 0, - "attackBonus": 0, - "defenseBonus": 0, - "movementBonus": 0, - "resistanceMind": 0, - "resistanceBody": 0, - "spellBonus": 0 + "stats": { + "damageBonus": 0, + "attackBonus": 0, + "defenseBonus": 0, + "movementBonus": 0, + "resistanceMind": 0, + "resistanceBody": 0, + "spellBonus": 0 + } }, "attributeSelection": { "attributes": { @@ -190,30 +189,46 @@ "rolls": { "formulas": {}, "output": "" - } + }, + "calc": {} }, "weapon": { "templates": ["itemDescription", "stats", "equippable"], + "magic": false, + "ranged": false, "defensive": false, - "skill": "", + "skillId": "", + "damageBase": "1d6", "rolls": { - "formulas": {}, + "formulas": { + "1": { + "formula": "1d20 + @i.calc.ew", + "type": "ew" + }, + "2": { + "formula": "@i.damageBase + @i.stats.damageBonus + @c.calc.stats.damageBonus", + "type": "dmg" + } + }, "output": "" - } + }, + "calc": {} }, "armor": { "templates": ["itemDescription", "stats", "equippable"], "rolls": { "formulas": {}, "output": "" - } + }, + "calc": {} }, "spell": { "templates": ["itemDescription"], "rolls": { "formulas": {}, "output": "" - } + }, + "calc": {} } } } \ No newline at end of file diff --git a/templates/sheets/character/gear.hbs b/templates/sheets/character/gear.hbs index e69de29..c3c985a 100644 --- a/templates/sheets/character/gear.hbs +++ b/templates/sheets/character/gear.hbs @@ -0,0 +1,18 @@ + + + + + + + + + + {{#each data.calc.gear.weapons as |weapon itemId|}} + + + + + + {{/each}} + +
{{localize "ITEM.TypeWeapon"}}{{localize "midgard5.ew"}}
{{weapon.label}}{{weapon.calc.ew}}
diff --git a/templates/sheets/character/skills.hbs b/templates/sheets/character/skills.hbs index bc3fc2a..6fd2db8 100644 --- a/templates/sheets/character/skills.hbs +++ b/templates/sheets/character/skills.hbs @@ -10,8 +10,8 @@ {{#each data.calc.skills.general as |skill skillId|}} - - {{skill.label}} + + {{skill.label}} {{skill.fw}} {{skill.calc.bonus}} {{skill.calc.ew}} @@ -41,8 +41,8 @@ {{#each data.calc.skills.language as |skill skillId|}} - - {{skill.label}} + + {{skill.label}} {{skill.fw}} {{skill.calc.bonus}} {{skill.calc.ew}} @@ -73,8 +73,8 @@ {{#each data.calc.skills.combat as |skill skillId|}} - - {{skill.label}} + + {{skill.label}} {{#if (eq skillId ../data.skills.preferredCombatSkill)}} diff --git a/templates/sheets/item/weapon.hbs b/templates/sheets/item/weapon.hbs index 0f256a2..e3b3e45 100644 --- a/templates/sheets/item/weapon.hbs +++ b/templates/sheets/item/weapon.hbs @@ -4,7 +4,56 @@

- + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + +
{{localize "midgard5.base-damage"}} + {{#if data.defensive}} + Not available for defensive weapons + {{else}} + + {{/if}} + {{localize "midgard5.weapon-skill"}} + {{#if data.calc.combatSkills}} + + {{else}} + Assign item to character to select weapon skill + {{/if}} +
{{localize "midgard5.attackBonus"}}{{localize "midgard5.damageBonus"}}
{{editor content=data.description target="data.description" button=true owner=owner editable=editable}}
\ No newline at end of file