1 #include <memory>
2 #include <vector>
3 
4 #include "calendar.h"
5 #include "catch/catch.hpp"
6 #include "common_types.h"
7 #include "coordinates.h"
8 #include "enums.h"
9 #include "game_constants.h"
10 #include "omdata.h"
11 #include "overmap.h"
12 #include "overmap_types.h"
13 #include "overmapbuffer.h"
14 #include "type_id.h"
15 
16 TEST_CASE( "set_and_get_overmap_scents" )
17 {
18     std::unique_ptr<overmap> test_overmap = std::make_unique<overmap>( point_abs_om() );
19 
20     // By default there are no scents set.
21     for( int x = 0; x < 180; ++x ) {
22         for( int y = 0; y < 180; ++y ) {
23             for( int z = -10; z < 10; ++z ) {
24                 REQUIRE( test_overmap->scent_at( { x, y, z } ).creation_time ==
25                          calendar::before_time_starts );
26             }
27         }
28     }
29 
30     time_point creation_time = calendar::turn_zero + 50_turns;
31     scent_trace test_scent( creation_time, 90 );
32     test_overmap->set_scent( { 75, 85, 0 }, test_scent );
33     REQUIRE( test_overmap->scent_at( { 75, 85, 0} ).creation_time == creation_time );
34     REQUIRE( test_overmap->scent_at( { 75, 85, 0} ).initial_strength == 90 );
35 }
36 
37 TEST_CASE( "default_overmap_generation_always_succeeds", "[slow]" )
38 {
39     int overmaps_to_construct = 10;
40     for( const point_abs_om &candidate_addr : closest_points_first( point_abs_om(), 10 ) ) {
41         // Skip populated overmaps.
42         if( overmap_buffer.has( candidate_addr ) ) {
43             continue;
44         }
45         overmap_special_batch test_specials = overmap_specials::get_default_batch( candidate_addr );
46         overmap_buffer.create_custom_overmap( candidate_addr, test_specials );
47         for( const auto &special_placement : test_specials ) {
48             const overmap_special *special = special_placement.special_details;
49             INFO( "In attempt #" << overmaps_to_construct
50                   << " failed to place " << special->id.str() );
51             CHECK( special->occurrences.min <= special_placement.instances_placed );
52         }
53         if( --overmaps_to_construct <= 0 ) {
54             break;
55         }
56     }
57 }
58 
59 TEST_CASE( "default_overmap_generation_has_non_mandatory_specials_at_origin", "[slow]" )
60 {
61     const point_abs_om origin{};
62 
63     overmap_special mandatory;
64     overmap_special optional;
65 
66     // Get some specific overmap specials so we can assert their presence later.
67     // This should probably be replaced with some custom specials created in
68     // memory rather than tying this test to these, but it works for now...
69     for( const auto &elem : overmap_specials::get_all() ) {
70         if( elem.id == overmap_special_id( "Cabin" ) ) {
71             optional = elem;
72         } else if( elem.id == overmap_special_id( "Lab" ) ) {
73             mandatory = elem;
74         }
75     }
76 
77     // Make this mandatory special impossible to place.
78     mandatory.city_size.min = 999;
79 
80     // Construct our own overmap_special_batch containing only our single mandatory
81     // and single optional special, so we can make some assertions.
82     std::vector<const overmap_special *> specials;
83     specials.push_back( &mandatory );
84     specials.push_back( &optional );
85     overmap_special_batch test_specials = overmap_special_batch( origin, specials );
86 
87     // Run the overmap creation, which will try to place our specials.
88     overmap_buffer.create_custom_overmap( origin, test_specials );
89 
90     // Get the origin overmap...
91     overmap *test_overmap = overmap_buffer.get_existing( origin );
92 
93     // ...and assert that the optional special exists on this map.
94     bool found_optional = false;
95     for( int x = 0; x < OMAPX; ++x ) {
96         for( int y = 0; y < OMAPY; ++y ) {
97             const oter_id t = test_overmap->ter( { x, y, 0 } );
98             if( t->id == "cabin" ||
99                 t->id == "cabin_north" || t->id == "cabin_east" ||
100                 t->id == "cabin_south" || t->id == "cabin_west" ) {
101                 found_optional = true;
102             }
103         }
104     }
105 
106     INFO( "Failed to place optional special on origin " );
107     CHECK( found_optional == true );
108 }
109 
110 TEST_CASE( "is_ot_match", "[overmap][terrain]" )
111 {
112     SECTION( "exact match" ) {
113         // Matches the complete string
114         CHECK( is_ot_match( "forest", oter_id( "forest" ), ot_match_type::exact ) );
115         CHECK( is_ot_match( "central_lab", oter_id( "central_lab" ), ot_match_type::exact ) );
116 
117         // Does not exactly match if rotation differs
118         CHECK_FALSE( is_ot_match( "sub_station", oter_id( "sub_station_north" ), ot_match_type::exact ) );
119         CHECK_FALSE( is_ot_match( "sub_station", oter_id( "sub_station_south" ), ot_match_type::exact ) );
120     }
121 
122     SECTION( "type match" ) {
123         // Matches regardless of rotation
124         CHECK( is_ot_match( "sub_station", oter_id( "sub_station_north" ), ot_match_type::type ) );
125         CHECK( is_ot_match( "sub_station", oter_id( "sub_station_south" ), ot_match_type::type ) );
126         CHECK( is_ot_match( "sub_station", oter_id( "sub_station_east" ), ot_match_type::type ) );
127         CHECK( is_ot_match( "sub_station", oter_id( "sub_station_west" ), ot_match_type::type ) );
128 
129         // Does not match if base type does not match
130         CHECK_FALSE( is_ot_match( "lab", oter_id( "central_lab" ), ot_match_type::type ) );
131         CHECK_FALSE( is_ot_match( "sub_station", oter_id( "sewer_sub_station" ), ot_match_type::type ) );
132     }
133 
134     SECTION( "prefix match" ) {
135         // Matches the complete string
136         CHECK( is_ot_match( "forest", oter_id( "forest" ), ot_match_type::prefix ) );
137         CHECK( is_ot_match( "central_lab", oter_id( "central_lab" ), ot_match_type::prefix ) );
138 
139         // Prefix matches when an underscore separator exists
140         CHECK( is_ot_match( "central", oter_id( "central_lab" ), ot_match_type::prefix ) );
141         CHECK( is_ot_match( "central", oter_id( "central_lab_stairs" ), ot_match_type::prefix ) );
142 
143         // Prefix itself may contain underscores
144         CHECK( is_ot_match( "central_lab", oter_id( "central_lab_stairs" ), ot_match_type::prefix ) );
145         CHECK( is_ot_match( "central_lab_train", oter_id( "central_lab_train_depot" ),
146                             ot_match_type::prefix ) );
147 
148         // Prefix does not match without an underscore separator
149         CHECK_FALSE( is_ot_match( "fore", oter_id( "forest" ), ot_match_type::prefix ) );
150         CHECK_FALSE( is_ot_match( "fore", oter_id( "forest_thick" ), ot_match_type::prefix ) );
151 
152         // Prefix does not match the middle or end
153         CHECK_FALSE( is_ot_match( "lab", oter_id( "central_lab" ), ot_match_type::prefix ) );
154         CHECK_FALSE( is_ot_match( "lab", oter_id( "central_lab_stairs" ), ot_match_type::prefix ) );
155     }
156 
157     SECTION( "contains match" ) {
158         // Matches the complete string
159         CHECK( is_ot_match( "forest", oter_id( "forest" ), ot_match_type::contains ) );
160         CHECK( is_ot_match( "central_lab", oter_id( "central_lab" ), ot_match_type::contains ) );
161 
162         // Matches the beginning/middle/end of an underscore-delimited id
163         CHECK( is_ot_match( "central", oter_id( "central_lab_stairs" ), ot_match_type::contains ) );
164         CHECK( is_ot_match( "lab", oter_id( "central_lab_stairs" ), ot_match_type::contains ) );
165         CHECK( is_ot_match( "stairs", oter_id( "central_lab_stairs" ), ot_match_type::contains ) );
166 
167         // Matches the beginning/middle/end without undercores as well
168         CHECK( is_ot_match( "cent", oter_id( "central_lab_stairs" ), ot_match_type::contains ) );
169         CHECK( is_ot_match( "ral_lab", oter_id( "central_lab_stairs" ), ot_match_type::contains ) );
170         CHECK( is_ot_match( "_lab_", oter_id( "central_lab_stairs" ), ot_match_type::contains ) );
171         CHECK( is_ot_match( "airs", oter_id( "central_lab_stairs" ), ot_match_type::contains ) );
172 
173         // Does not match if substring is not contained
174         CHECK_FALSE( is_ot_match( "forest", oter_id( "central_lab" ), ot_match_type::contains ) );
175         CHECK_FALSE( is_ot_match( "forestry", oter_id( "forest" ), ot_match_type::contains ) );
176     }
177 }
178 
179