math_counter, wrapping numbers?

duppy

L1: Registered
Feb 16, 2012
35
8
Anyone know how to can make a math_counter wrap around its value when it hits the min or max value? :confused: Seems simple, but for some reason it either locks up the game or it skips a number for me.

If my counter's min is 0, max is 9, initial value 0, and I have another entity telling it to "Add 1", I want the values to be like:

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, ....

and if I had an entity telling my counter to "Subtract 1", then, I'd want:

0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, ...

I thought these outputs for my math_counter would work, but it locks up the game:

OnHitMax, mycounter, SetValue, 0
OnHitMin, mycounter, SetValue, 9
[I use OutValue here also, to pass the counter value to another entity]

So then I tried using SetValueNoFire instead; it kind of works, but it ends up skipping a number. For example, with subtracting 1, it would do, 0, 8, 7, 6...since OutValue wouldn't be fired.

What I have set up is a func_button that Adds 1 to my math_counter and another func_button that Subtracts 1 from my math_counter. On the wall I have an overlay that's using a animated texture with 10 frames (the VMT file has a ToggleTexture proxy, btw). I then use an env_texturetoggle to change the animated texture's current frame with SetTextureIndex when my math_counter's OutValue is fired. Essentially an animated texture, whose current frame is controlled by an "up" and "down" button.

I think that pretty much explains it. One other thing though, is there a way to see the value of a math_counter when it changes? I set "developer 3", but I only get to see the value when (in my particular case), it gets passed to SetTextureIndex. I played with "ent_messages_draw 1" and "ent_messages" as well, but they didn't seem to show the value on the screen.
 

duppy

L1: Registered
Feb 16, 2012
35
8
Well, after a bit of messing around, I finally figured out a solution, although I don't quite like it. The solution was to set my min value to -1, and max value to 10. The outputs are the same as what I showed above, using SetValue:

OnMaxHit, mycounter, SetValue, 0
OnMinHit, mycounter, SetValue, 9
OutValue, digit_tt, SetTextureIndex, <none>

In my case, this ends up calling SetTextureIndex twice (first with out of range value, second with the correct value), but since it just switches the animation frame, it's quickly overwritten with the correct one. If I was doing something else, it might not turn out so well. [Edit: tweaked solution in [post=280705]post #9[/post] based on [post=280669]post #8[/post]]

So in general...for a math_counter that you want to cycle through a range of numbers [x,y], set its Min value property to x-1, and Max value to y+1. For its OnMaxHit output, SetValue to x, and OnMinHit output, SetValue to y.

If someone has a better solution, please let me know.
 
Last edited:

duppy

L1: Registered
Feb 16, 2012
35
8
Maybe you want to look into math_remap?

Hmm, like when it hits the max value, remap 0-9 to 9-0, and opposite for hitting the min value? I might have to play with that. Last time I used math_remap was just to change 0.0-1.0 to 0-9 range.

I'm actually quite confused why it would crash in what you originally tried, because I'm sure I've done that before with no issue.

It's not an actual crash, but more like in infinite loop that locks it up. I think It gets stuck in a loop because SetValue causes it to fire OutValue, and that causes it to recheck the values. For example, if we were at 8, and added 1, I think it would do something like this:

8
Add 1
9
OnHitMax asks, are we at Max Value? Yes, Set value to 9, fire OutVal
9
OnHitMax asks, are we at Max Value? Yes, Set value to 9, fire OutVal
9
...etc, etc, etc. (locked up)

[Edit: oops, OnHitMax should set value to 0, then OnHitMin would set value to 9, and it would bounce back and forth between OnHitMax and OnHitMin over and over again causing in infinite loop and lock up the game]


my solution was to increase the legal min/max range property to [-1, 10], instead of the actual wanted [0,9] range, so it would be something like this:

8
Add 1
9
OnHitMax asks, are we at Max Value? No, keep going
Add 1
10
OnHitMax asks, are we at Max Value? Yes, Set value to 0, fire OutVal (this is where an "out of range" value is used, SetTextureIndex(10))
0
OnHitMax asks, are we at Max Value? No, keep going
Add 1
1
OnHitMax asks, are we at Max Value? No, keep going
Add 1
....etc, we're fine, no problems.

I just wish I (or one of you) could come up with a way to get around that "out of range" value though. It must be something so simple that people don't even bother to write about it on the web though, 'cause I really couldn't find anyone with a similar problem after doing my best with google searches. *shrug*...at least I have one solution, even if it's not perfect.
 
Last edited:

A Boojum Snark

Toraipoddodezain Mazahabado
aa
Nov 2, 2007
4,775
7,670
But why would it be setting itself back to 9? I thought you were trying to set it to 0 when it gets to 9?

I just looked at what I was doing with counters, I was using them for an event tally. I have the range set 0 to 10, and OnHitMax will set itself back to 0. It works just fine.

Maybe you need an extra entity in there somewhere? What exactly is it your are trying to get done here?
 

duppy

L1: Registered
Feb 16, 2012
35
8
But why would it be setting itself back to 9? I thought you were trying to set it to 0 when it gets to 9?

I just looked at what I was doing with counters, I was using them for an event tally. I have the range set 0 to 10, and OnHitMax will set itself back to 0. It works just fine.

Maybe you need an extra entity in there somewhere? What exactly is it your are trying to get done here?

:blushing: Oops, yeah, you're right, it should set it to 0 for OnHitMax. Maybe I was actually doing that in Hammer. I need to double check, and maybe make a simplified map with just the bare essential entities for this.

Edit: made a simple map to test it, and it's still locking up when using [0,9] range. Download it and see if you can figure out what I'm doing wrong. The zip file is 86.5k and includes the VMF file and the animated texture for the numbers.

I'm making a simple map that's used to test how high/far you can rocket jump with different techniques and types of rocket launchers. It has a height-adjustable brush, which you control with buttons. I'm pretty much done with the main part of it, although there is some slight bugs with the left most digit. Screenshot link. Also, it's just for fun, and "for science!" :p...plus I've learned quite about entity inputs and outputs.
 
Last edited:

A Boojum Snark

Toraipoddodezain Mazahabado
aa
Nov 2, 2007
4,775
7,670
Oh, I see what it is now. Looking closer at my map I actually used the same system of having the max one more than what I wanted (that's why it went up to 10). Mine didn't count down though, so I didn't run into the infinite loop of bouncing between max and min via outputs.

Toomai was right about math_remap being a help. You could use it as a relay to the texture input. Don't change the numbers, keep the in and out both 0 - 9, but make use of the "ignore out of range values" flag to prevent -1 and 10 being sent to the material.
 

duppy

L1: Registered
Feb 16, 2012
35
8
Oh wow, I didn't notice that flag on math_remap. With that, math_remap gets the "out of range" value instead of SetTextureIndex...very nice. Now it looks like this in "developer 3" debug output:

[starting at 0 and subtracting 1, which results in the desired value 9]

Code:
output: (func_button,button_sub) -> (mycounter,Subtract)(1)
input button_sub: mycounter.Subtract(1)
output: (math_counter,mycounter) -> (mycounter,SetValue)(9)
output: (math_counter,mycounter) -> (remap_dummy,InValue)()
input mycounter: mycounter.SetValue(9)
output: (math_counter,mycounter) -> (remap_dummy,InValue)()
input mycounter: remap_dummy.InValue(-1)
input mycounter: remap_dummy.InValue(9)
output: (math_remap,remap_dummy) -> (number_overlay_tt,SetTextureIndex)()
input remap_dummy: number_overlay_tt.SetTextureIndex(9)

The remap gets called twice, once with out of range value and once with good value, but it doesn't matter since we just use it to pass good values to SetTextureIndex. It still seems like a strange kludge for something that should be simple, but at least there's no out of range value sent to the important parts.

So now I have it set up like this (for wrapping [0,9] range):

Code:
func_button named "button_sub"
outputs:
	OnDamaged, mycounter, Subtract, 1
	
func_button named "button_add"
outputs:
	OnDamaged, mycounter, Add, 1
	
info_overlay named "number_overlay"
outputs:
	none
	
env_texturetoggle named "number_overlay_tt"
outputs:
	none

math_counter named "mycounter"
properties:
	min legal value: -1
	max legal value: 10
outputs:
	OnHitMax, mycounter, SetValue, 9
	OnHitMin, mycounter, SetValue, 0
	OutValue, remap_dummy, InValue
	
math_remap named "remap_dummy"
properties:
	min input: 0
	max input: 9
	min output: 0
	max output: 9
outputs:
	OutValue, number_overlay_tt, SetTextureIndex, <none>

Thanks for your help with this A Boojum Snark, and Toomai as well :p