void scent_map::update( const tripoint ¢er, map &m ) { // Stop updating scent after X turns of the player not moving. // Once wind is added, need to reset this on wind shifts as well. if( center == player_last_position && player_last_moved + 1000 < calendar::turn ) { return; } player_last_position = center; player_last_moved = calendar::turn; // note: the next four intermediate matrices need to be at least // [2*SCENT_RADIUS+3][2*SCENT_RADIUS+1] in size to hold enough data // The code I'm modifying used [SEEX * MAPSIZE]. I'm staying with that to avoid new bugs. // These two matrices are transposed so that x addresses are contiguous in memory scent_array<int> sum_3_scent_y; scent_array<int> squares_used_y; // these are for caching flag lookups scent_array<bool> blocks_scent; // currently only TFLAG_WALL blocks scent scent_array<bool> reduces_scent; // for loop constants const int scentmap_minx = center.x - SCENT_RADIUS; const int scentmap_maxx = center.x + SCENT_RADIUS; const int scentmap_miny = center.y - SCENT_RADIUS; const int scentmap_maxy = center.y + SCENT_RADIUS; // decrease this to reduce gas spread. Keep it under 125 for // stability. This is essentially a decimal number * 1000. const int diffusivity = 100; // The new scent flag searching function. Should be wayyy faster than the old one. m.scent_blockers( blocks_scent, reduces_scent, scentmap_minx - 1, scentmap_miny - 1, 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 // SEEX*MAPSIZE, 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; } } } } } // Rest of the scent map for( int x = scentmap_minx; x <= scentmap_maxx; ++x ) { for( int y = scentmap_miny; y <= scentmap_maxy; ++y ) { auto &scent_here = grscent[x][y]; if( !blocks_scent[x][y] ) { // to how many neighboring squares do we diffuse out? (include our own square // since we also include our own square when diffusing in) int squares_used = squares_used_y[y][x - 1] + squares_used_y[y][x] + squares_used_y[y][x + 1]; int this_diffusivity; if( !reduces_scent[x][y] ) { this_diffusivity = diffusivity; } else { this_diffusivity = diffusivity / 5; //less air movement for REDUCE_SCENT square } int temp_scent; // take the old scent and subtract what diffuses out temp_scent = scent_here * ( 10 * 1000 - squares_used * this_diffusivity ); // neighboring walls and reduce_scent squares absorb some scent temp_scent -= scent_here * this_diffusivity * ( 90 - squares_used ) / 5; // we've already summed neighboring scent values in the y direction in the previous // loop. Now we do it for the x direction, multiply by diffusion, and this is what // diffuses into our current square. scent_here = ( temp_scent + this_diffusivity * ( sum_3_scent_y[y][x - 1] + sum_3_scent_y[y][x] + sum_3_scent_y[y][x + 1] ) ) / ( 1000 * 10 ); } else { // this cell blocks scent scent_here = 0; } } } }