Search code examples
javascriptobjecteval

Object "Item" is used to modify data on Object "player"


I'm trying to code a simple text RPG using JS and I wanted to perform this:

I have two objects: Player and Item. "Potion" is one instance of Item, and it increases Player hp by 30 when used.

I'm using the following code and it works fine, but I'd like to know if there is a "better" way to perform this without using "eval". Note that the "ef" key in the instance of Item must specify which keys of Player it affects and what it must do.

class Player {
    constructor(a={}) {
        this.na = a.na
        this.st = {hp: 100, atk: 10, def: 10, en: 50}
    }
}

class Item {
    static potion = new this({
        na: "Potion",
        ef: ['st.hp', '+= 30']
    })
    
    constructor(a={}) {
        this.na = a.na
        this.ef = a.ef ?? []
    }
    
    use(target) {
        eval(`target.${this.ef[0]} ${this.ef[1]}`)
    }
}

const me = new Player({na: "Azmuth"})
Item.potion.use(me)
console.log(me)

Sorry for bad english/explanation and thank you in advance.


Solution

  • I suggest to handle applying items in the player class since it has more info about itself to properly assign values, also storing data as an array isn't very good, just use separate properties. You can introduce negative values for assigning or a callback:

    class Player {
        constructor(a={}) {
            this.na = a.na
            this.st = {hp: 100, atk: 10, def: 10, en: 50}
        }
        useItem(item){
            const {key, value} = item;
            let node = this;
            const path = key.split('.');
            const valKey = path.pop();
            for(const k of path){
              node = node[k] ??= {};
            }
            if(typeof value === 'function') node[valKey] = value(node[valKey]);
            else node[valKey] += value;
            return this;
        }
    }
    
    class Item {
    
        static potion = new this({
            na: "Potion",
            key: 'st.hp',
            value: 30
        })
        
        constructor(a = {}) {
            return a;
        }
        
    }
    
    const me = new Player({na: "Azmuth"})
    me.useItem(Item.potion);
    console.log(me)
    
    me.useItem(new Item({key: 'st.atk', value: v => v * 2}));
    console.log(me)