All files / models Character.js

81.58% Statements 31/38
48.28% Branches 14/29
70.59% Functions 12/17
84.85% Lines 28/33
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89      1x                                         4x 4x 4x   4x                         7x 4x   4x   19x 19x   6x   6x 11x 33x 11x     6x 8x   8x     6x           8x 8x 8x 14x 11x         8x   8x   8x     8x      
import { defaultsDeep, flow, forOwn, pickBy } from 'lodash'
import math from '../vendor/mathjs'
 
const DEFAULT = {
  effects: [],
  equipment: [],
  layers: [{
    attributes: {},
    effects: [],
  }],
  attribute: {
    max: undefined,
    min: undefined,
    value: 0,
  },
}
 
export default class Character {
  constructor(
    /* Character Info */
    { effects = DEFAULT.effects, equipment = DEFAULT.equipment, layers = DEFAULT.layers } = {},
    /* Options */
    { attribute } = {}
  ) {
    this.effects = effects || DEFAULT.effects
    this.equipment = equipment || DEFAULT.equipment
    this.layers = layers || DEFAULT.layers
 
    this.defaults = {
      attribute: defaultsDeep(attribute, DEFAULT.attribute),
    }
  }
 
  get ActiveEffects() {
    return [
      ...this.layers.filter(layer => layer.active !== false).map(layer => layer.effects || []),
      ...this.equipment.filter(item => item.equipped).map(item => item.effects || []),
      ...this.effects || [],
    ]
  }
  get Attributes() {
    const activeLayers = this.layers.filter(layer => layer.active !== false)
    const attributeDefaults = this.defaults.attribute
 
    return (
      activeLayers.reduce((attrs, layer) => {
        const numericals = pickBy(layer.attributes, value => typeof(value) === 'number')
        const calculated = pickBy(layer.attributes, value => typeof(value) === 'string')
 
        const changes = {}
 
        forOwn(numericals, (value, key) => {
          const current = [attrs[key], attributeDefaults.value, 0]
                          .filter(v => typeof(v) === 'number')[0]
          attrs[key] = value + current
        })
 
        Object.keys(calculated)
        .map(key => ({ key, calc: calculated[key] }))
        .forEach(({ key, calc }) => {
          changes[key] = this.calculate(calc, attrs, attributeDefaults)
        })
 
        return { ...attrs, ...changes }
      }, {})
    )
  }
 
  calculate(formula, values, options) {
    const parser = math.parser()
    const parsed = math.parse(formula)
    parsed.traverse(node => {
      if (node.type === 'SymbolNode') {
        parser.set(node.name,
          values[node.name] !== undefined ? values[node.name] : options.value
        )
      }
    })
    let result = parser.eval(formula)
 
    Iif (typeof(options.min) === 'number' && result < options.min)
      result = options.min
    Iif (typeof(options.max) === 'number' && result > options.max)
      result = options.max
 
    return result
  }
}