1 #include "service.h"
2
3 #include "building/building.h"
4 #include "building/model.h"
5 #include "figuretype/crime.h"
6 #include "game/resource.h"
7 #include "map/building.h"
8 #include "map/grid.h"
9
10 #define MAX_COVERAGE 96
11
provide_culture(int x,int y,void (* callback)(building *))12 static int provide_culture(int x, int y, void (*callback)(building *))
13 {
14 int serviced = 0;
15 int x_min, y_min, x_max, y_max;
16 map_grid_get_area(x, y, 1, 2, &x_min, &y_min, &x_max, &y_max);
17 for (int yy = y_min; yy <= y_max; yy++) {
18 for (int xx = x_min; xx <= x_max; xx++) {
19 int grid_offset = map_grid_offset(xx, yy);
20 int building_id = map_building_at(grid_offset);
21 if (building_id) {
22 building *b = building_get(building_id);
23 if (b->house_size && b->house_population > 0) {
24 callback(b);
25 serviced++;
26 }
27 }
28 }
29 }
30 return serviced;
31 }
32
provide_entertainment(int x,int y,int shows,void (* callback)(building *,int))33 static int provide_entertainment(int x, int y, int shows, void (*callback)(building *, int))
34 {
35 int serviced = 0;
36 int x_min, y_min, x_max, y_max;
37 map_grid_get_area(x, y, 1, 2, &x_min, &y_min, &x_max, &y_max);
38 for (int yy = y_min; yy <= y_max; yy++) {
39 for (int xx = x_min; xx <= x_max; xx++) {
40 int grid_offset = map_grid_offset(xx, yy);
41 int building_id = map_building_at(grid_offset);
42 if (building_id) {
43 building *b = building_get(building_id);
44 if (b->house_size && b->house_population > 0) {
45 callback(b, shows);
46 serviced++;
47 }
48 }
49 }
50 }
51 return serviced;
52 }
53
labor_seeker_coverage(building * b)54 static void labor_seeker_coverage(building *b)
55 {
56 }
57
theater_coverage(building * b)58 static void theater_coverage(building *b)
59 {
60 b->data.house.theater = MAX_COVERAGE;
61 }
62
amphitheater_coverage(building * b,int shows)63 static void amphitheater_coverage(building *b, int shows)
64 {
65 b->data.house.amphitheater_actor = MAX_COVERAGE;
66 if (shows == 2) {
67 b->data.house.amphitheater_gladiator = MAX_COVERAGE;
68 }
69 }
70
colosseum_coverage(building * b,int shows)71 static void colosseum_coverage(building *b, int shows)
72 {
73 b->data.house.colosseum_gladiator = MAX_COVERAGE;
74 if (shows == 2) {
75 b->data.house.colosseum_lion = MAX_COVERAGE;
76 }
77 }
78
hippodrome_coverage(building * b)79 static void hippodrome_coverage(building *b)
80 {
81 b->data.house.hippodrome = MAX_COVERAGE;
82 }
83
bathhouse_coverage(building * b)84 static void bathhouse_coverage(building *b)
85 {
86 b->data.house.bathhouse = MAX_COVERAGE;
87 }
88
religion_coverage_ceres(building * b)89 static void religion_coverage_ceres(building *b)
90 {
91 b->data.house.temple_ceres = MAX_COVERAGE;
92 }
93
religion_coverage_neptune(building * b)94 static void religion_coverage_neptune(building *b)
95 {
96 b->data.house.temple_neptune = MAX_COVERAGE;
97 }
98
religion_coverage_mercury(building * b)99 static void religion_coverage_mercury(building *b)
100 {
101 b->data.house.temple_mercury = MAX_COVERAGE;
102 }
103
religion_coverage_mars(building * b)104 static void religion_coverage_mars(building *b)
105 {
106 b->data.house.temple_mars = MAX_COVERAGE;
107 }
108
religion_coverage_venus(building * b)109 static void religion_coverage_venus(building *b)
110 {
111 b->data.house.temple_venus = MAX_COVERAGE;
112 }
113
school_coverage(building * b)114 static void school_coverage(building *b)
115 {
116 b->data.house.school = MAX_COVERAGE;
117 }
118
academy_coverage(building * b)119 static void academy_coverage(building *b)
120 {
121 b->data.house.academy = MAX_COVERAGE;
122 }
123
library_coverage(building * b)124 static void library_coverage(building *b)
125 {
126 b->data.house.library = MAX_COVERAGE;
127 }
128
barber_coverage(building * b)129 static void barber_coverage(building *b)
130 {
131 b->data.house.barber = MAX_COVERAGE;
132 }
133
clinic_coverage(building * b)134 static void clinic_coverage(building *b)
135 {
136 b->data.house.clinic = MAX_COVERAGE;
137 }
138
hospital_coverage(building * b)139 static void hospital_coverage(building *b)
140 {
141 b->data.house.hospital = MAX_COVERAGE;
142 }
143
provide_missionary_coverage(int x,int y)144 static int provide_missionary_coverage(int x, int y)
145 {
146 int x_min, y_min, x_max, y_max;
147 map_grid_get_area(x, y, 1, 4, &x_min, &y_min, &x_max, &y_max);
148 for (int yy = y_min; yy <= y_max; yy++) {
149 for (int xx = x_min; xx <= x_max; xx++) {
150 int building_id = map_building_at(map_grid_offset(xx, yy));
151 if (building_id) {
152 building *b = building_get(building_id);
153 if (b->type == BUILDING_NATIVE_HUT || b->type == BUILDING_NATIVE_MEETING) {
154 b->sentiment.native_anger = 0;
155 }
156 }
157 }
158 }
159 return 1;
160 }
161
provide_service(int x,int y,int * data,void (* callback)(building *,int *))162 static int provide_service(int x, int y, int *data, void (*callback)(building *, int *))
163 {
164 int serviced = 0;
165 int x_min, y_min, x_max, y_max;
166 map_grid_get_area(x, y, 1, 2, &x_min, &y_min, &x_max, &y_max);
167 for (int yy = y_min; yy <= y_max; yy++) {
168 for (int xx = x_min; xx <= x_max; xx++) {
169 int grid_offset = map_grid_offset(xx, yy);
170 int building_id = map_building_at(grid_offset);
171 if (building_id) {
172 building *b = building_get(building_id);
173 callback(b, data);
174 if (b->house_size && b->house_population > 0) {
175 serviced++;
176 }
177 }
178 }
179 }
180 return serviced;
181 }
182
engineer_coverage(building * b,int * max_damage_seen)183 static void engineer_coverage(building *b, int *max_damage_seen)
184 {
185 if (b->type == BUILDING_HIPPODROME) {
186 b = building_main(b);
187 }
188 if (b->damage_risk > *max_damage_seen) {
189 *max_damage_seen = b->damage_risk;
190 }
191 b->damage_risk = 0;
192 }
193
prefect_coverage(building * b,int * min_happiness_seen)194 static void prefect_coverage(building *b, int *min_happiness_seen)
195 {
196 if (b->type == BUILDING_HIPPODROME) {
197 b = building_main(b);
198 }
199 b->fire_risk = 0;
200 if (b->sentiment.house_happiness < *min_happiness_seen) {
201 *min_happiness_seen = b->sentiment.house_happiness;
202 }
203 }
204
tax_collector_coverage(building * b,int * max_tax_multiplier)205 static void tax_collector_coverage(building *b, int *max_tax_multiplier)
206 {
207 if (b->house_size && b->house_population > 0) {
208 int tax_multiplier = model_get_house(b->subtype.house_level)->tax_multiplier;
209 if (tax_multiplier > *max_tax_multiplier) {
210 *max_tax_multiplier = tax_multiplier;
211 }
212 b->house_tax_coverage = 50;
213 }
214 }
215
distribute_good(building * b,building * market,int stock_wanted,int inventory_resource)216 static void distribute_good(building *b, building *market, int stock_wanted, int inventory_resource)
217 {
218 int amount_wanted = stock_wanted - b->data.house.inventory[inventory_resource];
219 if (market->data.market.inventory[inventory_resource] > 0 && amount_wanted > 0) {
220 if (amount_wanted <= market->data.market.inventory[inventory_resource]) {
221 b->data.house.inventory[inventory_resource] += amount_wanted;
222 market->data.market.inventory[inventory_resource] -= amount_wanted;
223 } else {
224 b->data.house.inventory[inventory_resource] += market->data.market.inventory[inventory_resource];
225 market->data.market.inventory[inventory_resource] = 0;
226 }
227 }
228 }
229
distribute_market_resources(building * b,building * market)230 static void distribute_market_resources(building *b, building *market)
231 {
232 int level = b->subtype.house_level;
233 if (level < HOUSE_LUXURY_PALACE) {
234 level++;
235 }
236 int max_food_stocks = 4 * b->house_highest_population;
237 int food_types_stored_max = 0;
238 for (int i = INVENTORY_MIN_FOOD; i < INVENTORY_MAX_FOOD; i++) {
239 if (b->data.house.inventory[i] >= max_food_stocks) {
240 food_types_stored_max++;
241 }
242 }
243 const model_house *model = model_get_house(level);
244 if (model->food_types > food_types_stored_max) {
245 for (int i = INVENTORY_MIN_FOOD; i < INVENTORY_MAX_FOOD; i++) {
246 if (b->data.house.inventory[i] >= max_food_stocks) {
247 continue;
248 }
249 if (market->data.market.inventory[i] >= max_food_stocks) {
250 b->data.house.inventory[i] += max_food_stocks;
251 market->data.market.inventory[i] -= max_food_stocks;
252 break;
253 } else if (market->data.market.inventory[i]) {
254 b->data.house.inventory[i] += market->data.market.inventory[i];
255 market->data.market.inventory[i] = 0;
256 break;
257 }
258 }
259 }
260 if (model->pottery) {
261 market->data.market.pottery_demand = 10;
262 distribute_good(b, market, 8 * model->pottery, INVENTORY_POTTERY);
263 }
264 if (model->furniture) {
265 market->data.market.furniture_demand = 10;
266 distribute_good(b, market, 4 * model->furniture, INVENTORY_FURNITURE);
267 }
268 if (model->oil) {
269 market->data.market.oil_demand = 10;
270 distribute_good(b, market, 4 * model->oil, INVENTORY_OIL);
271 }
272 if (model->wine) {
273 market->data.market.wine_demand = 10;
274 distribute_good(b, market, 4 * model->wine, INVENTORY_WINE);
275 }
276 }
277
provide_market_goods(int market_building_id,int x,int y)278 static int provide_market_goods(int market_building_id, int x, int y)
279 {
280 int serviced = 0;
281 building *market = building_get(market_building_id);
282 int x_min, y_min, x_max, y_max;
283 map_grid_get_area(x, y, 1, 2, &x_min, &y_min, &x_max, &y_max);
284 for (int yy = y_min; yy <= y_max; yy++) {
285 for (int xx = x_min; xx <= x_max; xx++) {
286 int grid_offset = map_grid_offset(xx, yy);
287 int building_id = map_building_at(grid_offset);
288 if (building_id) {
289 building *b = building_get(building_id);
290 if (b->house_size && b->house_population > 0) {
291 distribute_market_resources(b, market);
292 serviced++;
293 }
294 }
295 }
296 }
297 return serviced;
298 }
299
get_entertainment_building(const figure * f)300 static building *get_entertainment_building(const figure *f)
301 {
302 if (f->action_state == FIGURE_ACTION_94_ENTERTAINER_ROAMING ||
303 f->action_state == FIGURE_ACTION_95_ENTERTAINER_RETURNING) {
304 return building_get(f->building_id);
305 } else { // going to venue
306 return building_get(f->destination_building_id);
307 }
308 }
309
figure_service_provide_coverage(figure * f)310 int figure_service_provide_coverage(figure *f)
311 {
312 int houses_serviced = 0;
313 int x = f->x;
314 int y = f->y;
315 building *b;
316 switch (f->type) {
317 case FIGURE_PATRICIAN:
318 return 0;
319 case FIGURE_LABOR_SEEKER:
320 houses_serviced = provide_culture(x, y, labor_seeker_coverage);
321 break;
322 case FIGURE_TAX_COLLECTOR: {
323 int max_tax_rate = 0;
324 houses_serviced = provide_service(x, y, &max_tax_rate, tax_collector_coverage);
325 f->min_max_seen = max_tax_rate;
326 break;
327 }
328 case FIGURE_MARKET_TRADER:
329 case FIGURE_MARKET_BUYER:
330 houses_serviced = provide_market_goods(f->building_id, x, y);
331 break;
332 case FIGURE_BATHHOUSE_WORKER:
333 houses_serviced = provide_culture(x, y, bathhouse_coverage);
334 break;
335 case FIGURE_SCHOOL_CHILD:
336 houses_serviced = provide_culture(x, y, school_coverage);
337 break;
338 case FIGURE_TEACHER:
339 houses_serviced = provide_culture(x, y, academy_coverage);
340 break;
341 case FIGURE_LIBRARIAN:
342 houses_serviced = provide_culture(x, y, library_coverage);
343 break;
344 case FIGURE_BARBER:
345 houses_serviced = provide_culture(x, y, barber_coverage);
346 break;
347 case FIGURE_DOCTOR:
348 houses_serviced = provide_culture(x, y, clinic_coverage);
349 break;
350 case FIGURE_SURGEON:
351 houses_serviced = provide_culture(x, y, hospital_coverage);
352 break;
353 case FIGURE_MISSIONARY:
354 houses_serviced = provide_missionary_coverage(x, y);
355 break;
356 case FIGURE_PRIEST:
357 switch (building_get(f->building_id)->type) {
358 case BUILDING_SMALL_TEMPLE_CERES:
359 case BUILDING_LARGE_TEMPLE_CERES:
360 houses_serviced = provide_culture(x, y, religion_coverage_ceres);
361 break;
362 case BUILDING_SMALL_TEMPLE_NEPTUNE:
363 case BUILDING_LARGE_TEMPLE_NEPTUNE:
364 houses_serviced = provide_culture(x, y, religion_coverage_neptune);
365 break;
366 case BUILDING_SMALL_TEMPLE_MERCURY:
367 case BUILDING_LARGE_TEMPLE_MERCURY:
368 houses_serviced = provide_culture(x, y, religion_coverage_mercury);
369 break;
370 case BUILDING_SMALL_TEMPLE_MARS:
371 case BUILDING_LARGE_TEMPLE_MARS:
372 houses_serviced = provide_culture(x, y, religion_coverage_mars);
373 break;
374 case BUILDING_SMALL_TEMPLE_VENUS:
375 case BUILDING_LARGE_TEMPLE_VENUS:
376 houses_serviced = provide_culture(x, y, religion_coverage_venus);
377 break;
378 default:
379 break;
380 }
381 break;
382 case FIGURE_ACTOR:
383 b = get_entertainment_building(f);
384 if (b->type == BUILDING_THEATER) {
385 houses_serviced = provide_culture(x, y, theater_coverage);
386 } else if (b->type == BUILDING_AMPHITHEATER) {
387 houses_serviced = provide_entertainment(x, y,
388 b->data.entertainment.days1 ? 2 : 1, amphitheater_coverage);
389 }
390 break;
391 case FIGURE_GLADIATOR:
392 b = get_entertainment_building(f);
393 if (b->type == BUILDING_AMPHITHEATER) {
394 houses_serviced = provide_entertainment(x, y,
395 b->data.entertainment.days2 ? 2 : 1, amphitheater_coverage);
396 } else if (b->type == BUILDING_COLOSSEUM) {
397 houses_serviced = provide_entertainment(x, y,
398 b->data.entertainment.days1 ? 2 : 1, colosseum_coverage);
399 }
400 break;
401 case FIGURE_LION_TAMER:
402 b = get_entertainment_building(f);
403 houses_serviced = provide_entertainment(x, y,
404 b->data.entertainment.days2 ? 2 : 1, colosseum_coverage);
405 break;
406 case FIGURE_CHARIOTEER:
407 houses_serviced = provide_culture(x, y, hippodrome_coverage);
408 break;
409 case FIGURE_ENGINEER: {
410 int max_damage = 0;
411 houses_serviced = provide_service(x, y, &max_damage, engineer_coverage);
412 if (max_damage > f->min_max_seen) {
413 f->min_max_seen = max_damage;
414 } else if (f->min_max_seen <= 10) {
415 f->min_max_seen = 0;
416 } else {
417 f->min_max_seen -= 10;
418 }
419 break;
420 }
421 case FIGURE_PREFECT: {
422 int min_happiness = 100;
423 houses_serviced = provide_service(x, y, &min_happiness, prefect_coverage);
424 f->min_max_seen = min_happiness;
425 break;
426 }
427 case FIGURE_RIOTER:
428 if (figure_rioter_collapse_building(f) == 1) {
429 return 1;
430 }
431 break;
432 }
433 if (f->building_id) {
434 b = building_get(f->building_id);
435 b->houses_covered += houses_serviced;
436 if (b->houses_covered > 300) {
437 b->houses_covered = 300;
438 }
439 }
440 return 0;
441 }
442