I’ve looked into this a little bit, but some of the math is a little funky, so I’m not sure it’s really working as intended.
Probably the simplest thing to do is set some threshold before the loop based on how good the monster is at smelling, and do:
smell = g->scent(blabla);
if( smell < threshold ) continue;
Scent is currently a cloud that disperses very rapidly unless it’s refreshed constantly.
game::update_scent() is responsible for updating the scent cloud, which is maintained in game::grscent[][], a 2D array of scent intensity, this should probably live in the map, not the game structure for one thing.
what it does is fairly simple, first it sets the square the player is on equal to the player’s scent, then for each tile within an 18-square radius* it calculates a pseudo-average** of each square’s adjacent*** scent values, then overwrites the old scent map with the new one.
There’s a proposal to make the player’s scent “stick” to the area where the player has been more strongly, and make it spread less, so it acts more like a trail than a cloud.
*18 looks like a legacy value since the active area is 120 squares across. Additionally it looks like it’s going to leave phantom scent values in some cases if there is any scent left once the player is more than 18 squares away because it stops updating the values then, but they’re still used for monster navigation.
**This pseudo-average is kind of weird, it only counts squares that are stronger or as strong as the current square, but then adds one to the average, which means isolated pockets of scent die off VERY fast.
***Since it equally weights surrounding squares, the cloud would expand in a square as long as the player doesn’t move, but due to the weird averaging thing, the corners of the square will decay faster than the sides (since there aren’t as many adjacent equal-or-higher-strength squares)
BTW, here’s how the algorithm progresses if you cut the max value to 0xF and don’t move:
0000000 0000000 0000000 0000000
0000000 0000000 0000000 0000000
0000000 0011100 0032300 0064600
000F000 001F100 002F200 004F400
0000000 0011100 0032300 0064600
0000000 0000000 0000000 0000000
0000000 0000000 0000000 0000000
0000000 0000000 0000000 0000000
0011100 0023200 0044400 0045400
0175710 0276720 0476740 0476740
015F510 036F630 046F640 056F650
0175710 0266720 0466740 0476740
0011100 0023200 0044400 0045400
0000000 0000000 0000000 0000000
It progresses from left-to-right then top-down. As you can see, it spreads pretty fast (this would only take a minute in game, and would spread even faster if the max value was the default (600) instead of 0xF). I was really wasting my time with this, because with values this small the algorithm gets dominated by rounding errors. For example, it spreads to 0 tiles very slowly because every adjacent tile gets averaged in, which means the adjacent values have to add up to 10 before a 0 transitions to a 1. This isn’t an issue with large values, because that threshold of 10 is more easily met since the values start in the hundreds. You can see several features of the algorithm though, one is that each concentric circle is roughly half the next circle in, and at some point the whole thing reaches stasis because the averaging is so aggressive. As long as the player doesn’t move, that last scentmap will stay stable indefinitely. This points out another feature, which is that an area never develops “memory” of the player’s presence, the scentmap will roughly stabilize within 10 mins or so, after which it’s just a static feature. Another feature this doesn’t highlight is that walls block scent, or more properly they can never have scent. [size=12pt]Something that surprised me is that windows and doors don’t block scent at all, just walls, which means we’ve been giving people bad advice about avoiding being sniffed out by zombies :P[/size] I think I’ll want to do something about this in the short term while I’m still mulling over what to do about the system as a whole, because closed doors and windows should definitely attenuate scent more than that.