1 #include "resource.h"
2 
3 #include "building/building.h"
4 #include "building/count.h"
5 #include "building/industry.h"
6 #include "building/model.h"
7 #include "building/monument.h"
8 #include "city/data_private.h"
9 #include "city/message.h"
10 #include "city/military.h"
11 #include "city/trade.h"
12 #include "city/trade_policy.h"
13 #include "core/calc.h"
14 #include "empire/city.h"
15 #include "figure/figure.h"
16 #include "figure/formation.h"
17 #include "game/difficulty.h"
18 #include "game/tutorial.h"
19 #include "map/road_access.h"
20 #include "scenario/building.h"
21 #include "scenario/property.h"
22 
23 #include <math.h>
24 
25 static struct {
26     resource_list resource_list;
27     resource_list food_list;
28 } available;
29 
30 static struct {
31     resource_list resource_list;
32     resource_list food_list;
33 } potential;
34 
city_resource_count_food_on_granaries(resource_type food)35 int city_resource_count_food_on_granaries(resource_type food)
36 {
37     return city_data.resource.granary_food_stored[food];
38 }
39 
city_resource_count(resource_type resource)40 int city_resource_count(resource_type resource)
41 {
42     return city_data.resource.stored_in_warehouses[resource];
43 }
44 
city_resource_get_amount_including_granaries(int resource,int amount,int * checked_granaries)45 int city_resource_get_amount_including_granaries(int resource, int amount, int *checked_granaries)
46 {
47     if (checked_granaries) {
48         *checked_granaries = 0;
49     }
50     int amount_stored = city_data.resource.stored_in_warehouses[resource];
51     if (amount_stored < amount && resource_is_food(resource)) {
52         amount_stored += city_data.resource.granary_food_stored[resource] / 100;
53         if (checked_granaries) {
54             *checked_granaries = 1;
55         }
56     }
57     return amount_stored;
58 }
59 
city_resource_get_available(void)60 const resource_list *city_resource_get_available(void)
61 {
62     return &available.resource_list;
63 }
64 
city_resource_get_available_foods(void)65 const resource_list *city_resource_get_available_foods(void)
66 {
67     return &available.food_list;
68 }
69 
city_resource_get_potential(void)70 const resource_list *city_resource_get_potential(void)
71 {
72     return &potential.resource_list;
73 }
74 
city_resource_get_potential_foods(void)75 const resource_list *city_resource_get_potential_foods(void)
76 {
77     return &potential.food_list;
78 }
79 
city_resource_multiple_wine_available(void)80 int city_resource_multiple_wine_available(void)
81 {
82     return city_data.resource.wine_types_available >= 2;
83 }
84 
city_resource_food_types_available(void)85 int city_resource_food_types_available(void)
86 {
87     return city_data.resource.food_types_available;
88 }
89 
city_resource_food_stored(void)90 int city_resource_food_stored(void)
91 {
92     return city_data.resource.granary_total_stored;
93 }
94 
city_resource_food_needed(void)95 int city_resource_food_needed(void)
96 {
97     return city_data.resource.food_needed_per_month;
98 }
99 
city_resource_food_supply_months(void)100 int city_resource_food_supply_months(void)
101 {
102     return city_data.resource.food_supply_months;
103 }
104 
city_resource_food_percentage_produced(void)105 int city_resource_food_percentage_produced(void)
106 {
107     return calc_percentage(city_data.resource.food_produced_last_month, city_data.resource.food_consumed_last_month);
108 }
109 
city_resource_operating_granaries(void)110 int city_resource_operating_granaries(void)
111 {
112     return city_data.resource.granaries.operating;
113 }
114 
city_resource_last_used_warehouse(void)115 int city_resource_last_used_warehouse(void)
116 {
117     return city_data.resource.last_used_warehouse;
118 }
119 
city_resource_set_last_used_warehouse(int warehouse_id)120 void city_resource_set_last_used_warehouse(int warehouse_id)
121 {
122     city_data.resource.last_used_warehouse = warehouse_id;
123 }
124 
city_resource_trade_status(resource_type resource)125 resource_trade_status city_resource_trade_status(resource_type resource)
126 {
127     return city_data.resource.trade_status[resource];
128 }
129 
city_resource_cycle_trade_status(resource_type resource,resource_trade_status status)130 void city_resource_cycle_trade_status(resource_type resource, resource_trade_status status)
131 {
132     if (status == TRADE_STATUS_IMPORT && !empire_can_import_resource(resource)) {
133         city_data.resource.trade_status[resource] &= ~TRADE_STATUS_IMPORT;
134         return;
135     }
136     if (status == TRADE_STATUS_EXPORT && !empire_can_export_resource(resource)) {
137         city_data.resource.trade_status[resource] &= ~TRADE_STATUS_EXPORT;
138         return;
139     }
140     city_data.resource.trade_status[resource] ^= status;
141 
142     if (city_data.resource.trade_status[resource] & TRADE_STATUS_EXPORT) {
143         city_data.resource.stockpiled[resource] = 0;
144     }
145 }
146 
city_resource_import_over(resource_type resource)147 int city_resource_import_over(resource_type resource)
148 {
149     return city_data.resource.import_over[resource];
150 }
151 
city_resource_change_import_over(resource_type resource,int change)152 void city_resource_change_import_over(resource_type resource, int change)
153 {
154     city_data.resource.import_over[resource] = calc_bound(city_data.resource.import_over[resource] + change, 0, 100);
155 }
156 
city_resource_export_over(resource_type resource)157 int city_resource_export_over(resource_type resource)
158 {
159     return city_data.resource.export_over[resource];
160 }
161 
city_resource_change_export_over(resource_type resource,int change)162 void city_resource_change_export_over(resource_type resource, int change)
163 {
164     city_data.resource.export_over[resource] = calc_bound(city_data.resource.export_over[resource] + change, 0, 100);
165 }
166 
city_resource_is_stockpiled(resource_type resource)167 int city_resource_is_stockpiled(resource_type resource)
168 {
169     return city_data.resource.stockpiled[resource];
170 }
171 
city_resource_toggle_stockpiled(resource_type resource)172 void city_resource_toggle_stockpiled(resource_type resource)
173 {
174     if (city_data.resource.stockpiled[resource]) {
175         city_data.resource.stockpiled[resource] = 0;
176         city_data.resource.trade_status[resource] |= city_data.resource.export_status_before_stockpiling[resource];
177     } else {
178         city_data.resource.stockpiled[resource] = 1;
179         city_data.resource.export_status_before_stockpiling[resource] = city_data.resource.trade_status[resource] & TRADE_STATUS_EXPORT;
180         city_data.resource.trade_status[resource] &= ~TRADE_STATUS_EXPORT;
181     }
182 }
183 
city_resource_is_mothballed(resource_type resource)184 int city_resource_is_mothballed(resource_type resource)
185 {
186     return city_data.resource.mothballed[resource];
187 }
188 
city_resource_toggle_mothballed(resource_type resource)189 void city_resource_toggle_mothballed(resource_type resource)
190 {
191     city_data.resource.mothballed[resource] = city_data.resource.mothballed[resource] ? 0 : 1;
192 }
193 
city_resource_has_workshop_with_room(int workshop_type)194 int city_resource_has_workshop_with_room(int workshop_type)
195 {
196     return city_data.resource.space_in_workshops[workshop_type] > 0;
197 }
198 
city_resource_add_produced_to_granary(int amount)199 void city_resource_add_produced_to_granary(int amount)
200 {
201     city_data.resource.food_produced_this_month += amount;
202 }
203 
city_resource_add_to_granary(resource_type food,int amount)204 void city_resource_add_to_granary(resource_type food, int amount)
205 {
206     city_data.resource.granary_food_stored[food] += amount;
207 }
208 
city_resource_remove_from_granary(resource_type food,int amount)209 void city_resource_remove_from_granary(resource_type food, int amount)
210 {
211     city_data.resource.granary_food_stored[food] -= amount;
212 }
213 
city_resource_add_to_warehouse(resource_type resource,int amount)214 void city_resource_add_to_warehouse(resource_type resource, int amount)
215 {
216     city_data.resource.space_in_warehouses[resource] -= amount;
217     city_data.resource.stored_in_warehouses[resource] += amount;
218 }
219 
city_resource_remove_from_warehouse(resource_type resource,int amount)220 void city_resource_remove_from_warehouse(resource_type resource, int amount)
221 {
222     city_data.resource.space_in_warehouses[resource] += amount;
223     city_data.resource.stored_in_warehouses[resource] -= amount;
224 }
225 
city_resource_calculate_warehouse_stocks(void)226 void city_resource_calculate_warehouse_stocks(void)
227 {
228     for (int i = 0; i < RESOURCE_MAX; i++) {
229         city_data.resource.space_in_warehouses[i] = 0;
230         city_data.resource.stored_in_warehouses[i] = 0;
231     }
232     for (building *b = building_first_of_type(BUILDING_WAREHOUSE); b; b = b->next_of_type) {
233         if (b->state == BUILDING_STATE_IN_USE) {
234             b->has_road_access = 0;
235             if (map_has_road_access_rotation(b->subtype.orientation, b->x, b->y, b->size, 0)) {
236                 b->has_road_access = 1;
237             } else if (map_has_road_access_rotation(b->subtype.orientation, b->x, b->y, 3, 0)) {
238                 b->has_road_access = 2;
239             }
240         }
241     }
242     for (building *b = building_first_of_type(BUILDING_WAREHOUSE_SPACE); b; b = b->next_of_type) {
243         if (b->state != BUILDING_STATE_IN_USE) {
244             continue;
245         }
246         building *warehouse = building_main(b);
247         if (warehouse->state != BUILDING_STATE_IN_USE || warehouse->type != BUILDING_WAREHOUSE) {
248             continue;
249         }
250         if (warehouse->has_road_access) {
251             b->has_road_access = warehouse->has_road_access;
252             if (b->subtype.warehouse_resource_id) {
253                 int loads = b->loads_stored;
254                 int resource = b->subtype.warehouse_resource_id;
255                 city_data.resource.stored_in_warehouses[resource] += loads;
256                 city_data.resource.space_in_warehouses[resource] += 4 - loads;
257             } else {
258                 city_data.resource.space_in_warehouses[RESOURCE_NONE] += 4;
259             }
260         }
261     }
262 }
263 
city_resource_determine_available(void)264 void city_resource_determine_available(void)
265 {
266     for (int i = 0; i < RESOURCE_MAX; i++) {
267         available.resource_list.items[i] = 0;
268         available.food_list.items[i] = 0;
269         potential.resource_list.items[i] = 0;
270         potential.food_list.items[i] = 0;
271     }
272     available.resource_list.size = 0;
273     available.food_list.size = 0;
274     potential.resource_list.size = 0;
275     potential.food_list.size = 0;
276 
277     for (int i = RESOURCE_MIN; i < RESOURCE_MAX; i++) {
278         if (empire_can_produce_resource(i) || empire_can_import_resource(i) ||
279             (i == RESOURCE_MEAT && scenario_building_allowed(BUILDING_WHARF))) {
280             available.resource_list.items[available.resource_list.size++] = i;
281             potential.resource_list.items[potential.resource_list.size++] = i;
282         } else if (empire_can_produce_resource_potentially(i) || empire_can_import_resource_potentially(i)) {
283             potential.resource_list.items[potential.resource_list.size++] = i;
284         }
285     }
286     for (int i = RESOURCE_MIN_FOOD; i < RESOURCE_MAX_FOOD; i++) {
287         if (i == RESOURCE_OLIVES || i == RESOURCE_VINES) {
288             continue;
289         }
290         if (empire_can_produce_resource(i) || empire_can_import_resource(i) ||
291             (i == RESOURCE_MEAT && scenario_building_allowed(BUILDING_WHARF))) {
292             available.food_list.items[available.food_list.size++] = i;
293             potential.food_list.items[potential.food_list.size++] = i;
294         } else if (empire_can_produce_resource_potentially(i) || empire_can_import_resource_potentially(i)) {
295             potential.food_list.items[potential.food_list.size++] = i;
296         }
297     }
298 }
299 
city_resource_ceres_temple_food(void)300 int city_resource_ceres_temple_food(void)
301 {
302     // locally produced
303     for (int i = RESOURCE_MIN_FOOD; i < RESOURCE_MAX_FOOD; i++) {
304         if (i == RESOURCE_OLIVES || i == RESOURCE_VINES) {
305             continue;
306         }
307         if (can_produce_resource(i)) {
308             return i;
309         }
310     }
311 
312     // imported, if no food is locally produced
313     for (int i = RESOURCE_MIN_FOOD; i < RESOURCE_MAX_FOOD; i++) {
314         if (i == RESOURCE_OLIVES || i == RESOURCE_VINES) {
315             continue;
316         }
317         if (empire_can_import_resource_potentially(i)) {
318             return i;
319         }
320     }
321 
322     return RESOURCE_NONE;
323 }
324 
calculate_available_food(void)325 static void calculate_available_food(void)
326 {
327     for (int i = 0; i < RESOURCE_MAX_FOOD; i++) {
328         city_data.resource.granary_food_stored[i] = 0;
329     }
330     city_data.resource.granary_total_stored = 0;
331     city_data.resource.food_types_available = 0;
332     city_data.resource.food_supply_months = 0;
333     city_data.resource.granaries.operating = 0;
334     city_data.resource.granaries.understaffed = 0;
335     city_data.resource.granaries.not_operating = 0;
336     city_data.resource.granaries.not_operating_with_food = 0;
337     for (building *b = building_first_of_type(BUILDING_GRANARY); b; b = b->next_of_type) {
338         if (b->state != BUILDING_STATE_IN_USE) {
339             continue;
340         }
341         b->has_road_access = 0;
342         if (map_has_road_access_granary(b->x, b->y, 0)) {
343             b->has_road_access = 1;
344             int pct_workers = calc_percentage(
345                 b->num_workers, model_get_building(b->type)->laborers);
346             if (pct_workers < 100) {
347                 city_data.resource.granaries.understaffed++;
348             }
349             int amount_stored = 0;
350             for (int r = RESOURCE_MIN_FOOD; r < RESOURCE_MAX_FOOD; r++) {
351                 amount_stored += b->data.granary.resource_stored[r];
352             }
353             if (pct_workers < 50) {
354                 city_data.resource.granaries.not_operating++;
355                 if (amount_stored > 0) {
356                     city_data.resource.granaries.not_operating_with_food++;
357                 }
358             } else {
359                 city_data.resource.granaries.operating++;
360                 for (int r = 0; r < RESOURCE_MAX_FOOD; r++) {
361                     city_data.resource.granary_food_stored[r] += b->data.granary.resource_stored[r];
362                 }
363                 if (amount_stored > 400) {
364                     tutorial_on_filled_granary();
365                 }
366             }
367         }
368     }
369     for (int i = RESOURCE_MIN_FOOD; i < RESOURCE_MAX_FOOD; i++) {
370         if (city_data.resource.granary_food_stored[i]) {
371             city_data.resource.granary_total_stored += city_data.resource.granary_food_stored[i];
372             city_data.resource.food_types_available++;
373         }
374     }
375     city_data.resource.food_needed_per_month =
376         calc_adjust_with_percentage(city_data.population.population, 50);
377     if (city_data.resource.food_needed_per_month > 0) {
378         city_data.resource.food_supply_months =
379             city_data.resource.granary_total_stored / city_data.resource.food_needed_per_month;
380     } else {
381         city_data.resource.food_supply_months =
382             city_data.resource.granary_total_stored > 0 ? 1 : 0;
383     }
384     if (scenario_property_rome_supplies_wheat()) {
385         city_data.resource.food_types_available = 1;
386         city_data.resource.food_supply_months = 12;
387     }
388 }
389 
city_resource_calculate_food_stocks_and_supply_wheat(void)390 void city_resource_calculate_food_stocks_and_supply_wheat(void)
391 {
392     calculate_available_food();
393     if (scenario_property_rome_supplies_wheat()) {
394         building_type supplied_buildings[] = { BUILDING_MARKET, BUILDING_MESS_HALL };
395         for (int i = 0; i < 2; i++) {
396             building_type type = supplied_buildings[i];
397             for (building *b = building_first_of_type(type); b; b = b->next_of_type) {
398                 if (b->state == BUILDING_STATE_IN_USE) {
399                     b->data.market.inventory[INVENTORY_WHEAT] = 200;
400                 }
401             }
402         }
403     }
404 }
405 
city_resource_calculate_workshop_stocks(void)406 void city_resource_calculate_workshop_stocks(void)
407 {
408     for (int i = 0; i < 6; i++) {
409         city_data.resource.stored_in_workshops[i] = 0;
410         city_data.resource.space_in_workshops[i] = 0;
411     }
412     for (building_type type = BUILDING_WINE_WORKSHOP; type <= BUILDING_POTTERY_WORKSHOP; type++) {
413         for (building *b = building_first_of_type(type); b; b = b->next_of_type) {
414             if (b->state != BUILDING_STATE_IN_USE) {
415                 continue;
416             }
417             b->has_road_access = 0;
418             if (map_has_road_access(b->x, b->y, b->size, 0)) {
419                 b->has_road_access = 1;
420                 int room = 2 - b->loads_stored;
421                 if (room < 0) {
422                     room = 0;
423                 }
424                 int workshop_resource = b->subtype.workshop_type;
425                 city_data.resource.space_in_workshops[workshop_resource] += room;
426                 city_data.resource.stored_in_workshops[workshop_resource] += b->loads_stored;
427             }
428         }
429     }
430 }
431 
house_consume_food(void)432 static int house_consume_food(void)
433 {
434     int total_consumed = 0;
435     int ceres_module = (building_monument_gt_module_is_active(CERES_MODULE_1_REDUCE_FOOD));
436     for (building_type type = BUILDING_HOUSE_SMALL_TENT; type <= BUILDING_HOUSE_LUXURY_PALACE; type++) {
437         for (building *b = building_first_of_type(type); b; b = b->next_of_type) {
438             if (b->state != BUILDING_STATE_IN_USE || !b->house_size) {
439                 continue;
440             }
441             int num_types = model_get_house(b->subtype.house_level)->food_types;
442             int amount_per_type;
443             if (ceres_module && b->data.house.temple_ceres) {
444                 amount_per_type = calc_adjust_with_percentage(b->house_population, 40);
445             } else {
446                 amount_per_type = calc_adjust_with_percentage(b->house_population, 50);
447             }
448             int foodtypes_available = 0;
449             for (int i = INVENTORY_MIN_FOOD; i < INVENTORY_MAX_FOOD; i++) {
450                 if (b->data.house.inventory[i]) {
451                     foodtypes_available++;
452                 }
453             }
454             if (foodtypes_available) {
455                 amount_per_type /= foodtypes_available;
456             }
457 
458             b->data.house.num_foods = 0;
459             if (scenario_property_rome_supplies_wheat()) {
460                 city_data.resource.food_types_eaten = 1;
461                 city_data.resource.food_types_available = 1;
462                 b->data.house.inventory[INVENTORY_WHEAT] = amount_per_type;
463                 b->data.house.num_foods = 1;
464             } else if (num_types > 0) {
465                 for (int t = INVENTORY_MIN_FOOD; t < INVENTORY_MAX_FOOD; t++) {
466                     if (b->data.house.inventory[t] >= amount_per_type) {
467                         b->data.house.inventory[t] -= amount_per_type;
468                         b->data.house.num_foods++;
469                         total_consumed += amount_per_type;
470                     } else if (b->data.house.inventory[t]) {
471                         // has food but not enough
472                         b->data.house.inventory[t] = 0;
473                         b->data.house.num_foods++;
474                         total_consumed += amount_per_type;
475                     }
476                     if (b->data.house.num_foods > city_data.resource.food_types_eaten) {
477                         city_data.resource.food_types_eaten = b->data.house.num_foods;
478                     }
479                 }
480             }
481         }
482     }
483     return total_consumed;
484 }
485 
mess_hall_consume_food(void)486 static int mess_hall_consume_food(void)
487 {
488     int total_consumed = 0;
489     building *b = building_first_of_type(BUILDING_MESS_HALL);
490     if (!b || b->state != BUILDING_STATE_IN_USE) {
491         return 0;
492     };
493     int food_required = city_military_total_soldiers_in_city() *
494         difficulty_adjust_soldier_food_consumption(FOOD_PER_SOLDIER_MONTHLY);
495     int num_foods = 0;
496     int total_food_in_mess_hall = 0;
497     int proportionate_amount = 0;
498     int amount_for_type = 0;
499 
500     for (int i = INVENTORY_MIN_FOOD; i < INVENTORY_MAX_FOOD; ++i) {
501         total_food_in_mess_hall += b->data.market.inventory[i];
502     }
503 
504     city_data.mess_hall.total_food = total_food_in_mess_hall;
505     if (!food_required) {
506         return 0;
507     }
508 
509     if (total_food_in_mess_hall > 0) {
510         for (int i = INVENTORY_MIN_FOOD; i < INVENTORY_MAX_FOOD; ++i) {
511             proportionate_amount = food_required * b->data.market.inventory[i] / total_food_in_mess_hall;
512             if (proportionate_amount > 0) {
513                 amount_for_type = calc_bound((int) ceil(proportionate_amount), 0, b->data.market.inventory[i]);
514                 b->data.market.inventory[i] -= amount_for_type;
515                 ++num_foods;
516             }
517         }
518     }
519 
520     if (food_required > total_food_in_mess_hall) {
521         city_data.mess_hall.food_percentage_missing_this_month = 100 -
522             calc_percentage(total_food_in_mess_hall, food_required);
523         total_consumed += total_food_in_mess_hall;
524         city_data.mess_hall.total_food = 0;
525     } else {
526         city_data.mess_hall.food_percentage_missing_this_month = 0;
527         total_consumed += food_required;
528         city_data.mess_hall.total_food -= food_required;
529     }
530 
531     city_data.mess_hall.food_types = num_foods;
532 
533     return total_consumed;
534 }
535 
caravanserai_consume_food(void)536 static int caravanserai_consume_food(void)
537 {
538     if (!building_monument_working(BUILDING_CARAVANSERAI)) {
539         return 0;
540     }
541     int food_required = trade_caravan_count() * FOOD_PER_TRADER_MONTHLY;
542 
543     trade_policy policy = city_trade_policy_get(LAND_TRADE_POLICY);
544 
545     if (policy == TRADE_POLICY_3) { // consume 20% more
546         food_required = calc_adjust_with_percentage(food_required, 100 + POLICY_3_MALUS_PERCENT);
547     }
548 
549     int total_consumed = 0;
550     building *b = building_first_of_type(BUILDING_CARAVANSERAI);
551     if (!b) {
552         return 0;
553     }
554 
555     int total_food_in_caravanserai = 0;
556     int proportionate_amount = 0;
557     int amount_for_type = 0;
558 
559     for (int i = INVENTORY_MIN_FOOD; i < INVENTORY_MAX_FOOD; ++i) {
560         total_food_in_caravanserai += b->data.market.inventory[i];
561     }
562 
563     city_data.caravanserai.total_food = total_food_in_caravanserai;
564 
565 
566     if (!food_required || !total_food_in_caravanserai) {
567         return 0;
568     }
569 
570     for (int i = INVENTORY_MIN_FOOD; i < INVENTORY_MAX_FOOD; ++i) {
571         proportionate_amount = food_required * b->data.market.inventory[i] / total_food_in_caravanserai;
572         if (proportionate_amount > 0) {
573             amount_for_type = calc_bound(proportionate_amount, 0, b->data.market.inventory[i]);
574             b->data.market.inventory[i] -= amount_for_type;
575         }
576     }
577 
578     if (food_required > total_food_in_caravanserai) {
579         total_consumed += total_food_in_caravanserai;
580         city_data.caravanserai.total_food = 0;
581     } else {
582         total_consumed += food_required;
583         city_data.caravanserai.total_food -= food_required;
584     }
585 
586     return total_consumed;
587 }
588 
city_resource_consume_food(void)589 void city_resource_consume_food(void)
590 {
591     calculate_available_food();
592     city_data.resource.food_types_eaten = 0;
593 
594     int total_consumed = house_consume_food() + mess_hall_consume_food() + caravanserai_consume_food();
595 
596     if (city_military_total_soldiers_in_city() > 0 && !city_data.building.mess_hall_building_id &&
597         !city_data.mess_hall.missing_mess_hall_warning_shown) {
598         city_data.mess_hall.food_percentage_missing_this_month = 100;
599         city_message_post(1, MESSAGE_SOLDIERS_STARVING_NO_MESS_HALL, 0, 0);
600         city_data.mess_hall.missing_mess_hall_warning_shown = 1;
601     } else if (city_military_total_soldiers_in_city() > 0 && city_data.mess_hall.food_stress_cumulative > 50 &&
602         !city_data.mess_hall.mess_hall_warning_shown) {
603         city_message_post(1, MESSAGE_SOLDIERS_STARVING, 0, 0);
604         city_data.mess_hall.mess_hall_warning_shown = 1;
605     }
606 
607     city_data.mess_hall.food_stress_cumulative = ((city_data.mess_hall.food_percentage_missing_this_month +
608         city_data.mess_hall.food_stress_cumulative) / 2);
609     if (city_data.mess_hall.food_stress_cumulative < 20) {
610         city_data.mess_hall.mess_hall_warning_shown = 0;
611     }
612 
613     if (city_data.mess_hall.food_stress_cumulative > 100) {
614         city_data.mess_hall.food_stress_cumulative = 100;
615     }
616 
617     city_data.resource.food_consumed_last_month = total_consumed;
618     city_data.resource.food_produced_last_month = city_data.resource.food_produced_this_month;
619     city_data.resource.food_produced_this_month = 0;
620 }
621