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