3
\$\begingroup\$

In my game, each unit has two types of HP: Hard and Soft. Soft represents the human part of the unit, while hard represents anything mechanical. For example, a regular rifleman would have 100 softHP, and 0 hardHP. Another example would be the Tank which has 100 soft and 1000 hard (subject to balancing).

Now, the problem I'm facing is the fact that it should be enough for one of these types of HPs to be =< 0 for the unit to die - a Tank can't work without its driver, and it needs its gears, nuts, and bolts to function properly.

At first I was thinking of setting the soft and hard values for a unit, but leave, for example infantry, with an undefined value for hard HP, but this becomes an issue when a weapon hurts a unit: A weapon can hurt both hard and soft. A check for undefined value also becomes an issue, as many other things can affect HP as well, thus necessitating this check to be done many places, which to me seems very redundant. Another thing I was thinking of would be to set the hard HP for infantry abnormally high, to the point where it would "never" reach 0, but this is bound to bite me at a later point, I'm sure. I could easily overcome this hurdle some other way, but I would love some fresh eyes on this, in case there are any obvious solutions that I'm missing.

Any suggestions? Pseudo-code would be appreciated.

\$\endgroup\$
  • 1
    \$\begingroup\$ what about using a couple of attributes like bool canDieHard and bool canDieSoft ? \$\endgroup\$ – Leggy7 Aug 9 '16 at 13:36
  • 2
    \$\begingroup\$ Can you just have one HP per object, and some objects can be compound objects. A tank has a human object with 100HP and a tank object with 1000HP. Each sub-object tracks its own HP remaining, each sub-object can be customized on what weapons affect it, and how. Heck, a tank can have a special weapon attachment that could be damaged, but the tank can still be functional. Just a thought. \$\endgroup\$ – Doug.McFarlane Aug 9 '16 at 19:20
3
\$\begingroup\$

The solution by congusbongus is good, but I would suggest a solution which is scalable to even more HP types. The advantage of this method is that you can easily add more damage types later without editing any of the old units which aren't supposed to have them, like for example EMP damage which only affects high-tech units or PSI damage which only affects psionic units.

Implement the HP values of a unit as an associative array (also called "Dictionary" in some programming languages) with key HpType and value int. The array can have any number of entries (including none, which would be a completely invulnerable unit). The definition files could look like this:

units = [
    {   name: "Rifleman", 
        HP: { soft: 100 },
    },    
    {   name: "Psyker", 
        HP: { soft: 80 
              psi: 100 }
    },  
    {   name: "Tank", 
        HP: { soft: 100 
              hard: 1000 },
    },    
    {   name: "Anti-Grav Laser Tank", 
        HP: { soft: 100 
              hard: 1500 
              emp: 50 }
    },   
    {   name: "Psi Cyber Mecha Bot 3000", 
        HP: { soft: 80 
              hard: 3000 
              emp: 100
              psi: 100 }
    }
]

The method to reduce the amount of HP of a unit takes two arguments, HpType and value. The method first checks if the unit actually has an entry in the HP associative array for that damage type. When it doesn't find one, it does nothing. When it does find a corresponding entry, the value is decremented, and when less-or-equal zero afterwards the unit is destroyed:

function reduceHpIfApplicable(HpType type, int amount) {
     if (this.HP[type] != null) {
          this.HP[type] -= amount;
          if (this.HP[type] <= 0) {
               this.isAlive = false;
          }
     }
}

tl;dr: This is a variant of the "undefined" solution.

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Chosing this, as it's in line with something I've considering doing later on: Damage Types (piercing, slashing, bludgeoning, heat) \$\endgroup\$ – Jarmund Aug 10 '16 at 7:29
  • \$\begingroup\$ @Jarmund Do you want "slashing damage" to only reduce the target's "slashing hp"? It seems a bit like you want different damage types to have a different distribution over different HP types. In that case you should separate DamageType from HpType. Otherwise this is going to get really messy. \$\endgroup\$ – Philipp Aug 10 '16 at 14:47
4
\$\begingroup\$

Going with an "undefined", or "special" value for HP is the way to go, but you don't have to worry about having to check for it in many places as long as you abstract it well.

There are many ways to do it, but depending on your language one of the more abstract ways to do it is to use a different strategy for it, and use it to handle all the things you want out of a HP object, and don't worry about how it's actually represented - numeric or else. In your example, you may want to damage(), or ask it isDead(). So focus on those interfaces:

class HP {
    // private; don't worry about this if you're not the HP class
    int value;

    // used for things like the UI
    func getString() { return value; } 

    func damage(amount) { value -= amount; }

    func isDead() { return value <= 0; }
}

And then you have a special class for "undefined" HP:

class UndefinedHP : HP {
    // in your UI you may want to handle this like display a grayed-out bar
    func getString() { return "undefined"; }

    // does nothing
    func damage(amount) { }

    // always alive
    func isDead() { return false; }
}

And then your units might look like:

units = [
    {name: "rifleman", softHP: HP(100), hardHP: UndefinedHP()},
    {name: "tank", softHP: HP(100), hardHP: HP(100)}
]

Then you deal hard/soft damage to these units and things will just work - the rifleman will never die from hard damage, and so on.

|improve this answer|||||
\$\endgroup\$

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.