TUTORIAL: Inheritance and Other Time Savers

So you've probably got the basic theory of Decorate down, from the last few tutorials - but it tends to get pretty tedious to have to retype so much stuff when all you want to do is run the same function many times in a row, or if all you're doing is adding an alternate fire to an existing weapon. So in this tutorial, I'm going to show you some ways to save yourself a lot of time and effort.

Inheritance

Let's say you've got a chaingun. It fires really fast, uses bullets, and generally acts like a chaingun. But perhaps you want to allow the player to find an upgraded version that also has a rocket launcher attacked to it, and also fires somewhat faster. We'll use a little trick called inheritance. To inherit, in this case, means to create a new actor, but borrow all the code from another actor, add new things over top of the old ones, and just fill in the blanks using the code from the old actor. To make an actor inherit from another, you need only change the very first line of the actor.

ACTOR UberChaingun : Chaingun replaces RocketLauncher {}
You may remember from the last few tutorials that we put Weapon after the colon. That's a form of inheritance. In this case, we swapped Weapon out for one of the default Doom actors, Chaingun in this case. If we were to run ZDoom with this code, all instances of the rocket launcher would be replaced with a chaingun instead. Those opening and closing braces that I slipped on to the end of the ACTOR line are just there to make that line function on its own - this actor literally only uses the code from the Chaingun, as I have made no changes to the actor. (Take note of this trick - it can come in handy if you ever need an item to replace more than one default Doom item.)

Let's go ahead and change something, then. Get rid of the opening and closing braces on the end of the ACTOR line and position them as you normally would. Next, let's add the Altfire state (as detailed in Altfires, Projectiles, and Accuracy) and make it launch a Doom rocket using A_FireCustomMissile. Remember to set the Weapon.AmmoType2, etc. properties and make it use the ammo type RocketAmmo (Doom's rocket pickup). Your code would probably look something like this:

ACTOR UberChaingun : Chaingun replaces RocketLauncher
{
Weapon.AmmoType2 "RocketAmmo"
Weapon.AmmoUse2 1
Weapon.AmmoGive2 2
States
{
AltFire:
CHGF A 5 Bright A_FireCustomMissile("AwexomeRocket")
CHGG B 5 Bright
CHGG A 10
CHGG B 0 A_Refire
Goto Ready
}
}

At first glance, this code seems to be lacking a lot; it doesn't have Raise, Lower, Ready, or Fire states. But thanks to the fact that we're inheriting from the Chaingun, all those blanks are filled in from the Chaingun actor. Save and test - your new chaingun (which will be on Slot 4 with the other chaingun - make sure the right one is selected, or it obviously won't work) should now fire rockets when you press the alternate fire key.

Multiple Frames Per Line

One of Decorate's more useful features is the ability to put more than one frame on the same line. Say you need to repeat an action, such as firing a long burst of A_FireBullets from a chaingun with a single button press. You're probably thinking it should look a bit like this:

Fire:
CHGG A 2 BRIGHT A_FireBullets(4,4,-1,7,"BulletPuff",1)
CHGG B 2 BRIGHT A_FireBullets(4,4,-1,7,"BulletPuff",1)
CHGG A 2 BRIGHT A_FireBullets(4,4,-1,7,"BulletPuff",1)
CHGG B 2 BRIGHT A_FireBullets(4,4,-1,7,"BulletPuff",1)
CHGG A 2 BRIGHT A_FireBullets(4,4,-1,7,"BulletPuff",1)
CHGG B 2 BRIGHT A_FireBullets(4,4,-1,7,"BulletPuff",1)
CHGG A 2 BRIGHT A_FireBullets(4,4,-1,7,"BulletPuff",1)
CHGG B 2 BRIGHT A_FireBullets(4,4,-1,7,"BulletPuff",1)
CHGG A 2 BRIGHT A_FireBullets(4,4,-1,7,"BulletPuff",1)
CHGG B 2 BRIGHT A_FireBullets(4,4,-1,7,"BulletPuff",1)
CHGG A 2 A_Refire
Goto Ready

But what if you need to change how much damage each bullet is doing? You'd have to go back and change every single one of those lines. Sounds like a pain, right? That's where this little trick comes in handy. Have a look at this single line:

CHGG ABABABABAB 2 BRIGHT A_FireBullets(4,4,-1,7,"BulletPuff",1)

Instead of entering only one frame index, I've entered a long string of them. These strings can be just about as long as you like. ZDoom will run the entire string of indexes in sequence, using the one duration number you give to it, optionally render it Bright or Offset it, and repeat the assigned action function for each frame. This trick brings several advantages. First, you need only change one line if you feel that your weapon is doing too much damage, or isn't accurate enough. The second advantage is a little trickier and involves a small bit of basic arithmetic.

Let's say we want to make the UberChaingun have a spin-down animation when you let go of the trigger. That's actually another thing that the A_Refire function is good for. Look at this code:

Fire:
CHGG ABABABABAB 2 BRIGHT A_FireBullets(4,4,-1,7,"BulletPuff",1)
CHGG A 2 A_Refire
CHGG B 3
CHGG A 4
CHGG B 5
CHGG A 6
CHGG B 7
CHGG A 8
Goto Ready

In this case, the frame on the A_Refire line is not displayed on screen for as long as the trigger is still being held, as A_Refire will send the weapon back to the Fire/Altfire state if it detects the trigger being pressed. When released, the code immediately following A_Refire will be executed. If you define a Hold or AltHold state, A_Refire will go to those instead of Fire/Altfire, which allows much room for special effects, such as if you want to have a spin-up delay on your chaingun. (Also, as of more recent versions of ZDoom, you can tell A_Refire to direct to whichever state you want it to, by passing the state's name as an argument, like so: A_Refire("YourStateHere").)

But take a look at the six lines after the refire. There's no way we can consolidate them to a single line, because they all have different durations, right? Not quite - have a look at this line:

CHGG BBBAAAABBBBBAAAAAABBBBBBBAAAAAAAA 1

Instead of wasting lines retyping the same sprite name just to change its duration, I have set the line's duration to only 1 tic, and then set it to display the same frame multiple times in a row to add up to the same tic rate. Note the order: three B frames, four A frames, five B frames, et cetera. I've consolidated the six lines into just one with this trick. Just bear in mind, that overusing this trick can sometimes be even messier than just having them on separate lines, so I advise you to use it sparingly. (Ed the Bat also warns that using this trick will also not allow the weapon to be affected by powerups that double the player's firing speed. This might not be a problem for most mods, but if you have such a powerup in your mod, you will want to bear that warning in mind.)

Extra Added Bonus Trick

A player will probably find it frustrating that there is such a long wait time between releasing the trigger on the UberChaingun and being able to fire again. So try adding an A_WeaponReady to that long line up there, so that the player can pull the trigger again at any time to resume firing during the wind-down animation. Just one of those little gameplay fixes that'll go a long way toward making your mod feel more professional.