L4D2 EMS/Creating a Simple Mutation
In this tutorial we'll build a very simple Mutation that takes advantage of the fact that VScripts can now be used to build Mutations.
What's new about the Mutation System?
The Mutation System now provides Mutation authors with a Stage and Wave handler, each written in VScript. The Mutation system now uses an automatic file-naming scheme to locate files belonging to a Mutation.
If you create a new Mutation (<mutation_name>.nut) and you have it configured with the correct data then the Mutation System will include and operate all components of your Mutation automatically.
Creating a Simple Mutation that uses VScript
The following steps will walk you through creating a new Mutation we will name "Simple". This new Mutation will include some new, custom VScript code!
Defining what the "Simple" Mutation does
A good first step is to determine what we want our simple Mutation to do:
- This Mutation will be played in the map C3M3_SHANTYTOWN
- Once the game begins the players will have 10 seconds of setup time, after which a wave of infected will attack.
- After the infected have been "cleared out" the players will have 10 seconds in a 'cooldown' mode
- After the cooldown completes the game restarts and "YOU WIN!" will print to the console
Pretty simple! It seems we've done a fine job of naming our Mutation.
First things first: adding the Mutation Definition
In order that the game can locate and execute your Mutation, you must add a definition file representing your Mutation to the left4dead2/modes folder. This is where the game looks for files that describe new Mutations.
<your steam folder>\steamapps\common\Left4Dead2\Left4Dead2\modes
BETA TESTERS Use:
<your steam folder>\steamapps\common\Left4Dead2 Beta\Left4Dead2\modes
Create a new .txt file in the folder. This is to be the definition file for our new Mutation. Since our new Mutation is called "Simple", name this file simple.txt.
Next you'll edit the simple.txt file to provide some information about the Mutation. The contents of simple.txt should read:
"Description" "A simple game mode!"
"Author" "Snidely Whiplash"
NOTE: If you created simple.txt while the game engine was running, you will need to enter the console command mission_reload to detect the new file (or you can exit and restart the game engine).
This particular definition provides just the basic information that Left4Dead2 requires to operate the "Simple" Mutation we're building. More complex Mutations may need to provide more information but we'll discuss that later. In the unlikely event that you are not named "Snidely Whiplash" you may wish to provide a different name for the "Author" field in the Mutation definition file.
Be sure to save simple.txt before moving on to the next step. You can close this file now. We won't be editing it again.
Creating your Mutation's VScript file
Next, you need to create a VScript file for your new Mutation. This is the file that will contain the actual VScript code that makes your Mutation work the way you want it to. In this case the file will be called simple.nut:
Be sure to place simple.nut into the following folder:
<your steam folder>\steamapps\common\left4dead2\left4dead2\scripts\vscripts\simple.nut
BETA TESTERS Use the following folder:
<your steam folder>\steamapps\common\left4dead2 Beta\left4dead2\scripts\vscripts\simple.nut
Note: By default, Windows hides "known" extensions . Make sure the extension of your script ends in ".nut", not ".nut.txt"
VScript Code: The MutationOptions table
The first bit of VScript code we'll write for our simple Mutation will provide default values for some Director variables so that the game is configured the way we want it when our Mutation starts.
When the game runs your Mutation it will automatically search your VScript code for a table called MutationOptions. The MutationOptions table is where a lot of Director options can be initialized to the values you require for your Mutation. In our Simple Mutation we want to set a few options for common zombies, but otherwise keep it simple. This will remove the specials, tanks, and witches from spawning and let up to 10 zombies be alive in the world from a pool of up to 20.
CommonLimit = 10 // Maximum number of common zombies alive in the world at the same time
MegaMobSize = 20 // Total number of common zombies in a mob. (never more than CommonLimit at one time)
WanderingZombieDensityModifier = 0 // lets get rid of the wandering zombies
MaxSpecials = 0 // removes all special infected from spawning
TankLimit = 0 // removes all tanks from spawning
WitchLimit = 0 // removes all witches from spawning
BoomerLimit = 0
ChargerLimit = 0
HunterLimit = 0
JockeyLimit = 0
SpitterLimit = 0
SmokerLimit = 0
Wait. What's that arrow after MutationOptions? Left4Dead2's Mutations are written in a scripting language known as Squirrel, and you'll need to understand Squirrel to write Mutation scripts that do anything complicated. Documentation and a discussion group are online at http://squirrel-lang.org
The MutationState Table
The MutationState Table is another table that you may provide. This one is used to store any pieces of state data that your Mutation wants to keep track of. You might want to think of it as a place where the 'global' variables for your Mutation live.
Lets add the MutationState table to our VScript along with some state data for our Mutation, starting with which stage we're on. In that table create a variable called CurrentStage and initialize it to -1.
CurrentStage = -1
The table names MutationState and MutationOptions we used above are handled in a special way by the Mutation System. The data in those tables are merged into new tables called SessionState and SessionOptions. You won't use the names MutationState or MutationOptions again after creating the table. You will want to access them through SessionState and SessionOptions. Just think of MutationState and MutationOptions as your Mutation's contributions to the aggregated Session data.
For example, even though CurrentStage is in the MutationState table above, in order to access it later you will want to do so like this:
The core logic of the 'Simple' Mutation
We also need to provide a way for the Director to know what to do next. In the Mutation System, that is done with a function called GetNextStage(). We're going to use it to control when zombies spawn, when there are delays in attacks and when to display the win results. Think of it as the main loop of the mutation.
It's helpful to understand what is meant by the term stage: A stage is a 'phase' of gameplay. In Left4Dead2, some example stages are: PANIC, when huge mobs of infected are attacking and CLEAROUT, wherein the game is waiting for the Survivors to finish off any remaining infected before going on to the next stage. The Suvivors will go through many stages per map.
Each time the game finishes a stage (all the zombies get killed, the cooldown ends, etc.) it will call back into your Mutation VScript code asking what to do next. Our Mutation's response will be to change some fields in the SessionOptions table to reflect the type of stage we'd like to start next. In addition to choosing a type of stage we are also able to provide a single value to 'configure' the new stage we're requesting.
The first time GetNextStage() gets called is when the Mutation first starts. That gives us an opportunity to write some startup code. In general, all the logic to make game control decisions is in here.
Lets set up our Simple Mutation to have one cycle comprised of these stages - all of which map pretty 1-to-1 with the stage types the Director provides.
- STAGE_SETUP - This is our first stage the players will experience. The setup stage is quiet and lasts for 10 seconds
- STAGE_PANIC - Zombies attack!
- STAGE_CLEAROUT - Zombies have stopped spawning. You have 10 seconds until the clearout condition is met.
- STAGE_RESULTS - You win! Results are displayed.
Add the following function to simple.nut:
printl(" *** GetNextStage() called, my current stage is: " + SessionState.CurrentStage )
switch ( SessionState.CurrentStage )
case 0: // setup stage
SessionOptions.ScriptedStageType = STAGE_SETUP
SessionOptions.ScriptedStageValue = 10 // seconds to stay in this stage
case 1: // common zombie attack!
SessionOptions.ScriptedStageType = STAGE_PANIC
SessionOptions.ScriptedStageValue = 1 // one panic wave
case 2: // clear out the stragglers
SessionOptions.ScriptedStageType = STAGE_CLEAROUT
SessionOptions.ScriptedStageValue = 10 // Wait 10 seconds once all infected are dead
case 3: // you win! the game will restart after a few moments
SessionOptions.ScriptedStageType = STAGE_RESULTS
printl(" *** YOU WIN! YOU WIN! YOU WIN! *** ")
The second line in this function (the printl) will print a line to the Left4Dead2 console each time this function is called so that we can tell that our Mutation is working, as well as track the progress of the round.
Inside the GetNextStage we could have used if then or any other logic statements to walk through the stages. For ease of reading, we used a case statement.
Save your simple.nut file and you're done! You can now load your new Mutation and play it in any map.
To load and play your Mutation type this into the console:
map <map_name> <mutation_name> eg: map c3m3_shantytown simple
When you load a map (I suggest c3m3_shantytown since the rest of tutorial will specifically use that map) observe the console text that indicates that your Mutation running. This is also a good time to mention that any text in the console which originates in your VScript code will be light blue in color and prefixed with the word VSCRIPT, making it easier to spot:
When the mutation starts, the Survivors should spawn inside the safe room as usual. The infected should attack 10 seconds after the Survivors spawn, whether you open the safe room door or not! They won't be able to break into the saferoom though so grab a gun and kill all the infected. After killing them there should be a short delay and then the game will restart. You are now a Mutation author!*
NOTE: In the event that your mutation is not working as expected then we retract the statement that you are a Mutation author.
- Does the console state "Script not found (scripted_simple)" and "Script not found (simple)"? Double check that your file extensions are visible and you did not name your file "simple.nut.txt" and that your .nut file is in the correct folder.
- Zombies not spawning? Make sure your MutationOptions table sets the CommonLimit and MegaMobSize correctly.
- Script not loading and console complaining about a missing open curly brace? Chances are your text editor is adding in Unicode byte-order marks to the beginning of your text/nut files. If you are using Notepad++ to edit, go to the Encoding menu and either encode in ANSI or in UTF-8 without BOM.
Since the Infected can't get into the Survivors' Saferoom, maybe we should start the Survivors out in the open to give the Infected a fighting chance...
The next portion of this tutorial covers how to add entities to your Mutation using the Entity Placement Tool.