Using user variables in ZScript
Note: This feature is for ZScript only. |
Note: User variables in DECORATE DO NOT appear in the editor when defined, to make a configurable DECORATE actor, you need to use custom args. |
Guide written by inkoalawetrust
User variables in ZScript are normal variables, but unlike standard variables, user variables can be changed from a level editor like UDB or SLADE, allowing mappers to change the behaviour of actors without needing to ever touch the source code of the actor, or having to make multiple inheriting subclasses with minor differences between each other.
The example that will be used throughout this guide is a customizable Zombieman variant.
Before starting
Keep in mind that this guide will not cover how to use user variables in code, as they are identical to normal variables in usage, the guide only covers user variable-specific knowledge. Such as how to define them and give them default values.
Creating a user variable
The process of creating a user variable in ZScript is the same as creating normal variables. To make a user variable, you simply have to give it the User_ prefix like shown below:
int bulletAmount; //Normal variable.
int user_BulletAmount; //User variable.
Supported user variable types
- Integer (int)
- Floating point (float)
- Double-precision floating point (double)
- Boolean (bool)
- String (String)
You can find more about all the supported ZScript variable types here.
Note: Floats are the same as Doubles, and both show up as decimal types in the editor.
Setting a default value to a user variable
To give a user variable a default value, in case none is set in the editor. You can set a default value to it in your actors' BeginPlay() or PostBeginPlay() virtuals. The values given inside of the virtuals can be overwritten by the editor. Below is an example of how to do this:
override Void PostBeginPlay()
{
super.PostBeginPlay();
if (user_Firerate <= 0) user_FireRate = 5;
if (user_BulletAmount <= 0) bulletAmount = 5;
}
Using user variables in the editor
So, you have made your mega awesome actor that has user variables to be able to modify its behaviour, but where are the user variables even at ? Well, the user variables of an actor, if they have any, can be found in the "Custom" tab of the actors' "Edit Thing" window.
Once you find them, you can change their values around to whatever you want, as long as it is the variables' data type, for example, you can't assign text/strings to an integer variable.
Removing/Resetting user variable values
To reset the value of a user variable back to nothing in the editor, you need to click on top of the variables' name or stated type, and press the Delete key, NOT backspace.
Tips
- The contents of the Custom tab are updated only every time the Edit Thing window is opened again, so if you immediately place an actor with user variables in your map, or change the actor you've already placed to one which has some, and they don't appear in the Custom tab, just reopen the window and check again.
- If you are using GZDoom Builder Bugfix, Boolean user variables will appear as integers due to a bug, you can still change them, to set it to true, just add any numerical value above 0, to set it back to false just change the value back to 0. This is not an issue in Ultimate Doom Builder, which has already fixed this bug.
Full example
Below is an example of a Zombieman-derived actor with new custom behaviour, that uses multiple user variables to be able to modify said behaviour on a per-actor basis. It uses most of the information covered on this guide, and can be used a reference on how to use user variables and what they can be used for.
class CustomizableZombieman : Zombieman { bool user_EnableBurstFire; // if true, the zombie will shoot in bursts. bool user_AvoidMelee; // Makes the zombie avoid melee, as he has no melee attack. int user_BulletAmount; // How many bullets to fire at every burst. int user_Firerate; // How fast each round is fired, in tics. int bulletAmount; // Counts down how many bullets have been fired. Default { //$Title Former Human (Customizable) //$Category Monsters } override void PostBeginPlay() { super.PostBeginPlay(); if (user_Firerate <= 0) user_FireRate = 5; if (user_BulletAmount <= 0) bulletAmount = 5; } override void Tick() { super.Tick(); bAvoidMelee = user_AvoidMelee; // Turn the eponymous flag on or off based on the user variables' value. } States { Missile: TNT1 A 0 A_JumpIf (user_EnableBurstFire,"CustomMissile"); POSS E 10 A_FaceTarget; POSS F 8 A_PosAttack; POSS E 8; Goto See; CustomMissile: POSS E 10 { tics = user_Firerate; // Yes, you can directly change how many tics a frame state lasts, but A_SetTics works too. A_FaceTarget(); } POSS F 8 { tics = user_Firerate; A_PosAttack(); } POSS E 8 A_SetTics (user_Firerate); TNT1 A 0 { // if the amount of rounds to fire is left to 0 or less, and the eponymous user variable is set to 1 or above. if (bulletAmount <= 0 && user_BulletAmount >= 1) { bulletAmount = user_BulletAmount; Return State (Null); // Leave this state frame and go to the next state (Goto See;). } if (bulletAmount <= 0 && user_BulletAmount <= 0) // Default counter amount if no value is given. { bulletAmount = 5; Return State (Null); } // If bulletAmount is still above 0. bulletAmount--; // Decrement Return A_Jump (256,"CustomMissile"); // And jump back to the start of the state. } Goto See; } }