Home Reference Source

src/jg/character.js

import _ from 'lodash';
import qualities from "./qualities/index";

const _prioritySort = ({priority}) => -priority || 0;
const _groupOmitKeys = ['id', 'name', 'priority', 'hidden'];

/**
 * This class is created from the character object you specify in your game.
 */
export default class Character {
    /**
     * 
     * @param {object} args 
     * @param {string} args.id
     * @param {string} args.name
     * @param {number} args.priority
     * @param {Boolean} args.showInSidebar
     * @param {string|function(): string} args.description Currently unused
     * @param {quality[]} args.qualities
     * @param {*} args.state Initial value of {@link state}
     */
    constructor({qualities, id, name, priority = 0, showInSidebar = true, description = '', state = {}}) {
        /**
         * The ID you specified for this character. Must be unique across all characters.
         * @type {string}
         */
        this.id = id;

        /**
         * The name you specified for this character.
         * @type {string}
         */
        this.name = name;

        /**
         * Arbitrary, JSON-safe data about this character. You may update it any time you want.
         * @type {*}
         */
        this.state = _.cloneDeep(state); 

        Object.assign(this, {qualities, description, showInSidebar, priority});

        this.updateQualities()
    }

    /** @ignore */
    updateQualities() {
        this._shallowQualities = {};
        Object.keys(this.qualities).forEach((k) => {
            const group = this.qualities[k];
            group.id = k;
            for (const k2 of _.keys(_.omit(group, _groupOmitKeys))) {
                if (this._shallowQualities[k2]) {
                    throw Error("You have two qualities with the same ID. Please don't do that.")
                }
                group[k2].id = k2;
                this._shallowQualities[k2] = group[k2];
                if (group[k2].value === undefined) group[k2].value = group[k2].initialValue;
            }
        });
        /** @ignore */
        this.sortedQualityGroups = _.sortBy(Object.values(this.qualities), _prioritySort);
    }

    /** @ignore */
    toSave() {
        return _.pick(this, ['id', 'qualities', 'name', 'showInSidebar', 'description', 'state']);
    }

    /** @ignore */
    loadSave(obj) {
        _.assign(this, obj);
        this.updateQualities();
    }

    /** @ignore */
    getDescription() {
        if (_.isFunction(this.description)) {
            return this.description.apply(this, arguments);
        } else {
            return this.description || this.id;
        }
    }

    /** @ignore */
    sortedQualities(groupName) {
        return _.sortBy(Object.values(_.omit(this.qualities[groupName], _groupOmitKeys)), _prioritySort);
    }

    /**
     * Return the current value of this quality (without formatting it)
     * 
     * @param {string} id ID of the quality whose value you want
     * @returns {*}
     */
    getQuality(id) {
        return this._shallowQualities[id].value;
    }

    /**
     * Return the _initial_ value of this quality from the start of the game(without formatting it).
     * You can use this to see how the value has changed since the start of the game.
     * 
     * @param {string} id ID of the quality whose value you want
     * @returns {*}
     */
    getQualityInitial(id) {
        return this._shallowQualities[id].initialValue;
    }

    /**
     * Returns the formatted value of the given quality.
     * 
     * @param {string} id ID of the quality whose value you want
     * @returns {string}
     */
    formatQuality(id) {
        const quality = this._shallowQualities[id];
        if (!qualities[quality.type]) {
            console.error("Undefined quality type:", quality.type);
            return '';
        }
        return qualities[quality.type].format(this, quality, quality.value);
    }

    /**
     * Return the human-readable name for the given quality ID.
     * 
     * @param {string} id ID of the quality whose value you want
     * @returns {string}
     */
    formatQualityName(id) {
        const quality = this._shallowQualities[id];
        return quality.name;
    }

    /**
     * Qualities **must** be modified using this method.
     * 
     * @param {string} id ID of the quality to modify on this character
     * @param {*} value New value for the quality
     */
    setQuality(id, value) {
        this._shallowQualities[id].value = value;
    }

    /**
     * Add an integer value to the given quality.
     * 
     * @param {string} id ID of the quality to modify on this character
     * @param {number} delta Amount to add
     * @returns {number} The new value
     */
    addToQuality(id, delta) {
        return this._shallowQualities[id].value += delta;
    }
}