1 #include "tiles.h"
2
3 #include "city/map.h"
4 #include "city/view.h"
5 #include "core/direction.h"
6 #include "core/image.h"
7 #include "map/aqueduct.h"
8 #include "map/building.h"
9 #include "map/building_tiles.h"
10 #include "map/data.h"
11 #include "map/desirability.h"
12 #include "map/elevation.h"
13 #include "map/figure.h"
14 #include "map/grid.h"
15 #include "map/image.h"
16 #include "map/image_context.h"
17 #include "map/property.h"
18 #include "map/random.h"
19 #include "map/terrain.h"
20 #include "scenario/map.h"
21
22 #define OFFSET(x,y) (x + GRID_SIZE * y)
23
24 #define FORBIDDEN_TERRAIN_MEADOW (TERRAIN_AQUEDUCT | TERRAIN_ELEVATION | TERRAIN_ACCESS_RAMP |\
25 TERRAIN_RUBBLE | TERRAIN_ROAD | TERRAIN_BUILDING | TERRAIN_GARDEN)
26
27 #define FORBIDDEN_TERRAIN_RUBBLE (TERRAIN_AQUEDUCT | TERRAIN_ELEVATION | TERRAIN_ACCESS_RAMP |\
28 TERRAIN_ROAD | TERRAIN_BUILDING | TERRAIN_GARDEN)
29
30 static int aqueduct_include_construction = 0;
31
is_clear(int x,int y,int size,int disallowed_terrain,int check_image)32 static int is_clear(int x, int y, int size, int disallowed_terrain, int check_image)
33 {
34 if (!map_grid_is_inside(x, y, size)) {
35 return 0;
36 }
37 for (int dy = 0; dy < size; dy++) {
38 for (int dx = 0; dx < size; dx++) {
39 int grid_offset = map_grid_offset(x + dx, y + dy);
40 if (map_terrain_is(grid_offset, TERRAIN_NOT_CLEAR & disallowed_terrain)) {
41 return 0;
42 } else if (map_has_figure_at(grid_offset)) {
43 return 0;
44 } else if (check_image && map_image_at(grid_offset)) {
45 return 0;
46 }
47 }
48 }
49 return 1;
50 }
51
map_tiles_are_clear(int x,int y,int size,int disallowed_terrain)52 int map_tiles_are_clear(int x, int y, int size, int disallowed_terrain)
53 {
54 return is_clear(x, y, size, disallowed_terrain, 0);
55 }
56
foreach_map_tile(void (* callback)(int x,int y,int grid_offset))57 static void foreach_map_tile(void (*callback)(int x, int y, int grid_offset))
58 {
59 int grid_offset = map_data.start_offset;
60 for (int y = 0; y < map_data.height; y++, grid_offset += map_data.border_size) {
61 for (int x = 0; x < map_data.width; x++, grid_offset++) {
62 callback(x, y, grid_offset);
63 }
64 }
65 }
66
foreach_region_tile(int x_min,int y_min,int x_max,int y_max,void (* callback)(int x,int y,int grid_offset))67 static void foreach_region_tile(int x_min, int y_min, int x_max, int y_max,
68 void (*callback)(int x, int y, int grid_offset))
69 {
70 map_grid_bound_area(&x_min, &y_min, &x_max, &y_max);
71 int grid_offset = map_grid_offset(x_min, y_min);
72 for (int yy = y_min; yy <= y_max; yy++) {
73 for (int xx = x_min; xx <= x_max; xx++) {
74 callback(xx, yy, grid_offset);
75 ++grid_offset;
76 }
77 grid_offset += GRID_SIZE - (x_max - x_min + 1);
78 }
79 }
80
is_all_terrain_in_area(int x,int y,int size,int terrain)81 static int is_all_terrain_in_area(int x, int y, int size, int terrain)
82 {
83 if (!map_grid_is_inside(x, y, size)) {
84 return 0;
85 }
86 for (int dy = 0; dy < size; dy++) {
87 for (int dx = 0; dx < size; dx++) {
88 int grid_offset = map_grid_offset(x + dx, y + dy);
89 if ((map_terrain_get(grid_offset) & TERRAIN_NOT_CLEAR) != terrain) {
90 return 0;
91 }
92 if (map_image_at(grid_offset) != 0) {
93 return 0;
94 }
95 }
96 }
97 return 1;
98 }
99
is_updatable_rock(int grid_offset)100 static int is_updatable_rock(int grid_offset)
101 {
102 return map_terrain_is(grid_offset, TERRAIN_ROCK) &&
103 !map_property_is_plaza_or_earthquake(grid_offset) &&
104 !map_terrain_is(grid_offset, TERRAIN_ELEVATION | TERRAIN_ACCESS_RAMP);
105 }
106
clear_rock_image(int x,int y,int grid_offset)107 static void clear_rock_image(int x, int y, int grid_offset)
108 {
109 if (is_updatable_rock(grid_offset)) {
110 map_image_set(grid_offset, 0);
111 map_property_set_multi_tile_size(grid_offset, 1);
112 map_property_mark_draw_tile(grid_offset);
113 }
114 }
115
set_rock_image(int x,int y,int grid_offset)116 static void set_rock_image(int x, int y, int grid_offset)
117 {
118 if (is_updatable_rock(grid_offset)) {
119 if (!map_image_at(grid_offset)) {
120 if (is_all_terrain_in_area(x, y, 3, TERRAIN_ROCK)) {
121 int image_id = 12 + (map_random_get(grid_offset) & 1);
122 if (map_terrain_exists_tile_in_radius_with_type(x, y, 3, 4, TERRAIN_ELEVATION)) {
123 image_id += image_group(GROUP_TERRAIN_ELEVATION_ROCK);
124 } else {
125 image_id += image_group(GROUP_TERRAIN_ROCK);
126 }
127 map_building_tiles_add(0, x, y, 3, image_id, TERRAIN_ROCK);
128 } else if (is_all_terrain_in_area(x, y, 2, TERRAIN_ROCK)) {
129 int image_id = 8 + (map_random_get(grid_offset) & 3);
130 if (map_terrain_exists_tile_in_radius_with_type(x, y, 2, 4, TERRAIN_ELEVATION)) {
131 image_id += image_group(GROUP_TERRAIN_ELEVATION_ROCK);
132 } else {
133 image_id += image_group(GROUP_TERRAIN_ROCK);
134 }
135 map_building_tiles_add(0, x, y, 2, image_id, TERRAIN_ROCK);
136 } else {
137 int image_id = map_random_get(grid_offset) & 7;
138 if (map_terrain_exists_tile_in_radius_with_type(x, y, 1, 4, TERRAIN_ELEVATION)) {
139 image_id += image_group(GROUP_TERRAIN_ELEVATION_ROCK);
140 } else {
141 image_id += image_group(GROUP_TERRAIN_ROCK);
142 }
143 map_image_set(grid_offset, image_id);
144 }
145 }
146 }
147 }
148
map_tiles_update_all_rocks(void)149 void map_tiles_update_all_rocks(void)
150 {
151 foreach_map_tile(clear_rock_image);
152 foreach_map_tile(set_rock_image);
153 }
154
update_tree_image(int x,int y,int grid_offset)155 static void update_tree_image(int x, int y, int grid_offset)
156 {
157 if (map_terrain_is(grid_offset, TERRAIN_TREE) &&
158 !map_terrain_is(grid_offset, TERRAIN_ELEVATION | TERRAIN_ACCESS_RAMP)) {
159 int image_id = image_group(GROUP_TERRAIN_TREE) + (map_random_get(grid_offset) & 7);
160 if (map_terrain_has_only_rocks_trees_in_ring(x, y, 3)) {
161 map_image_set(grid_offset, image_id + 24);
162 } else if (map_terrain_has_only_rocks_trees_in_ring(x, y, 2)) {
163 map_image_set(grid_offset, image_id + 16);
164 } else if (map_terrain_has_only_rocks_trees_in_ring(x, y, 1)) {
165 map_image_set(grid_offset, image_id + 8);
166 } else {
167 map_image_set(grid_offset, image_id);
168 }
169 map_property_set_multi_tile_size(grid_offset, 1);
170 map_property_mark_draw_tile(grid_offset);
171 map_aqueduct_set(grid_offset, 0);
172 }
173 }
174
set_tree_image(int x,int y,int grid_offset)175 static void set_tree_image(int x, int y, int grid_offset)
176 {
177 if (map_terrain_is(grid_offset, TERRAIN_TREE) &&
178 !map_terrain_is(grid_offset, TERRAIN_ELEVATION | TERRAIN_ACCESS_RAMP)) {
179 foreach_region_tile(x - 1, y - 1, x + 1, y + 1, update_tree_image);
180 }
181 }
182
map_tiles_update_region_trees(int x_min,int y_min,int x_max,int y_max)183 void map_tiles_update_region_trees(int x_min, int y_min, int x_max, int y_max)
184 {
185 foreach_region_tile(x_min, y_min, x_max, y_max, set_tree_image);
186 }
187
set_shrub_image(int x,int y,int grid_offset)188 static void set_shrub_image(int x, int y, int grid_offset)
189 {
190 if (map_terrain_is(grid_offset, TERRAIN_SHRUB) &&
191 !map_terrain_is(grid_offset, TERRAIN_ELEVATION | TERRAIN_ACCESS_RAMP)) {
192 map_image_set(grid_offset, image_group(GROUP_TERRAIN_SHRUB) + (map_random_get(grid_offset) & 7));
193 map_property_set_multi_tile_size(grid_offset, 1);
194 map_property_mark_draw_tile(grid_offset);
195 }
196 }
197
map_tiles_update_region_shrub(int x_min,int y_min,int x_max,int y_max)198 void map_tiles_update_region_shrub(int x_min, int y_min, int x_max, int y_max)
199 {
200 foreach_region_tile(x_min, y_min, x_max, y_max, set_shrub_image);
201 }
202
clear_garden_image(int x,int y,int grid_offset)203 static void clear_garden_image(int x, int y, int grid_offset)
204 {
205 if (map_terrain_is(grid_offset, TERRAIN_GARDEN) &&
206 !map_terrain_is(grid_offset, TERRAIN_ELEVATION | TERRAIN_ACCESS_RAMP)) {
207 map_image_set(grid_offset, 0);
208 map_property_set_multi_tile_size(grid_offset, 1);
209 map_property_mark_draw_tile(grid_offset);
210 }
211 }
212
set_garden_image(int x,int y,int grid_offset)213 static void set_garden_image(int x, int y, int grid_offset)
214 {
215 if (map_terrain_is(grid_offset, TERRAIN_GARDEN)
216 && !map_terrain_is(grid_offset, TERRAIN_ELEVATION | TERRAIN_ACCESS_RAMP)) {
217 if (!map_image_at(grid_offset)) {
218 int image_id = image_group(GROUP_TERRAIN_GARDEN);
219 if (is_all_terrain_in_area(x, y, 2, TERRAIN_GARDEN)) {
220 switch (map_random_get(grid_offset) & 3) {
221 case 0: case 1:
222 image_id += 6;
223 break;
224 case 2:
225 image_id += 5;
226 break;
227 case 3:
228 image_id += 4;
229 break;
230 }
231 map_building_tiles_add(0, x, y, 2, image_id, TERRAIN_GARDEN);
232 } else {
233 if (y & 1) {
234 switch (x & 3) {
235 case 0: case 2:
236 image_id += 2;
237 break;
238 case 1: case 3:
239 image_id += 3;
240 break;
241 }
242 } else {
243 switch (x & 3) {
244 case 1: case 3:
245 image_id += 1;
246 break;
247 }
248 }
249 map_image_set(grid_offset, image_id);
250 }
251 }
252 }
253 }
254
remove_plaza_below_building(int x,int y,int grid_offset)255 static void remove_plaza_below_building(int x, int y, int grid_offset)
256 {
257 if (map_terrain_is(grid_offset, TERRAIN_ROAD) &&
258 map_property_is_plaza_or_earthquake(grid_offset)) {
259 if (map_terrain_is(grid_offset, TERRAIN_BUILDING)) {
260 map_property_clear_plaza_or_earthquake(grid_offset);
261 }
262 }
263 }
264
clear_plaza_image(int x,int y,int grid_offset)265 static void clear_plaza_image(int x, int y, int grid_offset)
266 {
267 if (map_terrain_is(grid_offset, TERRAIN_ROAD) &&
268 map_property_is_plaza_or_earthquake(grid_offset)) {
269 map_image_set(grid_offset, 0);
270 map_property_set_multi_tile_size(grid_offset, 1);
271 map_property_mark_draw_tile(grid_offset);
272 }
273 }
274
is_tile_plaza(int grid_offset)275 static int is_tile_plaza(int grid_offset)
276 {
277 if (map_terrain_is(grid_offset, TERRAIN_ROAD) &&
278 map_property_is_plaza_or_earthquake(grid_offset) &&
279 !map_terrain_is(grid_offset, TERRAIN_WATER | TERRAIN_BUILDING) &&
280 !map_image_at(grid_offset)) {
281 return 1;
282 }
283 return 0;
284 }
285
is_two_tile_square_plaza(int grid_offset)286 static int is_two_tile_square_plaza(int grid_offset)
287 {
288 return
289 is_tile_plaza(grid_offset + map_grid_delta(1, 0)) &&
290 is_tile_plaza(grid_offset + map_grid_delta(0, 1)) &&
291 is_tile_plaza(grid_offset + map_grid_delta(1, 1));
292 }
293
set_plaza_image(int x,int y,int grid_offset)294 static void set_plaza_image(int x, int y, int grid_offset)
295 {
296 if (map_terrain_is(grid_offset, TERRAIN_ROAD) &&
297 map_property_is_plaza_or_earthquake(grid_offset) &&
298 !map_image_at(grid_offset)) {
299 int image_id = image_group(GROUP_TERRAIN_PLAZA);
300 if (is_two_tile_square_plaza(grid_offset)) {
301 if (map_random_get(grid_offset) & 1) {
302 image_id += 7;
303 } else {
304 image_id += 6;
305 }
306 map_building_tiles_add(0, x, y, 2, image_id, TERRAIN_ROAD);
307 } else {
308 // single tile plaza
309 switch ((x & 1) + (y & 1)) {
310 case 2: image_id += 1; break;
311 case 1: image_id += 2; break;
312 }
313 map_image_set(grid_offset, image_id);
314 }
315 }
316 }
317
map_tiles_update_all_gardens(void)318 void map_tiles_update_all_gardens(void)
319 {
320 foreach_map_tile(clear_garden_image);
321 foreach_map_tile(set_garden_image);
322 }
323
determine_garden_tile(int x,int y,int grid_offset)324 static void determine_garden_tile(int x, int y, int grid_offset)
325 {
326 int base_image = image_group(GROUP_TERRAIN_GARDEN);
327 int image_id = map_image_at(grid_offset);
328 if (image_id >= base_image && image_id <= base_image + 6) {
329 map_terrain_add(grid_offset, TERRAIN_GARDEN);
330 map_property_clear_constructing(grid_offset);
331 map_aqueduct_set(grid_offset, 0);
332 }
333 }
334
map_tiles_determine_gardens(void)335 void map_tiles_determine_gardens(void)
336 {
337 foreach_map_tile(determine_garden_tile);
338 }
339
map_tiles_update_all_plazas(void)340 void map_tiles_update_all_plazas(void)
341 {
342 foreach_map_tile(remove_plaza_below_building);
343 foreach_map_tile(clear_plaza_image);
344 foreach_map_tile(set_plaza_image);
345 }
346
get_gatehouse_building_id(int grid_offset)347 static int get_gatehouse_building_id(int grid_offset)
348 {
349 if (map_terrain_is(grid_offset, TERRAIN_GATEHOUSE)) {
350 return map_building_at(grid_offset);
351 }
352 return 0;
353 }
354
get_gatehouse_position(int grid_offset,int direction,int building_id)355 static int get_gatehouse_position(int grid_offset, int direction, int building_id)
356 {
357 int result = 0;
358 if (direction == DIR_0_TOP) {
359 if (map_terrain_is(grid_offset + map_grid_delta(1, -1), TERRAIN_GATEHOUSE) &&
360 map_building_at(grid_offset + map_grid_delta(1, -1)) == building_id) {
361 result = 1;
362 if (!map_terrain_is(grid_offset + map_grid_delta(1, 0), TERRAIN_WALL)) {
363 result = 0;
364 }
365 if (map_terrain_is(grid_offset + map_grid_delta(-1, 0), TERRAIN_WALL) &&
366 map_terrain_is(grid_offset + map_grid_delta(-1, 1), TERRAIN_WALL)) {
367 result = 2;
368 }
369 if (!map_terrain_is(grid_offset + map_grid_delta(0, 1), TERRAIN_WALL_OR_GATEHOUSE)) {
370 result = 0;
371 }
372 if (!map_terrain_is(grid_offset + map_grid_delta(1, 1), TERRAIN_WALL_OR_GATEHOUSE)) {
373 result = 0;
374 }
375 } else if (map_terrain_is(grid_offset + map_grid_delta(-1, -1), TERRAIN_GATEHOUSE) &&
376 map_building_at(grid_offset + map_grid_delta(-1, -1)) == building_id) {
377 result = 3;
378 if (!map_terrain_is(grid_offset + map_grid_delta(-1, 0), TERRAIN_WALL)) {
379 result = 0;
380 }
381 if (map_terrain_is(grid_offset + map_grid_delta(1, 0), TERRAIN_WALL) &&
382 map_terrain_is(grid_offset + map_grid_delta(1, 1), TERRAIN_WALL)) {
383 result = 4;
384 }
385 if (!map_terrain_is(grid_offset + map_grid_delta(0, 1), TERRAIN_WALL_OR_GATEHOUSE)) {
386 result = 0;
387 }
388 if (!map_terrain_is(grid_offset + map_grid_delta(-1, 1), TERRAIN_WALL_OR_GATEHOUSE)) {
389 result = 0;
390 }
391 }
392 } else if (direction == DIR_6_LEFT) {
393 if (map_terrain_is(grid_offset + map_grid_delta(-1, 1), TERRAIN_GATEHOUSE) &&
394 map_building_at(grid_offset + map_grid_delta(-1, 1)) == building_id) {
395 result = 1;
396 if (!map_terrain_is(grid_offset + map_grid_delta(0, 1), TERRAIN_WALL)) {
397 result = 0;
398 }
399 if (map_terrain_is(grid_offset + map_grid_delta(0, -1), TERRAIN_WALL) &&
400 map_terrain_is(grid_offset + map_grid_delta(1, -1), TERRAIN_WALL)) {
401 result = 2;
402 }
403 if (!map_terrain_is(grid_offset + map_grid_delta(1, 0), TERRAIN_WALL_OR_GATEHOUSE)) {
404 result = 0;
405 }
406 if (!map_terrain_is(grid_offset + map_grid_delta(1, 1), TERRAIN_WALL_OR_GATEHOUSE)) {
407 result = 0;
408 }
409 } else if (map_terrain_is(grid_offset + map_grid_delta(-1, -1), TERRAIN_GATEHOUSE) &&
410 map_building_at(grid_offset + map_grid_delta(-1, -1)) == building_id) {
411 result = 3;
412 if (!map_terrain_is(grid_offset + map_grid_delta(0, -1), TERRAIN_WALL)) {
413 result = 0;
414 }
415 if (map_terrain_is(grid_offset + map_grid_delta(0, 1), TERRAIN_WALL) &&
416 map_terrain_is(grid_offset + map_grid_delta(1, 1), TERRAIN_WALL)) {
417 result = 4;
418 }
419 if (!map_terrain_is(grid_offset + map_grid_delta(1, 0), TERRAIN_WALL_OR_GATEHOUSE)) {
420 result = 0;
421 }
422 if (!map_terrain_is(grid_offset + map_grid_delta(1, -1), TERRAIN_WALL_OR_GATEHOUSE)) {
423 result = 0;
424 }
425 }
426 } else if (direction == DIR_4_BOTTOM) {
427 if (map_terrain_is(grid_offset + map_grid_delta(1, 1), TERRAIN_GATEHOUSE) &&
428 map_building_at(grid_offset + map_grid_delta(1, 1)) == building_id) {
429 result = 1;
430 if (!map_terrain_is(grid_offset + map_grid_delta(1, 0), TERRAIN_WALL)) {
431 result = 0;
432 }
433 if (map_terrain_is(grid_offset + map_grid_delta(-1, 0), TERRAIN_WALL) &&
434 map_terrain_is(grid_offset + map_grid_delta(-1, -1), TERRAIN_WALL)) {
435 result = 2;
436 }
437 if (!map_terrain_is(grid_offset + map_grid_delta(0, -1), TERRAIN_WALL_OR_GATEHOUSE)) {
438 result = 0;
439 }
440 if (!map_terrain_is(grid_offset + map_grid_delta(1, -1), TERRAIN_WALL_OR_GATEHOUSE)) {
441 result = 0;
442 }
443 } else if (map_terrain_is(grid_offset + map_grid_delta(-1, 1), TERRAIN_GATEHOUSE) &&
444 map_building_at(grid_offset + map_grid_delta(-1, 1)) == building_id) {
445 result = 3;
446 if (!map_terrain_is(grid_offset + map_grid_delta(-1, 0), TERRAIN_WALL)) {
447 result = 0;
448 }
449 if (map_terrain_is(grid_offset + map_grid_delta(1, 0), TERRAIN_WALL) &&
450 map_terrain_is(grid_offset + map_grid_delta(1, -1), TERRAIN_WALL)) {
451 result = 4;
452 }
453 if (!map_terrain_is(grid_offset + map_grid_delta(0, -1), TERRAIN_WALL_OR_GATEHOUSE)) {
454 result = 0;
455 }
456 if (!map_terrain_is(grid_offset + map_grid_delta(-1, -1), TERRAIN_WALL_OR_GATEHOUSE)) {
457 result = 0;
458 }
459 }
460 } else if (direction == DIR_2_RIGHT) {
461 if (map_terrain_is(grid_offset + map_grid_delta(1, 1), TERRAIN_GATEHOUSE) &&
462 map_building_at(grid_offset + map_grid_delta(1, 1)) == building_id) {
463 result = 1;
464 if (!map_terrain_is(grid_offset + map_grid_delta(0, 1), TERRAIN_WALL)) {
465 result = 0;
466 }
467 if (map_terrain_is(grid_offset + map_grid_delta(0, -1), TERRAIN_WALL) &&
468 map_terrain_is(grid_offset + map_grid_delta(-1, -1), TERRAIN_WALL)) {
469 result = 2;
470 }
471 if (!map_terrain_is(grid_offset + map_grid_delta(-1, 0), TERRAIN_WALL_OR_GATEHOUSE)) {
472 result = 0;
473 }
474 if (!map_terrain_is(grid_offset + map_grid_delta(-1, 1), TERRAIN_WALL_OR_GATEHOUSE)) {
475 result = 0;
476 }
477 } else if (map_terrain_is(grid_offset + map_grid_delta(1, -1), TERRAIN_GATEHOUSE) &&
478 map_building_at(grid_offset + map_grid_delta(1, -1)) == building_id) {
479 result = 3;
480 if (!map_terrain_is(grid_offset + map_grid_delta(0, -1), TERRAIN_WALL)) {
481 result = 0;
482 }
483 if (map_terrain_is(grid_offset + map_grid_delta(0, 1), TERRAIN_WALL) &&
484 map_terrain_is(grid_offset + map_grid_delta(-1, 1), TERRAIN_WALL)) {
485 result = 4;
486 }
487 if (!map_terrain_is(grid_offset + map_grid_delta(-1, 0), TERRAIN_WALL_OR_GATEHOUSE)) {
488 result = 0;
489 }
490 if (!map_terrain_is(grid_offset + map_grid_delta(-1, -1), TERRAIN_WALL_OR_GATEHOUSE)) {
491 result = 0;
492 }
493 }
494 }
495 return result;
496 }
497
set_wall_gatehouse_image_manually(int grid_offset)498 static void set_wall_gatehouse_image_manually(int grid_offset)
499 {
500 int gatehouse_up = get_gatehouse_building_id(grid_offset + map_grid_delta(0, -1));
501 int gatehouse_left = get_gatehouse_building_id(grid_offset + map_grid_delta(-1, 0));
502 int gatehouse_down = get_gatehouse_building_id(grid_offset + map_grid_delta(0, 1));
503 int gatehouse_right = get_gatehouse_building_id(grid_offset + map_grid_delta(1, 0));
504 int image_offset = 0;
505 int map_orientation = city_view_orientation();
506 if (map_orientation == DIR_0_TOP) {
507 if (gatehouse_up && !gatehouse_left) {
508 int pos = get_gatehouse_position(grid_offset, DIR_0_TOP, gatehouse_up);
509 if (pos > 0) {
510 if (pos <= 2) {
511 image_offset = 29;
512 } else if (pos == 3) {
513 image_offset = 31;
514 } else {
515 image_offset = 33;
516 }
517 }
518 } else if (gatehouse_left && !gatehouse_up) {
519 int pos = get_gatehouse_position(grid_offset, DIR_6_LEFT, gatehouse_left);
520 if (pos > 0) {
521 if (pos <= 2) {
522 image_offset = 30;
523 } else if (pos == 3) {
524 image_offset = 32;
525 } else {
526 image_offset = 33;
527 }
528 }
529 }
530 } else if (map_orientation == DIR_2_RIGHT) {
531 if (gatehouse_up && !gatehouse_right) {
532 int pos = get_gatehouse_position(grid_offset, DIR_0_TOP, gatehouse_up);
533 if (pos > 0) {
534 if (pos == 1) {
535 image_offset = 32;
536 } else if (pos == 2) {
537 image_offset = 33;
538 } else {
539 image_offset = 30;
540 }
541 }
542 } else if (gatehouse_right && !gatehouse_up) {
543 int pos = get_gatehouse_position(grid_offset, DIR_2_RIGHT, gatehouse_right);
544 if (pos > 0) {
545 if (pos <= 2) {
546 image_offset = 29;
547 } else if (pos == 3) {
548 image_offset = 31;
549 } else {
550 image_offset = 33;
551 }
552 }
553 }
554 } else if (map_orientation == DIR_4_BOTTOM) {
555 if (gatehouse_down && !gatehouse_right) {
556 int pos = get_gatehouse_position(grid_offset, DIR_4_BOTTOM, gatehouse_down);
557 if (pos > 0) {
558 if (pos == 1) {
559 image_offset = 31;
560 } else if (pos == 2) {
561 image_offset = 33;
562 } else {
563 image_offset = 29;
564 }
565 }
566 } else if (gatehouse_right && !gatehouse_down) {
567 int pos = get_gatehouse_position(grid_offset, DIR_2_RIGHT, gatehouse_right);
568 if (pos > 0) {
569 if (pos == 1) {
570 image_offset = 32;
571 } else if (pos == 2) {
572 image_offset = 33;
573 } else {
574 image_offset = 30;
575 }
576 }
577 }
578 } else if (map_orientation == DIR_6_LEFT) {
579 if (gatehouse_down && !gatehouse_left) {
580 int pos = get_gatehouse_position(grid_offset, DIR_4_BOTTOM, gatehouse_down);
581 if (pos > 0) {
582 if (pos <= 2) {
583 image_offset = 30;
584 } else if (pos == 3) {
585 image_offset = 32;
586 } else {
587 image_offset = 33;
588 }
589 }
590 } else if (gatehouse_left && !gatehouse_down) {
591 int pos = get_gatehouse_position(grid_offset, DIR_6_LEFT, gatehouse_left);
592 if (pos > 0) {
593 if (pos == 1) {
594 image_offset = 31;
595 } else if (pos == 2) {
596 image_offset = 33;
597 } else {
598 image_offset = 29;
599 }
600 }
601 }
602 }
603 if (image_offset) {
604 map_image_set(grid_offset, image_group(GROUP_BUILDING_WALL) + image_offset);
605 }
606 }
607
set_wall_image(int x,int y,int grid_offset)608 static void set_wall_image(int x, int y, int grid_offset)
609 {
610 if (!map_terrain_is(grid_offset, TERRAIN_WALL) ||
611 map_terrain_is(grid_offset, TERRAIN_BUILDING)) {
612 return;
613 }
614 const terrain_image *img = map_image_context_get_wall(grid_offset);
615 map_image_set(grid_offset, image_group(GROUP_BUILDING_WALL) +
616 img->group_offset + img->item_offset);
617 map_property_set_multi_tile_size(grid_offset, 1);
618 map_property_mark_draw_tile(grid_offset);
619 if (map_terrain_count_directly_adjacent_with_type(grid_offset, TERRAIN_GATEHOUSE) > 0) {
620 img = map_image_context_get_wall_gatehouse(grid_offset);
621 if (img->is_valid) {
622 map_image_set(grid_offset, image_group(GROUP_BUILDING_WALL) +
623 img->group_offset + img->item_offset);
624 } else {
625 set_wall_gatehouse_image_manually(grid_offset);
626 }
627 }
628 }
629
map_tiles_update_all_walls(void)630 void map_tiles_update_all_walls(void)
631 {
632 foreach_map_tile(set_wall_image);
633 }
634
map_tiles_update_area_walls(int x,int y,int size)635 void map_tiles_update_area_walls(int x, int y, int size)
636 {
637 foreach_region_tile(x - 1, y - 1, x + size - 2, y + size - 2, set_wall_image);
638 }
639
map_tiles_set_wall(int x,int y)640 int map_tiles_set_wall(int x, int y)
641 {
642 int grid_offset = map_grid_offset(x, y);
643 int tile_set = 0;
644 if (!map_terrain_is(grid_offset, TERRAIN_WALL)) {
645 tile_set = 1;
646 }
647 map_terrain_set(grid_offset, TERRAIN_WALL);
648 map_property_clear_constructing(grid_offset);
649
650 foreach_region_tile(x - 1, y - 1, x + 1, y + 1, set_wall_image);
651 return tile_set;
652 }
653
map_tiles_is_paved_road(int grid_offset)654 int map_tiles_is_paved_road(int grid_offset)
655 {
656 int desirability = map_desirability_get(grid_offset);
657 if (desirability > 4) {
658 return 1;
659 }
660 if (desirability > 0 && map_terrain_is(grid_offset, TERRAIN_FOUNTAIN_RANGE)) {
661 return 1;
662 }
663 return 0;
664 }
665
set_aqueduct_image(int grid_offset,int is_road,const terrain_image * img)666 static void set_aqueduct_image(int grid_offset, int is_road, const terrain_image *img)
667 {
668 int group_offset = img->group_offset;
669 if (is_road) {
670 if (!img->aqueduct_offset || (group_offset != 2 && group_offset != 3)) {
671 if (map_terrain_is(grid_offset + map_grid_delta(0, -1), TERRAIN_ROAD)) {
672 group_offset = 3;
673 } else {
674 group_offset = 2;
675 }
676 }
677 if (map_tiles_is_paved_road(grid_offset)) {
678 group_offset -= 2;
679 } else {
680 group_offset += 6;
681 }
682 }
683 int image_aqueduct = image_group(GROUP_BUILDING_AQUEDUCT);
684 int water_offset;
685 int image_id = map_image_at(grid_offset);
686 if (image_id >= image_aqueduct && image_id < image_aqueduct + 15) {
687 water_offset = 0;
688 } else {
689 water_offset = 15;
690 }
691 map_image_set(grid_offset, image_aqueduct + water_offset + group_offset);
692 map_property_set_multi_tile_size(grid_offset, 1);
693 map_property_mark_draw_tile(grid_offset);
694 }
695
set_road_with_aqueduct_image(int grid_offset)696 static void set_road_with_aqueduct_image(int grid_offset)
697 {
698 set_aqueduct_image(grid_offset, 1, map_image_context_get_aqueduct(grid_offset, 0));
699 }
700
set_road_image(int x,int y,int grid_offset)701 static void set_road_image(int x, int y, int grid_offset)
702 {
703 if (!map_terrain_is(grid_offset, TERRAIN_ROAD) ||
704 map_terrain_is(grid_offset, TERRAIN_WATER | TERRAIN_BUILDING)) {
705 return;
706 }
707 if (map_terrain_is(grid_offset, TERRAIN_AQUEDUCT)) {
708 set_road_with_aqueduct_image(grid_offset);
709 return;
710 }
711 if (map_property_is_plaza_or_earthquake(grid_offset)) {
712 return;
713 }
714 if (map_tiles_is_paved_road(grid_offset)) {
715 const terrain_image *img = map_image_context_get_paved_road(grid_offset);
716 map_image_set(grid_offset, image_group(GROUP_TERRAIN_ROAD) +
717 img->group_offset + img->item_offset);
718 } else {
719 const terrain_image *img = map_image_context_get_dirt_road(grid_offset);
720 map_image_set(grid_offset, image_group(GROUP_TERRAIN_ROAD) +
721 img->group_offset + img->item_offset + 49);
722 }
723 map_property_set_multi_tile_size(grid_offset, 1);
724 map_property_mark_draw_tile(grid_offset);
725 }
726
map_tiles_update_all_roads(void)727 void map_tiles_update_all_roads(void)
728 {
729 foreach_map_tile(set_road_image);
730 }
731
map_tiles_update_area_roads(int x,int y,int size)732 void map_tiles_update_area_roads(int x, int y, int size)
733 {
734 foreach_region_tile(x - 1, y - 1, x + size - 2, y + size - 2, set_road_image);
735 }
736
map_tiles_set_road(int x,int y)737 int map_tiles_set_road(int x, int y)
738 {
739 int grid_offset = map_grid_offset(x, y);
740 int tile_set = 0;
741 if (!map_terrain_is(grid_offset, TERRAIN_ROAD)) {
742 tile_set = 1;
743 }
744 map_terrain_add(grid_offset, TERRAIN_ROAD);
745 map_property_clear_constructing(grid_offset);
746
747 foreach_region_tile(x - 1, y - 1, x + 1, y + 1, set_road_image);
748 return tile_set;
749 }
750
clear_empty_land_image(int x,int y,int grid_offset)751 static void clear_empty_land_image(int x, int y, int grid_offset)
752 {
753 if (!map_terrain_is(grid_offset, TERRAIN_NOT_CLEAR)) {
754 map_image_set(grid_offset, 0);
755 map_property_set_multi_tile_size(grid_offset, 1);
756 map_property_mark_draw_tile(grid_offset);
757 }
758 }
759
set_empty_land_image(int x,int y,int size,int image_id)760 static void set_empty_land_image(int x, int y, int size, int image_id)
761 {
762 if (!map_grid_is_inside(x, y, size)) {
763 return;
764 }
765 int index = 0;
766 for (int dy = 0; dy < size; dy++) {
767 for (int dx = 0; dx < size; dx++) {
768 int grid_offset = map_grid_offset(x + dx, y + dy);
769 map_terrain_remove(grid_offset, TERRAIN_CLEARABLE);
770 map_building_set(grid_offset, 0);
771 map_property_clear_constructing(grid_offset);
772 map_property_set_multi_tile_size(grid_offset, 1);
773 map_property_mark_draw_tile(grid_offset);
774 map_image_set(grid_offset, image_id + index);
775 index++;
776 }
777 }
778 }
779
set_empty_land_pass1(int x,int y,int grid_offset)780 static void set_empty_land_pass1(int x, int y, int grid_offset)
781 {
782 if (!map_terrain_is(grid_offset, TERRAIN_NOT_CLEAR) && !map_image_at(grid_offset) &&
783 !(map_random_get(grid_offset) & 0xf0)) {
784 int image_id;
785 if (map_property_is_alternate_terrain(grid_offset)) {
786 image_id = image_group(GROUP_TERRAIN_GRASS_2);
787 } else {
788 image_id = image_group(GROUP_TERRAIN_GRASS_1);
789 }
790 set_empty_land_image(x, y, 1, image_id + (map_random_get(grid_offset) & 7));
791 }
792 }
793
set_empty_land_pass2(int x,int y,int grid_offset)794 static void set_empty_land_pass2(int x, int y, int grid_offset)
795 {
796 if (!map_terrain_is(grid_offset, TERRAIN_NOT_CLEAR) && !map_image_at(grid_offset)) {
797 int image_id;
798 if (map_property_is_alternate_terrain(grid_offset)) {
799 image_id = image_group(GROUP_TERRAIN_GRASS_2);
800 } else {
801 image_id = image_group(GROUP_TERRAIN_GRASS_1);
802 }
803 if (is_clear(x, y, 4, TERRAIN_ALL, 1)) {
804 set_empty_land_image(x, y, 4, image_id + 42);
805 } else if (is_clear(x, y, 3, TERRAIN_ALL, 1)) {
806 set_empty_land_image(x, y, 3, image_id + 24 + 9 * (map_random_get(grid_offset) & 1));
807 } else if (is_clear(x, y, 2, TERRAIN_ALL, 1)) {
808 set_empty_land_image(x, y, 2, image_id + 8 + 4 * (map_random_get(grid_offset) & 3));
809 } else {
810 set_empty_land_image(x, y, 1, image_id + (map_random_get(grid_offset) & 7));
811 }
812 }
813 }
814
map_tiles_update_all_empty_land(void)815 void map_tiles_update_all_empty_land(void)
816 {
817 foreach_map_tile(clear_empty_land_image);
818 foreach_map_tile(set_empty_land_pass1);
819 foreach_map_tile(set_empty_land_pass2);
820 }
821
map_tiles_update_region_empty_land(int x_min,int y_min,int x_max,int y_max)822 void map_tiles_update_region_empty_land(int x_min, int y_min, int x_max, int y_max)
823 {
824 foreach_region_tile(x_min, y_min, x_max, y_max, clear_empty_land_image);
825 foreach_region_tile(x_min, y_min, x_max, y_max, set_empty_land_pass1);
826 foreach_region_tile(x_min, y_min, x_max, y_max, set_empty_land_pass2);
827 }
828
set_meadow_image(int x,int y,int grid_offset)829 static void set_meadow_image(int x, int y, int grid_offset)
830 {
831 if (map_terrain_is(grid_offset, TERRAIN_MEADOW) && !map_terrain_is(grid_offset, FORBIDDEN_TERRAIN_MEADOW)) {
832 int random = map_random_get(grid_offset) & 3;
833 int image_id = image_group(GROUP_TERRAIN_MEADOW);
834 if (map_terrain_has_only_meadow_in_ring(x, y, 2)) {
835 map_image_set(grid_offset, image_id + random + 8);
836 } else if (map_terrain_has_only_meadow_in_ring(x, y, 1)) {
837 map_image_set(grid_offset, image_id + random + 4);
838 } else {
839 map_image_set(grid_offset, image_id + random);
840 }
841 map_property_set_multi_tile_size(grid_offset, 1);
842 map_property_mark_draw_tile(grid_offset);
843 map_aqueduct_set(grid_offset, 0);
844 }
845 }
846
update_meadow_tile(int x,int y,int grid_offset)847 static void update_meadow_tile(int x, int y, int grid_offset)
848 {
849 if (map_terrain_is(grid_offset, TERRAIN_MEADOW) && !map_terrain_is(grid_offset, FORBIDDEN_TERRAIN_MEADOW)) {
850 foreach_region_tile(x - 1, y - 1, x + 1, y + 1, set_meadow_image);
851 }
852 }
853
map_tiles_update_all_meadow(void)854 void map_tiles_update_all_meadow(void)
855 {
856 foreach_map_tile(update_meadow_tile);
857 }
858
map_tiles_update_region_meadow(int x_min,int y_min,int x_max,int y_max)859 void map_tiles_update_region_meadow(int x_min, int y_min, int x_max, int y_max)
860 {
861 foreach_region_tile(x_min, y_min, x_max, y_max, update_meadow_tile);
862 }
863
set_water_image(int x,int y,int grid_offset)864 static void set_water_image(int x, int y, int grid_offset)
865 {
866 if ((map_terrain_get(grid_offset) & (TERRAIN_WATER | TERRAIN_BUILDING)) == TERRAIN_WATER) {
867 const terrain_image *img = map_image_context_get_shore(grid_offset);
868 int image_id = image_group(GROUP_TERRAIN_WATER) + img->group_offset + img->item_offset;
869 if (map_terrain_exists_tile_in_radius_with_type(x, y, 1, 2, TERRAIN_BUILDING)) {
870 // fortified shore
871 int base = image_group(GROUP_TERRAIN_WATER_SHORE);
872 switch (img->group_offset) {
873 case 8: image_id = base + 10; break;
874 case 12: image_id = base + 11; break;
875 case 16: image_id = base + 9; break;
876 case 20: image_id = base + 8; break;
877 case 24: image_id = base + 18; break;
878 case 28: image_id = base + 16; break;
879 case 32: image_id = base + 19; break;
880 case 36: image_id = base + 17; break;
881 case 50: image_id = base + 12; break;
882 case 51: image_id = base + 14; break;
883 case 52: image_id = base + 13; break;
884 case 53: image_id = base + 15; break;
885 }
886 }
887 map_image_set(grid_offset, image_id);
888 map_property_set_multi_tile_size(grid_offset, 1);
889 map_property_mark_draw_tile(grid_offset);
890 }
891 }
892
update_water_tile(int x,int y,int grid_offset)893 static void update_water_tile(int x, int y, int grid_offset)
894 {
895 if (map_terrain_is(grid_offset, TERRAIN_WATER) && !map_terrain_is(grid_offset, TERRAIN_BUILDING)) {
896 foreach_region_tile(x - 1, y - 1, x + 1, y + 1, set_water_image);
897 }
898 }
899
map_tiles_update_all_water(void)900 void map_tiles_update_all_water(void)
901 {
902 foreach_map_tile(update_water_tile);
903 }
904
map_tiles_update_region_water(int x_min,int y_min,int x_max,int y_max)905 void map_tiles_update_region_water(int x_min, int y_min, int x_max, int y_max)
906 {
907 foreach_region_tile(x_min, y_min, x_max, y_max, update_water_tile);
908 }
909
map_tiles_set_water(int x,int y)910 void map_tiles_set_water(int x, int y)
911 {
912 map_terrain_add(map_grid_offset(x, y), TERRAIN_WATER);
913 foreach_region_tile(x - 1, y - 1, x + 1, y + 1, set_water_image);
914 }
915
set_aqueduct(int grid_offset)916 static void set_aqueduct(int grid_offset)
917 {
918 const terrain_image *img = map_image_context_get_aqueduct(grid_offset, aqueduct_include_construction);
919 int is_road = map_terrain_is(grid_offset, TERRAIN_ROAD);
920 if (is_road) {
921 map_property_clear_plaza_or_earthquake(grid_offset);
922 }
923 set_aqueduct_image(grid_offset, is_road, img);
924 map_aqueduct_set(grid_offset, img->aqueduct_offset);
925 }
926
update_aqueduct_tile(int x,int y,int grid_offset)927 static void update_aqueduct_tile(int x, int y, int grid_offset)
928 {
929 if (map_terrain_is(grid_offset, TERRAIN_AQUEDUCT) && map_aqueduct_at(grid_offset) <= 15) {
930 set_aqueduct(grid_offset);
931 }
932 }
933
map_tiles_update_all_aqueducts(int include_construction)934 void map_tiles_update_all_aqueducts(int include_construction)
935 {
936 aqueduct_include_construction = include_construction;
937 foreach_map_tile(update_aqueduct_tile);
938 aqueduct_include_construction = 0;
939 }
940
map_tiles_update_region_aqueducts(int x_min,int y_min,int x_max,int y_max)941 void map_tiles_update_region_aqueducts(int x_min, int y_min, int x_max, int y_max)
942 {
943 foreach_region_tile(x_min, y_min, x_max, y_max, update_aqueduct_tile);
944 }
945
set_earthquake_image(int x,int y,int grid_offset)946 static void set_earthquake_image(int x, int y, int grid_offset)
947 {
948 if (map_terrain_is(grid_offset, TERRAIN_ROCK) && map_property_is_plaza_or_earthquake(grid_offset)) {
949 const terrain_image *img = map_image_context_get_earthquake(grid_offset);
950 if (img->is_valid) {
951 map_image_set(grid_offset,
952 image_group(GROUP_TERRAIN_EARTHQUAKE) + img->group_offset + img->item_offset);
953 } else {
954 map_image_set(grid_offset, image_group(GROUP_TERRAIN_EARTHQUAKE));
955 }
956 map_property_set_multi_tile_size(grid_offset, 1);
957 map_property_mark_draw_tile(grid_offset);
958 }
959 }
960
update_earthquake_tile(int x,int y,int grid_offset)961 static void update_earthquake_tile(int x, int y, int grid_offset)
962 {
963 if (map_terrain_is(grid_offset, TERRAIN_ROCK) && map_property_is_plaza_or_earthquake(grid_offset)) {
964 map_terrain_add(grid_offset, TERRAIN_ROCK);
965 map_property_mark_plaza_or_earthquake(grid_offset);
966 foreach_region_tile(x - 1, y - 1, x + 1, y + 1, set_earthquake_image);
967 }
968 }
969
map_tiles_update_all_earthquake(void)970 void map_tiles_update_all_earthquake(void)
971 {
972 foreach_map_tile(update_earthquake_tile);
973 }
974
map_tiles_set_earthquake(int x,int y)975 void map_tiles_set_earthquake(int x, int y)
976 {
977 int grid_offset = map_grid_offset(x, y);
978 // earthquake: terrain = rock && bitfields = plaza
979 map_terrain_add(grid_offset, TERRAIN_ROCK);
980 map_property_mark_plaza_or_earthquake(grid_offset);
981
982 foreach_region_tile(x - 1, y - 1, x + 1, y + 1, set_earthquake_image);
983 }
984
set_rubble_image(int x,int y,int grid_offset)985 static void set_rubble_image(int x, int y, int grid_offset)
986 {
987 if (map_terrain_is(grid_offset, TERRAIN_RUBBLE) && !map_terrain_is(grid_offset, FORBIDDEN_TERRAIN_RUBBLE)) {
988 map_image_set(grid_offset, image_group(GROUP_TERRAIN_RUBBLE) + (map_random_get(grid_offset) & 7));
989 map_property_set_multi_tile_size(grid_offset, 1);
990 map_property_mark_draw_tile(grid_offset);
991 map_aqueduct_set(grid_offset, 0);
992 }
993 }
994
map_tiles_update_all_rubble(void)995 void map_tiles_update_all_rubble(void)
996 {
997 foreach_map_tile(set_rubble_image);
998 }
999
map_tiles_update_region_rubble(int x_min,int y_min,int x_max,int y_max)1000 void map_tiles_update_region_rubble(int x_min, int y_min, int x_max, int y_max)
1001 {
1002 foreach_region_tile(x_min, y_min, x_max, y_max, set_rubble_image);
1003 }
1004
clear_access_ramp_image(int x,int y,int grid_offset)1005 static void clear_access_ramp_image(int x, int y, int grid_offset)
1006 {
1007 if (map_terrain_is(grid_offset, TERRAIN_ACCESS_RAMP)) {
1008 map_image_set(grid_offset, 0);
1009 }
1010 }
1011
get_access_ramp_image_offset(int x,int y)1012 static int get_access_ramp_image_offset(int x, int y)
1013 {
1014 if (!map_grid_is_inside(x, y, 1)) {
1015 return -1;
1016 }
1017 static const int offsets[4][6] = {
1018 {OFFSET(0,1), OFFSET(1,1), OFFSET(0,0), OFFSET(1,0), OFFSET(0,2), OFFSET(1,2)},
1019 {OFFSET(0,0), OFFSET(0,1), OFFSET(1,0), OFFSET(1,1), OFFSET(-1,0), OFFSET(-1,1)},
1020 {OFFSET(0,0), OFFSET(1,0), OFFSET(0,1), OFFSET(1,1), OFFSET(0,-1), OFFSET(1,-1)},
1021 {OFFSET(1,0), OFFSET(1,1), OFFSET(0,0), OFFSET(0,1), OFFSET(2,0), OFFSET(2,1)},
1022 };
1023 int base_offset = map_grid_offset(x, y);
1024 int image_offset = -1;
1025 for (int dir = 0; dir < 4; dir++) {
1026 int right_tiles = 0;
1027 int height = -1;
1028 for (int i = 0; i < 6; i++) {
1029 int grid_offset = base_offset + offsets[dir][i];
1030 if (i < 2) { // 2nd row
1031 if (map_terrain_is(grid_offset, TERRAIN_ELEVATION)) {
1032 right_tiles++;
1033 }
1034 height = map_elevation_at(grid_offset);
1035 } else if (i < 4) { // 1st row
1036 if (map_terrain_is(grid_offset, TERRAIN_ACCESS_RAMP) &&
1037 map_elevation_at(grid_offset) < height) {
1038 right_tiles++;
1039 }
1040 } else { // higher row beyond access ramp
1041 if (map_terrain_is(grid_offset, TERRAIN_ELEVATION)) {
1042 if (map_elevation_at(grid_offset) != height) {
1043 right_tiles++;
1044 }
1045 } else if (map_elevation_at(grid_offset) >= height) {
1046 right_tiles++;
1047 }
1048 }
1049 }
1050 if (right_tiles == 6) {
1051 image_offset = dir;
1052 break;
1053 }
1054 }
1055 if (image_offset < 0) {
1056 return -1;
1057 }
1058 switch (city_view_orientation()) {
1059 case DIR_0_TOP: break;
1060 case DIR_6_LEFT: image_offset += 1; break;
1061 case DIR_4_BOTTOM: image_offset += 2; break;
1062 case DIR_2_RIGHT: image_offset += 3; break;
1063 }
1064 if (image_offset >= 4) {
1065 image_offset -= 4;
1066 }
1067 return image_offset;
1068 }
1069
set_elevation_aqueduct_image(int grid_offset)1070 static void set_elevation_aqueduct_image(int grid_offset)
1071 {
1072 if (map_aqueduct_at(grid_offset) <= 15 && !map_terrain_is(grid_offset, TERRAIN_BUILDING)) {
1073 set_aqueduct(grid_offset);
1074 }
1075 }
1076
set_elevation_image(int x,int y,int grid_offset)1077 static void set_elevation_image(int x, int y, int grid_offset)
1078 {
1079 if (map_terrain_is(grid_offset, TERRAIN_ACCESS_RAMP) && !map_image_at(grid_offset)) {
1080 int image_offset = get_access_ramp_image_offset(x, y);
1081 if (image_offset < 0) {
1082 // invalid map: remove access ramp
1083 map_terrain_remove(grid_offset, TERRAIN_ACCESS_RAMP);
1084 map_property_set_multi_tile_size(grid_offset, 1);
1085 map_property_mark_draw_tile(grid_offset);
1086 if (map_elevation_at(grid_offset)) {
1087 map_terrain_add(grid_offset, TERRAIN_ELEVATION);
1088 } else {
1089 map_terrain_remove(grid_offset, TERRAIN_ELEVATION);
1090 map_image_set(grid_offset,
1091 image_group(GROUP_TERRAIN_GRASS_1) + (map_random_get(grid_offset) & 7));
1092 }
1093 } else {
1094 map_building_tiles_add(0, x, y, 2,
1095 image_group(GROUP_TERRAIN_ACCESS_RAMP) + image_offset, TERRAIN_ACCESS_RAMP);
1096 }
1097 }
1098 if (map_elevation_at(grid_offset) && !map_terrain_is(grid_offset, TERRAIN_ACCESS_RAMP)) {
1099 const terrain_image *img = map_image_context_get_elevation(grid_offset, map_elevation_at(grid_offset));
1100 if (img->group_offset == 44) {
1101 map_terrain_remove(grid_offset, TERRAIN_ELEVATION);
1102 int terrain = map_terrain_get(grid_offset);
1103 if (!(terrain & TERRAIN_BUILDING)) {
1104 map_property_set_multi_tile_xy(grid_offset, 0, 0, 1);
1105 if (terrain & TERRAIN_SHRUB) {
1106 map_image_set(grid_offset, image_group(GROUP_TERRAIN_SHRUB) + (map_random_get(grid_offset) & 7));
1107 } else if (terrain & TERRAIN_TREE) {
1108 map_image_set(grid_offset, image_group(GROUP_TERRAIN_TREE) + (map_random_get(grid_offset) & 7));
1109 } else if (terrain & TERRAIN_ROAD) {
1110 map_tiles_set_road(x, y);
1111 } else if (terrain & TERRAIN_AQUEDUCT) {
1112 set_elevation_aqueduct_image(grid_offset);
1113 } else if (terrain & TERRAIN_MEADOW) {
1114 map_image_set(grid_offset, image_group(GROUP_TERRAIN_MEADOW) + (map_random_get(grid_offset) & 3));
1115 } else {
1116 map_image_set(grid_offset, image_group(GROUP_TERRAIN_GRASS_1) + (map_random_get(grid_offset) & 7));
1117 }
1118 }
1119 } else {
1120 map_property_set_multi_tile_xy(grid_offset, 0, 0, 1);
1121 map_terrain_add(grid_offset, TERRAIN_ELEVATION);
1122 map_image_set(grid_offset, image_group(GROUP_TERRAIN_ELEVATION) + img->group_offset + img->item_offset);
1123 }
1124 }
1125 }
1126
map_tiles_update_all_elevation(void)1127 void map_tiles_update_all_elevation(void)
1128 {
1129 int width = map_data.width - 2;
1130 int height = map_data.height - 2;
1131 foreach_region_tile(0, 0, width, height, clear_access_ramp_image);
1132 foreach_region_tile(0, 0, width, height, set_elevation_image);
1133 }
1134
map_tiles_add_entry_exit_flags(void)1135 void map_tiles_add_entry_exit_flags(void)
1136 {
1137 int entry_orientation;
1138 map_point entry_point = scenario_map_entry();
1139 if (entry_point.x == 0) {
1140 entry_orientation = DIR_2_RIGHT;
1141 } else if (entry_point.x == map_data.width - 1) {
1142 entry_orientation = DIR_6_LEFT;
1143 } else if (entry_point.y == 0) {
1144 entry_orientation = DIR_0_TOP;
1145 } else if (entry_point.y == map_data.height - 1) {
1146 entry_orientation = DIR_4_BOTTOM;
1147 } else {
1148 entry_orientation = -1;
1149 }
1150 int exit_orientation;
1151 map_point exit_point = scenario_map_exit();
1152 if (exit_point.x == 0) {
1153 exit_orientation = DIR_2_RIGHT;
1154 } else if (exit_point.x == map_data.width - 1) {
1155 exit_orientation = DIR_6_LEFT;
1156 } else if (exit_point.y == 0) {
1157 exit_orientation = DIR_0_TOP;
1158 } else if (exit_point.y == map_data.height - 1) {
1159 exit_orientation = DIR_4_BOTTOM;
1160 } else {
1161 exit_orientation = -1;
1162 }
1163 if (entry_orientation >= 0) {
1164 int grid_offset = map_grid_offset(entry_point.x, entry_point.y);
1165 int x_tile, y_tile;
1166 for (int i = 1; i < 10; i++) {
1167 if (map_terrain_exists_clear_tile_in_radius(entry_point.x, entry_point.y,
1168 1, i, grid_offset, &x_tile, &y_tile)) {
1169 break;
1170 }
1171 }
1172 int grid_offset_flag = city_map_set_entry_flag(x_tile, y_tile);
1173 map_terrain_add(grid_offset_flag, TERRAIN_ROCK);
1174 int orientation = (city_view_orientation() + entry_orientation) % 8;
1175 map_image_set(grid_offset_flag, image_group(GROUP_TERRAIN_ENTRY_EXIT_FLAGS) + orientation / 2);
1176 }
1177 if (exit_orientation >= 0) {
1178 int grid_offset = map_grid_offset(exit_point.x, exit_point.y);
1179 int x_tile, y_tile;
1180 for (int i = 1; i < 10; i++) {
1181 if (map_terrain_exists_clear_tile_in_radius(exit_point.x, exit_point.y,
1182 1, i, grid_offset, &x_tile, &y_tile)) {
1183 break;
1184 }
1185 }
1186 int grid_offset_flag = city_map_set_exit_flag(x_tile, y_tile);
1187 map_terrain_add(grid_offset_flag, TERRAIN_ROCK);
1188 int orientation = (city_view_orientation() + exit_orientation) % 8;
1189 map_image_set(grid_offset_flag, image_group(GROUP_TERRAIN_ENTRY_EXIT_FLAGS) + 4 + orientation / 2);
1190 }
1191 }
1192
remove_entry_exit_flag(const map_tile * tile)1193 static void remove_entry_exit_flag(const map_tile *tile)
1194 {
1195 // re-calculate grid_offset because the stored offset might be invalid
1196 map_terrain_remove(map_grid_offset(tile->x, tile->y), TERRAIN_ROCK);
1197 }
1198
map_tiles_remove_entry_exit_flags(void)1199 void map_tiles_remove_entry_exit_flags(void)
1200 {
1201 remove_entry_exit_flag(city_map_entry_flag());
1202 remove_entry_exit_flag(city_map_exit_flag());
1203 }
1204