0

I tried to be as clear as possibile in the title, but I'll be more specific to my situation.

Problem 1: I have a Player with some slots which can hold items. Each slot is a Slot<Equippable> where Equippable is an interface just to group different items together: Armor, Weapon, etc. Now I come to face a problem: the Player has some parameters (e.g. Dexterity, Strength, etc.) and when an item is worn, it may affect one of these parameters. Up until now, I had simple items which added a bonus to a parameter, which was determined by the slot on which the item was (e.g.: Hands -> Strength, Feet -> Dexterity); so I just checked the bonus in the worn item and calculated the right parameter, when I needed it. But I need to change this: I need a more versatile way to handle this situation, because I don't want to bind the parameter to the slot and I cannot check every worn item anytime I need to get a parameter. Instead, I think I should be able to do the converse, i.e. update the correct parameter when an item is worn. I know this can take long to design completely and, of course, I am not asking this. I just need the right input because I am stuck.
To put it simply, I need something like: player wears item, does item give one bonus or more? If yes, apply bonus to the correct parameters. If not, do something else.
Possible solution: make an Update method which is called anytime an item is worn or removed. Cons: I must be careful in every place I should call this method. Also, this method should check what type of item it is, if it gives a bonus or more (and to what), or if it does something completely different.

Problem 2: This is related to the first problem, so I put it in the same question. Conceptually, I divided parameters in independent and dependent. The first ones just depend on the Player so they are stored in there, the second ones are calculated from the first ones and, possibly, from items (directly). Until now, I kept the dependent parameters only as properties, whose getter calculated the right formula when needed. So the dependent parameters are not stored, but only calculated as an "output" when required.
But introducting the items requires me to change those values, according to items. Here I used to follow the same reasoning as before: I checked the right item and calculated directly into the formula. Since now I need to change direction (as in problem 1), I need to update them anytime the correct item is worn.
Two possible solutions:

  • Store a Bonus field and take it into account in the calculation. Pros: immediate change; Cons: I may need to store various different bonuses, ending with a mess.
  • Store also the dependent parameters. Pros: I could use the same reasoning as in Problem 1, when solved. Cons: now, I get a stored parameter and not just the result of a calculation, so I need to change it anytime the independent parameters are changed. This probably can be solved as in Problem 1.

I hope you really can help me with this. Maybe I'm just overdoing and it can be solved with a simpler approach, or by doing a smart implementation of the items.

Addendum: I'll give your more context, as to how items are implemented. For now, they just contain a plain bonus (or more) and the slot in which they are placed determines the parameter. For example, an Armor gives me two bonuses which need to be added to ArmorClass (parameter) and another value involved in calculation. Since only one slot contains Armor, I know where to check. To avoid depending on the slot, I plan to include a key for each bonus which tells me what to modify with it. Also, other items (like rings, etc.) don't have three fixed values like Armor but have a variable number of them. I'll probably need a dictionary. So the operation will be: wear item -> check bonuses -> check corresponding parameter in key -> modify it in Player; and this is more precisely what I'm asking in Problem 1.

  • I say every "equipage" adds (bonus) value. Sometimes that value is zero. Now there are no special cases. – radarbob Apr 22 '17 at 1:03
  • "I cannot check every worn item anytime I need to get a parameter" - Why not? Why do you need to change it? – Ben Cottrell Apr 22 '17 at 10:03
  • @radarbob: yeah, I had thought of that, though some items have more than one bonus, so I'll have to keep more than one default value for each item. But myabe I'll just stick with that :) – Harnak Apr 22 '17 at 10:18
  • @BenCottrell: the fact is that everytime I use a parameter it gets calculated from other parameters and this is not a problem because I exactly know which parameter changes which. Though, with items it's not a fixed thing. Say I have to get Armor Class, then I have to check every item to see if it modifies Armor Class and add the present bonuses. Also, sometimes two items give the same bonus which won't stack on the same parameters, so I should keep track of that also. The other way around seems more simple: wear item -> update bonus to correct param (if it already has of that type, don't). – Harnak Apr 22 '17 at 10:23
  • 2
    What I mean is - what is so bad about recalculating it each time? Presumably your calculation happens inside a method so you're not duplicating any code or making the code more complex by recalculating it? You'd just be calling a function again? – Ben Cottrell Apr 22 '17 at 10:37
1

This is just a quick thing that comes to my mind. I hope it helps and I hope I understood your problems correctly :)

For an approach to "solve" both problems and the things you stated in the addendum, this could be a possible design:

// Create an enum of possible stats
enum StatType {
    Strength, Dexterity, ...
};

// This is the basic idea of a stat/parameter. 
struct Stat {
    StatType Id;  // Example: Strength
    int Value;  // Example: 10
    // Whatever other fields you want to 
}

class Stats {
    public Stat GetStat(StatType Id) { 
        return statsDict[Id]; // Think about what you wanna do if the stat doesn't exist. You might wanna create that stat and initialize its value with 0 and then return it.
    }

    public void SetStat(StatType Id, Stat val) {
        // Set stat in dict
    }

    private Dictionary<StatType , Stat> statsDict;
}

In your Equippable interface, add the stats to store the stats affected by the equipment:

interface Equippable {
    Stats AffectedStats;
    ...
}

Then in the player class you could have fields storing the player's base stats and the combined stats. When a player equips an item, you'll need to recalculate the combined stats.

class Player {
    Stats BaseStats;
    Stats CombinedStats;

    void Equip(...) {
        // Code to equip item
        // Then recalculate the CombinedStats
        this.CalculateCombinedStats();
    }

    void CalculateCombindedStats() {
        // Add Base Stats + all Equipment Stats and store the results to this.CombinedStats
    }

    void PlayerStatsChange(...) {
       // Change Player's base stats (LevelUp, ...)
       // The recalculate the CombinedStats
       this.CalculateCombinedStats();
    }
}

This way you can always access Base and Combined stats separately (which solves problem 2) and you only update the combined stats when they actually change (which solves problem 1). An item that boosts multiple stats is not a problem any more, since the dictionary is flexible.

  • Grouping stats in that way is a nice and simple idea, that will probably do the trick. I will try this, thanks! – Harnak Apr 22 '17 at 10:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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