Michael Niggel Misc Scripts

ENTRY 1: SCRIPT SOURCE FROM ENTRY.WAD AND DESCRIPTION

If you remember DOOMWORLD's "WIN THIS BOX" contest, you'll remember that the winning entry was a ZDoom level, based very heavily on scripting. Well, as the creator of that level, I am willing to share the tricks I used to build it for all you aspiring scripters out there. I once knew nothing, and I only wish I had someone to do that very thing for me. Note that you'll need a basic knowledge of how scripting works to have this really help you, but I'll leave that to Rick. Here, I'll just do a script-by-script description so you can get an idea of the power of this awesome tool.

#include "zcommon.acs"

Always include this line. It makes things a lot easier! Also, to make thing easier, open a copy of ZDOOMREF.TXT, so you don't have to remember all those special names and args. Also, I keep ACS-SPEC.TXT around as well. Trust me: it's worth it.

       script 1 OPEN
       {
       print(s:"DOOM changed my life forever.");
       delay(const:35*3);
       ChangeCamera(40, 0, 0);
       print(s:"It got me a job.");
       Light_Fade(2, 255, 35);
       delay(const:35*3);
       ChangeCamera(41, 0, 0);
       print(s:"It got me into college.");
       Light_Fade(3, 255, 35);
       delay(const:35*3);
       ChangeCamera(0, 0, 0);
       delay(const:35);
       Polyobj_RotateRight(4, 8, 56);
       Elevator_RaiseToNearest(7, 255);
       }

This is the opening script. Notice it is declared as OPEN, and so runs immediately as the player enters the level. It begins by typing the text message, waiting about 3 seconds and changing the camera viewpoint. NOTE: you MUST set up corresponding camera things to do this! The script then adjusts the light level in a tagged sector to fade it into view. Behind is a custom texture, useful for describing the text accompanying it. The extra delay here gives you time to read it. This whole process is repeated for another message and texture. Then, it gives you your own first-person view back. The polyobject doors in front of you then swing open. I only need to declare one open special because the other polyobj is a mirror, and acts automatically.

The elevator special has to do with the broken elevator, and its function will be described later.

       script 2 (void)
       {
       print(s:"It forever etched the names of great designers who came before
       me into my memory,");
       Light_Fade(5, 255, 35);
       delay(const:35*3);
       Light_Fade(6, 255, 35);
       print(s:"as it has forever etched my name into the memories of
       others.");
       delay(const:35*5);
       Polyobj_RotateLeft(1, 8, 64);
       }

Here is another text-and-fade script, only it is activated when the player crosses a line in the center of the level. It also does not change your viewpoint.

       script 3 (void)
       {
       print(s:"In so doing, it has boosted my self-confidence.");
       delay(const:35*3);
       print(s:"I know I am someone, and that in itself is great.");
       }

This text is activated when the player kills a certain monster. In this case, an imp.

       script 4 (void)
       {
       Polyobj_Move(2, 4, 192, 48);
       delay(const:35*3);
       print(s:"Deathmatch has heightened my awareness.");
       Elevator_LowerToNearest(7, 24);
       delay(const:35*3);
       print(s:"It has raised my consciousness to new levels.");
       TagWait(7);
       Radius_Quake(5, 17, 3, 4, 8);
       Light_ChangeToValue(7, 96);
       Light_ChangeToValue(10, 112);
       ACS_Execute(5, 0, 0, 0, 0);
       delay(const:35*15);
       Teleport(9);
       print(s:"I am great!");
       }

       script 5 (void)
       {
       Light_RaiseByValue(7, 24);
       Thing_Activate(random(const:1,4));
       delay(const:3);
       Light_LowerByValue(7, 24);
       delay(random(const:7,35*3));
       restart;
       }

Here's the biggie. It's a masterpiece of scripting art - and I'll show you how it's done. This is the elevator you board in the middle of the level. The script is activated after the player walks in the elevator, and starts by closing the polyobject sliding doors behind him. (also note the mirrored sliding door.) At this time, a text massage is shown and the elevator begins its descent. Three seconds pass when another text message is displayed. Here, a special is used that suspends execution of the script until a sector with a certain tag has stopped motion. (Find this and other helpful non-map specials in ACS-SPEC.TXT) The elevator continues as directed until it hits the next lower floor, which happens to be one of the four small sectors bordering the elevator with lights on them. Stopping motion activates the rest of the script. This is the earthquake, used to simulate a sudden jolt, the light dimming in all related sectors, and the execution of another script. After 15 seconds pass, the player is teleported to another sector.

The second script activates the spark emitters and controls the light flickering. This script first raises the light level (light flash); chooses a random thing numbered 1 to 4 and activates it; and lowers the light level after a short delay. In the map structure, four spark emitters are placed at the light fixtures in the ceiling of the elevator. Each has its TID set from 1 to 4. In this way, only one of the four emitters are called at any moment. When the light has reset, the script delays again for a random period of time. It can be as short as 1/5 second or as long as 3 seconds.

Why the alternate script? True, this script could probably run in a subroutine of the first, but it has to do with timing and ease. Putting this random timer in another script allows the first to run without worrying about what the other is doing. A second script also offers the advantages of adding actions more easily as well as being a lot easier to manage. Restarting the entire script after it has made one complete runthrough becomes simple with the 'restart' keyword. It just makes more sense this way.

The last mystery behind this script is this: Why not set the elevator's height at its starting position? The reason for this lies in the limitations imposed on thing Z height settings. A thing can have a Z value to set it off from the floor. Unfortunately, it can only be set upwards from its starting floor position. Added to this as well are the fact that spark emitters are not subjected to gravity or any movement at all, even if it means the ceiling goes down through them. The only way to solve this problem is to have them start at their final location. The elevator floor must be at or below the spark emitter's position so that its Z height can be set correctly.

Once this is done at map start, the elevator can be moved (as is done in the opening script) to the desired position.

       script 6 (void)
       {
       print(s:"I have become one with death.");
       delay(const:35*3);
       print(s:"I AM DEATH!");
       }

Another monster-death-activated text script.

       script 7 (void)
       {
       print(s:"DOOM");
       setplayerproperty(0, 1, 0);
       Light_Fade(11, 255, 100);
       }

       script 8 (void)
       {
       print(s:"WILL");
       }

       script 9 (void)
       {
       print(s:"REIGN");
       }

       script 10 (void)
       {
       print(s:"UNTIL");
       }

       script 11 (void)
       {
       print(s:"MY");
       }

       script 12 (void)
       {
       print(s:"LIFE");
       }

       script 13 (void)
       {
       print(s:"IS");
       }

This string of scripts are activated along linedef triggers on a scrolling floor. Each one prints only a small text message, which display as the player is forced to cross the lines. The first script in the series also does a bit more. It starts the light fade at the end of the hall, so that by the time the player reaches it, it will come into view. It also sets the player's 'property' to 'frozen.' This should be used sparingly, as it makes the player incapable of movement. This particular instance is especially dangerous because it ends the level while the player is 'frozen.' This should be avoided AT ALL COSTS. The reason for this is that an opening script has no 'activator', so to speak. Many script functions deal with the thing that activated the script, or the 'activator.' If a script is run that calls a function to act on the 'activator,' and there is no 'activator,' you will crash the game. This particular case leaves the player 'frozen' when they enter the next level. Once the enter it, you can not run a script to un-freeze them at the beginning of the level - the must activate it themselves, (since SetPlayerProperty requires an 'activator' to operate.) As you can see, this can cause problems. In the case of this WAD, there is no need to do anything after the level is over, and so no script is ever needed to reverse the effects.

Hope this helps. I have just barely scratched the surface of the ultimate power of scripting myself, and I hope to create much more immersive environments as I learn more about it. Learning my tricks should help anyone get a jump-off point to create their own effects. In other words, I don't want to see this elevator in a hundred new ZDOOM wads because I made it available. I want to see quality WADs made that make me say "Wow! This guy knows what he's doing." Happy Scripting!

ENTRY 2: FROM PERSONAL ARCHIVE WITH DESCRIPTION

       script 1 (void)
       {
       polyobj_rotateright(1, 32, 64);
       polywait(const:1);
       polyobj_rotateleft(1, 24, 112);
       polywait(const:1);
       polyobj_rotateright(1, 24, 80);
       polywait(const:1);
       polyobj_rotateleft(1, 16, 48);
       polywait(const:1);
       polyobj_rotateright(1, 12, 24);
       polywait(const:1);
       polyobj_rotateleft(1, 8, 12);
       polywait(const:1);
       polyobj_rotateright(1, 4, 4);
       polywait(const:1);
       }

       script 2 (void)
       {
       polyobj_rotateleft(1, 32, 64);
       polywait(const:1);
       polyobj_rotateright(1, 24, 112);
       polywait(const:1);
       polyobj_rotateleft(1, 24, 80);
       polywait(const:1);
       polyobj_rotateright(1, 16, 48);
       polywait(const:1);
       polyobj_rotateleft(1, 12, 24);
       polywait(const:1);
       polyobj_rotateright(1, 8, 12);
       polywait(const:1);
       polyobj_rotateleft(1, 4, 4);
       polywait(const:1);
       }

This script activates a PolyObj that is a swinging door. There is one script for each side, depending on which side the player pushed it from. The script is actually very easy to construct, and I wouldn't mind if this was used as a prefab for anyone's swinging door. The door rotates 90 degrees and swings back past 0 to -45, then back past 0 again a bit slower. It really works well. The reason it looks so good is because of the polywait special. This suspends execution of the script until the object has stopped moving. Be sure to create your sectors in a way that the player can not stop the object as a result of being pinned to a wall, or use a crushing startspot. I can destroy the effect entirely. Use of appropriate sounds could also help.

Submitted by Michael Niggel.

Back