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