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