236 lines
7.0 KiB
TypeScript
236 lines
7.0 KiB
TypeScript
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 actor = (this.actor as any)
|
|
const character = actor as M5Character
|
|
const context = (this as any).data
|
|
const calc = context.data.calc
|
|
|
|
if (context.type === "skill") {
|
|
calc.fw = context.data.fw
|
|
calc.bonus = 0
|
|
|
|
let pairs: Array<M5ModPair> = [{
|
|
source: context.name,
|
|
mod: {
|
|
type: M5ModType.SKILL,
|
|
id: context._id,
|
|
operation: M5ModOperation.SET,
|
|
value: context.data.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(context._id) !== -1) {
|
|
pairs = pairs.concat(actorCalc.skillMods[context._id])
|
|
}
|
|
|
|
if (context.data?.attribute && context.data?.attribute !== "") {
|
|
pairs.push({
|
|
source: context.name,
|
|
mod: {
|
|
type: M5ModType.SKILL,
|
|
id: context._id,
|
|
operation: M5ModOperation.ADD,
|
|
value: actorCalc.attributes[context.data.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 (context.type === "weapon") {
|
|
calc.fw = 0
|
|
calc.bonus = 0
|
|
calc.special = context.data.special ? 2 : 0
|
|
calc.ew = calc.special + context.data.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
|
|
calc.combatSkills = actorCalc.skills.combat
|
|
}
|
|
|
|
const skill = character.getItem(context.data.skillId)
|
|
//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.bonus += skillData.calc.bonus
|
|
calc.fw += skillData.fw
|
|
}
|
|
}
|
|
} else if (context.type === "defensiveWeapon") {
|
|
calc.fw = 0
|
|
calc.bonus = 0
|
|
calc.special = context.data.special ? 2 : 0
|
|
calc.ew = calc.special + context.data.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(context.data.skillId)
|
|
//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.bonus += skillData.calc.bonus
|
|
calc.fw += skillData.fw
|
|
}
|
|
}
|
|
} else if (context.type === "spell") {
|
|
calc.ew = context.data.bonus
|
|
if (actor) {
|
|
const actorCalc = character.derivedData({ weapons: true, defensiveWeapons: true, armor: true, items: true, spells: true })
|
|
if (actorCalc) {
|
|
calc.ew += actorCalc.stats.spellCasting
|
|
}
|
|
}
|
|
} else if (context.type === "item") {
|
|
calc.mods = {}
|
|
Object.keys(context.data?.mods).forEach(key => {
|
|
const mod = context.data.mods[key]
|
|
const modCalc = {}
|
|
switch (mod.type) {
|
|
case M5ModType.ATTRIBUTE: {
|
|
for (const key of enumKeys(M5Attributes)) {
|
|
const val = M5Attributes[key]
|
|
modCalc[key] = (game as Game).i18n.localize(`midgard5.actor-${val}-long`)
|
|
}
|
|
break
|
|
}
|
|
case M5ModType.STAT: {
|
|
for (const key of enumKeys(M5Stats)) {
|
|
const val = M5Stats[key]
|
|
modCalc[key] = (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.data.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.data.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.data.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.data.name}`
|
|
})
|
|
}
|
|
}
|
|
break
|
|
}
|
|
}
|
|
|
|
calc.mods[key] = modCalc
|
|
})
|
|
}
|
|
}
|
|
|
|
getRollData() {
|
|
const actor = this.actor as any
|
|
const context = (this as any).data
|
|
|
|
let ret: M5RollData = actor?.getRollData() ?? {
|
|
c: null,
|
|
i: null,
|
|
iType: null,
|
|
rolls: {},
|
|
res: {}
|
|
}
|
|
|
|
ret.i = context.data
|
|
ret.iType = context.type
|
|
return ret
|
|
}
|
|
|
|
async roll() {
|
|
const item = (this as any).data
|
|
|
|
// 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.data.rolls?.formulas ? Object.keys(item.data.rolls.formulas) : []
|
|
if (formulaNames.length > 0) {
|
|
const rollData = this.getRollData()
|
|
formulaNames.forEach(formulaName => {
|
|
const formula = item.data.rolls.formulas[formulaName]
|
|
rollData.rolls[formulaName] = {
|
|
formula: formula.formula,
|
|
label: formula.label,
|
|
type: formula.type,
|
|
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.data.description ?? ''
|
|
})
|
|
return null
|
|
}
|
|
}
|
|
|
|
getItem(itemId: string): any {
|
|
return (this as any).getEmbeddedDocument("Item", itemId)
|
|
}
|
|
|
|
}
|