1 #pragma once 2 #ifndef CATA_SRC_SCENT_BLOCK_H 3 #define CATA_SRC_SCENT_BLOCK_H 4 5 #include <algorithm> 6 #include <array> 7 8 #include "coordinate_conversions.h" 9 #include "point.h" 10 #include "scent_map.h" 11 12 struct scent_block { 13 template<typename T> 14 using data_block = std::array < std::array < T, SEEY + 2 >, SEEX + 2 >; 15 16 enum class data_mode : int { 17 NONE = 0, 18 SET = 1, 19 MAX = 2 20 }; 21 22 struct datum { 23 data_mode mode; 24 int intensity; 25 }; 26 data_block<datum> assignment; 27 28 tripoint origin; 29 scent_map &scents; 30 int modification_count; 31 scent_blockscent_block32 scent_block( const tripoint &sub, scent_map &scents ) 33 // NOLINTNEXTLINE(cata-use-named-point-constants) 34 : origin( sm_to_ms_copy( sub ) + point( -1, -1 ) ) 35 , scents( scents ) 36 , modification_count( 0 ) { 37 for( int x = 0; x < SEEX + 2; ++x ) { 38 for( int y = 0; y < SEEY + 2; ++y ) { 39 assignment[x][y] = { data_mode::NONE, 0 }; 40 } 41 } 42 } 43 commit_modificationsscent_block44 void commit_modifications() { 45 if( modification_count == 0 ) { 46 return; 47 } 48 for( int x = 0; x < SEEX + 2; ++x ) { 49 for( int y = 0; y < SEEY + 2; ++y ) { 50 switch( assignment[x][y].mode ) { 51 case data_mode::NONE: 52 break; 53 case data_mode::SET: { 54 tripoint p = origin + tripoint( x, y, 0 ); 55 if( scents.inbounds( p ) ) { 56 scents.set_unsafe( p, assignment[x][y].intensity ); 57 } 58 break; 59 } 60 case data_mode::MAX: { 61 tripoint p = origin + tripoint( x, y, 0 ); 62 if( scents.inbounds( p ) ) { 63 scents.set_unsafe( p, std::max( assignment[x][y].intensity, scents.get_unsafe( p ) ) ); 64 } 65 break; 66 } 67 } 68 } 69 } 70 } 71 indexscent_block72 point index( const tripoint &p ) const { 73 return -origin.xy() + p.xy(); 74 } 75 76 // We should be working entirely within the range, so don't range check here 77 void apply_gas( const tripoint &p, const int nintensity = 0 ) { 78 const point ndx = index( p ); 79 assignment[ndx.x][ndx.y].mode = data_mode::SET; 80 assignment[ndx.x][ndx.y].intensity = std::max( 0, assignment[ndx.x][ndx.y].intensity - nintensity ); 81 ++modification_count; 82 } apply_slimescent_block83 void apply_slime( const tripoint &p, int intensity ) { 84 const point ndx = index( p ); 85 datum &dat = assignment[ndx.x][ndx.y]; 86 switch( dat.mode ) { 87 case data_mode::NONE: { 88 // we don't know what the current intensity is, so we must do a max operation 89 dat.mode = data_mode::MAX; 90 dat.intensity = intensity; 91 break; 92 } 93 case data_mode::SET: { 94 // new intensity is going to be dat.intensity, so we just need to make it larger 95 // but cannot change 96 dat.intensity = std::max( dat.intensity, intensity ); 97 break; 98 } 99 case data_mode::MAX: { 100 // Already max for some reason, shouldn't occur. If it does we want to grow if possible 101 dat.intensity = std::max( dat.intensity, intensity ); 102 break; 103 } 104 } 105 ++modification_count; 106 } 107 }; 108 109 #endif // CATA_SRC_SCENT_BLOCK_H 110