454 lines
11 KiB
TypeScript
454 lines
11 KiB
TypeScript
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('TYPES.Actor.character');
|
|
|
|
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.defenseBonus.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.movement.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
|
|
);
|
|
this.push(
|
|
{
|
|
type: M5ModType.STAT,
|
|
id: M5Stats.PROTECTION_LP,
|
|
operation: M5ModOperation.SET,
|
|
value: calc.stats.lpProtection.value,
|
|
},
|
|
characterString
|
|
);
|
|
this.push(
|
|
{
|
|
type: M5ModType.STAT,
|
|
id: M5Stats.PROTECTION_AP,
|
|
operation: M5ModOperation.SET,
|
|
value: calc.stats.apProtection.value,
|
|
},
|
|
characterString
|
|
);
|
|
this.push(
|
|
{
|
|
type: M5ModType.STAT,
|
|
id: M5Stats.PERCEPTION,
|
|
operation: M5ModOperation.SET,
|
|
value: calc.stats.perception.value,
|
|
},
|
|
characterString
|
|
);
|
|
this.push(
|
|
{
|
|
type: M5ModType.STAT,
|
|
id: M5Stats.DRINKING,
|
|
operation: M5ModOperation.SET,
|
|
value: calc.stats.drinking.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,
|
|
};
|
|
|
|
if (map.has(mod.id)) map.get(mod.id).push(pair);
|
|
else map.set(mod.id, [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);
|
|
}
|
|
|
|
mods = arr.filter(pair => pair.mod.operation === M5ModOperation.SUBTRACT);
|
|
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 = ret.value - bonus;
|
|
}
|
|
|
|
mods = arr.filter(pair => pair.mod.operation === M5ModOperation.MULTIPLY);
|
|
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, 1);
|
|
ret.value = Math.max(0, ret.value * bonus);
|
|
}
|
|
|
|
mods = arr.filter(pair => pair.mod.operation === M5ModOperation.DIVISION);
|
|
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, 1);
|
|
ret.value = Math.max(0, Math.floor(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 { }
|
|
}
|