import { M5Character } from "../actors/M5Character" import M5ModAggregate from "../actors/M5ModAggregate" import { enumKeys, M5Attributes, M5ModOperation, M5ModPair, M5ModType, M5RollData, M5RollResult, M5Stats } from "../M5Base" import { M5Roll } from "../rolls/M5Roll" export class M5Item extends Item { static readonly SKILL = "skill" prepareDerivedData() { const itemId: string = (this as any).id const itemType: string = (this as any).type const actor = (this.actor as any) const character = actor as M5Character const itemData = (this as any).system const calc = itemData.calc if (itemType === "skill") { calc.fw = itemData.fw calc.bonus = 0 let pairs: Array = [{ source: (this as any).name, mod: { type: M5ModType.SKILL, id: itemId, operation: M5ModOperation.SET, value: itemData.fw } }] if (character) { const actorCalc = character.derivedData({ skills: true, weapons: true, defensiveWeapons: true, armor: true, items: true, spells: true }) if (actorCalc?.skillMods && Object.keys(actorCalc.skillMods).indexOf(itemId) !== -1) { pairs = pairs.concat(actorCalc.skillMods[itemId]) } if (itemData?.attribute && itemData.attribute !== "") { pairs.push({ source: (this as any).name, mod: { type: M5ModType.SKILL, id: itemId, operation: M5ModOperation.ADD, value: actorCalc.attributes[itemData.attribute].bonus } }) } } const res = M5ModAggregate.processPairs(pairs) res.mods.forEach(mod => { if ([M5ModOperation.SET, M5ModOperation.FIXED].includes(mod.operation)) calc.fw = mod.value else calc.bonus += mod.value }) calc.ew = calc.fw + calc.bonus calc.sources = res.mods } else if (itemType === "weapon") { calc.fw = 0 calc.bonus = 0 calc.special = itemData.special ? 2 : 0 calc.ew = calc.special + itemData.stats.attackBonus calc.combatSkills = null if (actor) { const actorCalc = character.derivedData({ weapons: true, defensiveWeapons: true, armor: true, items: true, spells: true }) if (actorCalc) { calc.ew += actorCalc.stats.attackBonus.value calc.combatSkills = actorCalc.skills.combat } const skill = character.getItem(itemData.skillId) //console.log("M5Item.prepareDerivedData:weapon", itemData, skill?.system) if (skill) { skill.prepareDerivedData() const skillData = skill.system calc.ew += skillData.calc.ew calc.bonus += skillData.calc.bonus calc.fw += skillData.fw } } } else if (itemType === "defensiveWeapon") { calc.fw = 0 calc.bonus = 0 calc.special = itemData.special ? 2 : 0 calc.ew = calc.special + itemData.stats.defenseBonus calc.combatSkills = null if (actor) { const actorCalc = character.derivedData({ weapons: true, defensiveWeapons: true, armor: true, items: true, spells: true }) if (actorCalc) { calc.ew += actorCalc.stats.defense.value + actorCalc.stats.defenseBonus.value calc.combatSkills = actorCalc.skills.combat } const skill = character.getItem(itemData.skillId) //console.log("M5Item.prepareDerivedData:weapon", itemData, skill?.system) if (skill) { skill.prepareDerivedData() const skillData = skill.system calc.ew += skillData.calc.ew calc.bonus += skillData.calc.bonus calc.fw += skillData.fw } } } else if (itemType === "spell") { calc.ew = itemData.bonus if (actor) { const actorCalc = character.derivedData({ weapons: true, defensiveWeapons: true, armor: true, items: true, spells: true }) if (actorCalc) { calc.ew += actorCalc.stats.spellCasting.value } } } else if (itemType === "item") { calc.mods = {} Object.keys(itemData?.mods).forEach(key => { const mod = itemData.mods[key] const modCalc = {} switch (mod.type) { case M5ModType.ATTRIBUTE: { for (const key of enumKeys(M5Attributes)) { const val: string = M5Attributes[key] modCalc[val] = (game as Game).i18n.localize(`midgard5.actor-${val}-long`) } break } case M5ModType.STAT: { for (const key of enumKeys(M5Stats)) { const val: string = M5Stats[key] modCalc[val] = (game as Game).i18n.localize(`midgard5.mod-stat-${val}`) } break } case M5ModType.SKILL: { if (character) { const actorCalc = character.derivedData({ weapons: true, defensiveWeapons: true, armor: true, items: true, spells: true }) if (actorCalc) { let category = (game as Game).i18n.localize("midgard5.skill") Object.keys(actorCalc.skills.general).forEach(skillId => { const skill = character.getItem(skillId) if (skill) modCalc[skillId] = `${category}: ${skill.name}` }) category = (game as Game).i18n.localize("midgard5.language") Object.keys(actorCalc.skills.language).forEach(skillId => { const skill = character.getItem(skillId) if (skill) modCalc[skillId] = `${category}: ${skill.name}` }) category = (game as Game).i18n.localize("midgard5.weapon-skill") Object.keys(actorCalc.skills.combat).forEach(skillId => { const skill = character.getItem(skillId) if (skill) modCalc[skillId] = `${category}: ${skill.name}` }) category = (game as Game).i18n.localize("midgard5.innate-ability") Object.keys(actorCalc.skills.innate).forEach(skillId => { const skill = character.getItem(skillId) if (skill) modCalc[skillId] = `${category}: ${skill.name}` }) } } break } } calc.mods[key] = modCalc }) } } getRollData() { const actor = this.actor as any const item = this as any let ret: M5RollData = actor?.getRollData() ?? { c: null, i: null, iType: null, rolls: {}, res: {} } ret.i = item.system ret.iType = item.type return ret } async roll() { const item = (this as any) // Initialize chat data. const speaker = ChatMessage.getSpeaker({ actor: this.actor }) const rollMode = (game as Game).settings.get('core', 'rollMode') const label = `[${item.type}] ${item.name}` // If there's no roll data, send a chat message. const formulaNames = item.system.rolls?.formulas ? Object.keys(item.system.rolls.formulas) : [] if (formulaNames.length > 0) { const rollData = this.getRollData() formulaNames.forEach(formulaName => { const formula = item.system.rolls.formulas[formulaName] if (formula) { rollData.rolls[formulaName] = { formula: formula.formula, label: formula.label, enabled: formula.enabled, result: "", total: 0, totalStr: "", dice: {} } as M5RollResult } }) const roll = new M5Roll(rollData, this.actor, item.name) return roll.toMessage() } else { ChatMessage.create({ speaker: speaker, rollMode: rollMode, flavor: label, content: item.system.description ?? '' }) return null } } getItem(itemId: string): any { return (this as any).getEmbeddedDocument("Item", itemId) } }