-
Notifications
You must be signed in to change notification settings - Fork 280
/
ground_destroy_test.cpp
241 lines (217 loc) · 8 KB
/
ground_destroy_test.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#include "catch/catch.hpp"
#include <set>
#include <vector>
#include "avatar.h"
#include "int_id.h"
#include "item.h"
#include "itype.h"
#include "map.h"
#include "map_helpers.h"
#include "map_iterator.h"
#include "mapdata.h"
#include "options.h"
#include "point.h"
#include "state_helpers.h"
#include "type_id.h"
// Destroying pavement with a pickaxe should not leave t_flat_roof.
// See issue #24707:
// https://github.com/CleverRaven/Cataclysm-DDA/issues/24707
TEST_CASE( "pavement_destroy", "[.]" )
{
clear_all_state();
const ter_id flat_roof_id = ter_id( "t_flat_roof" );
REQUIRE( flat_roof_id != t_null );
put_player_underground();
map &here = get_map();
// Populate the map with pavement.
here.ter_set( tripoint_zero, ter_id( "t_pavement" ) );
// Destroy it
here.destroy( tripoint_zero, true );
ter_id after_destroy = here.ter( tripoint_zero );
if( after_destroy == flat_roof_id ) {
FAIL( flat_roof_id.obj().name() << " found after destroying pavement" );
} else {
INFO( "After destroy, ground is " << after_destroy.obj().name() );
}
}
// Ground-destroying explosions on dirt or grass shouldn't leave t_flat_roof.
// See issue #23250:
// https://github.com/CleverRaven/Cataclysm-DDA/issues/23250
TEST_CASE( "explosion_on_ground", "[.]" )
{
clear_all_state();
ter_id flat_roof_id = ter_id( "t_flat_roof" );
REQUIRE( flat_roof_id != t_null );
put_player_underground();
std::vector<ter_id> test_terrain_id = {
ter_id( "t_dirt" ), ter_id( "t_grass" )
};
map &here = get_map();
int idx = 0;
const int area_dim = 16;
// Populate map with various test terrain.
for( int x = 0; x < area_dim; x++ ) {
for( int y = 0; y < area_dim; y++ ) {
here.ter_set( tripoint( x, y, 0 ), test_terrain_id[idx] );
idx = ( idx + 1 ) % test_terrain_id.size();
}
}
// Detonate an RDX keg item in the middle of the populated map space
itype_id rdx_keg_typeid( "tool_rdx_charge_act" );
REQUIRE( rdx_keg_typeid.is_valid() );
const tripoint area_center( area_dim / 2, area_dim / 2, 0 );
item &rdx_keg = *item::spawn_temporary( rdx_keg_typeid );
rdx_keg.charges = 0;
rdx_keg.type->invoke( get_avatar(), rdx_keg, area_center );
// Check area to see if any t_flat_roof is present.
for( int x = 0; x < area_dim; x++ ) {
for( int y = 0; y < area_dim; y++ ) {
tripoint pt( x, y, 0 );
ter_id t_id = here.ter( pt );
if( t_id == flat_roof_id ) {
FAIL( "After explosion, " << t_id.obj().name() << " found at " << x << "," << y );
}
}
}
}
// Ground-destroying explosions on t_floor with a t_rock_floor basement
// below should create some t_open_air, not just t_flat_roof (which is
// the defined roof of a t_rock-floor).
TEST_CASE( "explosion_on_floor_with_rock_floor_basement", "[.]" )
{
clear_all_state();
ter_id flat_roof_id = ter_id( "t_flat_roof" );
ter_id floor_id = ter_id( "t_floor" );
ter_id rock_floor_id = ter_id( "t_rock_floor" );
ter_id open_air_id = ter_id( "t_open_air" );
REQUIRE( flat_roof_id != t_null );
REQUIRE( floor_id != t_null );
REQUIRE( rock_floor_id != t_null );
REQUIRE( open_air_id != t_null );
put_player_underground();
map &here = get_map();
const int area_dim = 24;
for( int x = 0; x < area_dim; x++ ) {
for( int y = 0; y < area_dim; y++ ) {
here.ter_set( tripoint( x, y, 0 ), floor_id );
here.ter_set( tripoint( x, y, -1 ), rock_floor_id );
}
}
// Detonate an RDX keg item in the middle of the populated map space
itype_id rdx_keg_typeid( "tool_rdx_charge_act" );
REQUIRE( rdx_keg_typeid.is_valid() );
const tripoint area_center( area_dim / 2, area_dim / 2, 0 );
item &rdx_keg = *item::spawn_temporary( rdx_keg_typeid );
rdx_keg.charges = 0;
rdx_keg.type->invoke( get_avatar(), rdx_keg, area_center );
// Check z0 for open air
bool found_open_air = false;
for( int x = 0; x < area_dim; x++ ) {
for( int y = 0; y < area_dim; y++ ) {
tripoint pt( x, y, 0 );
ter_id t_id = here.ter( pt );
INFO( "t " << t_id.obj().name() << " at " << x << "," << y );
if( t_id == open_air_id ) {
found_open_air = true;
break;
}
}
if( found_open_air ) {
break;
}
}
if( !found_open_air ) {
FAIL( "After explosion, no open air was found" );
}
}
// Destroying interior floors shouldn't cause the roofs above to collapse.
// Destroying supporting walls should cause the roofs above to collapse.
TEST_CASE( "collapse_checks", "[.]" )
{
clear_all_state();
constexpr int wall_size = 5;
const ter_id floor_id = ter_id( "t_floor" );
const ter_id dirt_id = ter_id( "t_dirt" );
const ter_id wall_id = ter_id( "t_wall" );
const ter_id open_air_id = ter_id( "t_open_air" );
REQUIRE( floor_id != t_null );
REQUIRE( dirt_id != t_null );
REQUIRE( wall_id != t_null );
REQUIRE( open_air_id != t_null );
put_player_underground();
map &here = get_map();
// build a structure
const tripoint &midair = tripoint( tripoint_zero.xy(), tripoint_zero.z + 1 );
for( const tripoint &pt : here.points_in_radius( midair, wall_size, 1 ) ) {
here.ter_set( pt, floor_id );
}
std::set<tripoint> corners;
for( int delta_z = 0; delta_z < 3; delta_z++ ) {
for( int delta_x = 0; delta_x <= 1; delta_x++ ) {
for( int delta_y = 0; delta_y <= 1; delta_y++ ) {
const tripoint pt( delta_x * wall_size, delta_y * wall_size, delta_z );
corners.insert( pt );
here.ter_set( pt, wall_id );
}
}
}
// make sure it's a valid structure
for( const tripoint &pt : here.points_in_radius( midair, wall_size, 1 ) ) {
if( corners.find( pt ) != corners.end() ) {
REQUIRE( here.ter( pt ) == wall_id );
} else {
REQUIRE( here.ter( pt ) == floor_id );
}
}
// destroy the floor on the first floor; floor above should not collapse
for( const tripoint &pt : here.points_in_radius( tripoint_zero, wall_size ) ) {
if( corners.find( pt ) == corners.end() ) {
here.destroy( pt, true );
}
}
for( const tripoint &pt : here.points_in_radius( midair, wall_size ) ) {
if( corners.find( pt ) != corners.end() ) {
CHECK( here.ter( pt ) == wall_id );
} else {
CHECK( here.ter( pt ) == floor_id );
}
}
// destroy the walls on the first floor; upper floors should mostly collapse
for( int delta_x = 0; delta_x <= 1; delta_x++ ) {
for( int delta_y = 0; delta_y <= 1; delta_y++ ) {
const tripoint pt( delta_x * wall_size, delta_y * wall_size, 0 );
here.destroy( pt, true );
}
}
int open_air_count = 0;
int tile_count = 0;
int no_wall_count = 0;
for( const tripoint &pt : here.points_in_radius( midair, wall_size, 1 ) ) {
if( pt.z == 0 ) {
continue;
}
const ter_id t_id = here.ter( pt );
tile_count += 1;
if( t_id == t_open_air ) {
open_air_count += 1;
if( corners.find( pt ) != corners.end() ) {
no_wall_count += 1;
}
}
}
int partial_tiles = tile_count / 5;
CHECK( open_air_count > partial_tiles );
if( open_air_count < partial_tiles ) {
FAIL( open_air_count << " open air tiles were found on the upper floors after the walls "
"collapsed." );
} else {
INFO( open_air_count << " open air tiles were found on the upper floors after the walls "
"collapsed." );
}
CHECK( no_wall_count == 8 );
if( no_wall_count != 8 ) {
FAIL( "Only " << no_wall_count << " walls on the upper floors collapsed." );
} else {
INFO( "All " << no_wall_count << " walls on the upper floors collapsed." );
}
}