L4D2 Level Design/Director Queries
logic_director_query is a new L4D2-specific entity that, when triggered, returns a value that corresponds with how "angry" the A.I. Director is at that moment. The better survivors are doing, the angrier the Director will be, and the more aggressive the game will be in spawning infected.
You can take advantage of this to make your maps more dynamic and responsive to player skill level. A simple example would be to create multiple paths through an area of varying length/difficulty, then using a Director query to open and close the appropriate paths. In versus, the system will automatically repeat the decision when teams swap, thus providing for an even playing context.
Firing a query
Let's look at how this works.
The Director is constantly updating its state internally, but for map-editing purposes, you must explicitly query it with some kind of trigger. The query gives us a snapshot of the Director's anger value and allows our game logic setup to respond accordingly.
For this example, let's fire off the query once the survivors reach a certain point in the map. Go ahead and place a trigger volume in the hallway. Querying the Director so close to the very beginning of a first map is not always useful, since survivors will be at full health and the Director will always be at its most angry. But for learning purposes, this will do.
Place a solid, then select it and choose Tools > Tie to entity from the menu bar. Change the entity class to "trigger_once" and assign it the material "
We'll want this trigger to happen for survivors only, so we'll need to filter its output. To do so, let's place a new entity of class "filter_activator_team" and name it "
filter_survivor" The trigger will now only be activated by survivors, and not by infected.
Next, let's move down the other end of the hallway to the ladder leading up to the safe room. Place a new entity of class "logic_director_query". For a name, use "
Under Properties, set the Min. Anger Range to
0, and the Max Anger Range to
9. The Director itself keeps track of anger between 0 and 50, but for our purposes we will want to divide it into 10 cases. These settings remap the values that the Director query reports back to a scale between 0 and 10.
Noise in the anger value is a very important part of gameplay. A little bit of unpredictability is necessary to keep players on their toes. For tutorial purposes, let's set Noise to "
Pure". This effectively turns off the built-in in randomness in the anger system. You typically will not want to do this, as it removes the element of procedural surprise, making gameplay boring and predictable.
Go ahead and select the trigger volume at the start of the map and add an output "OnStartTouch" which will target "
director_query_zombie" with an input of "
Hitto run the map. Once it loads, step into the hallway to trigger the volume and then immediately bring up the console. The Director query will have spit out something like the following:
TRUE Anger: 50.00 Processed Anger: 50 Out Anger: 9
So your query is now firing for players. While working on your map, you will want to set
sv_cheats to 1, thus allowing you to manually trigger the Director query from the console. For us that would be:
ent_fire director_query_zombie howangry
Reacting to the query
Now that we can have information about the Director, we need to do something with it, and that will typically be some kind of change in the world. Let's spawn an infected, but have the type vary depending on the anger.Place a new entity of class
commentary_zombie_spawnerjust above the
Next, let's create a new
logic_case entity named "
zombie_case" and put in property values for each of the conditions we want to respond to. In this example, we've set it up to be able to respond to 10 different conditions.
Once the Properties are set up, we move on to the Outputs and signal the zombie spawner to do different things depending on the case.
Now, go back to your
logic_query_director entity and go to Outputs there. Choose OutAnger as your output, "
zombie_case" as your target, and InValue as your input. This will tell your logic_query_director to send the exact value of its remapped anger values to the logic_case. The logic_case will take this number and will correspond it to the cases you have set up.
If the case doesn't match the property, it won't do anything. So in this example, if the Director anger is 5 or below, it won't do anything.Above 6, the case signals the spawner to force spawn a zombie, which will be either a common infected, a boomer, a charger, or a tank, depending on what the anger level was.
When you're developing your maps, you'll want to carefully tune your map logic so that each Director-responsive scenario is FUN FOR PLAYERS. If your setup is too predictable, players will be able to anticipate it, and that's not fun. If it's so random that it's not clear that how well they are doing has some correlation with what happens, then they will not be motivated to do what you're asking them to do.
How much randomness should you use? It depends. The fun zone is different for each scenario, and achieving it seldom happens straight off. It is recommended that you plan for several iterations of observing players, tweaking the behavior, observing again.
Here's an example that you may find useful in developing and debugging your maps:
Open the file:
Here we have a logic timer that has the info_query fire off a query at regular intervals. The logic_case evaluates the anger and enables the appropriate func_brush number. This gives a numerical readout of the anger value directly to players based on the Director query.
Of course, instead of numbers, you can do more subtle things. People often assume that correlation equals causality. You can use this to your advantage for entertainment and thrills. (And eventually perhaps even profit.)
Here's another example you should check out:
The first map of Deadline2 example add-on campaign uses this to select alternate paths, one short and direct, one less direct and kinked. There is also a spawner that may place in the survivors path, depending on anger, a boomer or a witch, neither of which is good to have in a tight constrained space.