1 #include "building_tiles.h"
2
3 #include "building/building.h"
4 #include "building/industry.h"
5 #include "city/view.h"
6 #include "core/direction.h"
7 #include "core/image.h"
8 #include "map/aqueduct.h"
9 #include "map/bridge.h"
10 #include "map/building.h"
11 #include "map/figure.h"
12 #include "map/grid.h"
13 #include "map/image.h"
14 #include "map/property.h"
15 #include "map/random.h"
16 #include "map/sprite.h"
17 #include "map/terrain.h"
18 #include "map/tiles.h"
19
map_building_tiles_add(int building_id,int x,int y,int size,int image_id,int terrain)20 void map_building_tiles_add(int building_id, int x, int y, int size, int image_id, int terrain)
21 {
22 if (!map_grid_is_inside(x, y, size)) {
23 return;
24 }
25 int x_leftmost, y_leftmost;
26 switch (city_view_orientation()) {
27 case DIR_0_TOP:
28 x_leftmost = 0;
29 y_leftmost = size - 1;
30 break;
31 case DIR_2_RIGHT:
32 x_leftmost = y_leftmost = 0;
33 break;
34 case DIR_4_BOTTOM:
35 x_leftmost = size - 1;
36 y_leftmost = 0;
37 break;
38 case DIR_6_LEFT:
39 x_leftmost = y_leftmost = size - 1;
40 break;
41 default:
42 return;
43 }
44 for (int dy = 0; dy < size; dy++) {
45 for (int dx = 0; dx < size; dx++) {
46 int grid_offset = map_grid_offset(x + dx, y + dy);
47 map_terrain_remove(grid_offset, TERRAIN_CLEARABLE);
48 map_terrain_add(grid_offset, terrain);
49 map_building_set(grid_offset, building_id);
50 map_property_clear_constructing(grid_offset);
51 map_property_set_multi_tile_size(grid_offset, size);
52 map_image_set(grid_offset, image_id);
53 map_property_set_multi_tile_xy(grid_offset, dx, dy,
54 dx == x_leftmost && dy == y_leftmost);
55 }
56 }
57 }
58
set_crop_tile(int building_id,int x,int y,int dx,int dy,int crop_image_id,int growth)59 static void set_crop_tile(int building_id, int x, int y, int dx, int dy, int crop_image_id, int growth)
60 {
61 int grid_offset = map_grid_offset(x + dx, y + dy);
62 map_terrain_remove(grid_offset, TERRAIN_CLEARABLE);
63 map_terrain_add(grid_offset, TERRAIN_BUILDING);
64 map_building_set(grid_offset, building_id);
65 map_property_clear_constructing(grid_offset);
66 map_property_set_multi_tile_xy(grid_offset, dx, dy, 1);
67 map_image_set(grid_offset, crop_image_id + (growth < 4 ? growth : 4));
68 }
69
map_building_tiles_add_farm(int building_id,int x,int y,int crop_image_id,int progress)70 void map_building_tiles_add_farm(int building_id, int x, int y, int crop_image_id, int progress)
71 {
72 if (!map_grid_is_inside(x, y, 3)) {
73 return;
74 }
75 // farmhouse
76 int x_leftmost, y_leftmost;
77 switch (city_view_orientation()) {
78 case DIR_0_TOP:
79 x_leftmost = 0;
80 y_leftmost = 1;
81 break;
82 case DIR_2_RIGHT:
83 x_leftmost = 0;
84 y_leftmost = 0;
85 break;
86 case DIR_4_BOTTOM:
87 x_leftmost = 1;
88 y_leftmost = 0;
89 break;
90 case DIR_6_LEFT:
91 x_leftmost = 1;
92 y_leftmost = 1;
93 break;
94 default:
95 return;
96 }
97 for (int dy = 0; dy < 2; dy++) {
98 for (int dx = 0; dx < 2; dx++) {
99 int grid_offset = map_grid_offset(x + dx, y + dy);
100 map_terrain_remove(grid_offset, TERRAIN_CLEARABLE);
101 map_terrain_add(grid_offset, TERRAIN_BUILDING);
102 map_building_set(grid_offset, building_id);
103 map_property_clear_constructing(grid_offset);
104 map_property_set_multi_tile_size(grid_offset, 2);
105 map_image_set(grid_offset, image_group(GROUP_BUILDING_FARM_HOUSE));
106 map_property_set_multi_tile_xy(grid_offset, dx, dy,
107 dx == x_leftmost && dy == y_leftmost);
108 }
109 }
110 // crop tile 1
111 int growth = progress / 10;
112 set_crop_tile(building_id, x, y, 0, 2, crop_image_id, growth);
113
114 // crop tile 2
115 growth -= 4;
116 if (growth < 0) {
117 growth = 0;
118 }
119 set_crop_tile(building_id, x, y, 1, 2, crop_image_id, growth);
120
121 // crop tile 3
122 growth -= 4;
123 if (growth < 0) {
124 growth = 0;
125 }
126 set_crop_tile(building_id, x, y, 2, 2, crop_image_id, growth);
127
128 // crop tile 4
129 growth -= 4;
130 if (growth < 0) {
131 growth = 0;
132 }
133 set_crop_tile(building_id, x, y, 2, 1, crop_image_id, growth);
134
135 // crop tile 5
136 growth -= 4;
137 if (growth < 0) {
138 growth = 0;
139 }
140 set_crop_tile(building_id, x, y, 2, 0, crop_image_id, growth);
141 }
142
map_building_tiles_add_aqueduct(int x,int y)143 int map_building_tiles_add_aqueduct(int x, int y)
144 {
145 int grid_offset = map_grid_offset(x,y);
146 map_terrain_add(grid_offset, TERRAIN_AQUEDUCT);
147 map_property_clear_constructing(grid_offset);
148 return 1;
149 }
150
north_tile_grid_offset(int x,int y,int * size)151 static int north_tile_grid_offset(int x, int y, int *size)
152 {
153 int grid_offset = map_grid_offset(x, y);
154 *size = map_property_multi_tile_size(grid_offset);
155 for (int i = 0; i < *size && map_property_multi_tile_x(grid_offset); i++) {
156 grid_offset += map_grid_delta(-1, 0);
157 }
158 for (int i = 0; i < *size && map_property_multi_tile_y(grid_offset); i++) {
159 grid_offset += map_grid_delta(0, -1);
160 }
161 return grid_offset;
162 }
163
map_building_tiles_remove(int building_id,int x,int y)164 void map_building_tiles_remove(int building_id, int x, int y)
165 {
166 if (!map_grid_is_inside(x, y, 1)) {
167 return;
168 }
169 int size;
170 int base_grid_offset = north_tile_grid_offset(x, y, &size);
171 x = map_grid_offset_to_x(base_grid_offset);
172 y = map_grid_offset_to_y(base_grid_offset);
173 if (map_terrain_get(base_grid_offset) == TERRAIN_ROCK) {
174 return;
175 }
176 building *b = building_get(building_id);
177 if (building_id && building_is_farm(b->type)) {
178 size = 3;
179 }
180 for (int dy = 0; dy < size; dy++) {
181 for (int dx = 0; dx < size; dx++) {
182 int grid_offset = map_grid_offset(x + dx, y + dy);
183 if (building_id && map_building_at(grid_offset) != building_id) {
184 continue;
185 }
186 if (building_id && b->type != BUILDING_BURNING_RUIN) {
187 map_set_rubble_building_type(grid_offset, b->type);
188 }
189 map_property_clear_constructing(grid_offset);
190 map_property_set_multi_tile_size(grid_offset, 1);
191 map_property_clear_multi_tile_xy(grid_offset);
192 map_property_mark_draw_tile(grid_offset);
193 map_aqueduct_set(grid_offset, 0);
194 map_building_set(grid_offset, 0);
195 map_building_damage_clear(grid_offset);
196 map_sprite_clear_tile(grid_offset);
197 if (map_terrain_is(grid_offset, TERRAIN_WATER)) {
198 map_terrain_set(grid_offset, TERRAIN_WATER); // clear other flags
199 map_tiles_set_water(x + dx, y + dy);
200 } else {
201 map_image_set(grid_offset,
202 image_group(GROUP_TERRAIN_UGLY_GRASS) +
203 (map_random_get(grid_offset) & 7));
204 map_terrain_remove(grid_offset, TERRAIN_CLEARABLE);
205 }
206 }
207 }
208 map_tiles_update_region_empty_land(x, y, x + size, y + size);
209 map_tiles_update_region_meadow(x, y, x + size, y + size);
210 map_tiles_update_region_rubble(x, y, x + size, y + size);
211 }
212
map_building_tiles_set_rubble(int building_id,int x,int y,int size)213 void map_building_tiles_set_rubble(int building_id, int x, int y, int size)
214 {
215 if (!map_grid_is_inside(x, y, size)) {
216 return;
217 }
218 building *b = building_get(building_id);
219 for (int dy = 0; dy < size; dy++) {
220 for (int dx = 0; dx < size; dx++) {
221 int grid_offset = map_grid_offset(x + dx, y + dy);
222 if (map_building_at(grid_offset) != building_id) {
223 continue;
224 }
225 if (building_id && building_get(map_building_at(grid_offset))->type != BUILDING_BURNING_RUIN) {
226 map_set_rubble_building_type(grid_offset, b->type);
227 } else if (!building_id && map_terrain_get(grid_offset) & TERRAIN_WALL) {
228 map_set_rubble_building_type(grid_offset, BUILDING_WALL);
229 }
230 map_property_clear_constructing(grid_offset);
231 map_property_set_multi_tile_size(grid_offset, 1);
232 map_aqueduct_set(grid_offset, 0);
233 map_building_set(grid_offset, 0);
234 map_building_damage_clear(grid_offset);
235 map_sprite_clear_tile(grid_offset);
236 map_property_set_multi_tile_xy(grid_offset, 0, 0, 1);
237 if (map_terrain_is(grid_offset, TERRAIN_WATER)) {
238 map_terrain_set(grid_offset, TERRAIN_WATER); // clear other flags
239 map_tiles_set_water(x + dx, y + dy);
240 } else {
241 map_terrain_remove(grid_offset, TERRAIN_CLEARABLE);
242 map_terrain_add(grid_offset, TERRAIN_RUBBLE);
243 map_image_set(grid_offset, image_group(GROUP_TERRAIN_RUBBLE) + (map_random_get(grid_offset) & 7));
244 }
245 }
246 }
247 }
248
adjust_to_absolute_xy(int * x,int * y,int size)249 static void adjust_to_absolute_xy(int *x, int *y, int size)
250 {
251 switch (city_view_orientation()) {
252 case DIR_2_RIGHT:
253 *x = *x - size + 1;
254 break;
255 case DIR_4_BOTTOM:
256 *x = *x - size + 1;
257 // fall-through
258 case DIR_6_LEFT:
259 *y = *y - size + 1;
260 break;
261 }
262 }
263
map_building_tiles_mark_construction(int x,int y,int size,int terrain,int absolute_xy)264 int map_building_tiles_mark_construction(int x, int y, int size, int terrain, int absolute_xy)
265 {
266 if (!absolute_xy) {
267 adjust_to_absolute_xy(&x, &y, size);
268 }
269 if (!map_grid_is_inside(x, y, size)) {
270 return 0;
271 }
272 for (int dy = 0; dy < size; dy++) {
273 for (int dx = 0; dx < size; dx++) {
274 int grid_offset = map_grid_offset(x + dx, y + dy);
275 if (map_terrain_is(grid_offset, terrain & TERRAIN_NOT_CLEAR) || map_has_figure_at(grid_offset)) {
276 return 0;
277 }
278 }
279 }
280 // mark as being constructed
281 for (int dy = 0; dy < size; dy++) {
282 for (int dx = 0; dx < size; dx++) {
283 int grid_offset = map_grid_offset(x + dx, y + dy);
284 map_property_mark_constructing(grid_offset);
285 }
286 }
287 return 1;
288 }
289
map_building_tiles_mark_deleting(int grid_offset)290 void map_building_tiles_mark_deleting(int grid_offset)
291 {
292 int building_id = map_building_at(grid_offset);
293 if (!building_id) {
294 map_bridge_remove(grid_offset, 1);
295 } else {
296 grid_offset = building_main(building_get(building_id))->grid_offset;
297 }
298 map_property_mark_deleted(grid_offset);
299 }
300
map_building_tiles_are_clear(int x,int y,int size,int terrain)301 int map_building_tiles_are_clear(int x, int y, int size, int terrain)
302 {
303 adjust_to_absolute_xy(&x, &y, size);
304 if (!map_grid_is_inside(x, y, size)) {
305 return 0;
306 }
307 for (int dy = 0; dy < size; dy++) {
308 for (int dx = 0; dx < size; dx++) {
309 int grid_offset = map_grid_offset(x + dx, y + dy);
310 if (map_terrain_is(grid_offset, terrain & TERRAIN_NOT_CLEAR)) {
311 return 0;
312 }
313 }
314 }
315 return 1;
316 }
317