Boxdroppers and rapid destruction of multiple WCCs

Avatar
Dewin
43 Posts
Posted Jan 09, 2008
Thought I'd post about this since it's a problem I encountered on my map and came up with a fix for.

Say you have a map that involves multiple weighted storage cubes, but only one box dropper.

Triggering the box dropper every time a cube gets destroyed can cause interesting things if two cubes get destroyed simultaneously or near-simultaneously. For instance, you might end up with two cubes stuck inside the dropper (instead of the usual one cube that is waiting for the next trigger), or something else. Either way, while you're likely to get one cube back, you're not likely to get all of them.

My solution was this:
1. Create a math_counter. Give it an initial value of -1, min and max of 0.
2. On the env_entity_maker part of the boxdropper (i.e. CP4P_dropper_boxmaker_1 if you are using CP4P prefabs), add an output for:
My output named: OnEntitySpawned
Target: name_of_math_counter
Target Input: add
Target Value: 1

  1. Create a logic_compare. Set its Initial Value to 0 and Compare Value to the minimum number of boxes that should be existing at the time.
    For its outputs, add:
    My output named: OnLessThan
    <<stuff to trigger your boxdropper here. For example (CP4P): CP4P_boxdropper_trigger=>Trigger>>

  2. On the math_counter, add:
    OutValue => name_of_logic_compare => SetValue
    with no parameter override

  3. Create a trigger_multiple covering the area around the box dropper. Set its Delay Before Reset to 4.
    The only Flags that should be set are "Client". For its outputs, add
    OnTrigger => name_of_logic_compare => Compare

  4. On any object that destroys a box, add the appropriate outputs to Subtract 1 from the math_counter.

If all works well, you'll have a box dropper that will replenish destroyed (or not yet spawned) boxes at a rate of 1 every 4 seconds until the requisite number has been made.

Notes:
1. Make sure there's space for all your boxes to be created, else you may clog the dropper.
2. It's important that the math_counter start at -1 instead of 0, since the boxdropper has always spawned one more box than is really available (the box that is 'waiting' at the bottom)
3. I tried doing this without the logic_compare using min/max values on the counter and SetHitMin/SetHitMax trickery. Don't try it, it doesn't work. If a counter has a max of 3 and a min of 2 with OnHitMin set to change min to -1, and has a current value of 3 and receives two Subtract(1) events simultaneously, the second will be clamped (thus keeping it at a value of 2, not 1) before the SetHitMin event fires, thus only one replacement box will be issued.

Advertisement
Registered users don't see ads! Register now!
Avatar
Hedgehog
43 Posts
Posted Jan 09, 2008
Replied 1 hour later
Didn't need it yet, but it's surely interesting. Thanks for sharing it
Avatar
DaMaGepy
361 Posts
Posted Jan 09, 2008
Replied 8 hours later

I made a math counter too, and a timer. If there is 4 box and all destroyed at the same time, after every destruction it adds 1 to the counter and if a box created them removes 1. If its not 0 then it activates a timer that spawns a box every 2 sec until there are no boxes in the queue. Simple and safe.
I posted my map sources before, just check the map 03, the room with 5 button and 4 box and a box dropper before the last big room:

http://heroes.hardwired.hu/-/portal/damagepy_source.zip

Avatar
Hunter
17 Posts
Posted Jan 09, 2008
Replied 4 hours later
So you can use a trigger_multiple OR a logic_timer to accomplish this task. My question is, which is more efficient? Obviously, a logic_timer, being a point entity, takes up less space in the file, but it activates every few seconds as long as the map is loaded. To prevent that from happening, you could have triggers at the start and end of the puzzle that uses the dropper, but that would negate the file size advantage. I guess the more important thing is how much overhead is required by trigger collision detection. Anyone know anything about that?
Avatar
Dewin
43 Posts
Posted Jan 09, 2008
Replied 28 minutes later
I prefer the trigger method myself, because I like to not generate the box until the player is near it. (The idea being that this will cause the player to actually see the box being generated, and it will draw their attention to it.)

The catch in this case is that the player might walk out of the trigger while it is still generating boxes... they might wait for 1, grab it and leave before the other two are generated. This doesn't permanently break anything (the trigger will still happily generate more as soon as the player comes back), but still is not perfect.

In reality, however, there is no need for a logic_timer at all even if you aren't using a trigger. Simply have your env_entity_maker run the compare event 4 seconds after it spawns the box, such that:

env_entity_maker OnEntitySpawned => math_counter Add 1 in 0.00
env_entity_maker OnEntitySpawned => logic_compare Compare in 4.00
math_counter Outvalue => logic_compare SetValue in 0.00
logic_compare OnLessThan => env_entity_maker Forcespawn in 0.00

This gives you a loop where the env_entity_maker will effectively check to see if it should make a new box every 4 seconds (until it no longer needs to, at which point the loop is broken.). There's only two more things required to make it work:

  1. a logic_auto (or similiar) to ForceSpawn the env_entity_maker to get the initial 'waiting' box spawned. (But you need this anyways), and
  2. Call math_counter Subtract 1 any time a box is lost.

The catch to doing it this way is you no longer have precise control over when boxes are released -- they'll be released as soon as they're required, instead of waiting for the player to be near the dropper. Well, it might be possible to get around this by disabling/enabling the entity_spawner... which would be the route to go if you had multiple boxdroppers and wanted the first one the player approached to give a box without having extra boxes....

Multiple boxes sharing one counter:
Same setup as before, but the math_counter's initial value is negative N, where N is the number of boxdroppers. (3 boxdroppers = -3)
logic_auto OnMapSpawn => env_entity_maker ForceSpawn @ 0.00
logic_auto OnMapSpawn => env_entity_maker
Disable @ 0.01

then a proximity trigger near each box dropper:
trigger_multiple OnTrigger => env_entity_maker* Disable @ 0.00
trigger_multiple OnTrigger => env_entity_maker_4 Enable @ 0.01
trigger_multiple OnTrigger => logic_compare Compaer @ 0.02

Avatar
username
67 Posts
Posted Jan 09, 2008
Replied 1 minute later

Hunter wrote:
So you can use a trigger_multiple OR a logic_timer to accomplish this task. My question is, which is more efficient? Obviously, a logic_timer, being a point entity, takes up less space in the file, but it activates every few seconds as long as the map is loaded. To prevent that from happening, you could have triggers at the start and end of the puzzle that uses the dropper, but that would negate the file size advantage. I guess the more important thing is how much overhead is required by trigger collision detection. Anyone know anything about that?

The overhead is negligible, unless you're using hundreds of triggers in a small area. The only triggers checked are the ones that the player could see in their visleaf.

Avatar
msleeper
4,095 Posts
Member
Posted Jan 09, 2008
Replied 1 minute later

Hunter wrote:
My question is, which is more efficient? Obviously, a logic_timer, being a point entity, takes up less space in the file, but it activates every few seconds as long as the map is loaded.

This is more or less not entirely correct. The amount of file space difference between using a logic_timer or a trigger_multiple is completely negligible, we're talking less than 1 KB at absolute most for each entity.

As for what is more expensive in-game to operate and use, that is also a null issue. Handling logic entities doesn't even show up as a blip on a budget screen until you start getting into extreme amounts and/or calculations using them, which figuring out if a new WCC should be created isn't one of them. It takes more processing power for the engine to render a single WCC than it would to send 1,000 messages telling it to create a new one.

The logic_timer vs trigger_multiple comes down mostly to preference, and also partly to practice - how do you want your box dropper to work? Personally, I'd suggest not using logic_timer and use logic_relay, and having two logic_relays and a trigger_multiple:

  • The first relay is fired at the beginning of the chain, when the cube is destroyed. The OnDestroyed or OnOutOfWorld or whatever Outputs you are using, fires a Trigger to this first relay. After a 1 or 2 second delay, it Outputs to the spawner to create a new cube and enables the trigger_multiple.

  • The trigger_multiple sits at the bottom of the dropper. It does an OnStartTouch -> Trigger on the second relay.

  • The second logic_relay, after 1 or 2 seconds, Disables the trigger_multiple and fires the Open animation for the box dropper door. After another 1 or 2 seconds, it fires the Close animation, and that's it.

Avatar
Hunter
17 Posts
Posted Jan 10, 2008
Replied 22 hours later

msleeper wrote:
This is more or less not entirely correct. The amount of file space difference between using a logic_timer or a trigger_multiple is completely negligible, we're talking less than 1 KB at absolute most for each entity.

But there is a difference. Besides, I'm sure some idiot will manage to make a map where the triggers and logic are more costly than the physics and graphics, so it doesn't hurt to think about these things. (NB: I don't intend to be that idiot.)

Also, it looks like what you're describing is for a single box dropper, but it shouldn't be too hard to adapt those logic_relays to work with a multiple box dropper. Just throw in a math_counter and a few inputs and outputs to make sure there's only one box in the tube at a time, and there you go.

Avatar
msleeper
4,095 Posts
Member
Posted Jan 10, 2008
Replied 40 minutes later
You could have a sort of master logic_relay that sends commands to dropper-specific logic_relays.
Avatar
Hunter
17 Posts
Posted Jan 10, 2008
Replied 1 hour later
Eh, sorry. When I said "multiple box droppers," I meant "multiple-box" droppers. As in, a single dropper that is designed to keep more than one box in play. Of course, there are probably situations where the reverse would be handy, but that's not what this thread is about.
Avatar
msleeper
4,095 Posts
Member
Posted Jan 10, 2008
Replied 2 minutes later
Still easy, you'd have your math_counter start a 0 and whenever a box is destroyed have it Add 1. At whatever interval (either have a timer, or a OnHitValue in the math_counter), have it tell another entity (such as a logic_case) to create however many boxes need to be created.
Advertisement
Registered users don't see ads! Register now!
Avatar
Hunter
17 Posts
Posted Jan 11, 2008
Replied 7 hours later
Yeah, but then you have the problem of too many boxes being dropped at once and clogging the vital apparatus vent. I forget where the link is, but I saw a YouTube video of that, and it wasn't pretty. So here's all of what you'd need to make your particular version work (pardon the pseudocode):

int NUM_BOXES; // However many cubes the player needs
math_counter counter;
logic_compare comparator(CompareValue = NUM_BOXES);
logic_relay spawn_relay, drop_relay;
trigger_multiple player_detector(Wait = 4, StartDisabled);

logic_auto.OnMapSpawn = spawn_relay.Trigger;

box.OnOutOfWorld =
- counter.Subtract 1;
- spawn_relay.Trigger;

counter.OutValue = comparator.SetValue;

spawn_relay.OnTrigger = comparator.Compare;

comparator.OnLessThan =
- spawn_relay.Disable;
- box_maker.ForceSpawn;
- player_detector.Enable;

player_detector.OnStartTouch = drop_relay.Trigger;

drop_relay.OnTrigger =
- player_detector.Disable;
- box_dropper_cover.SetAnimation Open after 2;
- box_dropper_cover.SetAnimation Close after 4;
- counter.Add 1 after 4;
- spawn_relay.Enable after 4;
- spawn_relay.Trigger after 4;

This way you only have one box in the tube at a time and everything else is as you designed it, assuming I wrote all this correctly. I don't know; it's way late, and I have no intention of firing up Hammer to test it.