General Half-Life 2/Scripting

description

Setting up an entity system to manage map events and logical states.

keywords

flags, state, events, logic, func_button, logic_branch, math_counter, logic_case.

Using Logical "Flags" to manage states in entity setups

So this tutorial has quite the mouthful of a title I know, perhaps I should explain that a bit. You are familiar with the "Flags" tab on an entities properties (if you aren't then this tutorial is beyond you), but you may not be aware of how it stores data. Each flag is assigned a number, starting with 1, which is four times the value of the previous flag. So let's say that an entity has four flags, they would be assigned the values 1, 2, 4, and 8. This allows all the flags values to be stored as one number, the sum of the values of the flags you check. So let's say you check the first, third, and fourth flags: the entities "flag value" would be 41. This works because well because each possible combination of any number of powers of 2 and the number 1 yields a unique number. In fact, with 1, 2, 4, and 8 you get the numbers 1 through 15.

So that's all great and all, but it's not what this tutorial is about. What we will be doing is setting up an entity system that uses this same theory to manage map events and logical states.

The Goal

As an example of what can be done with this we will make a puzzle with four buttons (though it can easily be expanded to as many as you want). For every combination of the buttons something different will happen. This equals 14 combinations. For buttons named A, B, C, and D:

- Code: Select all
`A B C D AB AC AD BC BD CD ABC ABD ACD BCD ABCD`

Fifteen combinations! With five buttons it's a LOT more:

- Code: Select all
`A B C D E AB AC AD AE BC BD BE CD CE DE ABC ABD ABE ACD ACE ADE BCD BDE CDE ABCD ABCE ACDE ABDE BCDE ABCDE`

So you can see how this can quickly spiral out of control. Still, it's rare that you'll need more than three states (six combinations) to keep track of and even if you need four or more states it's rare you'll need to keep track of all combinations. Either way the setup is VERY simple no matter how many states you are doing. Anyway, let's get cracking. We start with:

A test box! And then we move on to...

The Logic

Entities Used: func_button OR logic_branch, math_counter, logic_case

Ok, so first let's make four buttons. Just basic no frills buttons, they don't even need names for this test but we set the "Toggle" flag. Then we make a math_counter and a logic_case. Name the math_counter mc_buttonflags and the logic_case lc_buttonflags. We don't need to change any other keyvalues on the math_counter but we do need to set some on the logic_case. What we will be doing is assigning each func_button a value either 1, 2, 4, or 8, adding those up with the math_counter and checking the sum against the logic_case. So enter each of the possible combinations into one of the logic_case's "Case" fields.

Now we give each button two ouputs. The first button targets the math_counter with "OnIn: Add 1; OnOut: Subtract 1", the second button with "OnIn: Add 2; OnOut: Subtract 2" the third with "OnIn: Add 4; OnOut: Subtract 4" and the fourth with "OnIn: Add 8; OnOut Subtract 8". Then we set an "OutValue" output on the math_counter targeting the logic_case with "InValue." Output out, input in, oh so simple and sweet.

The button get's pressed in it adds it's value to the system's state, the math_counter tells the logic_case which fires the relevant output. The button get's pressed again (unpressed), it's value is removed, and the appropriate case is fired.

And that's basically it, now we just need to setup some stuff to happen based on the different combinations. Each of the OnCaseXX outputs on the logic_case now represents a different combination of buttons, OnCase07, for example, which represents the combination of buttons one two and three (vales 1, 2, and 4 respectively). Of course you might have four buttons but only, say, five unique combinations with the other nine combinations nonfunctional or the same. If this is the case you can change the logic_case's settings removing the CaseXX value for each of the value that aren't unique, and using the OnDefault output if those other nine states trigger something generic OR, if they don't trigger anything at all, just leaving things as they are and not giving them any outputs. The OnDefault output fires when the input value does not equal any of the CaseXX values. Oh, and the logic_case's OnDefault ouput is triggered if all the buttons are unpressed. So, if you press the first button the OnCase01 output will end up firing, and if you unpress it, the logic_case is now set to 0, which doesn't have an entry, so it fires OnDefault.

Using five states

In the VERY unlikely event that you have unique outcomes for every possibly combination of five or more states, which is dozens of possibilities, you simply create a second logic_case or even third logic_case to hold the additional possibilities. The sequence continues with powers of two: 16, 32, 64, 128, etc. If the value is present in the second logic_case it will fire the proper outputs and the first logic_case will fire default.

Note on the prefab

Place the Prefabs Logic folder in either steam/steamapps/<usernam>/sourcesdk/bin/ep1/bin/prefabs/ or ...bin/orangebox/bin/prefabs. or ...bin/source2007/bin/prefabs/, whichever engine version you are working with.

I wrote this tutorial using func_button's instead of logic_branch's like the prefab because it is simpler to setup which you should do yourself the first time if there's anything that's unclear. Both the prefab and the level with the button logic are included.

Prefabs use the wildcard &i for instancing. If you place a prefab in your level each place &i shows up will be changed to the number 1. If you place it a second time it will be changed to the number 2, and so on. The prefab (in Prefabs Logic/logical_flags.vmf) has all of this correctly setup.

The prefab uses logic_branch's instead of func_buttons. In this case the OnTrue output adds the number and the OnFalse output subtracts it. This can then be linked to buttons, triggers, or whatever by using each logic_branch's SetValueTest input with either 0 or 1. Sending the lb_value8_&i logic_branch the input "SetValueTest: 1" will cause it to add the value 8 to the math_counter. This way you can easily link map events to the systeme by targeting the logic_branch's. Just create two outputs for each event targeting a unique logic_branch! The logic_branch's are named lb_value1A, 24B, 4C, and 8D so you have both a number and a letter for easy identification! Then you just add the appropriate OnCaseXX output to the logic_case!

Goodbye

You may want to organize your "OnCaseXX" outputs with logic_relay's if you have alot going on but the prefab does not include that as it would clutter everything oh so much!

Anyway, I hope this was clear enough. It's a pretty simple concept that is easy to setup and has a LOT of power. Even if you are just managing three buttons for seven unique states and only using three or four of those this is the way to go. If anything didn't make sense just look at the included files. Adios!

http://www.interlopers.net/downloads/ma ... torial.rar

Mr. Happy