Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I am developing an MMORPG server using NodeJS.

I am not sure how to implement Buffs, i mean, equipped objects or used skills have effects on the Player() which has many Stats(), some of them have a max cap...

Effects can change the Stat value, increasing or decreasing it by a value, a percentage or completly rewrite the value of the stat.

After a while I have decided to create a base class for buffs, which can be hidden (if they are casted from an equipped object) or shown if they came from an ability (Spell).

Anyway I need suggestion how to implement it, use an array for all active buffs for a stat and have a function calculate the value of the stat affected by buffs each time I need the value of the stat or...? Other more OOP's ways to do it?

I have read this What's a way to implement a flexible buff/debuff system? but this implements only a percentage system, which buffs can only say "+10%, +20%, etc...", but I would love to have an hybrid system, which can have percentage values or static values (like WoW does), and using modifiers it's hard to implement, because modifiers refers to the current value of stat :/

Thanks for suggestions :)

share|improve this question
add comment

3 Answers

up vote 2 down vote accepted

Just some short ideas:

  1. Only re-calculate the Player's stats when buffs/debuffs occure, not when you need the value. Much likely to what Sequel-based Databases do with indicies (MySQL for example updates the index cache on each write execution providing a verry fast interface for reading data).

  2. When you have multiple Types of values, you need to think of a formula or a hirachy. EvE online for example uses mostly percentage values with a stacking penalty. You take each percentage value into an array, sort it so the highest value comes in first, then for each percentage value in the array the following recieves a higher penalty. This is basicly a formula instead of a hierachy. Ragnarok Online did something simillar, there you had fixed values and percentages, you first took all your fixed + and - modifiers, added them to your base value, then added all the percentages onto that value.

its really up to your game design, everyone does it diferently.

for the OOP question:

I would highly recommend looking into entity systems, using effects as baseclass for buffs, debuffs, item boni, etc and stack them all into one array, or remove them when their timer runns out or whatever you like.

share|improve this answer
1  
+1 For entity systems and the pluralization of bonus. –  akled Nov 16 '12 at 21:05
add comment

Since you wish to have three types of buffs, you will need a priority system. Which types of buffs comes first? Do you completely change the stat and then add values or ignore other buffs?

Since you wish to use OOP I would use an Interface for this. Every spell, weapon or piece of equipment that is imbued with power should implement the the interface. The interface will include a getter function that classifies the type of buff and when it comes into play(priority) and another getter that determines the potency of the buff for the calculation.

Weapons or equipment that is not buffed should implement the interface and possibly return some generic value such as -1, 0 or null for these values.

share|improve this answer
add comment

A little example for you, i hope it will be helpful.

// Base game object
var GObject = function () {
    // Entities storage
    this.entity = {
        hp: new GEntityHp()
        // ...
    };

    // Storage for buffs, debuffs
    this.buffs = [];
};

GObject.prototype.addBuff = function (buff) {
    buff.applyTo(this);

    this.buffs.push(buff);
};

// Entity Health
var GEntityHp = function () {
    // Unique entity name
    this.name = 'hp';

    // Entity components
    this.data = {
        curValue: 1, // current health value
        maxValue: 1, // maximum health value
        maxBonus: 0  // maximum health bonus, %
    }
};

GEntityHp.prototype.getCur = function () {
    return this.data.curValue;
};

GEntityHp.prototype.getMax = function () {
    return this.data.maxValue + this.data.maxValue * this.data.maxBonus / 100;
};

GEntityHp.prototype.update = function (list) {
    var self = this;
    list.forEach(function (data) {
        data.key in self.data && (self.data[data.key] += data.value);
    });
};

// Game buff
var GBuff = function (data) {
    // Buff bonuses grouped by entity name
    this.data = data || {};

    this._applied = false;
};

// Apply buff to given game object..
GBuff.prototype.applyTo = function (gObject) {
    if (!this._applied) {
        this._applied = true;

        var self = this;

        Object.keys(this.data).forEach(function (entityName) {
            var entity = gObject.entity[entityName];

            if (entity) {
                entity.update(self.data[entityName]);
            }
        });

    }
};

// Let test

var gObject = new GObject();

gObject.addBuff(new GBuff({
    hp: [
        {key: 'maxValue', value: 99},
        {key: 'maxBonus', value: 25}
    ]
}));

alert('hp: ' + gObject.entity.hp.getCur() + ',' + gObject.entity.hp.getMax());​
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.