1 #include "road_access.h"
2 
3 #include "building/building.h"
4 #include "building/roadblock.h"
5 #include "building/rotation.h"
6 #include "core/config.h"
7 #include "city/map.h"
8 #include "map/building.h"
9 #include "map/grid.h"
10 #include "map/property.h"
11 #include "map/road_network.h"
12 #include "map/routing.h"
13 #include "map/routing_terrain.h"
14 #include "map/terrain.h"
15 
find_minimum_road_tile(int x,int y,int size,int * min_value,int * min_grid_offset)16 static void find_minimum_road_tile(int x, int y, int size, int *min_value, int *min_grid_offset)
17 {
18     int base_offset = map_grid_offset(x, y);
19     for (const int *tile_delta = map_grid_adjacent_offsets(size); *tile_delta; tile_delta++) {
20         int grid_offset = base_offset + *tile_delta;
21         if (!map_terrain_is(grid_offset, TERRAIN_BUILDING) ||
22             building_get(map_building_at(grid_offset))->type != BUILDING_GATEHOUSE) {
23             if (map_terrain_is(grid_offset, TERRAIN_ROAD)) {
24                 if (building_type_is_roadblock(building_get(map_building_at(grid_offset))->type)) {
25                     continue;
26                 }
27                 int road_index = city_map_road_network_index(map_road_network_get(grid_offset));
28                 if (road_index < *min_value) {
29                     *min_value = road_index;
30                     *min_grid_offset = grid_offset;
31                 }
32             }
33         }
34     }
35 }
36 
map_has_road_access(int x,int y,int size,map_point * road)37 int map_has_road_access(int x, int y, int size, map_point *road)
38 {
39     return map_has_road_access_rotation(0, x, y, size, road);
40 }
41 
map_has_road_access_rotation(int rotation,int x,int y,int size,map_point * road)42 int map_has_road_access_rotation(int rotation, int x, int y, int size, map_point *road)
43 {
44     switch (rotation) {
45         case 3:
46             x = x - size + 1;
47             break;
48         case 2:
49             x = x - size + 1;
50             y = y - size + 1;
51             break;
52         case 1:
53             y = y - size + 1;
54             break;
55         default:
56             break;
57     }
58     int min_value = 12;
59     int min_grid_offset = map_grid_offset(x, y);
60     find_minimum_road_tile(x, y, size, &min_value, &min_grid_offset);
61     if (min_value < 12) {
62         if (road) {
63             map_point_store_result(map_grid_offset_to_x(min_grid_offset),
64                 map_grid_offset_to_y(min_grid_offset), road);
65         }
66         return 1;
67     }
68     return 0;
69 }
70 
map_has_road_access_hippodrome_rotation(int x,int y,map_point * road,int rotation)71 int map_has_road_access_hippodrome_rotation(int x, int y, map_point *road, int rotation)
72 {
73     int min_value = 12;
74     int min_grid_offset = map_grid_offset(x, y);
75     int x_offset, y_offset;
76     building_rotation_get_offset_with_rotation(5, rotation, &x_offset, &y_offset);
77     find_minimum_road_tile(x, y, 5, &min_value, &min_grid_offset);
78     find_minimum_road_tile(x + x_offset, y + y_offset, 5, &min_value, &min_grid_offset);
79     building_rotation_get_offset_with_rotation(10, rotation, &x_offset, &y_offset);
80     find_minimum_road_tile(x + x_offset, y + y_offset, 5, &min_value, &min_grid_offset);
81     if (min_value < 12) {
82         if (road) {
83             map_point_store_result(map_grid_offset_to_x(min_grid_offset), map_grid_offset_to_y(min_grid_offset), road);
84         }
85         return 1;
86     }
87     return 0;
88 }
89 
map_has_road_access_hippodrome(int x,int y,map_point * road)90 int map_has_road_access_hippodrome(int x, int y, map_point *road)
91 {
92     return map_has_road_access_hippodrome_rotation(x, y, road, building_rotation_get_rotation());
93 }
94 
map_has_road_access_granary(int x,int y,map_point * road)95 int map_has_road_access_granary(int x, int y, map_point *road)
96 {
97     int rx = -1, ry = -1;
98     if (map_terrain_is(map_grid_offset(x + 1, y - 1), TERRAIN_ROAD) &&
99         (!building_type_is_roadblock(building_get(map_building_at(map_grid_offset(x + 1, y - 1)))->type))) {
100         rx = x + 1;
101         ry = y - 1;
102     } else if (map_terrain_is(map_grid_offset(x + 3, y + 1), TERRAIN_ROAD) &&
103         (!building_type_is_roadblock(building_get(map_building_at(map_grid_offset(x + 3, y + 1)))->type ))) {
104         rx = x + 3;
105         ry = y + 1;
106     } else if (map_terrain_is(map_grid_offset(x + 1, y + 3), TERRAIN_ROAD) &&
107         (!building_type_is_roadblock(building_get(map_building_at(map_grid_offset(x + 1, y + 3)))->type))) {
108         rx = x + 1;
109         ry = y + 3;
110     } else if (map_terrain_is(map_grid_offset(x - 1, y + 1), TERRAIN_ROAD) &&
111         (!building_type_is_roadblock(building_get(map_building_at(map_grid_offset(x - 1, y + 1)))->type))) {
112         rx = x - 1;
113         ry = y + 1;
114     }
115     if (rx >= 0 && ry >= 0) {
116         if (road) {
117             map_point_store_result(rx, ry, road);
118         }
119         return 1;
120     }
121     return 0;
122 }
123 
map_has_road_access_monument_size7(int x,int y,map_point * road)124 int map_has_road_access_monument_size7(int x, int y, map_point *road)
125 {
126     int min_value = 12;
127     int min_grid_offset = map_grid_offset(x, y);
128     find_minimum_road_tile(x, y + 3, 1, &min_value, &min_grid_offset);
129     find_minimum_road_tile(x + 3, y, 1, &min_value, &min_grid_offset);
130     find_minimum_road_tile(x + 3, y + 6, 1, &min_value, &min_grid_offset);
131     find_minimum_road_tile(x + 6, y + 3, 1, &min_value, &min_grid_offset);
132 
133     if (min_value < 12) {
134         if (road) {
135             map_point_store_result(map_grid_offset_to_x(min_grid_offset), map_grid_offset_to_y(min_grid_offset), road);
136         }
137         return 1;
138     }
139     return 0;
140 }
141 
map_has_road_access_monument_size5(int x,int y,map_point * road)142 int map_has_road_access_monument_size5(int x, int y, map_point *road)
143 {
144     int min_value = 12;
145     int min_grid_offset = map_grid_offset(x, y);
146     find_minimum_road_tile(x, y + 2, 1, &min_value, &min_grid_offset);
147     find_minimum_road_tile(x + 2, y, 1, &min_value, &min_grid_offset);
148     find_minimum_road_tile(x + 2, y + 4, 1, &min_value, &min_grid_offset);
149     find_minimum_road_tile(x + 4, y + 2, 1, &min_value, &min_grid_offset);
150     if (min_value < 12) {
151         if (road) {
152             map_point_store_result(map_grid_offset_to_x(min_grid_offset), map_grid_offset_to_y(min_grid_offset), road);
153         }
154         return 1;
155     }
156     return 0;
157 }
158 
map_has_road_access_monument_size3(int x,int y,map_point * road)159 int map_has_road_access_monument_size3(int x, int y, map_point *road)
160 {
161     int min_value = 12;
162     int min_grid_offset = map_grid_offset(x, y);
163     find_minimum_road_tile(x, y + 1, 1, &min_value, &min_grid_offset);
164     find_minimum_road_tile(x + 1, y, 1, &min_value, &min_grid_offset);
165     find_minimum_road_tile(x + 1, y + 2, 1, &min_value, &min_grid_offset);
166     find_minimum_road_tile(x + 2, y + 1, 1, &min_value, &min_grid_offset);
167     if (min_value < 12) {
168         if (road) {
169             map_point_store_result(map_grid_offset_to_x(min_grid_offset), map_grid_offset_to_y(min_grid_offset), road);
170         }
171         return 1;
172     }
173     return 0;
174 }
175 
map_has_road_access_monument_size4(int x,int y,map_point * road)176 int map_has_road_access_monument_size4(int x, int y, map_point *road)
177 {
178     int min_value = 12;
179     int min_grid_offset = map_grid_offset(x, y);
180     find_minimum_road_tile(x + 1, y + 3, 1, &min_value, &min_grid_offset);
181     find_minimum_road_tile(x + 2, y + 3, 1, &min_value, &min_grid_offset);
182     find_minimum_road_tile(x + 3, y + 1, 1, &min_value, &min_grid_offset);
183     find_minimum_road_tile(x + 3, y + 2, 1, &min_value, &min_grid_offset);
184     find_minimum_road_tile(x, y + 1, 1, &min_value, &min_grid_offset);
185     find_minimum_road_tile(x, y + 2, 1, &min_value, &min_grid_offset);
186     find_minimum_road_tile(x + 1, y, 1, &min_value, &min_grid_offset);
187     find_minimum_road_tile(x + 2, y, 1, &min_value, &min_grid_offset);
188 
189 
190     if (min_value < 12) {
191         if (road) {
192             map_point_store_result(map_grid_offset_to_x(min_grid_offset), map_grid_offset_to_y(min_grid_offset), road);
193         }
194         return 1;
195     }
196     return 0;
197 }
198 
road_within_radius(int x,int y,int size,int radius,int * x_road,int * y_road)199 static int road_within_radius(int x, int y, int size, int radius, int *x_road, int *y_road)
200 {
201     int x_min, y_min, x_max, y_max;
202     map_grid_get_area(x, y, size, radius, &x_min, &y_min, &x_max, &y_max);
203 
204     for (int yy = y_min; yy <= y_max; yy++) {
205         for (int xx = x_min; xx <= x_max; xx++) {
206             if (map_terrain_is(map_grid_offset(xx, yy), TERRAIN_ROAD)) {
207                 // Don't spawn walkers on roadblocks
208                 if (building_type_is_roadblock(building_get(map_building_at(map_grid_offset(xx, yy)))->type)) {
209                     continue;
210                 }
211                 if (x_road && y_road) {
212                     *x_road = xx;
213                     *y_road = yy;
214                 }
215                 return 1;
216             }
217         }
218     }
219     return 0;
220 }
221 
map_closest_road_within_radius(int x,int y,int size,int radius,int * x_road,int * y_road)222 int map_closest_road_within_radius(int x, int y, int size, int radius, int *x_road, int *y_road)
223 {
224     for (int r = 1; r <= radius; r++) {
225         if (road_within_radius(x, y, size, r, x_road, y_road)) {
226             return 1;
227         }
228     }
229     return 0;
230 }
231 
reachable_road_within_radius(int x,int y,int size,int radius,int * x_road,int * y_road)232 static int reachable_road_within_radius(int x, int y, int size, int radius, int *x_road, int *y_road)
233 {
234     int x_min, y_min, x_max, y_max;
235     map_grid_get_area(x, y, size, radius, &x_min, &y_min, &x_max, &y_max);
236 
237     for (int yy = y_min; yy <= y_max; yy++) {
238         for (int xx = x_min; xx <= x_max; xx++) {
239             int grid_offset = map_grid_offset(xx, yy);
240             if (map_terrain_is(grid_offset, TERRAIN_ROAD)) {
241                 if (map_routing_distance(grid_offset) > 0) {
242                     if (x_road && y_road) {
243                         *x_road = xx;
244                         *y_road = yy;
245                     }
246                     return 1;
247                 }
248             }
249         }
250     }
251     return 0;
252 }
253 
map_closest_reachable_road_within_radius(int x,int y,int size,int radius,int * x_road,int * y_road)254 int map_closest_reachable_road_within_radius(int x, int y, int size, int radius, int *x_road, int *y_road)
255 {
256     for (int r = 1; r <= radius; r++) {
257         if (reachable_road_within_radius(x, y, size, r, x_road, y_road)) {
258             return 1;
259         }
260     }
261     return 0;
262 }
263 
map_road_to_largest_network_rotation(int rotation,int x,int y,int size,int * x_road,int * y_road)264 int map_road_to_largest_network_rotation(int rotation, int x, int y, int size, int *x_road, int *y_road)
265 {
266     switch (rotation) {
267         case 1:
268             x = x - size + 1;
269             break;
270         case 2:
271             x = x - size + 1;
272             y = y - size + 1;
273             break;
274         case 3:
275             y = y - size + 1;
276             break;
277         default:
278             break;
279     }
280     int min_index = 12;
281     int min_grid_offset = -1;
282     int base_offset = map_grid_offset(x, y);
283     for (const int *tile_delta = map_grid_adjacent_offsets(size); *tile_delta; tile_delta++) {
284         int grid_offset = base_offset + *tile_delta;
285         if (map_terrain_is(grid_offset, TERRAIN_ROAD) && map_routing_distance(grid_offset) > 0) {
286             int index = city_map_road_network_index(map_road_network_get(grid_offset));
287             if (index < min_index) {
288                 min_index = index;
289                 min_grid_offset = grid_offset;
290             }
291         }
292     }
293     if (min_index < 12) {
294         *x_road = map_grid_offset_to_x(min_grid_offset);
295         *y_road = map_grid_offset_to_y(min_grid_offset);
296         return min_grid_offset;
297     }
298     int min_dist = 100000;
299     min_grid_offset = -1;
300     for (const int *tile_delta = map_grid_adjacent_offsets(size); *tile_delta; tile_delta++) {
301         int grid_offset = base_offset + *tile_delta;
302         int dist = map_routing_distance(grid_offset);
303         if (dist > 0 && dist < min_dist) {
304             min_dist = dist;
305             min_grid_offset = grid_offset;
306         }
307     }
308     if (min_grid_offset >= 0) {
309         *x_road = map_grid_offset_to_x(min_grid_offset);
310         *y_road = map_grid_offset_to_y(min_grid_offset);
311         return min_grid_offset;
312     }
313     return -1;
314 }
map_road_to_largest_network(int x,int y,int size,int * x_road,int * y_road)315 int map_road_to_largest_network(int x, int y, int size, int *x_road, int *y_road)
316 {
317     return map_road_to_largest_network_rotation(0, x, y, size, x_road, y_road);
318 }
319 
check_road_to_largest_network_hippodrome(int x,int y,int * min_index,int * min_grid_offset)320 static void check_road_to_largest_network_hippodrome(int x, int y, int *min_index, int *min_grid_offset)
321 {
322     int base_offset = map_grid_offset(x, y);
323     for (const int *tile_delta = map_grid_adjacent_offsets(5); *tile_delta; tile_delta++) {
324         int grid_offset = base_offset + *tile_delta;
325         if (map_terrain_is(grid_offset, TERRAIN_ROAD) && map_routing_distance(grid_offset) > 0) {
326             int index = city_map_road_network_index(map_road_network_get(grid_offset));
327             if (index < *min_index) {
328                 *min_index = index;
329                 *min_grid_offset = grid_offset;
330             }
331         }
332     }
333 }
334 
335 
check_min_dist_hippodrome(int base_offset,int x_offset,int * min_dist,int * min_grid_offset,int * min_x_offset)336 static void check_min_dist_hippodrome(int base_offset, int x_offset,
337     int *min_dist, int *min_grid_offset, int *min_x_offset)
338 {
339     for (const int *tile_delta = map_grid_adjacent_offsets(5); *tile_delta; tile_delta++) {
340         int grid_offset = base_offset + *tile_delta;
341         int dist = map_routing_distance(grid_offset);
342         if (dist > 0 && dist < *min_dist) {
343             *min_dist = dist;
344             *min_grid_offset = grid_offset;
345             *min_x_offset = x_offset;
346         }
347     }
348 }
349 
map_road_to_largest_network_hippodrome(int x,int y,int * x_road,int * y_road,int rotated)350 int map_road_to_largest_network_hippodrome(int x, int y, int *x_road, int *y_road, int rotated)
351 {
352     int min_index = 12;
353     int min_grid_offset = -1;
354     if (rotated) {
355         check_road_to_largest_network_hippodrome(x, y, &min_index, &min_grid_offset);
356         check_road_to_largest_network_hippodrome(x, y + 5, &min_index, &min_grid_offset);
357         check_road_to_largest_network_hippodrome(x, y + 10, &min_index, &min_grid_offset);
358     } else {
359         check_road_to_largest_network_hippodrome(x, y, &min_index, &min_grid_offset);
360         check_road_to_largest_network_hippodrome(x + 5, y, &min_index, &min_grid_offset);
361         check_road_to_largest_network_hippodrome(x + 10, y, &min_index, &min_grid_offset);
362     }
363 
364     if (min_index < 12) {
365         *x_road = map_grid_offset_to_x(min_grid_offset);
366         *y_road = map_grid_offset_to_y(min_grid_offset);
367         return min_grid_offset;
368     }
369 
370     int min_dist = 100000;
371     min_grid_offset = -1;
372     int min_x_offset = -1;
373     if (rotated) {
374         check_min_dist_hippodrome(map_grid_offset(x, y), 0, &min_dist, &min_grid_offset, &min_x_offset);
375         check_min_dist_hippodrome(map_grid_offset(x, y + 5), 5, &min_dist, &min_grid_offset, &min_x_offset);
376         check_min_dist_hippodrome(map_grid_offset(x, y + 10), 10, &min_dist, &min_grid_offset, &min_x_offset);
377     } else {
378         check_min_dist_hippodrome(map_grid_offset(x, y), 0, &min_dist, &min_grid_offset, &min_x_offset);
379         check_min_dist_hippodrome(map_grid_offset(x + 5, y), 5, &min_dist, &min_grid_offset, &min_x_offset);
380         check_min_dist_hippodrome(map_grid_offset(x + 10, y), 10, &min_dist, &min_grid_offset, &min_x_offset);
381     }
382     if (min_grid_offset >= 0) {
383         *x_road = map_grid_offset_to_x(min_grid_offset) + min_x_offset;
384         *y_road = map_grid_offset_to_y(min_grid_offset);
385         return min_grid_offset + min_x_offset;
386     }
387     return -1;
388 }
389 
check_road_to_largest_network_monument(int x,int y,int * min_index,int * min_grid_offset)390 static void check_road_to_largest_network_monument(int x, int y, int *min_index, int *min_grid_offset)
391 {
392     int base_offset = map_grid_offset(x, y);
393     for (const int *tile_delta = map_grid_adjacent_offsets(1); *tile_delta; tile_delta++) {
394         int grid_offset = base_offset + *tile_delta;
395         if (map_terrain_is(grid_offset, TERRAIN_ROAD) && map_routing_distance(grid_offset) > 0) {
396             int index = city_map_road_network_index(map_road_network_get(grid_offset));
397             if (index < *min_index) {
398                 *min_index = index;
399                 *min_grid_offset = grid_offset;
400             }
401         }
402     }
403 }
404 
map_road_to_largest_network_grand_temple(int x,int y,int * x_road,int * y_road)405 int map_road_to_largest_network_grand_temple(int x, int y, int *x_road, int *y_road)
406 {
407     int min_index = 12;
408     int min_grid_offset = -1;
409     check_road_to_largest_network_monument(x + 3, y + 6, &min_index, &min_grid_offset);
410     check_road_to_largest_network_monument(x + 6, y + 3, &min_index, &min_grid_offset);
411     check_road_to_largest_network_monument(x + 3, y, &min_index, &min_grid_offset);
412     check_road_to_largest_network_monument(x, y + 3, &min_index, &min_grid_offset);
413 
414     if (min_index < 12) {
415         *x_road = map_grid_offset_to_x(min_grid_offset);
416         *y_road = map_grid_offset_to_y(min_grid_offset);
417         return min_grid_offset;
418     }
419 
420     return -1;
421 }
422 
map_road_to_largest_network_colosseum(int x,int y,int * x_road,int * y_road)423 int map_road_to_largest_network_colosseum(int x, int y, int *x_road, int *y_road)
424 {
425     int min_index = 12;
426     int min_grid_offset = -1;
427     check_road_to_largest_network_monument(x + 2, y + 4, &min_index, &min_grid_offset);
428     check_road_to_largest_network_monument(x + 4, y + 2, &min_index, &min_grid_offset);
429     check_road_to_largest_network_monument(x + 2, y, &min_index, &min_grid_offset);
430     check_road_to_largest_network_monument(x, y + 2, &min_index, &min_grid_offset);
431 
432     if (min_index < 12) {
433         *x_road = map_grid_offset_to_x(min_grid_offset);
434         *y_road = map_grid_offset_to_y(min_grid_offset);
435         return min_grid_offset;
436     }
437 
438     return -1;
439 }
440 
map_road_to_largest_network_lighthouse(int x,int y,int * x_road,int * y_road)441 int map_road_to_largest_network_lighthouse(int x, int y, int *x_road, int *y_road)
442 {
443     int min_index = 12;
444     int min_grid_offset = -1;
445     check_road_to_largest_network_monument(x + 1, y, &min_index, &min_grid_offset);
446     check_road_to_largest_network_monument(x, y + 1, &min_index, &min_grid_offset);
447     check_road_to_largest_network_monument(x + 2, y + 1, &min_index, &min_grid_offset);
448     check_road_to_largest_network_monument(x + 1, y + 2, &min_index, &min_grid_offset);
449 
450     if (min_index < 12) {
451         *x_road = map_grid_offset_to_x(min_grid_offset);
452         *y_road = map_grid_offset_to_y(min_grid_offset);
453         return min_grid_offset;
454     }
455 
456     return -1;
457 }
458 
map_road_to_largest_network_caravanserai(int x,int y,int * x_road,int * y_road)459 int map_road_to_largest_network_caravanserai(int x, int y, int *x_road, int *y_road)
460 {
461     int min_index = 12;
462     int min_grid_offset = -1;
463     check_road_to_largest_network_monument(x + 1, y + 3, &min_index, &min_grid_offset);
464     check_road_to_largest_network_monument(x + 2, y + 3, &min_index, &min_grid_offset);
465     check_road_to_largest_network_monument(x + 3, y + 1, &min_index, &min_grid_offset);
466     check_road_to_largest_network_monument(x + 3, y + 2, &min_index, &min_grid_offset);
467     check_road_to_largest_network_monument(x + 1, y, &min_index, &min_grid_offset);
468     check_road_to_largest_network_monument(x + 2, y, &min_index, &min_grid_offset);
469     check_road_to_largest_network_monument(x, y + 1, &min_index, &min_grid_offset);
470     check_road_to_largest_network_monument(x, y + 2, &min_index, &min_grid_offset);
471 
472     if (min_index < 12) {
473         *x_road = map_grid_offset_to_x(min_grid_offset);
474         *y_road = map_grid_offset_to_y(min_grid_offset);
475         return min_grid_offset;
476     }
477 
478     return -1;
479 }
480 
terrain_is_road_like(int grid_offset)481 static int terrain_is_road_like(int grid_offset)
482 {
483     return map_terrain_is(grid_offset, TERRAIN_ROAD | TERRAIN_ACCESS_RAMP) ? 1 : 0;
484 }
485 
get_adjacent_road_tile_for_roaming(int grid_offset,roadblock_permission perm)486 static int get_adjacent_road_tile_for_roaming(int grid_offset, roadblock_permission perm)
487 {
488     int is_road = terrain_is_road_like(grid_offset);
489     if (map_terrain_is(grid_offset, TERRAIN_BUILDING)) {
490         building *b = building_get(map_building_at(grid_offset));
491         if (b->type == BUILDING_GATEHOUSE) {
492             is_road = 0;
493         } else if (building_type_is_roadblock(b->type)) {
494             if (!building_roadblock_get_permission(perm, b)) {
495                 is_road = 0;
496             }
497         } else if (b->type == BUILDING_GRANARY) {
498             if (map_routing_citizen_is_road(grid_offset)) {
499                 if (map_property_multi_tile_xy(grid_offset) == EDGE_X1Y1 ||
500                     map_has_adjacent_road_tiles(grid_offset) || map_has_adjacent_granary_road(grid_offset)) {
501                     is_road = 1;
502                 }
503             }
504         } else if (b->type == BUILDING_TRIUMPHAL_ARCH) {
505             if (map_routing_citizen_is_road(grid_offset)) {
506                 is_road = 1;
507             }
508         }
509     }
510     return is_road;
511 }
512 
map_get_adjacent_road_tiles_for_roaming(int grid_offset,int * road_tiles,int perm)513 int map_get_adjacent_road_tiles_for_roaming(int grid_offset, int *road_tiles, int perm)
514 {
515     road_tiles[1] = road_tiles[3] = road_tiles[5] = road_tiles[7] = 0;
516 
517     road_tiles[0] = get_adjacent_road_tile_for_roaming(grid_offset + map_grid_delta(0, -1), perm);
518     road_tiles[2] = get_adjacent_road_tile_for_roaming(grid_offset + map_grid_delta(1, 0), perm);
519     road_tiles[4] = get_adjacent_road_tile_for_roaming(grid_offset + map_grid_delta(0, 1), perm);
520     road_tiles[6] = get_adjacent_road_tile_for_roaming(grid_offset + map_grid_delta(-1, 0), perm);
521 
522     return road_tiles[0] + road_tiles[2] + road_tiles[4] + road_tiles[6];
523 }
524 
map_get_diagonal_road_tiles_for_roaming(int grid_offset,int * road_tiles)525 int map_get_diagonal_road_tiles_for_roaming(int grid_offset, int *road_tiles)
526 {
527     road_tiles[1] = terrain_is_road_like(grid_offset + map_grid_delta(1, -1));
528     road_tiles[3] = terrain_is_road_like(grid_offset + map_grid_delta(1, 1));
529     road_tiles[5] = terrain_is_road_like(grid_offset + map_grid_delta(-1, 1));
530     road_tiles[7] = terrain_is_road_like(grid_offset + map_grid_delta(-1, -1));
531 
532     int max_stretch = 0;
533     int stretch = 0;
534     for (int i = 0; i < 16; i++) {
535         if (road_tiles[i % 8]) {
536             stretch++;
537             if (stretch > max_stretch) {
538                 max_stretch = stretch;
539             }
540         } else {
541             stretch = 0;
542         }
543     }
544     return max_stretch;
545 }
546 
map_has_adjacent_road_tiles(int grid_offset)547 int map_has_adjacent_road_tiles(int grid_offset)
548 {
549     int tiles[4];
550     tiles[0] = grid_offset + map_grid_delta(0, -1);
551     tiles[1] = grid_offset + map_grid_delta(1, 0);
552     tiles[2] = grid_offset + map_grid_delta(0, 1);
553     tiles[3] = grid_offset + map_grid_delta(-1, 0);
554     int adjacent_roads = 0;
555     for (int i = 0; i < 4; i++) {
556         building *b = building_get(map_building_at(tiles[i]));
557         if (!building_type_is_roadblock(b->type)) {
558             adjacent_roads += terrain_is_road_like(tiles[i]);
559         }
560     }
561     return adjacent_roads;
562 }
563 
map_has_adjacent_granary_road(int grid_offset)564 int map_has_adjacent_granary_road(int grid_offset)
565 {
566     int tiles[4];
567     tiles[0] = grid_offset + map_grid_delta(0, -1);
568     tiles[1] = grid_offset + map_grid_delta(1, 0);
569     tiles[2] = grid_offset + map_grid_delta(0, 1);
570     tiles[3] = grid_offset + map_grid_delta(-1, 0);
571     for (int i = 0; i < 4; i++) {
572         if (building_get(map_building_at(tiles[i]))->type != BUILDING_GRANARY) {
573             continue;
574         }
575         switch (map_property_multi_tile_xy(tiles[i])) {
576             case EDGE_X1Y0:
577             case EDGE_X0Y1:
578             case EDGE_X2Y1:
579             case EDGE_X1Y2:
580                 return 1;
581         }
582     }
583     return 0;
584 }
585