```
if( random->RandomFloat( 0.0f, 1.0f ) >= 0.5f )
{
// Fire event
}
m_flNextCheck = gpGlobals->curtime + 10.0f;
```

I named this one "discrete extrapolation" because of how it works. The reasoning here is that if you take a discrete event, and perform this event every so often, then you have effectively modeled the case where an event has a certain probability of happening every period of time. However this isn't the case. This event is hardly random because it only occurs at 10 second intervals, if at all. It's usually the intention of the author that a certain event has a given chance of firing over the course of a period of time. This leads me to my next example:
```
if( random->RandomFloat( 0.0f, 1.0f ) >= 0.5f )
{
// Fire event
}
m_flNextCheck = gpGlobals->curtime + 0.1f;
```

The common misconception is that if you want an event to occur within a given probability, you simply perform this event as often as possible, and in the long-run it will have happened that often. However, what people forget is that when you're dealing with something continuous like time, events happen within a certain probability within a ```
// Fire event
float randomNext = random->RandomFloat( 10.0f, 15.0f );
m_flNextCheck = gpGlobals->curtime + randomNext;
```

The above specifies that the waiting time between events is randomly distributed between 10 and 15 seconds. That's great, but... what exactly are the parameters of this event? In other words, what's the probability this event happens every 10 seconds? 15 seconds? What's the average frequency of this event in the long-run? While these answers certainly exist, you wouldn't be able to determine them without the help of more advanced statistical model. Thus it follows that without these complex models, you won't be able to condition the values to what they need to be.
`a`

and `b`

to determine the probability of an event hapening in that span of time: Evaluating this function with `a`

and `b`

will tell us the probability the event will occur between those two times.
What we have to do next is convert our specifications into their effective parameter. For example, if we want an event to happen on average 6 times every minute, this is the same as 6 times every 60 seconds and thus our parameter would be 0.1 (0.1 times per second). On the other hand, let's say we want an event to happen with probability of 30% every two minutes. In the case of a Poisson distribution, we can actually turn our probability directly into a value, 0.3, and use that in our calculations. Thus our parameter would be 0.0025 (0.0025 times per second). The parameter can also be very small, such as in the case when we want an event to occur with a probability of 10% every hour - our parameter would be 2.8e-5. Lastly, if it's the case where we want an event to happen multiple times per second, then that value becomes the parameter directly.

`a`

, and take the `b`

. You can then plug those values into the formula to get a probability. Then you can generate a value between 0.0f and 1.0f and check if it's less than or equal to the generated probability. Is so, fire your event and reset your base time. In all cases, make sure to update your last check time. A sample implementation might look like this:
```
float a = m_flLastCheck - m_flBaseTime;
float b = gpGlobals->curtime - m_flBaseTime;
Assert( a < b ); // Should never happen where b <= a
float thisProb = log(-rate*a) - log(-rate*b);
if( random->RandomFloat( 0.0f, 1.0f ) <= thisProb )
{
// Fire event
m_flBaseTime = gpGlobals->curtime;
}
m_flLastCheck = gpGlobals->curtime;
```

Second, you can add a "grace" period for after events are fired. This is a minimum amount of time to wait before firing another event. Use this when your event is something like a sound or animation that takes a certain amount of time to finish before it can be triggered again. Unlike increasing the check time interval, which essential keeps the process from being evaluated for a certain period of time, when implementing a grace period you want to keep evaluating the process as usual. The only different is before you fire the event, you check to see if the grace time has expired. If it has, then you fire the event. Otherwise, do nothing. Note that you still want to update the base time. Remember, all we're changing is whether or not the event gets fired.

Lastly, try to be as flexible as possible when designing the Hammer entity for your mappers. Provide a TurnOn, TurnOff, and Toggle input so that they can control when the entity generates events. Allow them to specify the parameter as either the number of events per period of time, or as a probability of an event occurring within a period of time. Maybe even let them chose their units (seconds, minutes, hours) if the period of time is large.

If you have any other questions regarding the actual implementation of this entity, remember that it's just like any other logical entity in the SDK that thinks, accepts inputs, and triggers outputs. You can use these entities as an outline for your new logical entity.

Poisson Distribution

Poisson Process

The Poisson Process

You must log in to post a comment. You can login or register a new account.