The following articles describe the new functionalities that have been implemented into Blade of Agony. It's mostly for us and other developers as an easy to find and use documentation.

'Base'- and 'Nazi'-Class Actor Configuration

There are two ZScript classes in Blade of Agony that define additional enemy behavior. The 'Base' class is used directly as a base for non-human enemies, such as sharks, rats, and the non-human bosses. The 'Nazi' class inherits all of the functionality of the 'Base' class, but adds additional capabilities that are used by human and human-like actors.

Custom UDMF Attributes

'Base' Class and 'Nazi' Class:
  • If set to 1, the actor's health bar is always drawn, regardless of it has the BOSS flag or if it's in view of the player
  • The underlying variable for the Base.AlwaysDrawHealthBar property
  • If set to 1, forces the enemy to always drop their weapon when killed
  • Has the side effect of *not* dropping any other defined DropItems
user_conversation (currently unused in BoA) 
  • Intended to mark actors that can be interacted with via dialogue
  • If set to 1, marks the actor with an interaction excalamation point marker that will follow them as they move, and will grey out once the player 'uses' the actor and enters a conversation with them.
  • Marker is removed when the actor is killed or this value is reset to 0
  • Intended to mark actors that can be harmed by a specific light level (e.g. zombies)
  • If set to 1, makes the actor burn at a specific light level which can be defined with the appropriate Base. properties (see below)
  • If set to 1, the actor will be shown on the player's compass
  'Nazi' Class Only:
  • The underlying variable for the Nazi.Sneakable property. If set to 1, this can be used to set actors as sneakable in-editor, without creating a custom actor class.
  • IF set to 1, actor will remain at its spawn location until the player is within 256 units
  • The actor will still aim and fire at the player, but won't walk toward him until the player is within the 256-unit range
  • Has no mapper use
  • Just a leftover variable name from the original DECORATE code

Flag effects

Certain editor flags have been given additional meaning when applied to a 'Nazi'-class actor.

'Nazi' Class Only:
  • Actors with the AMBUSH flag set will default to their 'aiming' frame - there's no behavioral change, just the actor's appearance
  • Actors with the BOSS flag set will show a health bar at the top of the screen when the player is aiming at them
Properties for new actor definitions 'Base' Class and 'Nazi' Class:
  • String property that is used to look up the icon image that is displayed with the enemy's health bar
  • Must be used in combination with the +BOSS flag (which enables the boss health bar to be drawn) or the Base.AlwaysDrawHealthBar property below.
  • Has no effect if the enemy is not flagged to have health bar drawn.
  • Boolean value that is used to tell the game if the enemy's health bar should always be drawn.
  • Does not require the +BOSS flag to be set, and can alternatively be controlled via ACS or in-editor by setting the user_DrawHealthBar variable
  • Integer value that determines the light level at which the actor becomes afraid and runs away from the light
  • Boolean value that, paired with LightThreshold, kills the actor with 'Fire' death if they enter (or are caught in) an area that is brighter than their light threshold allows them to tolerate
  • The actor will also spawn small smoke puffs immediately before dying
  • Boolean value that sets whether the actor should be restricted to staying underwater or not. Used by sharks.
  • Integer value that sets the range from the spawn point that this actor will wander while it is idle (normally only on spawn).
  • Default is zero. Currently used by dogs and sharks.
  • Flags the actor to not be able to be healed by a medic.
'Nazi' Class Only:
  • Boolean that controls if the enemy is a sneakable enemy or not.
  • Can also be set in-editor on a per-actor basis by setting the user_sneakable variable.
  • Can be set in-game (e.g., after a cutscene using normal actors) by setting the actor's state to "MakeSneakable" via ACS.
  • Integer value that controls how close to the actor the player must be before visibility amount begins to increase dramatically (essentially, when the meter begins to ramp up as you get within touching distance)
  • Default value is 64
  • Integer value that controls how many tics a disguised player must remain in sight of this enemy before the player's disguise fails.
  • Default value is 0, meaning "can't see through disguises"
  • Used by SneakableEyesIdle actor (as seen on sneakable Gestapo)
  • Integer value that controls the FOV of the enemy when trying to see through player disguises.
  • Used by SneakableEyesIdle actor (as seen on sneakable Gestapo)
  • Integer value that sets the distance at which a perceptive enemy will begin to be suspicious of the player
  • Used by SneakableEyesIdle actor (as seen on sneakable Gestapo)
  • Value 1 (defined as HLR_ALLIES) is normal medic behavior.
  • Value 2 (HLR_ZOMBIES) changes the behavior to only search for dead enemies that have a zombie counterpart, and to replace the dead actor with the zombie variant on resurrection.
  • Defines the zombie actor that should be resurrected from this actor's corpse by "Totengraber" et al
  • If not provided (or set to ""), resurrection will not occur (this doesn't affect normal medic healing).

Actor States

'Nazi' Class Only:
Sneakable State Changes

These are intended to be used as workarounds to set up certain actor effects from ACS. e.g., 'SetActorState(0, "MakeSneakable");' will turn the current actor into a sneakable actor. This is used in the beginnning of C2M1 after the (non-sneakable) 'firing squad' that you see through the vent is done executing their prisoners to make them sneakable

  • Actor will be made into a sneakable actor
  • Actor will be alerted as if it were sneakable and had seen a player
  • Note that this will turn non-sneakables into sneakable actors! They will go idle, etc. just like any other sneakable after this is used.
Walking Speed Modification

These are only really useful if you are defining a new class - instead of copy and pasting all of the 'See' state, you can simply use "Goto See.Faster", etc.

State Walking Frame Duration Footstep sounds? Frames
See.Normal 8 tics Normal footsteps ABCD
See.Fast 6 tics Normal footsteps ABCD
See.Faster 4 tics Normal footsteps ABCD
See.MutantFaster 4 tics Normal footsteps ABCD (Sounds play on opposite frames from See.Faster)
See.MutantFasterAlt 4 tics Normal footsteps BCDE
See.Boss 8 tics Heavy footsteps ABCD
See.BossFast 6 tics Heavy footsteps ABCD
See.BossMech 8 tics Mech footsteps ABCD
See.Static 1 tic - intended for non-moving actors N/A A
Other miscellaneous states
Alarm Activation

A 'Nazi'-class actor that activates an alarm has special handling. When they activate an alarm, they are set to the 'Alarm' state.

Actor Spawners

These actors spawn enemies when activated, and maintain a set number of those enemies alive (1 by default). Actors will not be spawned if a player can see the spawn point or if a player is within a defined minimum spawn distance from the spawner (default 512 units).

By default, the spawner will spawn a single guard. Once that guard is killed, the spawner will spawn another guard, and so on. This can replace situations where an ACS script might mindlessly spam a huge flood enemies, regardless of how many are being killed or not, by metering how many enemies are active at once.

Spawned actors can be given a TID and can be set to navigate to a specific PatrolPoint TID after spawn as well.

11519 - ActorSpawner

Custom UDMF Attributes
Attribute Usage
arg0str Sets the class of actor to be spawned (default "Guard"). Note that you must select the 'String' value to enter a string in the arg0 field in GZDB, otherwise, you will be forced to enter an integer which will be interpreted internally as a spawn ID - so you'll end up with imps, or cyberdemons, or whatever, spawning...
user_tid Sets the TID that the spawned enemies are given. By default they have no TID.
user_goal Sets the goal/patrolpoint TID that the spawned enemies will walk to once they return to being idle. By default, they go back to their spawn point and stand still.
user_maxactors Sets how many enemies from this spawner to maintain alive at once (default 1)
user_minspawndistance Distance from player inside of which the spawner will stop spawning (default 512)
user_oncompass When set to 1, spawned enemies will be added to the player's compass as grey dot


Alarm Configuration

There are three main actors that should be configured together to make realistic alarm scenarios.

Alarms and Alarm Spawners must be given the same TID as an Alarm Panel that will control them, otherwise they will not function unless activated via ACS. You can have multiple Alarm Panels with the same TID (e.g., so that the player can turn of alarms from a side office after the alarms are turned on by a guard in a main area).

11516 - Alarm

These are simple actors that, upon activation, alert all actors within a 512-unit radius. If activated from an alarm panel, they set the alerted actors' target to the alarm panel activator's target.

11517 - AlarmSpawner

These are specialized ActorSpawners that spawn up to three SneakableSSMP40Guard actors when they are activated. A maximum of three guards will be present at any time; if three guards were spawned and one guard was killed before the alarm was shut off, the next time the alarm goes off, only one additional guard will spawn. A major difference from the ActorSpawner is that this spawner will only spawn the specified number of actors per activation; it will not maintain a continuous stream of new actors.

Spawning only occurs when no player can see the spawn point.

Custom UDMF Attributes
Attribute Usage
user_tid Sets the TID that the spawned enemies are given. By default they have no TID.
user_goal Sets the goal/patrolpoint TID that the spawned enemies will walk to once they return to being idle. By default, they go back to their spawn point and stand still.

11518 - AlarmPanel

These are usable flatsprite actors that control Alarms and Alarm Spawners that have the same TID as the panel. The 'Nazi'-class descendant actor who is closest to the alarm panel (within 1024 units) will be automatically selected as the activator, and, once alerted, will automatically walk to the alarm panel and activate it.

Any actors with the same TID as the Alarm Panel will be toggled to their 'Active' or 'Inactive' state, as appropriate, so any Alarm of Alarm Spawner actors (as well as any other switchable decorations) that have the same TID as the panel can be controlled by the panel.

To silence alarms, the player must manually deactivate the alarm, or the Alarm Panel can be deactivated via ACS to set inactive all controlled actors.

Players can also turn deactivated alarms on... This would normally be dumb, but might be useful for flushing guards into a courtyard away from a key, or something similar.

Active AlarmPanel actors have a red glow on them.

Color Grading

Color Grading in Scripts

For transitioning to a color grading directly in a script, the following two scripts can be used:

   ScriptCall("ColorGradeThinker", "TransitionTo", 0, 1, 140);
ScriptCall("ColorGradeThinker", "TransitionTo", 0, 2, 700);

The first one makes a seamless transition to the color grade with the index number 1 in 140 tics, the second one a very slow transition to index number 15 (max) in 700 tics (which is about 10 seconds)

   ScriptCall("ColorGradeThinker", "Set", 0, 1);

Instead of transitioning to a color grading in a certain amount of time, you can also directly set it in a script. The above line sets the color grading instantly to the look-up table index 1.

Color Grading on Lines

ColorGradeSet immediately sets the supplied LUT index on the player who called the script.

   ACS_NamedAlwaysExecute("ColorGradeSet", 0, 9); // Instantly sets to index 9

ColorGradeTo transitions to the supplied LUT index over the course of the specified number of tics. If a transition is already taking place, the LUT is queued to transition to after the current transition is done.

   ACS_NamedAlwaysExecute("ColorGradeTo", 0, 4, 70); // Index 4, in 70 tics (what is standard if set to 0)

ColorGradeBetween is meant to be used as a linedef action. It will transition to a LUT depending on which side the line is triggered from. This is useful to mark a LUT "boundary" between two areas without having to use two linedefs with a ColorGradeTo call. 

   ACS_NamedAlwaysExecute("ColorGradeBetween", 0, 0, 4, 70); // Repeatable and player walkover

Color Grading Types

The textures/pplut.png look-up table has a wide variety of different color gradings for different situations.

Grading Index Type
0 Standard
1 Old photography (brown with low contrast, red to yellow stay, other colors desaturated)
2 Ending Sequence (light, blue to cyan, green to lime, low contrast)
3 C1M4 (blue teint, high contrast, dark look)
4 C2M2 (blue saturated, green to olive and weak, red to purple)
5 C3M1 (green tone, higher contrast)
6 C3M0_A (colder white, higher contrast, darker middle tones)

More Grading Types will be added soon.

Compass Markers

These actor types will show up on the player's compass automatically when they are placed in the map. A good reference map for how these should be implemented is C3M2.

As a general rule, Primary Objective Markers (red) should be used to mark mission-critical areas that must be visited, and Secondary Markers (orange) should be used to indicate necessary specific actions/conversations/pickups.

Additionally, any other actors that are tagged with a specific TID can be made to show up as a grey dot on the compass via ACS by calling the "BoA_CompassQueue" script.

   ACS_NamedExecuteAlways("BoA_CompassQueue", 0, thingTID);

Or, you can specify a specific image ("ICON", here) to be used as the icon.

   ACS_NamedExecuteAlways("BoA_CompassAddIcon", 0, "ICON", thingTID);

Note that calling this script will add all actors with the matching TID to the compass.

Primary Objective Markers

These actors are used to indicate the general area of a primary objective or significant waypoint in the map. They should be used sparingly, so that seeing a red exclamation pointon the compass doesn't lose importance; only major mission-related locations should have a red marker.

These actors can be spawned as DORMANT, then activated via "Thing_Activate" in ACS, or they can be spawned normally and hidden or removed later using "Thing_Deactivate" or "Thing_Remove".

Take special care to properly activated/deactivated/removed markers via ACS as the mission progresses in order to keep the path of progression clearly indicated on the compass... In other words, as the path to a specific objective becomes available to the player, the marker for that objective should become active, then, once the objective is reached, the marker should be deactivated or removed.

These don't have to correspond perfectly to the listed objectives - For example, most maps essentially have a final objective of "Find Douglas/Ryan/Asher in order to return to HQ" upon completion of all of the primary objectives; even though "Finish the map" is not a listed objective, there should probably still be a red marker placed once that becomes the player's next goal. As another example, if a single objective requires multiple similar actions across the map to complete (like placing Comp B charges), each of those locations should be marked with a red marker.

Editor number Type
21238 ObjectiveIcon - Red exclamation mark that shows up on both the compass and the automap; it is invisible during gameplay.
21239 ExclamationCompass - Red exclamation mark that only shows up on the compass; it is invisible during gameplay.

Secondary Objective Markers

These actors are typically used to mark NPCs that can be talked to, switches that should be activated, etc. These markers will not be added to the player's compass until the player is within 2048 units and has a line of sight to the marker.

Editor number Type
21236 Exclamation - Static static orange exclamation mark.
These should be spawned/removed via ACS as the mission progresses in order to avoid cluttering the compass with no-longer-needed markers.
21237 ExclamationTouchable - Orange exclamation mark that changes to grey when a player approaches.

Mission/Quest Item Markers

All items which inherit from the 'CompassItem' class, as well as any disguise/uniform pickups, will automatically be added to the player's compass. These actors will use their inventory icon as their compass icon; if one is not set, they will use their spawn state sprite as their icon.

   Akten         AktenEisenmann      AktenV2
   AktenDream      AktenDreamClue      ArtifactAstrostrein
   ArtifactAstrostreinIM   ArtifactEgyptian   ArtifactEgyptian_H1
   ArtifactEgyptian_H2   SpearOfDestiny      Cartridge51
   Cartridge52      Cartridge53      RepairKit
   Crank         RadioPickup      Kennkarte
   GrapplingHook      ChutePickup      ScientistUniform
   SSBJUniform      CCBJUniform      ZombieArmClue
   ZombieHeadClue      MineralClue

Base- and Nazi-class Enemies

By setting the 'user_oncompass' UDMF attribute of an enemy actor to 1, that actor will be added to the player's compass automatically. These actors will use a grey dot as their compass icon. The icon for actors that are also tagged with the 'user_drawhealthbar' UDMF property will be tinted with color to indicate the health level of that actor.

ActorSpawner-Spawned Enemies

By setting the 'user_oncompass' UDMF attribute of an ActorSpawner actor to 1, all enemies spawned by that actor will be added to the player's compass automatically. These actors will use a grey dot as their compass icon. See the initial machine-gun turret fight in C3M2 for a working example.

Custom Crosshairs & Hold-to-activate Lines

The player's crosshair can be set via ACS or by setting the user_crosshair UDMF property on a linedef that the player is directly looking at.

Setting via ACS

The player's current crosshair can also be changed via ACS by setting the player's 'crosshair' property to a valid crosshair number, as discussed above. This change takes precedence over any line-set crosshair. This can only be reverted by setting the 'crosshair' variable to zero.

  • This command will set the crosshair to the XHAIR90 graphic:
    SetUserVariable(0, "crosshair", 90);
  • This command will restore the crosshair to the player's set crosshair:
    SetUserVariable(0, "crosshair", 0);

Setting when looking at a line

Any blocking line (in essence, any line that could be hit by a hitscan) can be set up to show the player a custom crosshair/icon by setting the 'user_crosshair' UDMF property on the line. The value of this property must correspond to a thing class or a text string - e.g., a "RepairKit" string will display the corresponding actor graphic. The crosshair will be restored to normal once the player is no longer looking at the line.

This effect can be used on an activation line to give a hint as to a required inventory item, key, etc. (as with the generator repair points in C3M0_A).

Custom UDMF Attributes
  • Sets the crosshair of the player when the player's crosshair is over a portion of the line (can be thing class or text)

"Hold-to-activate" lines

Within Blade of Agony, player control handling has been altered so that holding down the 'use' button while facing a 'repeatable' activation line will cause that line's special to be run once per tick for as long as the 'use' button is held (and not just once per 'use' press, as is normal). In most cases, this change doesn't alter gameplay at all, however, scripts can be written to take advantage of this implementation.

The line to be activated must be set up to be activated "When player presses use" and as a "Repeatable Action", and must be assigned a unique id/tag.
If the portion of the line that you want to be activated is the midtexture rather than an upper or lower section, you must set the line to "Block Everything" or "Block Hitscans".

The line's special must be set to 80 - Script Execute, and pointed to a custom script that takes, at a minimum, the line's id as a parameter.

  • A generic "hold-to-activate" script will look something like this:
    Script "ActivateGenerator" (int lineid)
       if (ACS_NamedExecuteWithResult("Activate", lineid, 5)) // The 'Activate' script takes line id and activation time in seconds as parameters.
          /* Activation complete.  Do post-activation stuff here. */
       else { PlaySound(0, "effects/repair", CHAN_AUTO, 0.7); } // Play repair sounds

Player Followers

An actor that will stand dormant until it sees a player, then will follow that player. The actor can be set to carry a specific weapon.

If a playerfollower has no weapon, and falls significantly far behind the player, when he re-appears, he will have gained a pistol.

Editor number Type
12710 PrisonerAgent - Agent Ryan as a prisoner (No weapon)
12740 AgentArmed - Agent Ryan after returning to duty (Luger)
12741 AgentArmedMP40 - Agent Ryan after returning to duty (MP40 - but with no new sprites)
12742 DouglasArmed - Douglas (Pistol)
12743 SoldierArmed - Generic Soldier (Pistol)
12744 SoldierArmedRifle - Generic Soldier (Rifle)
12745 AscherArmed - Lt Ascher (Rifle)
No editor number Dog Follower - A German Shepherd (Melee, with handling to patrol the general area instead of standing still)

Custom Properties

Weapon that the PlayerFollower will spawn with, set based on FollowerWeapons enum:
  • If true, actor will immediately forget its target if the player moves out of range.
  • This has the effect of making the actor follow the player more closely
  • Behavior and following is more predictable, but more realistic for an escaping prisoner (vice a soldier in combat)
  • Chance that the actor will stop while chasing to attack enemies
  • because of how often this check is performed, values will need to be *very* low (e.g., 2-4) to see any change in actor behavior.
  • FOV used for look/search/sight calls
  • Chance of using grenades. By default, the actor has an infinite supply of grenades
  • Alternatively, if you give the actor a specific number of grenades via a script, then the PlayerFollower will throw up to that many grenades, then no more
Useful Variables

These are intended to be set via ACS using 'SetUserVariable(tid, "variable", value);'

  • Normally, if a PlayerFollower falls 100 pathmarkers behind the player, the actor will be warped ahead to the 50th pathmarker (if the player can't see the marker)
  • Setting this boolean to 1 disables that behavior. This is useful if you want to force a PlayerFollower along a certain route in the map, and don't want him skipping ahead
  • Be cautious! If the PlayerFollower gets stuck somewhere in the level geometry while this is set, then the PlayerFollower will never be able to become un-stuck
  • Setting this boolean to 1 causes the PlayerFollower to stand in place and not follow the player anymore
  • This differs from being dormant/Deactivated in that the PlayerFollower will still look for players, look for enemies, and open fire on enemies
Editing Tricks
Block the PlayerFollower
Normally the PlayerFollowers are not blocked by Monster-Blocking lines. If you want to limit where a PlayerFollower can go, just remove the NOBLOCKMONST flag in ACS:
SetActorFlag(tid, "NOBLOCKMONST", 0);
Then place monster blocking lines in the map, and the PlayerFollower won't be able to cross them.
Change PlayerFollower Weapon
  • You can change the weapon that a PlayerFollower is carrying by giving them a new weapon via ACS. Note that the weapon must be one of those that is coded into the actors...
  • Valid weapons are: Luger9mm, MP40, Sten, KnifeSilent (and GrenadePickup, as discussed in the PlayerFollower.GrenadeChance property section above)

Screen Shaders

There are various post-processing shaders for the player screen that can be used at any time as effects to support certain situations. Just give or take the corresponding tokens to the player inventory to activate or deactivate time ingame.

Inventory Token Effect
BlurShaderControl Distords the sight after an explosion. The amount of the item that you give sets how long the effect lasts - if you give 35, the effect will last 35 tics, 70 -> ~2 seconds, 350 -> ~10 seconds, etc.  The effect will stack if you give more when there's already a blur in action. There's also a ~0.5 second fade in to the blur effect, then a slow fade back to normal over time once the blur is in place
OldVideoShaderControl Adds an old video effect to the screen. To enable a shader, give 2 of the ShaderControl subclass item to the player. To disable a shader, take 1 of the shader control item away so that the player only has 1 of said item.
ShakeShaderControl Adds an shake effect to the screen, works well for situations when being on a truck or a minecart. To enable a shader, give 2 of the ShaderControl subclass item to the player. To disable a shader, take 1 of the shader control item away so that the player only has 1 of said item.


Static Skyboxes

A derivative of the skybox viewpoint actor that moves in relation to the player's movement, giving the illusion that the skybox is a part of normal level geometry.

The map author can specify the amount that the skybox's movement is scaled relative to the player's motion, allowing for a very small skybox to appear much larger and closer in relation to the player.

By default, the "anchor", or the neutral origin point of the skybox view, will be the player's spawn location. Alternatively, the viewpoint can also be "anchored" to a map actor by specifying the TID of the actor to use as the anchor.

19990 - SkyViewpointStatic - The viewpoint actor for use in static skyboxes

Editor Arguments
Argument Usage
Arg[1] - Skybox Scene Scale The scale of the skybox's scene (default is 100). The larger this number is, the farther away the skybox contents will appear to be.
Arg[2] - Anchor Object TID TID of an actor to anchor the skybox on. Default value (0) means to anchor on player start spot.

19991 - SkyViewpointAnchor - A generic mapspot that can be assigned a TID and used as an anchor for static skybox viewpoints

We use cookies on our website. Some of them are essential for the operation of the site, while others help us to improve this site and the user experience (tracking cookies). You can decide for yourself whether you want to allow cookies or not. Please note that if you reject them, you may not be able to use all the functionalities of the site.