-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove scent diffusion over water by implementing NO_SCENT flag #37129
Conversation
Adding REDUCE_SCENT tag to liquid tiles in order to make sure water reduces scent trails
REDUCE_SCENT is working as intended, but arguably has a bad name. |
Aha! What do you think about me adding a new flag (say, DISSIPATES_SCENT) intended to reduce scent trails over water? |
I'm ok with that in principle, but this is an incredibly complicated and fragile piece of code, so good luck. |
Ok... Trying a new tack and found something weird maybe: TFLAG_WALL is supposed to block scent but it doesn't seem to. In scent_map.cpp there's a comment that says: "currently only TFLAG_WALL blocks scent", and from the code it looks like it should in fact do that. However, when I put TFLAG_WALL instead of REDUCES_SCENT into the water terrain tiles in terrain-liquids.json... It doesn't seem to do anything. Scent seems to be propagating over water without being blocked by TFLAG_WALL. From a quick search of the code, it seems to me like TFLAG_WALL is only really (intended to be?) used for two things:
// The new scent flag searching function. Should be wayyy faster than the old one.
m.scent_blockers( blocks_scent, reduces_scent, point( scentmap_minx - 1, scentmap_miny - 1 ),
point( scentmap_maxx + 1, scentmap_maxy + 1 ) );
// Sum neighbors in the y direction. This way, each square gets called 3 times instead of 9
// times. This cost us an extra loop here, but it also eliminated a loop at the end, so there
// is a net performance improvement over the old code. Could probably still be better.
// note: this method needs an array that is one square larger on each side in the x direction
// than the final scent matrix. I think this is fine since SCENT_RADIUS is less than
// MAPSIZE_X, but if that changes, this may need tweaking.
for( int x = scentmap_minx - 1; x <= scentmap_maxx + 1; ++x ) {
for( int y = scentmap_miny; y <= scentmap_maxy; ++y ) {
// remember the sum of the scent val for the 3 neighboring squares that can defuse into
sum_3_scent_y[y][x] = 0;
squares_used_y[y][x] = 0;
for( int i = y - 1; i <= y + 1; ++i ) {
if( !blocks_scent[x][i] ) {
if( reduces_scent[x][i] ) {
// only 20% of scent can diffuse on REDUCE_SCENT squares
sum_3_scent_y[y][x] += 2 * grscent[x][i];
squares_used_y[y][x] += 2;
} else {
sum_3_scent_y[y][x] += 10 * grscent[x][i];
squares_used_y[y][x] += 10;
}
}
}
}
}
void map::scent_blockers( std::array<std::array<bool, MAPSIZE_X>, MAPSIZE_Y> &blocks_scent,
std::array<std::array<bool, MAPSIZE_X>, MAPSIZE_Y> &reduces_scent,
const point &min, const point &max )
{
auto reduce = TFLAG_REDUCE_SCENT;
auto block = TFLAG_WALL;
auto fill_values = [&]( const tripoint & gp, const submap * sm, const point & lp ) {
// We need to generate the x/y coordinates, because we can't get them "for free"
const int x = gp.x * SEEX + lp.x;
const int y = gp.y * SEEY + lp.y;
if( sm->get_ter( lp ).obj().has_flag( block ) ) {
blocks_scent[x][y] = true;
reduces_scent[x][y] = false;
} else if( sm->get_ter( lp ).obj().has_flag( reduce ) ||
sm->get_furn( lp ).obj().has_flag( reduce ) ) {
blocks_scent[x][y] = false;
reduces_scent[x][y] = true;
} else {
blocks_scent[x][y] = false;
reduces_scent[x][y] = false;
}
return ITER_CONTINUE;
}; (...then in map_data_common_t::set_flag() in mapdata.cpp): void map_data_common_t::set_flag( const std::string &flag )
{
flags.insert( flag );
const auto it = ter_bitflags_map.find( flag );
if( it != ter_bitflags_map.end() ) {
bitflags.set( it->second );
if( !transparent && it->second == TFLAG_TRANSPARENT ) {
transparent = true;
}
// wall connection check for JSON backwards compatibility
if( it->second == TFLAG_WALL || it->second == TFLAG_CONNECT_TO_WALL ) {
set_connects( "WALL" );
}
}
} So, in theory, if TFLAG_WALL actually did zero out scent, then adding it to the liquid terrains should basically do the trick: Scent wouldn't exist on water tiles, so crossing water would stop monsters from tracking you by scent. ...However, TFLAG_WALL doesn't seem to be affecting scent at all on water tiles! At least when I added it to water tiles it didn't seem to... I think I'm testing this right. Can you reproduce? If necessary, I think I could split TFLAG_WALL into two flags - NO_SCENT and TFLAG_WALL, using NO_SCENT for the few parts of the code that currently use TFLAG_WALL for blocking scent propagation, and leaving TFLAG_WALL for the rest of the code (basically just in defining mapgen wall connections). What am I missing? Am I thinking about this right? |
Did you add Those flags are converted to Line 152 in 2809e4f
|
Update from using REDUCE_SCENT tag to WALL tag. WALL eliminates scent over water completely, which makes sense in most cases (like there being no scent trail from sweat or chemical traces left on surfaces) but not all (smoke should be able to waft some distance over water)... This still has interesting tactical implications: It means suvivors (especially suvivors with Strong Scent) can benefit by ducking in and out of rivers and lakes, jumping in a canoe to avoid being tracked by smell, etc.
Thank you for that, @anothersimulacrum! I changed it from REDUCE _SCENT to WALL and it works great now. WALL eliminates scent over water completely, which I think makes sense in most cases (like there being no scent trail from sweat or chemical traces left on surfaces) but not all (smoke should be able to waft some distance over water)... This still has interesting tactical implications: It means survivors (especially survivors with Strong Scent) can benefit by ducking in and out of rivers and lakes, jumping in a canoe to avoid being tracked by smell, hiding in the swimming pool, etc. It's a bit messy, because obviously water tiles aren't walls, and I'm not sure how it could interact with map-generation code (in scent_map::update() in scent_map.cpp and in map::scent_blockers() in map.cpp)... But I just generated a world and tested it out and it seems to work. |
You should implement a new flag that has the same effect on scent as the |
My c++ is totally rusty but I'm up for that. Let me see if I can try to figure it out... |
* Created new NO_SCENT (json) and TFLAG_NO_SCENT (in-memory) flags * Updated the scent-diffusion code to use the NO_SCENT flag instead of the WALL flag (the WALL flag no longer affects scent diffusion) * Left the map-generation and tile-linking code that uses the WALL flag alone (the WALL flag affects map generation and drawing the same way it did before) * Updated the terrain-types json definitions that previously used WALL to also use NO_SCENT * Fixed a few tile defintions that seemed like they should have NO_SCENT, REDUCE_SCENT, or be PERMIABLE, but previously weren't * Updated documentation
…sion across things besides WALLs" Fixing summary
Ok! This PR now:
|
I believe the premise of this PR is incorrect. See: https://skeptics.stackexchange.com/questions/7196/will-running-through-water-lose-ones-scent-when-being-tracked-by-dogs |
In the Mythbusters episode the bloodhounds didn't track Jamie in the water. They tracked him on the shore by the water, where he got in and where he got out. Bloodhounds can't track you in the water proper. If Jamie had swam out into the lake and the bloodhound couldn't see him, it would only know where he got into the water - it wouldn't be able to track him in the water: "If you cross a body of water and a tracking dog and its handler believes you’ve entered the water, they will either have to cross the water also, or circle around to the other side where they will likely pick up your scent again where you exited the water as your scent drips off you and along the ground." (from here) As noted at the top here, this change isn't perfect but it approximates that behavior. |
Okay. Mythbusters is probably not the most reliable source for this, but based on my understanding, the scent goes through the air, not the ground, and going into water doesn't stop it from spreading, and some quick searches (again, not the most reliable source, but still) seem to agree that dogs can track people through water just fine. I'm not an expect on this, however, but I think that adding this to do game would need some sources that would show that it actually works. |
Dogs don't track scent through water. If you get in a kayak on the shore and then paddle off into the sea, the best bloodhounds in the world aren't going to be able to follow your path over the ocean. As noted at the top here, this change isn't perfect but it improves on previous functionality and approximates ideal behavior. |
Also, I note that a build test appears to fail for reasons unrelated to this PR:
I updated the summary line too, which should (I think?) fix the PR Validator block. |
Update: That did not fix the summary line so the PR Validator tests still fail. How do I fix it? |
Your own source says: What About Crossing A Lake, Pond, Or River? Unfortunately, all water is said to do is carry your scent back to the ground as water drips off you, making it even easier for a dog to pick up your scent (so say the experts). If you cross a body of water and a tracking dog and its handler believes you’ve entered the water, they will either have to cross the water also, or circle around to the other side where they will likely pick up your scent again where you exited the water as your scent drips off you and along the ground. Crossing bodies of water is a trick to lose human trackers, who rely mostly on visuals. It breaks off your track because you won’t leave footprints or other telltale signs of human activity in a body of water. But this doesn’t work on dogs, who rely primarily on scent. Obviously if you kayak into the sea, you're not going to be followed by dogs. But not because of the scent. It's because most dogs don't have kayaks, and even fewer can navigate oceans. Zombies aren't dogs, they're not concerned with breathing, and will blindly follow your scent into the water, kayak or no. So far there have been three sources in this tread that say the scent is not broken by the water, do you have any reliable sources that indicate otherwise? |
That's already been addressed. See where it says "all water is said to do is carry your scent back to the ground as water drips off you"? Air scent is only detectable downwind and dissipates very quickly (in a matter of minutes at most), which is why the scent trail ("track") that bloodhounds follow is mostly on the ground. Ground scent doesn't exist on the water, in the water, or over the water. This makes sense, because (according to the CIA) air scent is mostly derived from sebum, while (according to books cited by Wikipedia) ground scent is mostly derived from trampled vegetation, bugs, mud, and soil disturbed by an individuals footprints. Sebum can be left on the ground and on objects touched, but can only be detected from distance over the air when immediately downwind. Water that drips off you will thus leave a strong ground scent trail, but ground scent trails don't exist on the water, so that only matters when you reach shore. As Karthas077 pointed out in the Discord: "This is why when tracking someone with dogs, you want at least four dogs. Come to a river? Two split up to search up and down the current bank, two cross to search up and down the opposite bank. Regroup once scent is found again." As noted at the top here, this change isn't perfect but it improves on previous functionality, creates interesting tactical options for the player, and approximates ideal behavior: Ground scent trails don't exist on the water. |
Zombies aren't bloodhounds anyway. If dogs have increased difficulty tracking scents over water, zombies would be much worse at it. Keeping this as a different flag is a good idea, because going forward we'd probably want it to reduce but not eliminate scent. In the meantime this is a good solution I think. I'm not going to merge it because it has C++ changes so I shouldn't be trusted with it, but I have no problem with adding it. |
Summary
SUMMARY: Bugfixes "Removes scent diffusion over water by implementing NO_SCENT flag"
Purpose of change
Scent trails shouldn't persist over water, and zombies/hordes shouldn't easily follow scent trails over water, such that survivors taking a boat or swimming across water shouldn't be easily tracked by scent. With this change, zombies/hordes will be less likely to follow survivors across bodies of water.
This has other interesting tactical implications as well: It means survivors (especially survivors with Strong Scent) can benefit by ducking in and out of rivers and lakes, jumping in a canoe to avoid being tracked by smell, building a base in relative safety across a river, hiding in the deep end, etc.
Describe the solution
Describe alternatives you've considered
I originally just added REDUCE_SCENT to water tiles in the json but that just resulted in extremely concentrated scent trails when moving across water, rather than reducing the total scent trail left behind, like so:
That didn't work, but adding WALL did, so as per suggestions I implemented new NO_SCENT and TFLAG_NO_SCENT flags and updated the code to use them.
I think removing scent from water makes sense in most cases: For example, there shouldn't be the same kind of scent trails from sweat or chemical traces left on water, because water doesn't have the kind of surface that human sweat etc can stick to. This effectively makes water tiles into wall tiles for scent-diffusion purposes.
However, I don't think this solution makes sense all cases: For example, smoke should ideally be able to waft some distance over water, even if a bloodhound can only follow a trail up to the edge of the water and sniff around there... This code doesn't support that, but I have no idea what a more complex scent diffusion system should look like, and in any case this slightly extends existing functionality to create interesting and realistic tactical options for creative survivors.
Testing
Additional context
Scent trail over water before this change:
Scent trail over water after this change: