Manifest is a competitive, two-player, turn-based strategy mod for Warcraft III developed by Finn Haverkamp.

Report RSS Hero Revival: An Excercise in Revision Part 1

The fantastic story of one man's efforts to rewrite perfectly working code for absolutely no reason. Part 1 of the epic saga begins here.

Posted by on

I missed posting yesterday. And I mean "missed" both in the sense that I did not post and in the sense that I psychologically did not enjoy having not posted. But I'm here today to make up for it. Just for you. So let's get down to it.

Today ladies and gentlemen, we're going to discuss hero revival. Hero revival is when a hero dies and then, later, revives. Heroes in Manifest are trained. Players may have only five heroes, and they choose their hero load-out at the beginning of the game. For a while, heroes were manually revivable as soon as they died. To my knowledge, I am unable to set cooldown periods for individual heroes, limiting when they may be revived individually. I'm on a turn-based system, remember, so I can't simply set a preset revival timer for each hero as turn lengths are extremely variable. I needed something concrete, and allowing players to revive their heroes as they wished wasn't cutting it.

I decided to automatically revive heroes on a set turn following their deaths. Puzzling together this code was extremely enjoyable, and I'm happy to share it with you today. First, though, I need to explain a couple of things about magical little code elements called "variables" for those who do not know.

I don't actually know how to explain this perfectly technically, so I'll explain in layman's the best I can. Variables are savable, storable, named pieces of data. Variables may come in many types, determined by the coding language used. In the World Editor, this includes integers, units, regions, pretty much anything. I'd say that variables are on par with If/Then/Else statements as the most useful programmer's tool available. When in doubt, use a variable.

Let's talk about some examples. Let's say you have 5 units. And you want to remember how many units there are. "How many," in this case, would be an integer (if there were decimal points it would be a "real"). So, to store how many units there are, you would create and name a blank variable, then "set" that variable. Example:

  • Set NumberOfUnits=number of units.

That's not actually how the code would look, since you'd need to select the units, but you get the idea. Now, the integer variable NumberOfUnits would be set to "5." Later, you can reference NumberOfUnits for your own purposes. For example, you could say, "When a unit dies, If the number of units alive is less than NumberOfUnits, then create a new unit." If there were 4 or fewer units, a new unit would indeed be created, as requested.

We're not done yet! There's one more thing you need to know, which is Arrays. A variable array is a variable that has multiple spots, wherein spots are denoted by an integer. A variable array would look like this: NumberOfUnits[x]. The "x" inside of the "[]" is the array spot and is always an integer. Essentially, a variable array is a fast, efficient way of making a bunch of variables all nested into one neat little variable.

Let's say we had a variable array called RushSongs[]. The variable array can be as large as we want it to be. So if we had a whole bunch of rush songs under a variable type song, we could set them underneath one super variable. Like so:

  • Set RushSongs[1] = "Here Again"
  • Set RushSongs[2] = "2112"
  • Set RushSongs[3] = "The Fountain of Lamneth"

Simple, eh? Now, whenever we could hypothetically say something like the following:

  • Listen to RushSongs[2]

And "2112" would miraculously begin to play. But that's not all! The field inside of the brackets, the array integer, can be another variable. Madness! As long as the field inside of the brackets is, in the end, an integer, then we can put whatever we want in there.We could even do this:

  • Set PartsInTrilogy=3
  • Set RushSongs[1]=RushSongs[PartsInTrilogy]

Pop quiz hotshot, what song is now set to RushSongs[1]? If you answered "The Fountain of Lamneth," congratulations! If you actually went and listened to any of these songs, bonus kudos as well.

I think that's enough of the lesson. Let's get to the code.

For my hero revival code, I decided to automatically respawn heroes on the third turn following their deaths. This would be enough of a boon to the winning player to get ahead but short enough to allow for a comeback (theoretically; everything is still being tested for balancing).

My first stab at revival code actually works perfectly, and was fun to implement. The code features two triggers. The first trigger fires upon the death of a unit.

Let's talk about the variables here.

  1. RedHeroesDeadInt: An Integer variable that counts hero deaths. Multiple heroes may die upon any given turn, so I needed to make sure that all potential deaths are accounted for and aren't overwritten.
  2. RedHeroesDead[x]: A Unit Array variable. Each time a unit dies, I first add a number to RedHeroesDeadInt, then set the integer as the array number for RedHeroesDead.
  3. RedRevivalCooldown[x]: An Integer Array variable. It keeps track of how many turns a given unit has been dead. The array integer in RedRevivalCooldown is RedHeroesDeadInt, the same integer applied to the dead unit as the array for RedHereosDead.

At the end of the trigger, I run an If/Then/Else that resets RedHeroesDeadInt to zero if it becomes greater than five. Since there are only five heroes on a given player's team at any time, the integer need be no higher.

My second trigger revives dead heroes.

This trigger fires whenever it becomes player red's turn. Each hero that has potentially died has been assigned an array spot in a variable. Each time player red's turn come around, the "revival cooldown" for each dead hero is notched up an integer, which is the count for how many turns that unit has been dead. I achieve this be resetting the integer variable to it's current value plus one.

Next, I run an If/Then/Else statement for each dead hero. If a hero has been dead for three turns, that hero instantly revives at the building from which it was trained. The unit and the cooldown is set to none and zero respectively, to make sure that my code doesn't become confused later on. This code works flawlessly. No matter how many heroes are dead or how often they have died, they will revive three turns respective to the turn on which they died.

However, last night, I was researching For loops a bit for some code I'm working on. And when I took a look at my revival code again, I thought to myself, "You know, this looks suspiciously like a perfect For loop." And it was. Hence my neglect to post yesterday (and today, technically. But I'm still awake. So it's still Saturday for me). So, I decided to rewrite my revival code in an effort to make it more streamlined, efficient, and more awesome. Check out Part 2 of this epic saga for the continued story.

Post a comment

Your comment will be anonymous unless you join the community. Or sign in with your social account: