1 /**********************************************************************
2 Freeciv - Copyright (C) 2004 - The Freeciv Team
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
13 #ifdef HAVE_CONFIG_H
14 #include <fc_config.h>
15 #endif
16
17 #include <ctype.h>
18 #include <string.h>
19
20 /* utility */
21 #include "astring.h"
22 #include "fcintl.h"
23 #include "log.h"
24 #include "mem.h"
25 #include "support.h"
26 #include "shared.h" /* ARRAY_SIZE */
27 #include "string_vector.h"
28
29 /* common */
30 #include "city.h"
31 #include "game.h"
32 #include "government.h"
33 #include "improvement.h"
34 #include "map.h"
35 #include "packets.h"
36 #include "player.h"
37 #include "tech.h"
38
39 #include "effects.h"
40
41
42 static bool initialized = FALSE;
43
44 /**************************************************************************
45 The code creates a ruleset cache on ruleset load. This constant cache
46 is used to speed up effects queries. After the cache is created it is
47 not modified again (though it may later be freed).
48
49 Since the cache is constant, the server only needs to send effects data to
50 the client upon connect. It also means that an AI can do fast searches in
51 the effects space by trying the possible combinations of addition or
52 removal of buildings with the effects it cares about.
53
54
55 To know how much a target is being affected, simply use the convenience
56 functions:
57
58 * get_player_bonus
59 * get_city_bonus
60 * get_city_tile_bonus
61 * get_building_bonus
62
63 These functions require as arguments the target and the effect type to be
64 queried.
65
66 Effect sources are unique and at a well known place in the
67 data structures. This allows the above queries to be fast:
68 - Look up the possible sources for the effect (O(1) lookup)
69 - For each source, find out if it is present (O(1) lookup per source).
70 The first is commonly called the "ruleset cache" and is stored statically
71 in this file. The second is the "sources cache" and is stored all over.
72
73 Any type of effect range and "survives" is possible if we have a sources
74 cache for that combination. For instance
75 - There is a sources cache of all existing buildings in a city; thus any
76 building effect in a city can have city range.
77 - There is a sources cache of all wonders in the world; thus any wonder
78 effect can have world range.
79 - There is a sources cache of all wonders for each player; thus any
80 wonder effect can have player range.
81 - There is a sources cache of all wonders ever built; thus any wonder
82 effect that survives can have world range.
83 However there is no sources cache for many of the possible sources. For
84 instance non-unique buildings do not have a world-range sources cahce, so
85 you can't have a non-wonder building have a world-ranged effect.
86
87 The sources caches could easily be extended by generalizing it to a set
88 of arrays
89 game.buildings[], pplayer->buildings[],
90 pisland->builidngs[], pcity->buildings[]
91 which would store the number of buildings of that type present by game,
92 player, island (continent) or city. This would allow non-surviving effects
93 to come from any building at any range. However to allow surviving effects
94 a second set of arrays would be needed. This should enable basic support
95 for small wonders and satellites.
96
97 No matter which sources caches are present, we should always know where
98 to look for a source and so the lookups will always be fast even as the
99 number of possible sources increases.
100 **************************************************************************/
101
102 /**************************************************************************
103 Ruleset cache. The cache is created during ruleset loading and the data
104 is organized to enable fast queries.
105 **************************************************************************/
106 static struct {
107 /* A single list containing every effect. */
108 struct effect_list *tracker;
109
110 /* This array provides a full list of the effects of this type
111 * (It's not really a cache, it's the real data.) */
112 struct effect_list *effects[EFT_COUNT];
113
114 struct {
115 /* This cache shows for each building, which effects it provides. */
116 struct effect_list *buildings[B_LAST];
117 /* Same for governments */
118 struct effect_list *govs[G_LAST];
119 /* ...advances... */
120 struct effect_list *advances[A_LAST];
121 } reqs;
122 } ruleset_cache;
123
124
125 /**************************************************************************
126 Get a list of effects of this type.
127 **************************************************************************/
get_effects(enum effect_type effect_type)128 struct effect_list *get_effects(enum effect_type effect_type)
129 {
130 return ruleset_cache.effects[effect_type];
131 }
132
133 /**************************************************************************
134 Get a list of effects with this requirement source.
135
136 Note: currently only buildings and governments are supported.
137 **************************************************************************/
get_req_source_effects(struct universal * psource)138 struct effect_list *get_req_source_effects(struct universal *psource)
139 {
140 int type, value;
141
142 universal_extraction(psource, &type, &value);
143
144 switch (type) {
145 case VUT_GOVERNMENT:
146 if (value >= 0 && value < government_count()) {
147 return ruleset_cache.reqs.govs[value];
148 } else {
149 return NULL;
150 }
151 case VUT_IMPROVEMENT:
152 if (value >= 0 && value < improvement_count()) {
153 return ruleset_cache.reqs.buildings[value];
154 } else {
155 return NULL;
156 }
157 case VUT_ADVANCE:
158 if (value >= 0 && value < advance_count()) {
159 return ruleset_cache.reqs.advances[value];
160 } else {
161 return NULL;
162 }
163 default:
164 return NULL;
165 }
166 }
167
168 /**************************************************************************
169 Add effect to ruleset cache.
170 **************************************************************************/
effect_new(enum effect_type type,int value,struct multiplier * pmul)171 struct effect *effect_new(enum effect_type type, int value,
172 struct multiplier *pmul)
173 {
174 struct effect *peffect;
175
176 /* Create the effect. */
177 peffect = fc_malloc(sizeof(*peffect));
178 peffect->type = type;
179 peffect->value = value;
180 peffect->multiplier = pmul;
181
182 requirement_vector_init(&peffect->reqs);
183
184 /* Now add the effect to the ruleset cache. */
185 effect_list_append(ruleset_cache.tracker, peffect);
186 effect_list_append(get_effects(type), peffect);
187 return peffect;
188 }
189
190 /**************************************************************************
191 Append requirement to effect.
192 **************************************************************************/
effect_req_append(struct effect * peffect,struct requirement req)193 void effect_req_append(struct effect *peffect, struct requirement req)
194 {
195 struct effect_list *eff_list = get_req_source_effects(&req.source);
196
197 requirement_vector_append(&peffect->reqs, req);
198
199 if (eff_list) {
200 effect_list_append(eff_list, peffect);
201 }
202 }
203
204 /**************************************************************************
205 Initialize the ruleset cache. The ruleset cache should be empty
206 before this is done (so if it's previously been initialized, it needs
207 to be freed (see ruleset_cache_free) before it can be reused).
208 **************************************************************************/
ruleset_cache_init(void)209 void ruleset_cache_init(void)
210 {
211 int i;
212
213 initialized = TRUE;
214
215 ruleset_cache.tracker = effect_list_new();
216
217 for (i = 0; i < ARRAY_SIZE(ruleset_cache.effects); i++) {
218 ruleset_cache.effects[i] = effect_list_new();
219 }
220 for (i = 0; i < ARRAY_SIZE(ruleset_cache.reqs.buildings); i++) {
221 ruleset_cache.reqs.buildings[i] = effect_list_new();
222 }
223 for (i = 0; i < ARRAY_SIZE(ruleset_cache.reqs.govs); i++) {
224 ruleset_cache.reqs.govs[i] = effect_list_new();
225 }
226 for (i = 0; i < ARRAY_SIZE(ruleset_cache.reqs.advances); i++) {
227 ruleset_cache.reqs.advances[i] = effect_list_new();
228 }
229 }
230
231 /**************************************************************************
232 Free the ruleset cache. This should be called at the end of the game or
233 when the client disconnects from the server. See ruleset_cache_init.
234 **************************************************************************/
ruleset_cache_free(void)235 void ruleset_cache_free(void)
236 {
237 int i;
238 struct effect_list *tracker_list = ruleset_cache.tracker;
239
240 if (tracker_list) {
241 effect_list_iterate(tracker_list, peffect) {
242 requirement_vector_free(&peffect->reqs);
243 free(peffect);
244 } effect_list_iterate_end;
245 effect_list_destroy(tracker_list);
246 ruleset_cache.tracker = NULL;
247 }
248
249 for (i = 0; i < ARRAY_SIZE(ruleset_cache.effects); i++) {
250 struct effect_list *plist = ruleset_cache.effects[i];
251
252 if (plist) {
253 effect_list_destroy(plist);
254 ruleset_cache.effects[i] = NULL;
255 }
256 }
257
258 for (i = 0; i < ARRAY_SIZE(ruleset_cache.reqs.buildings); i++) {
259 struct effect_list *plist = ruleset_cache.reqs.buildings[i];
260
261 if (plist) {
262 effect_list_destroy(plist);
263 ruleset_cache.reqs.buildings[i] = NULL;
264 }
265 }
266
267 for (i = 0; i < ARRAY_SIZE(ruleset_cache.reqs.govs); i++) {
268 struct effect_list *plist = ruleset_cache.reqs.govs[i];
269
270 if (plist) {
271 effect_list_destroy(plist);
272 ruleset_cache.reqs.govs[i] = NULL;
273 }
274 }
275
276 for (i = 0; i < ARRAY_SIZE(ruleset_cache.reqs.advances); i++) {
277 struct effect_list *plist = ruleset_cache.reqs.advances[i];
278
279 if (plist) {
280 effect_list_destroy(plist);
281 ruleset_cache.reqs.advances[i] = NULL;
282 }
283 }
284
285 initialized = FALSE;
286 }
287
288 /****************************************************************************
289 Get the maximum effect value in this ruleset for the universal
290 (that is, the sum of all positive effects clauses that apply specifically
291 to this universal -- this can be an overestimate in the case of
292 mutually exclusive effects).
293 for_uni can be NULL to get max effect value ignoring requirements.
294 ****************************************************************************/
effect_cumulative_max(enum effect_type type,struct universal * for_uni)295 int effect_cumulative_max(enum effect_type type, struct universal *for_uni)
296 {
297 struct effect_list *plist = ruleset_cache.tracker;
298 int value = 0;
299
300 if (plist) {
301 effect_list_iterate(plist, peffect) {
302 if (peffect->type == type && peffect->value > 0) {
303 if (for_uni == NULL
304 || universal_fulfills_requirements(FALSE, &(peffect->reqs),
305 for_uni)) {
306 value += peffect->value;
307 }
308 }
309 } effect_list_iterate_end;
310 }
311
312 return value;
313 }
314
315 /****************************************************************************
316 Get the minimum effect value in this ruleset for the universal
317 (that is, the sum of all negative effects clauses that apply specifically
318 to this universal -- this can be an overestimate in the case of
319 mutually exclusive effects).
320 for_uni can be NULL to get min effect value ignoring requirements.
321 ****************************************************************************/
effect_cumulative_min(enum effect_type type,struct universal * for_uni)322 int effect_cumulative_min(enum effect_type type, struct universal *for_uni)
323 {
324 struct effect_list *plist = ruleset_cache.tracker;
325 int value = 0;
326
327 if (plist) {
328 effect_list_iterate(plist, peffect) {
329 if (peffect->type == type && peffect->value < 0) {
330 if (for_uni == NULL
331 || universal_fulfills_requirements(FALSE, &(peffect->reqs),
332 for_uni)) {
333 value += peffect->value;
334 }
335 }
336 } effect_list_iterate_end;
337 }
338
339 return value;
340 }
341
342 /**********************************************************************//**
343 Return the base value of a given effect that can always be expected from
344 just the sources in the list, independent of other factors.
345 Adds up all the effects that rely only on these universals; effects that
346 have extra conditions are ignored. In effect, 'unis' is a template
347 against which effects are matched.
348 The first universal in the list is special: effects must have a
349 condition that specifically applies to that source to be included
350 (may be a superset requirement, e.g. ExtraFlag for VUT_EXTRA source).
351 **************************************************************************/
effect_value_from_universals(enum effect_type type,struct universal * unis,size_t n_unis)352 int effect_value_from_universals(enum effect_type type,
353 struct universal *unis, size_t n_unis)
354 {
355 int value = 0;
356 struct effect_list *el = get_effects(type);
357
358 effect_list_iterate(el, peffect) {
359 bool effect_applies = TRUE;
360 bool first_source_mentioned = FALSE;
361
362 if (peffect->multiplier) {
363 /* Discount any effects with multipliers; we are looking for constant
364 * effects */
365 continue;
366 }
367
368 requirement_vector_iterate(&(peffect->reqs), preq) {
369 int i;
370 bool req_mentioned_a_source = FALSE;
371
372 for (i = 0; effect_applies && i < n_unis; i++) {
373 switch (universal_fulfills_requirement(preq, &(unis[i]))) {
374 case ITF_NOT_APPLICABLE:
375 /* This req not applicable to this source (but might be relevant
376 * to another source in our template). Keep looking. */
377 break;
378 case ITF_NO:
379 req_mentioned_a_source = TRUE; /* this req matched this source */
380 if (preq->present) {
381 /* Requirement contradicts template. Effect doesn't apply. */
382 effect_applies = FALSE;
383 } /* but negative req doesn't count for first_source_mentioned */
384 break;
385 case ITF_YES:
386 req_mentioned_a_source = TRUE; /* this req matched this source */
387 if (preq->present) {
388 if (i == 0) {
389 first_source_mentioned = TRUE;
390 }
391 /* keep looking */
392 } else /* !present */ {
393 /* Requirement contradicts template. Effect doesn't apply. */
394 effect_applies = FALSE;
395 }
396 break;
397 }
398 }
399 if (!req_mentioned_a_source) {
400 /* This requirement isn't relevant to any source in our template,
401 * so it's an extra condition and the effect should be ignored. */
402 effect_applies = FALSE;
403 }
404 if (!effect_applies) {
405 /* Already known to be irrelevant, bail out early */
406 break;
407 }
408 } requirement_vector_iterate_end;
409
410 if (!first_source_mentioned) {
411 /* First source not positively mentioned anywhere in requirements,
412 * so ignore this effect */
413 continue;
414 }
415 if (effect_applies) {
416 value += peffect->value;
417 }
418 } effect_list_iterate_end;
419
420 return value;
421 }
422
423 /****************************************************************************
424 Receives a new effect. This is called by the client when the packet
425 arrives.
426 ****************************************************************************/
recv_ruleset_effect(const struct packet_ruleset_effect * packet)427 void recv_ruleset_effect(const struct packet_ruleset_effect *packet)
428 {
429 struct effect *peffect;
430 struct multiplier *pmul;
431 int i;
432
433 pmul = packet->has_multiplier ? multiplier_by_number(packet->multiplier)
434 : NULL;
435 peffect = effect_new(packet->effect_type, packet->effect_value, pmul);
436
437 for (i = 0; i < packet->reqs_count; i++) {
438 effect_req_append(peffect, packet->reqs[i]);
439 }
440 fc_assert(peffect->reqs.size == packet->reqs_count);
441 }
442
443 /**************************************************************************
444 Send the ruleset cache data over the network.
445 **************************************************************************/
send_ruleset_cache(struct conn_list * dest)446 void send_ruleset_cache(struct conn_list *dest)
447 {
448 effect_list_iterate(ruleset_cache.tracker, peffect) {
449 struct packet_ruleset_effect effect_packet;
450 int counter;
451
452 effect_packet.effect_type = peffect->type;
453 effect_packet.effect_value = peffect->value;
454 if (peffect->multiplier) {
455 effect_packet.has_multiplier = TRUE;
456 effect_packet.multiplier = multiplier_number(peffect->multiplier);
457 } else {
458 effect_packet.has_multiplier = FALSE;
459 effect_packet.multiplier = 0; /* arbitrary */
460 }
461
462 counter = 0;
463 requirement_vector_iterate(&(peffect->reqs), req) {
464 effect_packet.reqs[counter++] = *req;
465 } requirement_vector_iterate_end;
466 effect_packet.reqs_count = counter;
467
468 lsend_packet_ruleset_effect(dest, &effect_packet);
469 } effect_list_iterate_end;
470 }
471
472 /**************************************************************************
473 Returns TRUE if the building has any effect bonuses of the given type.
474
475 Note that this function returns a boolean rather than an integer value
476 giving the exact bonus. Finding the exact bonus requires knowing the
477 effect range and may take longer. This function should only be used
478 in situations where the range doesn't matter.
479 **************************************************************************/
building_has_effect(const struct impr_type * pimprove,enum effect_type effect_type)480 bool building_has_effect(const struct impr_type *pimprove,
481 enum effect_type effect_type)
482 {
483 struct universal source = {
484 .kind = VUT_IMPROVEMENT,
485 /* just to bamboozle the annoying compiler warning */
486 .value = {.building = improvement_by_number(improvement_number(pimprove))}
487 };
488 struct effect_list *plist = get_req_source_effects(&source);
489
490 if (!plist) {
491 return FALSE;
492 }
493
494 effect_list_iterate(plist, peffect) {
495 if (peffect->type == effect_type) {
496 return TRUE;
497 }
498 } effect_list_iterate_end;
499 return FALSE;
500 }
501
502 /**************************************************************************
503 Return TRUE iff any of the disabling requirements for this effect are
504 active, which would prevent it from taking effect.
505 (Assumes that any requirement specified in the ruleset with a negative
506 sense is an impediment.)
507 **************************************************************************/
is_effect_prevented(const struct player * target_player,const struct player * other_player,const struct city * target_city,const struct impr_type * target_building,const struct tile * target_tile,const struct unit * target_unit,const struct unit_type * target_unittype,const struct output_type * target_output,const struct specialist * target_specialist,const struct effect * peffect,const enum req_problem_type prob_type)508 static bool is_effect_prevented(const struct player *target_player,
509 const struct player *other_player,
510 const struct city *target_city,
511 const struct impr_type *target_building,
512 const struct tile *target_tile,
513 const struct unit *target_unit,
514 const struct unit_type *target_unittype,
515 const struct output_type *target_output,
516 const struct specialist *target_specialist,
517 const struct effect *peffect,
518 const enum req_problem_type prob_type)
519 {
520 requirement_vector_iterate(&peffect->reqs, preq) {
521 /* Only check present=FALSE requirements; these will return _FALSE_
522 * from is_req_active() if met, and need reversed prob_type */
523 if (!preq->present
524 && !is_req_active(target_player, other_player, target_city,
525 target_building, target_tile,
526 target_unit, target_unittype,
527 target_output, target_specialist,
528 preq, REVERSED_RPT(prob_type))) {
529 return TRUE;
530 }
531 } requirement_vector_iterate_end;
532 return FALSE;
533 }
534
535 /**************************************************************************
536 Returns TRUE if a building is replaced. To be replaced, all its effects
537 must be made redundant by groups that it is in.
538 prob_type CERTAIN or POSSIBLE is answer to function name.
539 **************************************************************************/
is_building_replaced(const struct city * pcity,struct impr_type * pimprove,const enum req_problem_type prob_type)540 bool is_building_replaced(const struct city *pcity,
541 struct impr_type *pimprove,
542 const enum req_problem_type prob_type)
543 {
544 struct effect_list *plist;
545 struct universal source = {
546 .kind = VUT_IMPROVEMENT,
547 .value = {.building = pimprove}
548 };
549
550 plist = get_req_source_effects(&source);
551
552 /* A building with no effects and no flags is always redundant! */
553 if (!plist) {
554 return TRUE;
555 }
556
557 effect_list_iterate(plist, peffect) {
558 /* We use TARGET_BUILDING as the lowest common denominator. Note that
559 * the building is its own target - but whether this is actually
560 * checked depends on the range of the effect. */
561 /* Prob_type is not reversed here. disabled is equal to replaced, not
562 * reverse */
563 if (!is_effect_prevented(city_owner(pcity), NULL, pcity,
564 pimprove,
565 NULL, NULL, NULL, NULL, NULL,
566 peffect, prob_type)) {
567 return FALSE;
568 }
569 } effect_list_iterate_end;
570 return TRUE;
571 }
572
573 /**************************************************************************
574 Returns the effect bonus of a given type for any target.
575
576 target gives the type of the target
577 (player,city,building,tile) give the exact target
578 effect_type gives the effect type to be considered
579
580 Returns the effect sources of this type _currently active_.
581
582 The returned vector must be freed (building_vector_free) when the caller
583 is done with it.
584 **************************************************************************/
get_target_bonus_effects(struct effect_list * plist,const struct player * target_player,const struct player * other_player,const struct city * target_city,const struct impr_type * target_building,const struct tile * target_tile,const struct unit * target_unit,const struct unit_type * target_unittype,const struct output_type * target_output,const struct specialist * target_specialist,enum effect_type effect_type)585 int get_target_bonus_effects(struct effect_list *plist,
586 const struct player *target_player,
587 const struct player *other_player,
588 const struct city *target_city,
589 const struct impr_type *target_building,
590 const struct tile *target_tile,
591 const struct unit *target_unit,
592 const struct unit_type *target_unittype,
593 const struct output_type *target_output,
594 const struct specialist *target_specialist,
595 enum effect_type effect_type)
596 {
597 int bonus = 0;
598
599 /* Loop over all effects of this type. */
600 effect_list_iterate(get_effects(effect_type), peffect) {
601 /* For each effect, see if it is active. */
602 if (are_reqs_active(target_player, other_player, target_city,
603 target_building, target_tile,
604 target_unit, target_unittype,
605 target_output, target_specialist,
606 &peffect->reqs, RPT_CERTAIN)) {
607 /* This code will add value of effect. If there's multiplier for
608 * effect and target_player aren't null, then value is multiplied
609 * by player's multiplier factor. */
610 if (peffect->multiplier) {
611 if (target_player) {
612 bonus += (peffect->value
613 * player_multiplier_effect_value(target_player,
614 peffect->multiplier)) / 100;
615 }
616 } else {
617 bonus += peffect->value;
618 }
619
620 if (plist) {
621 effect_list_append(plist, peffect);
622 }
623 }
624 } effect_list_iterate_end;
625
626 return bonus;
627 }
628
629 /**************************************************************************
630 Returns the effect bonus for the whole world.
631 **************************************************************************/
get_world_bonus(enum effect_type effect_type)632 int get_world_bonus(enum effect_type effect_type)
633 {
634 if (!initialized) {
635 return 0;
636 }
637
638 return get_target_bonus_effects(NULL,
639 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
640 NULL, NULL,
641 effect_type);
642 }
643
644 /**************************************************************************
645 Returns the effect bonus for a player.
646 **************************************************************************/
get_player_bonus(const struct player * pplayer,enum effect_type effect_type)647 int get_player_bonus(const struct player *pplayer,
648 enum effect_type effect_type)
649 {
650 if (!initialized) {
651 return 0;
652 }
653
654 return get_target_bonus_effects(NULL,
655 pplayer, NULL, NULL, NULL,
656 NULL, NULL, NULL, NULL,
657 NULL, effect_type);
658 }
659
660 /**************************************************************************
661 Returns the effect bonus at a city.
662 **************************************************************************/
get_city_bonus(const struct city * pcity,enum effect_type effect_type)663 int get_city_bonus(const struct city *pcity, enum effect_type effect_type)
664 {
665 if (!initialized) {
666 return 0;
667 }
668
669 return get_target_bonus_effects(NULL,
670 city_owner(pcity), NULL, pcity, NULL,
671 city_tile(pcity), NULL, NULL, NULL,
672 NULL, effect_type);
673 }
674
675 /**************************************************************************
676 Returns the effect bonus of a specialist in a city.
677 **************************************************************************/
get_city_specialist_output_bonus(const struct city * pcity,const struct specialist * pspecialist,const struct output_type * poutput,enum effect_type effect_type)678 int get_city_specialist_output_bonus(const struct city *pcity,
679 const struct specialist *pspecialist,
680 const struct output_type *poutput,
681 enum effect_type effect_type)
682 {
683 fc_assert_ret_val(pcity != NULL, 0);
684 fc_assert_ret_val(pspecialist != NULL, 0);
685 fc_assert_ret_val(poutput != NULL, 0);
686 return get_target_bonus_effects(NULL,
687 city_owner(pcity), NULL, pcity, NULL,
688 NULL, NULL, NULL, poutput, pspecialist,
689 effect_type);
690 }
691
692 /**************************************************************************
693 Returns the effect bonus at a city tile.
694 pcity must be supplied.
695
696 FIXME: this is now used both for tile bonuses, tile-output bonuses,
697 and city-output bonuses. Thus ptile or poutput may be NULL for
698 certain callers. This could be changed by adding 2 new functions to
699 the interface but they'd be almost identical and their likely names
700 would conflict with functions already in city.c.
701 It's also very similar to get_tile_output_bonus(); it should be
702 called when the city is mandatory.
703 **************************************************************************/
get_city_tile_output_bonus(const struct city * pcity,const struct tile * ptile,const struct output_type * poutput,enum effect_type effect_type)704 int get_city_tile_output_bonus(const struct city *pcity,
705 const struct tile *ptile,
706 const struct output_type *poutput,
707 enum effect_type effect_type)
708 {
709 fc_assert_ret_val(pcity != NULL, 0);
710 return get_target_bonus_effects(NULL,
711 city_owner(pcity), NULL, pcity, NULL,
712 ptile, NULL, NULL, poutput, NULL,
713 effect_type);
714 }
715
716 /**************************************************************************
717 Returns the effect bonus at a tile for given output type (or NULL for
718 output-type-independent bonus).
719 If pcity is supplied, it's the bonus for that particular city, otherwise
720 it's the player/city-independent bonus (and any city on the tile is
721 ignored).
722 **************************************************************************/
get_tile_output_bonus(const struct city * pcity,const struct tile * ptile,const struct output_type * poutput,enum effect_type effect_type)723 int get_tile_output_bonus(const struct city *pcity,
724 const struct tile *ptile,
725 const struct output_type *poutput,
726 enum effect_type effect_type)
727 {
728 const struct player *pplayer = pcity ? city_owner(pcity) : NULL;
729
730 return get_target_bonus_effects(NULL,
731 pplayer, NULL, pcity, NULL,
732 ptile, NULL, NULL, poutput, NULL,
733 effect_type);
734 }
735
736 /**************************************************************************
737 Returns the player effect bonus of an output.
738 **************************************************************************/
get_player_output_bonus(const struct player * pplayer,const struct output_type * poutput,enum effect_type effect_type)739 int get_player_output_bonus(const struct player *pplayer,
740 const struct output_type *poutput,
741 enum effect_type effect_type)
742 {
743 if (!initialized) {
744 return 0;
745 }
746
747 fc_assert_ret_val(pplayer != NULL, 0);
748 fc_assert_ret_val(poutput != NULL, 0);
749 fc_assert_ret_val(effect_type != EFT_COUNT, 0);
750 return get_target_bonus_effects(NULL, pplayer, NULL, NULL, NULL, NULL,
751 NULL, NULL, poutput, NULL, effect_type);
752 }
753
754 /**************************************************************************
755 Returns the player effect bonus of an output.
756 **************************************************************************/
get_city_output_bonus(const struct city * pcity,const struct output_type * poutput,enum effect_type effect_type)757 int get_city_output_bonus(const struct city *pcity,
758 const struct output_type *poutput,
759 enum effect_type effect_type)
760 {
761 if (!initialized) {
762 return 0;
763 }
764
765 fc_assert_ret_val(pcity != NULL, 0);
766 fc_assert_ret_val(poutput != NULL, 0);
767 fc_assert_ret_val(effect_type != EFT_COUNT, 0);
768 return get_target_bonus_effects(NULL, city_owner(pcity), NULL, pcity,
769 NULL, NULL, NULL, NULL, poutput, NULL,
770 effect_type);
771 }
772
773 /**************************************************************************
774 Returns the effect bonus at a building.
775 **************************************************************************/
get_building_bonus(const struct city * pcity,const struct impr_type * building,enum effect_type effect_type)776 int get_building_bonus(const struct city *pcity,
777 const struct impr_type *building,
778 enum effect_type effect_type)
779 {
780 if (!initialized) {
781 return 0;
782 }
783
784 fc_assert_ret_val(NULL != pcity && NULL != building, 0);
785 return get_target_bonus_effects(NULL,
786 city_owner(pcity), NULL, pcity,
787 building,
788 NULL, NULL, NULL, NULL,
789 NULL, effect_type);
790 }
791
792 /**************************************************************************
793 Returns the effect bonus that applies at a tile for a given unittype.
794
795 For instance with EFT_DEFEND_BONUS the attacker's unittype and the
796 defending tile should be passed in. Slightly counter-intuitive!
797 See doc/README.effects to see how the unittype applies for each effect
798 here.
799 **************************************************************************/
get_unittype_bonus(const struct player * pplayer,const struct tile * ptile,const struct unit_type * punittype,enum effect_type effect_type)800 int get_unittype_bonus(const struct player *pplayer,
801 const struct tile *ptile,
802 const struct unit_type *punittype,
803 enum effect_type effect_type)
804 {
805 struct city *pcity;
806
807 if (!initialized) {
808 return 0;
809 }
810
811 fc_assert_ret_val(pplayer != NULL && punittype != NULL, 0);
812
813 if (ptile != NULL) {
814 pcity = tile_city(ptile);
815 } else {
816 pcity = NULL;
817 }
818
819 return get_target_bonus_effects(NULL,
820 pplayer, NULL, pcity, NULL, ptile,
821 NULL, punittype, NULL,
822 NULL, effect_type);
823 }
824
825 /**************************************************************************
826 Returns the effect bonus at a unit
827 **************************************************************************/
get_unit_bonus(const struct unit * punit,enum effect_type effect_type)828 int get_unit_bonus(const struct unit *punit, enum effect_type effect_type)
829 {
830 if (!initialized) {
831 return 0;
832 }
833
834 fc_assert_ret_val(punit != NULL, 0);
835 return get_target_bonus_effects(NULL,
836 unit_owner(punit),
837 NULL,
838 unit_tile(punit)
839 ? tile_city(unit_tile(punit)) : NULL,
840 NULL, unit_tile(punit),
841 punit, unit_type_get(punit), NULL, NULL,
842 effect_type);
843 }
844
845 /**************************************************************************
846 Returns the effect bonus at a tile
847 **************************************************************************/
get_tile_bonus(const struct tile * ptile,const struct unit * punit,enum effect_type etype)848 int get_tile_bonus(const struct tile *ptile, const struct unit *punit,
849 enum effect_type etype)
850 {
851 struct player *pplayer = NULL;
852 struct unit_type *utype = NULL;
853
854 if (!initialized) {
855 return 0;
856 }
857
858 fc_assert_ret_val(ptile != NULL, 0);
859
860 if (punit != NULL) {
861 pplayer = unit_owner(punit);
862 utype = unit_type_get(punit);
863 }
864
865 return get_target_bonus_effects(NULL,
866 pplayer,
867 NULL,
868 tile_city(ptile),
869 NULL,
870 ptile,
871 punit,
872 utype,
873 NULL, NULL,
874 etype);
875 }
876
877 /**************************************************************************
878 Returns the effect sources of this type _currently active_ at the player.
879
880 The returned vector must be freed (building_vector_free) when the caller
881 is done with it.
882 **************************************************************************/
get_player_bonus_effects(struct effect_list * plist,const struct player * pplayer,enum effect_type effect_type)883 int get_player_bonus_effects(struct effect_list *plist,
884 const struct player *pplayer,
885 enum effect_type effect_type)
886 {
887 if (!initialized) {
888 return 0;
889 }
890
891 fc_assert_ret_val(pplayer != NULL, 0);
892 return get_target_bonus_effects(plist,
893 pplayer, NULL, NULL, NULL,
894 NULL, NULL, NULL, NULL, NULL,
895 effect_type);
896 }
897
898 /**************************************************************************
899 Returns the effect sources of this type _currently active_ at the city.
900
901 The returned vector must be freed (building_vector_free) when the caller
902 is done with it.
903 **************************************************************************/
get_city_bonus_effects(struct effect_list * plist,const struct city * pcity,const struct output_type * poutput,enum effect_type effect_type)904 int get_city_bonus_effects(struct effect_list *plist,
905 const struct city *pcity,
906 const struct output_type *poutput,
907 enum effect_type effect_type)
908 {
909 if (!initialized) {
910 return 0;
911 }
912
913 fc_assert_ret_val(pcity != NULL, 0);
914 return get_target_bonus_effects(plist,
915 city_owner(pcity), NULL, pcity, NULL,
916 NULL, NULL, NULL, poutput, NULL,
917 effect_type);
918 }
919
920 /**************************************************************************
921 Returns the effect bonus the currently-in-construction-item will provide.
922
923 Note this is not called get_current_production_bonus because that would
924 be confused with EFT_PROD_BONUS.
925
926 Problem type tells if we need to be CERTAIN about bonus before counting
927 it or is POSSIBLE bonus enough.
928 **************************************************************************/
get_current_construction_bonus(const struct city * pcity,enum effect_type effect_type,const enum req_problem_type prob_type)929 int get_current_construction_bonus(const struct city *pcity,
930 enum effect_type effect_type,
931 const enum req_problem_type prob_type)
932 {
933 if (!initialized) {
934 return 0;
935 }
936
937 if (VUT_IMPROVEMENT == pcity->production.kind) {
938 return get_potential_improvement_bonus(pcity->production.value.building,
939 pcity, effect_type, prob_type);
940 }
941 return 0;
942 }
943
944 /**************************************************************************
945 Returns the effect bonus the improvement would or does provide if present.
946
947 Problem type tells if we need to be CERTAIN about bonus before counting
948 it or is POSSIBLE bonus enough.
949 **************************************************************************/
get_potential_improvement_bonus(struct impr_type * pimprove,const struct city * pcity,enum effect_type effect_type,const enum req_problem_type prob_type)950 int get_potential_improvement_bonus(struct impr_type *pimprove,
951 const struct city *pcity,
952 enum effect_type effect_type,
953 const enum req_problem_type prob_type)
954 {
955 struct universal source = { .kind = VUT_IMPROVEMENT,
956 .value = {.building = pimprove}};
957 struct effect_list *plist = get_req_source_effects(&source);
958
959
960 if (plist) {
961 int power = 0;
962
963 effect_list_iterate(plist, peffect) {
964 bool present = TRUE;
965 bool useful = TRUE;
966
967 if (peffect->type != effect_type) {
968 continue;
969 }
970
971 requirement_vector_iterate(&peffect->reqs, preq) {
972 if (VUT_IMPROVEMENT == preq->source.kind
973 && preq->source.value.building == pimprove) {
974 present = preq->present;
975 continue;
976 }
977
978 if (!is_req_active(city_owner(pcity), NULL, pcity, pimprove,
979 NULL, NULL, NULL, NULL, NULL,
980 preq, prob_type)) {
981 useful = FALSE;
982 break;
983 }
984 } requirement_vector_iterate_end;
985
986 if (useful) {
987 if (present) {
988 power += peffect->value;
989 } else {
990 power -= peffect->value;
991 }
992 }
993 } effect_list_iterate_end;
994
995 return power;
996 }
997 return 0;
998 }
999
1000 /**************************************************************************
1001 Make user-friendly text for the source. The text is put into a user
1002 buffer.
1003 **************************************************************************/
get_effect_req_text(const struct effect * peffect,char * buf,size_t buf_len)1004 void get_effect_req_text(const struct effect *peffect,
1005 char *buf, size_t buf_len)
1006 {
1007 buf[0] = '\0';
1008
1009 if (peffect->multiplier) {
1010 fc_strlcat(buf, multiplier_name_translation(peffect->multiplier), buf_len);
1011 }
1012
1013 /* FIXME: should we do something for present==FALSE reqs?
1014 * Currently we just ignore them. */
1015 requirement_vector_iterate(&peffect->reqs, preq) {
1016 if (!preq->present) {
1017 continue;
1018 }
1019 if (buf[0] != '\0') {
1020 fc_strlcat(buf, Q_("?req-list-separator:+"), buf_len);
1021 }
1022
1023 universal_name_translation(&preq->source,
1024 buf + strlen(buf), buf_len - strlen(buf));
1025 } requirement_vector_iterate_end;
1026 }
1027
1028 /****************************************************************************
1029 Make user-friendly text for an effect list. The text is put into a user
1030 astring.
1031 ****************************************************************************/
get_effect_list_req_text(const struct effect_list * plist,struct astring * astr)1032 void get_effect_list_req_text(const struct effect_list *plist,
1033 struct astring *astr)
1034 {
1035 struct strvec *psv = strvec_new();
1036 char req_text[512];
1037
1038 effect_list_iterate(plist, peffect) {
1039 get_effect_req_text(peffect, req_text, sizeof(req_text));
1040 strvec_append(psv, req_text);
1041 } effect_list_iterate_end;
1042
1043 strvec_to_and_list(psv, astr);
1044 strvec_destroy(psv);
1045 }
1046
1047 /**************************************************************************
1048 Iterate through all the effects in cache, and call callback for each.
1049 If any callback returns FALSE, there is no further checking and
1050 this will return FALSE.
1051 **************************************************************************/
iterate_effect_cache(iec_cb cb,void * data)1052 bool iterate_effect_cache(iec_cb cb, void *data)
1053 {
1054 fc_assert_ret_val(cb != NULL, FALSE);
1055
1056 effect_list_iterate(ruleset_cache.tracker, peffect) {
1057 if (!cb(peffect, data)) {
1058 return FALSE;
1059 }
1060 } effect_list_iterate_end;
1061
1062 return TRUE;
1063 }
1064