1 #include "monument.h"
2 
3 #include "assets/assets.h"
4 #include "building/image.h"
5 #include "building/model.h"
6 #include "city/finance.h"
7 #include "city/message.h"
8 #include "city/resource.h"
9 #include "core/array.h"
10 #include "core/calc.h"
11 #include "core/log.h"
12 #include "map/building_tiles.h"
13 #include "map/grid.h"
14 #include "map/orientation.h"
15 #include "map/road_access.h"
16 #include "map/terrain.h"
17 #include "scenario/property.h"
18 
19 #define MONUMENTS_SIZE_STEP 100
20 #define DELIVERY_ARRAY_SIZE_STEP 200
21 #define ORIGINAL_DELIVERY_BUFFER_SIZE 16
22 #define MODULES_PER_TEMPLE 2
23 #define INFINITE 10000
24 
25 static int grand_temple_resources[6][RESOURCE_MAX] = {
26     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0 },
27     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 20, 0, 0, 0 },
28     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 16, 0, 0, 0 },
29     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 28, 12, 0, 0, 0 },
30     { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
31     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
32 };
33 static int pantheon_resources[6][RESOURCE_MAX] = {
34     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0 },
35     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 16, 0, 0, 0 },
36     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 32, 0, 0, 0 },
37     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 40, 32, 0, 0, 0 },
38     { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
39     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
40 };
41 static int lighthouse_resources[5][RESOURCE_MAX] = {
42     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0 },
43     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 12, 0, 0, 0 },
44     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 8, 0, 0, 0 },
45     { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 20, 8, 0, 0, 0 },
46     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
47 };
48 static int colosseum_resources[5][RESOURCE_MAX] = {
49     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0 },
50     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 16, 0, 0, 0 },
51     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 16, 0, 0, 0 },
52     { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 16, 12, 0, 0, 0 },
53     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
54 };
55 static int hippodrome_resources[5][RESOURCE_MAX] = {
56     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0 },
57     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 32, 0, 0, 0 },
58     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 32, 0, 0, 0 },
59     { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 46, 32, 0, 0, 0 },
60     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
61 };
62 static int oracle_lt_resources[2][RESOURCE_MAX] = {
63     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0 },
64     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
65 };
66 static int large_temple_resources[2][RESOURCE_MAX] = {
67     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0 },
68     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
69 };
70 static int nymphaeum_resources[2][RESOURCE_MAX] = {
71     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0 },
72     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
73 };
74 static int small_mausoleum_resources[2][RESOURCE_MAX] = {
75     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0 },
76     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
77 };
78 static int large_mausoleum_resources[2][RESOURCE_MAX] = {
79     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0 },
80     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
81 };
82 static int caravanserai_resources[2][RESOURCE_MAX] = {
83     { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 8, 6, 0, 0, 0 },
84     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
85 };
86 
87 static const building_type MONUMENT_BUILDING_TYPES[] = {
88     BUILDING_ORACLE,
89     BUILDING_LARGE_TEMPLE_CERES,
90     BUILDING_LARGE_TEMPLE_NEPTUNE,
91     BUILDING_LARGE_TEMPLE_MERCURY,
92     BUILDING_LARGE_TEMPLE_MARS,
93     BUILDING_LARGE_TEMPLE_VENUS,
94     BUILDING_GRAND_TEMPLE_CERES,
95     BUILDING_GRAND_TEMPLE_NEPTUNE,
96     BUILDING_GRAND_TEMPLE_MERCURY,
97     BUILDING_GRAND_TEMPLE_MARS,
98     BUILDING_GRAND_TEMPLE_VENUS,
99     BUILDING_PANTHEON,
100     BUILDING_LIGHTHOUSE,
101     BUILDING_COLOSSEUM,
102     BUILDING_HIPPODROME,
103     BUILDING_NYMPHAEUM,
104     BUILDING_LARGE_MAUSOLEUM,
105     BUILDING_SMALL_MAUSOLEUM,
106     BUILDING_CARAVANSERAI
107 };
108 
109 #define MAX_MONUMENT_TYPES (sizeof(MONUMENT_BUILDING_TYPES) / sizeof(building_type))
110 
111 typedef struct {
112     int walker_id;
113     int destination_id;
114     int resource;
115     int cartloads;
116 } monument_delivery;
117 
118 array(monument_delivery) monument_deliveries;
119 
building_monument_deliver_resource(building * b,int resource)120 int building_monument_deliver_resource(building *b, int resource)
121 {
122     if (b->id <= 0 || !building_monument_is_monument(b) ||
123         b->data.monument.resources_needed[resource] <= 0) {
124         return 0;
125     }
126 
127     while (b->prev_part_building_id) {
128         b = building_get(b->prev_part_building_id);
129     }
130 
131     b->data.monument.resources_needed[resource]--;
132 
133     while (b->next_part_building_id) {
134         b = building_get(b->next_part_building_id);
135         b->data.monument.resources_needed[resource]--;
136     }
137     return 1;
138 }
139 
building_monument_access_point(building * b,map_point * dst)140 int building_monument_access_point(building *b, map_point *dst)
141 {
142     int dx = b->x - b->road_access_x;
143     int dy = b->y - b->road_access_y;
144     switch (b->type) {
145         default:
146             return 0;
147         case BUILDING_LARGE_TEMPLE_CERES:
148         case BUILDING_LARGE_TEMPLE_NEPTUNE:
149         case BUILDING_LARGE_TEMPLE_MERCURY:
150         case BUILDING_LARGE_TEMPLE_MARS:
151         case BUILDING_LARGE_TEMPLE_VENUS:
152         case BUILDING_LIGHTHOUSE:
153         case BUILDING_NYMPHAEUM:
154         case BUILDING_LARGE_MAUSOLEUM:
155             if (dx == -1 && dy == -3) {
156                 dst->x = b->x + 1;
157                 dst->y = b->y + 2;
158             } else if (dx == 1 && dy == -1) {
159                 dst->x = b->x;
160                 dst->y = b->y + 1;
161             } else if (dx == -3 && dy == -1) {
162                 dst->x = b->x + 2;
163                 dst->y = b->y + 1;
164             } else if (dx == -1 && dy == 1) {
165                 dst->x = b->x + 1;
166                 dst->y = b->y;
167             } else {
168                 return 0;
169             }
170             return 1;
171         case BUILDING_GRAND_TEMPLE_CERES:
172         case BUILDING_GRAND_TEMPLE_NEPTUNE:
173         case BUILDING_GRAND_TEMPLE_MERCURY:
174         case BUILDING_GRAND_TEMPLE_MARS:
175         case BUILDING_GRAND_TEMPLE_VENUS:
176         case BUILDING_PANTHEON:
177             if (dx == -3 && dy == -7) {
178                 dst->x = b->x + 3;
179                 dst->y = b->y + 6;
180             } else if (dx == 1 && dy == -3) {
181                 dst->x = b->x;
182                 dst->y = b->y + 3;
183             } else if (dx == -3 && dy == 1) {
184                 dst->x = b->x + 3;
185                 dst->y = b->y;
186             } else if (dx == -7 && dy == -3) {
187                 dst->x = b->x + 6;
188                 dst->y = b->y + 3;
189             } else {
190                 return 0;
191             }
192             return 1;
193         case BUILDING_COLOSSEUM:
194             if (dx == -2 && dy == -5) {
195                 dst->x = b->x + 2;
196                 dst->y = b->y + 4;
197             } else if (dx == 1 && dy == -2) {
198                 dst->x = b->x;
199                 dst->y = b->y + 2;
200             } else if (dx == -2 && dy == 1) {
201                 dst->x = b->x + 2;
202                 dst->y = b->y;
203             } else if (dx == -5 && dy == -2) {
204                 dst->x = b->x + 4;
205                 dst->y = b->y + 2;
206             } else {
207                 return 0;
208             }
209             return 1;
210         case BUILDING_ORACLE:
211         case BUILDING_SMALL_MAUSOLEUM:
212         case BUILDING_HIPPODROME:
213             dst->x = b->x;
214             dst->y = b->y;
215             return 1;
216         case BUILDING_CARAVANSERAI:
217             if (dx == -2 && dy == -4) {
218                 dst->x = b->x + 2;
219                 dst->y = b->y + 3;
220             } else if (dx == -1 && dy == -4) {
221                 dst->x = b->x + 1;
222                 dst->y = b->y + 3;
223             } else if (dx == 1 && dy == -1) {
224                 dst->x = b->x;
225                 dst->y = b->y + 1;
226             } else if (dx == 1 && dy == -2) {
227                 dst->x = b->x;
228                 dst->y = b->y + 2;
229             } else if (dx == -2 && dy == 1) {
230                 dst->x = b->x + 2;
231                 dst->y = b->y;
232             } else if (dx == -1 && dy == 1) {
233                 dst->x = b->x + 1;
234                 dst->y = b->y;
235             } else if (dx == -4 && dy == -1) {
236                 dst->x = b->x + 3;
237                 dst->y = b->y + 1;
238             } else if (dx == -4 && dy == -2) {
239                 dst->x = b->x + 3;
240                 dst->y = b->y + 2;
241             } else {
242                 return 0;
243             }
244             return 1;
245     }
246     return 0;
247 }
248 
building_monument_add_module(building * b,int module_type)249 int building_monument_add_module(building *b, int module_type)
250 {
251     if (!building_monument_is_monument(b) ||
252         b->data.monument.phase != MONUMENT_FINISHED ||
253         (b->data.monument.upgrades && b->type != BUILDING_CARAVANSERAI && b->type != BUILDING_LIGHTHOUSE)) {
254         return 0;
255     }
256     b->data.monument.upgrades = module_type;
257     map_building_tiles_add(b->id, b->x, b->y, b->size, building_image_get(b), TERRAIN_BUILDING);
258     return 1;
259 }
260 
building_monument_get_monument(int x,int y,int resource,int road_network_id,int distance_from_entry,map_point * dst)261 int building_monument_get_monument(int x, int y, int resource, int road_network_id,
262     int distance_from_entry, map_point *dst)
263 {
264     if (city_resource_is_stockpiled(resource)) {
265         return 0;
266     }
267     int min_dist = INFINITE;
268     building *min_building = 0;
269     for (int i = 0; i < MAX_MONUMENT_TYPES; i++) {
270         building_type type = MONUMENT_BUILDING_TYPES[i];
271         for (building *b = building_first_of_type(type); b; b = b->next_of_type) {
272             if (b->data.monument.phase == MONUMENT_FINISHED ||
273                 b->data.monument.phase < MONUMENT_START ||
274                 building_monument_is_construction_halted(b) ||
275                 (!resource && building_monument_needs_resources(b))) {
276                 continue;
277             }
278             short needed = b->data.monument.resources_needed[resource];
279             if ((needed - building_monument_resource_in_delivery(b, resource)) <= 0) {
280                 continue;
281             }
282             if (!map_has_road_access(b->x, b->y, b->size, 0) ||
283                 b->distance_from_entry <= 0 || b->road_network_id != road_network_id) {
284                 continue;
285             }
286             int dist = calc_maximum_distance(b->x, b->y, x, y);
287             if (dist < min_dist) {
288                 min_dist = dist;
289                 min_building = b;
290             }
291         }
292     }
293     if (min_building && min_dist < INFINITE) {
294         if (dst) {
295             map_point_store_result(min_building->road_access_x, min_building->road_access_y, dst);
296         }
297         return min_building->id;
298     }
299     return 0;
300 }
301 
building_monument_has_unfinished_monuments(void)302 int building_monument_has_unfinished_monuments(void)
303 {
304     for (int i = 0; i < MAX_MONUMENT_TYPES; i++) {
305         building_type type = MONUMENT_BUILDING_TYPES[i];
306         for (building *b = building_first_of_type(type); b; b = b->next_of_type) {
307             if (b->data.monument.phase != MONUMENT_FINISHED) {
308                 return 1;
309             }
310         }
311     }
312     return 0;
313 }
314 
building_monument_resources_needed_for_monument_type(building_type type,int resource,int phase)315 int building_monument_resources_needed_for_monument_type(building_type type, int resource, int phase)
316 {
317     switch (type) {
318         case BUILDING_LARGE_TEMPLE_CERES:
319         case BUILDING_LARGE_TEMPLE_MERCURY:
320         case BUILDING_LARGE_TEMPLE_NEPTUNE:
321         case BUILDING_LARGE_TEMPLE_MARS:
322         case BUILDING_LARGE_TEMPLE_VENUS:
323             return large_temple_resources[phase - 1][resource];
324         case BUILDING_ORACLE:
325             return oracle_lt_resources[phase - 1][resource];
326         case BUILDING_GRAND_TEMPLE_CERES:
327         case BUILDING_GRAND_TEMPLE_MERCURY:
328         case BUILDING_GRAND_TEMPLE_NEPTUNE:
329         case BUILDING_GRAND_TEMPLE_MARS:
330         case BUILDING_GRAND_TEMPLE_VENUS:
331             return grand_temple_resources[phase - 1][resource];
332         case BUILDING_PANTHEON:
333             return pantheon_resources[phase - 1][resource];
334         case BUILDING_LIGHTHOUSE:
335             return lighthouse_resources[phase - 1][resource];
336         case BUILDING_COLOSSEUM:
337             return colosseum_resources[phase - 1][resource];
338         case BUILDING_HIPPODROME:
339             return hippodrome_resources[phase - 1][resource];
340         case BUILDING_NYMPHAEUM:
341             return nymphaeum_resources[phase - 1][resource];
342         case BUILDING_LARGE_MAUSOLEUM:
343             return large_mausoleum_resources[phase - 1][resource];
344         case BUILDING_SMALL_MAUSOLEUM:
345             return small_mausoleum_resources[phase - 1][resource];
346         case BUILDING_CARAVANSERAI:
347             return caravanserai_resources[phase - 1][resource];
348         default:
349             return 0;
350     }
351 }
352 
building_monument_set_phase(building * b,int phase)353 void building_monument_set_phase(building *b, int phase)
354 {
355     if (phase == building_monument_phases(b->type)) {
356         phase = MONUMENT_FINISHED;
357     }
358     if (phase == b->data.monument.phase) {
359         return;
360     }
361     b->data.monument.phase = phase;
362     map_building_tiles_add(b->id, b->x, b->y, b->size, building_image_get(b), TERRAIN_BUILDING);
363     if (b->data.monument.phase != MONUMENT_FINISHED) {
364         for (int resource = 0; resource < RESOURCE_MAX; resource++) {
365             b->data.monument.resources_needed[resource] =
366                 building_monument_resources_needed_for_monument_type(b->type, resource,
367                 b->data.monument.phase);
368         }
369     }
370 }
371 
building_monument_is_monument(const building * b)372 int building_monument_is_monument(const building *b)
373 {
374     return building_monument_type_is_monument(b->type);
375 }
376 
building_monument_type_is_monument(building_type type)377 int building_monument_type_is_monument(building_type type)
378 {
379     for (int i = 0; i < MAX_MONUMENT_TYPES; i++) {
380         if (type == MONUMENT_BUILDING_TYPES[i]) {
381             return 1;
382         }
383     }
384     return 0;
385 }
386 
building_monument_type_is_mini_monument(building_type type)387 int building_monument_type_is_mini_monument(building_type type)
388 {
389     switch (type) {
390         case BUILDING_ORACLE:
391         case BUILDING_LARGE_TEMPLE_CERES:
392         case BUILDING_LARGE_TEMPLE_NEPTUNE:
393         case BUILDING_LARGE_TEMPLE_MERCURY:
394         case BUILDING_LARGE_TEMPLE_MARS:
395         case BUILDING_LARGE_TEMPLE_VENUS:
396         case BUILDING_SMALL_MAUSOLEUM:
397         case BUILDING_LARGE_MAUSOLEUM:
398         case BUILDING_NYMPHAEUM:
399         case BUILDING_CARAVANSERAI:
400             return 1;
401         default:
402             return 0;
403     }
404 }
405 
building_monument_is_grand_temple(building_type type)406 int building_monument_is_grand_temple(building_type type)
407 {
408     switch (type) {
409         case BUILDING_GRAND_TEMPLE_CERES:
410         case BUILDING_GRAND_TEMPLE_NEPTUNE:
411         case BUILDING_GRAND_TEMPLE_MERCURY:
412         case BUILDING_GRAND_TEMPLE_MARS:
413         case BUILDING_GRAND_TEMPLE_VENUS:
414             return 1;
415         default:
416             return 0;
417     }
418 }
419 
building_monument_needs_resource(building * b,int resource)420 int building_monument_needs_resource(building *b, int resource)
421 {
422     if (b->data.monument.phase == MONUMENT_FINISHED) {
423         return 0;
424     }
425     return (b->data.monument.resources_needed[resource]);
426 }
427 
building_monuments_set_construction_phase(int phase)428 void building_monuments_set_construction_phase(int phase)
429 {
430     for (int i = 0; i < MAX_MONUMENT_TYPES; i++) {
431         building_type type = MONUMENT_BUILDING_TYPES[i];
432         for (building *b = building_first_of_type(type); b; b = b->next_of_type) {
433             building_monument_set_phase(b, phase);
434         }
435     }
436 }
437 
building_monument_get_venus_gt(void)438 int building_monument_get_venus_gt(void)
439 {
440     building *monument = building_first_of_type(BUILDING_GRAND_TEMPLE_VENUS);
441     return monument ? monument->id : 0;
442 }
443 
building_monument_get_neptune_gt(void)444 int building_monument_get_neptune_gt(void)
445 {
446     building *monument = building_first_of_type(BUILDING_GRAND_TEMPLE_NEPTUNE);
447     return monument ? monument->id : 0;
448 }
449 
building_monument_phases(building_type type)450 int building_monument_phases(building_type type)
451 {
452     switch (type) {
453         case BUILDING_PANTHEON:
454         case BUILDING_GRAND_TEMPLE_CERES:
455         case BUILDING_GRAND_TEMPLE_MERCURY:
456         case BUILDING_GRAND_TEMPLE_NEPTUNE:
457         case BUILDING_GRAND_TEMPLE_MARS:
458         case BUILDING_GRAND_TEMPLE_VENUS:
459             return 6;
460         case BUILDING_LIGHTHOUSE:
461         case BUILDING_COLOSSEUM:
462         case BUILDING_HIPPODROME:
463             return 5;
464         case BUILDING_ORACLE:
465         case BUILDING_LARGE_TEMPLE_CERES:
466         case BUILDING_LARGE_TEMPLE_NEPTUNE:
467         case BUILDING_LARGE_TEMPLE_MERCURY:
468         case BUILDING_LARGE_TEMPLE_MARS:
469         case BUILDING_LARGE_TEMPLE_VENUS:
470         case BUILDING_LARGE_MAUSOLEUM:
471         case BUILDING_SMALL_MAUSOLEUM:
472         case BUILDING_NYMPHAEUM:
473         case BUILDING_CARAVANSERAI:
474             return 2;
475         default:
476             return 0;
477     }
478 }
479 
building_monument_finish_monuments(void)480 void building_monument_finish_monuments(void)
481 {
482     for (int i = 0; i < MAX_MONUMENT_TYPES; i++) {
483         building_type type = MONUMENT_BUILDING_TYPES[i];
484         for (building *b = building_first_of_type(type); b; b = b->next_of_type) {
485             if (b->data.monument.phase == MONUMENT_FINISHED) {
486                 continue;
487             }
488             building_monument_set_phase(b, MONUMENT_FINISHED);
489             for (int resource = 0; resource < RESOURCE_MAX; resource++) {
490                 b->data.monument.resources_needed[resource] = 0;
491             }
492         }
493     }
494 }
495 
building_monument_needs_resources(building * b)496 int building_monument_needs_resources(building *b)
497 {
498     if (b->data.monument.phase == MONUMENT_FINISHED) {
499         return 0;
500     }
501     for (int resource = RESOURCE_MIN; resource < RESOURCE_MAX; resource++) {
502         if (b->data.monument.resources_needed[resource]) {
503             return 1;
504         }
505     }
506     return 0;
507 }
508 
building_monument_progress(building * b)509 int building_monument_progress(building *b)
510 {
511     if (building_monument_needs_resources(b)) {
512         return 0;
513     }
514     if (b->data.monument.phase == MONUMENT_FINISHED) {
515         return 0;
516     }
517     while (b->prev_part_building_id) {
518         b = building_get(b->prev_part_building_id);
519     }
520     building_monument_set_phase(b, b->data.monument.phase + 1);
521 
522     while (b->next_part_building_id) {
523         b = building_get(b->next_part_building_id);
524         building_monument_set_phase(b, b->data.monument.phase + 1);
525     }
526     if (b->data.monument.phase == MONUMENT_FINISHED) {
527         if (building_monument_is_grand_temple(b->type)) {
528             city_message_post(1, MESSAGE_GRAND_TEMPLE_COMPLETE, 0, b->grid_offset);
529         } else if (b->type == BUILDING_PANTHEON) {
530             city_message_post(1, MESSAGE_PANTHEON_COMPLETE, 0, b->grid_offset);
531         } else if (b->type == BUILDING_LIGHTHOUSE) {
532             city_message_post(1, MESSAGE_LIGHTHOUSE_COMPLETE, 0, b->grid_offset);
533         } else if (b->type == BUILDING_COLOSSEUM) {
534             city_message_post(1, MESSAGE_COLOSSEUM_COMPLETE, 0, b->grid_offset);
535         } else if (b->type == BUILDING_HIPPODROME) {
536             city_message_post(1, MESSAGE_HIPPODROME_COMPLETE, 0, b->grid_offset);
537         }
538     }
539     return 1;
540 }
541 
delivery_in_use(const monument_delivery * delivery)542 static int delivery_in_use(const monument_delivery *delivery)
543 {
544     return delivery->destination_id != 0;
545 }
546 
building_monument_initialize_deliveries(void)547 void building_monument_initialize_deliveries(void)
548 {
549     if (!array_init(monument_deliveries, DELIVERY_ARRAY_SIZE_STEP, 0, delivery_in_use)) {
550         log_error("Failed to create monument array. The game will likely crash.", 0, 0);
551     }
552 }
553 
building_monument_add_delivery(int monument_id,int figure_id,int resource_id,int loads_no)554 void building_monument_add_delivery(int monument_id, int figure_id, int resource_id, int loads_no)
555 {
556     monument_delivery *delivery;
557     array_new_item(monument_deliveries, 0, delivery);
558     if (!delivery) {
559         log_error("Failed to create a new monument delivery. The game maybe running out of memory", 0, 0);
560         return;
561     }
562     delivery->destination_id = monument_id;
563     delivery->walker_id = figure_id;
564     delivery->resource = resource_id;
565     delivery->cartloads = loads_no;
566 }
567 
building_monument_remove_delivery(int figure_id)568 void building_monument_remove_delivery(int figure_id)
569 {
570     monument_delivery *delivery;
571     array_foreach(monument_deliveries, delivery)
572     {
573         if (delivery->walker_id == figure_id) {
574             delivery->destination_id = 0;
575         }
576     }
577     array_trim(monument_deliveries);
578 }
579 
resource_in_delivery(int monument_id,int resource_id)580 static int resource_in_delivery(int monument_id, int resource_id)
581 {
582     int resources = 0;
583     monument_delivery *delivery;
584     array_foreach(monument_deliveries, delivery)
585     {
586         if (delivery->destination_id == monument_id &&
587             delivery->resource == resource_id) {
588             resources += delivery->cartloads;
589         }
590     }
591     return resources;
592 }
593 
resource_in_delivery_multipart(building * b,int resource_id)594 static int resource_in_delivery_multipart(building *b, int resource_id)
595 {
596     int resources = 0;
597 
598     while (b->prev_part_building_id) {
599         b = building_get(b->prev_part_building_id);
600     }
601 
602     while (b->id) {
603         monument_delivery *delivery;
604         array_foreach(monument_deliveries, delivery)
605         {
606             if (delivery->destination_id == b->id &&
607                 delivery->resource == resource_id) {
608                 resources += delivery->cartloads;
609             }
610         }
611         b = building_get(b->next_part_building_id);
612     }
613 
614     return resources;
615 }
616 
building_monument_resource_in_delivery(building * b,int resource_id)617 int building_monument_resource_in_delivery(building *b, int resource_id)
618 {
619     if (b->next_part_building_id || b->prev_part_building_id) {
620         return resource_in_delivery_multipart(b, resource_id);
621     } else {
622         return resource_in_delivery(b->id, resource_id);
623     }
624 }
625 
building_monument_has_monument(building_type type)626 int building_monument_has_monument(building_type type)
627 {
628     building *b = building_first_of_type(type);
629     if (!building_monument_type_is_monument(type) || !b) {
630         return 0;
631     }
632     return b->id;
633 }
634 
building_monument_count_grand_temples(void)635 int building_monument_count_grand_temples(void)
636 {
637     int count = 0;
638     static const building_type grand_temples[] = {
639         BUILDING_GRAND_TEMPLE_CERES,
640         BUILDING_GRAND_TEMPLE_NEPTUNE,
641         BUILDING_GRAND_TEMPLE_MERCURY,
642         BUILDING_GRAND_TEMPLE_MARS,
643         BUILDING_GRAND_TEMPLE_VENUS
644     };
645     for (int i = 0; i < 5; i++) {
646         building_type type = grand_temples[i];
647         for (building *b = building_first_of_type(type); b; b = b->next_of_type) {
648             count++;
649         }
650     }
651     return count;
652 }
653 
building_monument_has_labour_problems(building * b)654 int building_monument_has_labour_problems(building *b)
655 {
656     const model_building *model = model_get_building(b->type);
657 
658     if (b->num_workers < model->laborers) {
659         return 1;
660     } else {
661         return 0;
662     }
663 }
664 
building_monument_working(building_type type)665 int building_monument_working(building_type type)
666 {
667     int monument_id = building_monument_has_monument(type);
668     building *b = building_get(monument_id);
669     if (!monument_id) {
670         return 0;
671     }
672     if (b->data.monument.phase != MONUMENT_FINISHED || b->state != BUILDING_STATE_IN_USE) {
673         return 0;
674     }
675 
676     if (building_monument_has_labour_problems(b)) {
677         return 0;
678     }
679 
680     return monument_id;
681 }
682 
building_monument_upgraded(building_type type)683 int building_monument_upgraded(building_type type)
684 {
685     int monument_id = building_monument_working(type);
686     building *b = building_get(monument_id);
687     if (!monument_id) {
688         return 0;
689     }
690     if (!b->data.monument.upgrades) {
691         return 0;
692     }
693     return monument_id;
694 }
695 
building_monument_module_type(building_type type)696 int building_monument_module_type(building_type type)
697 {
698     int monument_id = building_monument_working(type);
699 
700     if (!monument_id) {
701         return 0;
702     }
703 
704     building *b = building_get(monument_id);
705     return b->data.monument.upgrades;
706 }
707 
building_monument_gt_module_is_active(int module)708 int building_monument_gt_module_is_active(int module)
709 {
710     int module_num = module % MODULES_PER_TEMPLE + 1;
711     int temple_type = module / MODULES_PER_TEMPLE + BUILDING_GRAND_TEMPLE_CERES;
712 
713     return building_monument_module_type(temple_type) == module_num;
714 }
715 
building_monument_pantheon_module_is_active(int module)716 int building_monument_pantheon_module_is_active(int module)
717 {
718     return building_monument_module_type(BUILDING_PANTHEON) == (module - (PANTHEON_MODULE_1_DESTINATION_PRIESTS - 1));
719 }
720 
delivery_save(buffer * buf,monument_delivery * delivery)721 static void delivery_save(buffer *buf, monument_delivery *delivery)
722 {
723     buffer_write_i32(buf, delivery->walker_id);
724     buffer_write_i32(buf, delivery->destination_id);
725     buffer_write_i32(buf, delivery->resource);
726     buffer_write_i32(buf, delivery->cartloads);
727 }
728 
delivery_load(buffer * buf,monument_delivery * delivery,int size)729 static void delivery_load(buffer *buf, monument_delivery *delivery, int size)
730 {
731     delivery->walker_id = buffer_read_i32(buf);
732     delivery->destination_id = buffer_read_i32(buf);
733     delivery->resource = buffer_read_i32(buf);
734     delivery->cartloads = buffer_read_i32(buf);
735 
736     if (size > ORIGINAL_DELIVERY_BUFFER_SIZE) {
737         buffer_skip(buf, size - ORIGINAL_DELIVERY_BUFFER_SIZE);
738     }
739 }
740 
building_monument_delivery_save_state(buffer * buf)741 void building_monument_delivery_save_state(buffer *buf)
742 {
743     int buf_size = 4 + monument_deliveries.size * ORIGINAL_DELIVERY_BUFFER_SIZE;
744     uint8_t *buf_data = malloc(buf_size);
745     buffer_init(buf, buf_data, buf_size);
746     buffer_write_i32(buf, ORIGINAL_DELIVERY_BUFFER_SIZE);
747 
748     monument_delivery *delivery;
749     array_foreach(monument_deliveries, delivery)
750     {
751         delivery_save(buf, delivery);
752     }
753 }
754 
building_monument_delivery_load_state(buffer * buf,int includes_delivery_buffer_size)755 void building_monument_delivery_load_state(buffer *buf, int includes_delivery_buffer_size)
756 {
757     int delivery_buf_size = ORIGINAL_DELIVERY_BUFFER_SIZE;
758     int buf_size = buf->size;
759 
760     if (includes_delivery_buffer_size) {
761         delivery_buf_size = buffer_read_i32(buf);
762         buf_size -= 4;
763     }
764 
765     int deliveries_to_load = buf_size / delivery_buf_size;
766 
767     if (!array_init(monument_deliveries, DELIVERY_ARRAY_SIZE_STEP, 0, delivery_in_use) ||
768         !array_expand(monument_deliveries, deliveries_to_load)) {
769         log_error("Failed to create the monument deliveries array. The game may crash.", 0, 0);
770     }
771 
772     for (int i = 0; i < deliveries_to_load; i++) {
773         delivery_load(buf, array_next(monument_deliveries), delivery_buf_size);
774     }
775 }
776 
building_monument_is_construction_halted(building * b)777 int building_monument_is_construction_halted(building *b)
778 {
779     return building_main(b)->state == BUILDING_STATE_MOTHBALLED;
780 }
781 
building_monument_toggle_construction_halted(building * b)782 int building_monument_toggle_construction_halted(building *b)
783 {
784     if (b->state == BUILDING_STATE_MOTHBALLED) {
785         b->state = BUILDING_STATE_IN_USE;
786         return 0;
787     } else {
788         b->state = BUILDING_STATE_MOTHBALLED;
789         return 1;
790     }
791 }
792 
building_monument_is_unfinished_monument(const building * b)793 int building_monument_is_unfinished_monument(const building *b)
794 {
795     return building_monument_is_monument(b) && b->data.monument.phase != MONUMENT_FINISHED;
796 }
797