Adds mod calculation

This commit is contained in:
mstein
2022-07-13 02:44:14 +02:00
parent c8d59588e0
commit c827693e72
15 changed files with 497 additions and 131 deletions
+64 -32
View File
@@ -1,5 +1,6 @@
import { M5Item } from "../items/M5Item"
import { M5Attribute, M5CharacterCalculatedData, M5RollData, M5Skill, M5SkillCalculated, M5SkillLearned } from "../M5Base"
import { M5Attribute, M5CharacterCalculatedData, M5ItemMod, M5ModOperation, M5ModResult, M5RollData, M5Skill, M5SkillCalculated, M5SkillLearned } from "../M5Base"
import M5ModAggregate from "./M5ModAggregate"
export class M5Character extends Actor {
@@ -28,35 +29,38 @@ export class M5Character extends Actor {
return -2
}
derivedData(skip: { skills?: boolean, weapons?: boolean, defensiveWeapons?: boolean, armor?: boolean, items?: boolean, spells?: boolean } = {} ): M5CharacterCalculatedData {
derivedData(skip: { mods?: boolean, skills?: boolean, weapons?: boolean, defensiveWeapons?: boolean, armor?: boolean, items?: boolean, spells?: boolean } = {} ): M5CharacterCalculatedData {
let ret: M5CharacterCalculatedData = {
level: 0,
attributes: {
st: { value: 0, bonus: 0 },
gs: { value: 0, bonus: 0 },
gw: { value: 0, bonus: 0 },
ko: { value: 0, bonus: 0 },
in: { value: 0, bonus: 0 },
zt: { value: 0, bonus: 0 },
au: { value: 0, bonus: 0 },
pa: { value: 0, bonus: 0 },
wk: { value: 0, bonus: 0 }
st: { value: 0, bonus: 0, mods: [] },
gs: { value: 0, bonus: 0, mods: [] },
gw: { value: 0, bonus: 0, mods: [] },
ko: { value: 0, bonus: 0, mods: [] },
in: { value: 0, bonus: 0, mods: [] },
zt: { value: 0, bonus: 0, mods: [] },
au: { value: 0, bonus: 0, mods: [] },
pa: { value: 0, bonus: 0, mods: [] },
wk: { value: 0, bonus: 0, mods: [] }
},
stats: {
lp: { value: 0, mods: [] },
ap: { value: 0, mods: [] },
armor: 0,
defense: 0,
damageBonus: 0,
attackBonus: 0,
defenseBonus: 0,
movementBonus: 0,
resistanceMind: 0,
resistanceBody: 0,
spellCasting: 0,
brawl: 0,
defense: { value: 0, mods: [] },
damageBonus: { value: 0, mods: [] },
attackBonus: { value: 0, mods: [] },
defenseBonus: { value: 0, mods: [] },
movementBonus: { value: 0, mods: [] },
resistanceMind: { value: 0, mods: [] },
resistanceBody: { value: 0, mods: [] },
spellCasting: { value: 0, mods: [] },
brawl: { value: 0, mods: [] },
brawlEw: 0,
poisonResistance: 0,
poisonResistance: { value: 0, mods: [] },
enduranceBonus: 0
},
skillMods: {},
skills: {
innate: {},
general: {},
@@ -103,20 +107,37 @@ export class M5Character extends Actor {
ret.attributes.pa.bonus = M5Character.attributeBonus(data.attributes.pa)
ret.attributes.wk.bonus = M5Character.attributeBonus(data.attributes.wk)
ret.stats.lp = this.modResult(data.lp)
ret.stats.ap = this.modResult(data.ap)
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.brawlEw = ret.stats.brawl + ret.stats.attackBonus
ret.stats.poisonResistance = 30 + Math.floor(ret.attributes.ko.value / 2)
ret.stats.defense = this.modResult(M5Character.defenseFromLevel(ret.level))
ret.stats.damageBonus = this.modResult(Math.floor(ret.attributes.st.value/20) + Math.floor(ret.attributes.gs.value/30) - 3)
ret.stats.attackBonus = this.modResult(ret.attributes.gs.bonus)
ret.stats.defenseBonus = this.modResult(ret.attributes.gw.bonus)
ret.stats.movementBonus = this.modResult(0)
ret.stats.resistanceMind = this.modResult(ret.stats.defense.value)
ret.stats.resistanceBody = this.modResult(ret.stats.defense.value + 1)
ret.stats.spellCasting = this.modResult((data.info.magicUsing ? M5Character.spellCastingFromLevel(ret.level) : 3) + ret.attributes.zt.bonus)
ret.stats.brawl = this.modResult(Math.floor((ret.attributes.st.value + ret.attributes.gw.value) / 20))
ret.stats.brawlEw = ret.stats.brawl.value + ret.stats.attackBonus.value
ret.stats.poisonResistance = this.modResult(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)
if (!skip.mods) {
const aggregate = new M5ModAggregate(data, ret)
context.items?.filter(item => item.data.type === "item").forEach(item => {
const mods = item.data.data.mods
console.log("Actor item mods", mods)
Object.keys(mods).forEach(modIndex => {
const mod = mods[modIndex] as M5ItemMod
aggregate.push(mod, item.data.name)
})
})
ret.skillMods = aggregate.calculate()
}
if (!skip.items) {
context.items?.filter(item => item.data.type === "item").forEach(item => {
item.prepareDerivedData()
@@ -306,4 +327,15 @@ export class M5Character extends Actor {
return (this as any).getEmbeddedDocument("Item", itemId)
}
private modResult(value: number): M5ModResult {
return {
value: value,
mods: [{
item: (game as Game).i18n.localize("ACTOR.TypeCharacter"),
operation: M5ModOperation.SET,
value: value
}]
}
}
}
+164
View File
@@ -0,0 +1,164 @@
import { M5Attribute, M5AttributeCalculated, M5Attributes, M5CharacterCalculatedData, M5ItemMod, M5ModOperation, M5ModResult, M5ModSource, M5ModType, M5Stats, M5ModPair } from "../M5Base"
export default class M5ModAggregate {
private attributes = new Map<string, Array<M5ModPair>>()
private stats = new Map<string, Array<M5ModPair>>()
private skills = new Map<string, Array<M5ModPair>>()
constructor(public data: any, public calc: M5CharacterCalculatedData) {
const characterString = (game as Game).i18n.localize("ACTOR.TypeCharacter")
this.push({ type: M5ModType.ATTRIBUTE, id: M5Attributes.ST, operation: M5ModOperation.SET, value: data.attributes.st.value }, characterString)
this.push({ type: M5ModType.ATTRIBUTE, id: M5Attributes.GS, operation: M5ModOperation.SET, value: data.attributes.gs.value }, characterString)
this.push({ type: M5ModType.ATTRIBUTE, id: M5Attributes.GW, operation: M5ModOperation.SET, value: data.attributes.gw.value }, characterString)
this.push({ type: M5ModType.ATTRIBUTE, id: M5Attributes.KO, operation: M5ModOperation.SET, value: data.attributes.ko.value }, characterString)
this.push({ type: M5ModType.ATTRIBUTE, id: M5Attributes.IN, operation: M5ModOperation.SET, value: data.attributes.in.value }, characterString)
this.push({ type: M5ModType.ATTRIBUTE, id: M5Attributes.ZT, operation: M5ModOperation.SET, value: data.attributes.zt.value }, characterString)
this.push({ type: M5ModType.ATTRIBUTE, id: M5Attributes.AU, operation: M5ModOperation.SET, value: data.attributes.au.value }, characterString)
this.push({ type: M5ModType.ATTRIBUTE, id: M5Attributes.PA, operation: M5ModOperation.SET, value: data.attributes.pa.value }, characterString)
this.push({ type: M5ModType.ATTRIBUTE, id: M5Attributes.WK, operation: M5ModOperation.SET, value: data.attributes.wk.value }, characterString)
this.push({ type: M5ModType.ATTRIBUTE, id: M5Attributes.ST, operation: M5ModOperation.ADD_100, value: data.attributes.st.bonus }, characterString)
this.push({ type: M5ModType.ATTRIBUTE, id: M5Attributes.GS, operation: M5ModOperation.ADD_100, value: data.attributes.gs.bonus }, characterString)
this.push({ type: M5ModType.ATTRIBUTE, id: M5Attributes.GW, operation: M5ModOperation.ADD_100, value: data.attributes.gw.bonus }, characterString)
this.push({ type: M5ModType.ATTRIBUTE, id: M5Attributes.KO, operation: M5ModOperation.ADD_100, value: data.attributes.ko.bonus }, characterString)
this.push({ type: M5ModType.ATTRIBUTE, id: M5Attributes.IN, operation: M5ModOperation.ADD_100, value: data.attributes.in.bonus }, characterString)
this.push({ type: M5ModType.ATTRIBUTE, id: M5Attributes.ZT, operation: M5ModOperation.ADD_100, value: data.attributes.zt.bonus }, characterString)
this.push({ type: M5ModType.ATTRIBUTE, id: M5Attributes.AU, operation: M5ModOperation.ADD_100, value: data.attributes.au.bonus }, characterString)
this.push({ type: M5ModType.ATTRIBUTE, id: M5Attributes.PA, operation: M5ModOperation.ADD_100, value: data.attributes.pa.bonus }, characterString)
this.push({ type: M5ModType.ATTRIBUTE, id: M5Attributes.WK, operation: M5ModOperation.ADD_100, value: data.attributes.wk.bonus }, characterString)
this.push({ type: M5ModType.STAT, id: M5Stats.DEFENSE, operation: M5ModOperation.SET, value: calc.stats.defense.value }, characterString)
this.push({ type: M5ModType.STAT, id: M5Stats.ATTACK, operation: M5ModOperation.SET, value: calc.stats.attackBonus.value }, characterString)
this.push({ type: M5ModType.STAT, id: M5Stats.DAMAGE, operation: M5ModOperation.SET, value: calc.stats.damageBonus.value }, characterString)
this.push({ type: M5ModType.STAT, id: M5Stats.MOVEMENT, operation: M5ModOperation.SET, value: calc.stats.movementBonus.value }, characterString)
this.push({ type: M5ModType.STAT, id: M5Stats.RESISTANCE_MIND, operation: M5ModOperation.SET, value: calc.stats.resistanceMind.value }, characterString)
this.push({ type: M5ModType.STAT, id: M5Stats.RESISTANCE_BODY, operation: M5ModOperation.SET, value: calc.stats.resistanceBody.value }, characterString)
this.push({ type: M5ModType.STAT, id: M5Stats.SPELL_CASTING, operation: M5ModOperation.SET, value: calc.stats.spellCasting.value }, characterString)
this.push({ type: M5ModType.STAT, id: M5Stats.BRAWL, operation: M5ModOperation.SET, value: calc.stats.brawl.value }, characterString)
this.push({ type: M5ModType.STAT, id: M5Stats.POISON_RESISTANCE, operation: M5ModOperation.SET, value: calc.stats.poisonResistance.value }, characterString)
this.push({ type: M5ModType.STAT, id: M5Stats.LP, operation: M5ModOperation.SET, value: calc.stats.lp.value }, characterString)
this.push({ type: M5ModType.STAT, id: M5Stats.AP, operation: M5ModOperation.SET, value: calc.stats.ap.value }, characterString)
}
push(mod: M5ItemMod, source: string) {
if (!mod?.id || mod.id === "")
return
let map: Map<string, Array<M5ModPair>> = null
if (mod.type === M5ModType.ATTRIBUTE)
map = this.attributes
else if (mod.type === M5ModType.STAT)
map = this.stats
else if (mod.type === M5ModType.SKILL)
map = this.skills
if (map) {
const pair: M5ModPair = {
mod: mod,
source: source
}
let key = mod.id
if (mod.type === M5ModType.ATTRIBUTE)
key = (mod.id + "").toLowerCase()
else if (mod.type === M5ModType.STAT)
key = (mod.id + "").toLowerCase()
if (map.has(key))
map.get(key).push(pair)
else
map.set(key, [pair])
}
}
calculate() {
const calc = this.calc
this.attributes.forEach((pairs, id) => {
const res = M5ModAggregate.processPairs(pairs)
calc.attributes[id] = {
value: res.value,
bonus: M5ModAggregate.attributeBonus(res.value),
mods: res.mods
} as M5AttributeCalculated
//console.log("calc.attributes." + id, calc.attributes[id])
})
this.stats.forEach((pairs, id) => {
const res = M5ModAggregate.processPairs(pairs)
calc.stats[id] = res
})
const ret = {}
this.skills.forEach((pairs, id) => {
ret[id] = pairs
})
return ret
}
static pairAsSource(pair: M5ModPair): M5ModSource {
return {
operation: pair.mod.operation,
value: pair.mod.value,
item: pair.source
}
}
static processPairs(arr: Array<M5ModPair>): M5ModResult {
let ret: M5ModResult = {
mods: [],
value: 0
}
let mods = arr.filter(pair => pair.mod.operation === M5ModOperation.FIXED).sort((a, b) => b.mod.value - a.mod.value)
let pair = mods.length === 0 ? null : mods[0]
if (pair) {
ret.mods.push(this.pairAsSource(pair))
ret.value = pair.mod.value
} else {
mods = arr.filter(pair => pair.mod.operation === M5ModOperation.SET).sort((a, b) => b.mod.value - a.mod.value)
if (mods.length !== 0) {
ret.mods.push(this.pairAsSource(mods[0]))
ret.value = mods[0].mod.value
}
mods = arr.filter(pair => pair.mod.operation === M5ModOperation.ADD_100)
if (mods.length !== 0) {
ret.mods = ret.mods.concat(mods.map(this.pairAsSource))
const bonus = mods.map(p => p.mod.value).reduce((a, b) => a + b, 0)
ret.value = Math.min(100, Math.max(0, ret.value + bonus))
}
mods = arr.filter(pair => pair.mod.operation === M5ModOperation.ADD)
if (mods.length !== 0) {
ret.mods = ret.mods.concat(mods.map(this.pairAsSource))
const bonus = mods.map(p => p.mod.value).reduce((a, b) => a + b, 0)
ret.value = Math.max(0, ret.value + bonus)
}
}
return ret
}
static attributeMinMax(attribute: M5Attribute) {
return Math.min(100, Math.max(0, attribute.value + attribute.bonus))
}
static attributeBonus(value: number) {
if (value > 95)
return 2
if (value > 80)
return 1
if (value > 20)
return 0
if (value > 5)
return -1
return -2
}
//static modToString(mod: M5ItemMod): string { }
}