Last active
January 23, 2019 19:34
-
-
Save Alpvax/cb0bf68dcc3b82d2b128cb713df41bfb to your computer and use it in GitHub Desktop.
Attribute
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const enum ModifyType {BASE_ADD, BASE_MULTIPLY, STACKING_MULTIPLY}; | |
interface Modifier<T extends ModifyType> { | |
amount: number; | |
modType: T; | |
}; | |
interface ChangeListener { | |
(attributeInstance: Attribute, oldValue: number): void; | |
} | |
export default class Attribute { | |
private baseValue: number; | |
private readonly modifiers: { | |
[mType in ModifyType]: Array<Modifier<mType>>; | |
}; | |
private readonly listeners: ChangeListener[]; | |
private cachedValue: number; | |
private dirty: boolean; | |
private min: number | void; | |
private max: number | void; | |
constructor(base: number, min?: number, max?: number) { | |
this.baseValue = base; | |
this.min = min; | |
this.max = max; | |
this.modifiers = [[], [], []]; | |
this.dirty = true; | |
this.listeners = []; | |
} | |
private markDirty(): void { | |
this.dirty = true; | |
this.listeners.forEach((l) => l(this, this.cachedValue)); | |
} | |
setRange(min: number, max?: number, base?: number): void { | |
if (max != undefined && min >= max) { | |
throw Error(`Cannot set minimum attribute value higher than maximum: {min: ${min}, max: ${max}}`); | |
} | |
this.min = min; | |
if (max != undefined) { | |
this.max = max; | |
} | |
if (base != undefined) { | |
this.baseValue = base; | |
this.markDirty(); | |
} else if (this.min > this.value || this.max < this.value) { | |
this.markDirty() | |
} | |
} | |
/* | |
* @param {function} listener A function called whenever the value is changed. Will recieve the attribute instance, and the old value as arguments. | |
* The new value can be calculated and retrieved with `attribute.value` | |
* @returns the same `listener` passed in for convenience. | |
*/ | |
onChange(listener): ChangeListener { | |
this.listeners.push(listener); | |
return listener; | |
} | |
offChange(listener): void { | |
const index = this.listeners.indexOf(listener); | |
if (index > -1) { | |
this.listeners.splice(index, 1); | |
} | |
} | |
get value(): number { | |
if(this.dirty) { | |
let val = this.baseValue; | |
let basemult = 1; | |
let mult = 1; | |
this.modifiers[ModifyType.BASE_ADD].forEach((m) => val += m.amount); | |
this.modifiers[ModifyType.BASE_MULTIPLY].forEach((m) => basemult += m.amount); | |
this.modifiers[ModifyType.STACKING_MULTIPLY].forEach((m) => mult *= m.amount); | |
this.cachedValue = val * basemult * mult; | |
this.dirty = false; | |
} | |
return this.cachedValue; | |
} | |
/* | |
* @param {Object} modifier An object containing a "key" property and one or more of the following keys with numerical values: | |
* @param {number} [modifier.baseAdd] Number to add to the base value before further calculations. | |
* @param {number} [modifier.baseMult] Number to multiply the modified base value by. Does not stack, so 2 `2x` multipliers will be a `3x` multiplier in total. | |
* @param {number} [modifier.stackingMult] Number to multiple the final value by. Stacks, so 2 `2x` multipliers will be a `4x` multiplier in total | |
* @param {number} [baseAdd] If `modifier` was just the key, this will be the value used for the modifier baseAdd property | |
* @param {number} [baseMult] If `modifier` was just the key, this will be the value used for the modifier baseMult property | |
* @param {number} [stackingMult] If `modifier` was just the key, this will be the value used for the modifier stackingMult property | |
* | |
* @example //Will increase the value by 3 | |
* attribute.addModifier({key: "exampleModifierKey", baseAdd: 3}); | |
* //Will multiply the (modified) base value by 2 (does not stack, so 2 *2 multipliers will be a x3 multiplier in total) | |
* attribute.addModifier({key: "exampleModifierKey2", baseMult: 2}); | |
* //Will multiply the final value by 4 (stacks, so 2 *2 multipliers will be a *4 multiplier in total) | |
* attribute.addModifier({key: "exampleModifierKey3", stackingMult: 4}); | |
*/ | |
addModifier<T extends ModifyType>(modifier: Modifier<T>): void { | |
(this.modifiers[modifier.modType] as Modifier<T>[]).push(modifier); | |
this.markDirty(); | |
} | |
removeModifier<T extends ModifyType>(modifier: Modifier<T>): boolean { | |
let list = this.modifiers[modifier.modType] as Modifier<T>[]; | |
const index = list.indexOf(modifier); | |
let flag = index > -1; | |
if (flag) { | |
list.splice(index, 1); | |
this.markDirty(); | |
} | |
return flag; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment