Updated hexemplio road types.
[freeciv.git] / common / effects.c
blob84bd84092b62994006635847f3e5d13bca1556a3
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.
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
17 #include <ctype.h>
18 #include <string.h>
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"
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"
39 #include "effects.h"
42 static bool initialized = FALSE;
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).
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.
55 To know how much a target is being affected, simply use the convenience
56 functions:
58 * get_player_bonus
59 * get_city_bonus
60 * get_city_tile_bonus
61 * get_building_bonus
63 These functions require as arguments the target and the effect type to be
64 queried.
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.
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.
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.
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 **************************************************************************/
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;
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];
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;
125 /**************************************************************************
126 Get a list of effects of this type.
127 **************************************************************************/
128 struct effect_list *get_effects(enum effect_type effect_type)
130 return ruleset_cache.effects[effect_type];
133 /**************************************************************************
134 Get a list of effects with this requirement source.
136 Note: currently only buildings and governments are supported.
137 **************************************************************************/
138 struct effect_list *get_req_source_effects(struct universal *psource)
140 int type, value;
142 universal_extraction(psource, &type, &value);
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;
151 case VUT_IMPROVEMENT:
152 if (value >= 0 && value < improvement_count()) {
153 return ruleset_cache.reqs.buildings[value];
154 } else {
155 return NULL;
157 case VUT_ADVANCE:
158 if (value >= 0 && value < advance_count()) {
159 return ruleset_cache.reqs.advances[value];
160 } else {
161 return NULL;
163 default:
164 return NULL;
168 /**************************************************************************
169 Add effect to ruleset cache.
170 **************************************************************************/
171 struct effect *effect_new(enum effect_type type, int value,
172 struct multiplier *pmul)
174 struct effect *peffect;
176 /* Create the effect. */
177 peffect = fc_malloc(sizeof(*peffect));
178 peffect->type = type;
179 peffect->value = value;
180 peffect->multiplier = pmul;
182 requirement_vector_init(&peffect->reqs);
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;
190 /**************************************************************************
191 Append requirement to effect.
192 **************************************************************************/
193 void effect_req_append(struct effect *peffect, struct requirement req)
195 struct effect_list *eff_list = get_req_source_effects(&req.source);
197 requirement_vector_append(&peffect->reqs, req);
199 if (eff_list) {
200 effect_list_append(eff_list, peffect);
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 **************************************************************************/
209 void ruleset_cache_init(void)
211 int i;
213 initialized = TRUE;
215 ruleset_cache.tracker = effect_list_new();
217 for (i = 0; i < ARRAY_SIZE(ruleset_cache.effects); i++) {
218 ruleset_cache.effects[i] = effect_list_new();
220 for (i = 0; i < ARRAY_SIZE(ruleset_cache.reqs.buildings); i++) {
221 ruleset_cache.reqs.buildings[i] = effect_list_new();
223 for (i = 0; i < ARRAY_SIZE(ruleset_cache.reqs.govs); i++) {
224 ruleset_cache.reqs.govs[i] = effect_list_new();
226 for (i = 0; i < ARRAY_SIZE(ruleset_cache.reqs.advances); i++) {
227 ruleset_cache.reqs.advances[i] = effect_list_new();
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 **************************************************************************/
235 void ruleset_cache_free(void)
237 int i;
238 struct effect_list *tracker_list = ruleset_cache.tracker;
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;
249 for (i = 0; i < ARRAY_SIZE(ruleset_cache.effects); i++) {
250 struct effect_list *plist = ruleset_cache.effects[i];
252 if (plist) {
253 effect_list_destroy(plist);
254 ruleset_cache.effects[i] = NULL;
258 for (i = 0; i < ARRAY_SIZE(ruleset_cache.reqs.buildings); i++) {
259 struct effect_list *plist = ruleset_cache.reqs.buildings[i];
261 if (plist) {
262 effect_list_destroy(plist);
263 ruleset_cache.reqs.buildings[i] = NULL;
267 for (i = 0; i < ARRAY_SIZE(ruleset_cache.reqs.govs); i++) {
268 struct effect_list *plist = ruleset_cache.reqs.govs[i];
270 if (plist) {
271 effect_list_destroy(plist);
272 ruleset_cache.reqs.govs[i] = NULL;
276 for (i = 0; i < ARRAY_SIZE(ruleset_cache.reqs.advances); i++) {
277 struct effect_list *plist = ruleset_cache.reqs.advances[i];
279 if (plist) {
280 effect_list_destroy(plist);
281 ruleset_cache.reqs.advances[i] = NULL;
285 initialized = FALSE;
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 ****************************************************************************/
295 int effect_cumulative_max(enum effect_type type, struct universal *for_uni)
297 struct effect_list *plist = ruleset_cache.tracker;
298 int value = 0;
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_requirement(FALSE, &(peffect->reqs), for_uni)) {
305 value += peffect->value;
308 } effect_list_iterate_end;
311 return value;
314 /****************************************************************************
315 Get the minimum effect value in this ruleset for the universal
316 (that is, the sum of all negative effects clauses that apply specifically
317 to this universal -- this can be an overestimate in the case of
318 mutually exclusive effects).
319 for_uni can be NULL to get min effect value ignoring requirements.
320 ****************************************************************************/
321 int effect_cumulative_min(enum effect_type type, struct universal *for_uni)
323 struct effect_list *plist = ruleset_cache.tracker;
324 int value = 0;
326 if (plist) {
327 effect_list_iterate(plist, peffect) {
328 if (peffect->type == type && peffect->value < 0) {
329 if (for_uni == NULL
330 || universal_fulfills_requirement(FALSE, &(peffect->reqs), for_uni)) {
331 value += peffect->value;
334 } effect_list_iterate_end;
337 return value;
340 /****************************************************************************
341 Receives a new effect. This is called by the client when the packet
342 arrives.
343 ****************************************************************************/
344 void recv_ruleset_effect(const struct packet_ruleset_effect *packet)
346 struct effect *peffect;
347 struct multiplier *pmul;
348 int i;
350 pmul = packet->has_multiplier ? multiplier_by_number(packet->multiplier)
351 : NULL;
352 peffect = effect_new(packet->effect_type, packet->effect_value, pmul);
354 for (i = 0; i < packet->reqs_count; i++) {
355 effect_req_append(peffect, packet->reqs[i]);
357 fc_assert(peffect->reqs.size == packet->reqs_count);
360 /**************************************************************************
361 Send the ruleset cache data over the network.
362 **************************************************************************/
363 void send_ruleset_cache(struct conn_list *dest)
365 effect_list_iterate(ruleset_cache.tracker, peffect) {
366 struct packet_ruleset_effect effect_packet;
367 int counter;
369 effect_packet.effect_type = peffect->type;
370 effect_packet.effect_value = peffect->value;
371 if (peffect->multiplier) {
372 effect_packet.has_multiplier = TRUE;
373 effect_packet.multiplier = multiplier_number(peffect->multiplier);
374 } else {
375 effect_packet.has_multiplier = FALSE;
376 effect_packet.multiplier = 0; /* arbitrary */
379 counter = 0;
380 requirement_vector_iterate(&(peffect->reqs), req) {
381 effect_packet.reqs[counter++] = *req;
382 } requirement_vector_iterate_end;
383 effect_packet.reqs_count = counter;
385 lsend_packet_ruleset_effect(dest, &effect_packet);
386 } effect_list_iterate_end;
389 /**************************************************************************
390 Returns TRUE if the building has any effect bonuses of the given type.
392 Note that this function returns a boolean rather than an integer value
393 giving the exact bonus. Finding the exact bonus requires knowing the
394 effect range and may take longer. This function should only be used
395 in situations where the range doesn't matter.
396 **************************************************************************/
397 bool building_has_effect(const struct impr_type *pimprove,
398 enum effect_type effect_type)
400 struct universal source = {
401 .kind = VUT_IMPROVEMENT,
402 /* just to bamboozle the annoying compiler warning */
403 .value = {.building = improvement_by_number(improvement_number(pimprove))}
405 struct effect_list *plist = get_req_source_effects(&source);
407 if (!plist) {
408 return FALSE;
411 effect_list_iterate(plist, peffect) {
412 if (peffect->type == effect_type) {
413 return TRUE;
415 } effect_list_iterate_end;
416 return FALSE;
419 /**************************************************************************
420 Return TRUE iff any of the disabling requirements for this effect are
421 active, which would prevent it from taking effect.
422 (Assumes that any requirement specified in the ruleset with a negative
423 sense is an impediment.)
424 **************************************************************************/
425 static bool is_effect_prevented(const struct player *target_player,
426 const struct player *other_player,
427 const struct city *target_city,
428 const struct impr_type *target_building,
429 const struct tile *target_tile,
430 const struct unit *target_unit,
431 const struct unit_type *target_unittype,
432 const struct output_type *target_output,
433 const struct specialist *target_specialist,
434 const struct effect *peffect,
435 const enum req_problem_type prob_type)
437 requirement_vector_iterate(&peffect->reqs, preq) {
438 /* Only check present=FALSE requirements; these will return _FALSE_
439 * from is_req_active() if met, and need reversed prob_type */
440 if (!preq->present
441 && !is_req_active(target_player, other_player, target_city,
442 target_building, target_tile,
443 target_unit, target_unittype,
444 target_output, target_specialist,
445 preq, REVERSED_RPT(prob_type))) {
446 return TRUE;
448 } requirement_vector_iterate_end;
449 return FALSE;
452 /**************************************************************************
453 Returns TRUE if a building is replaced. To be replaced, all its effects
454 must be made redundant by groups that it is in.
455 prob_type CERTAIN or POSSIBLE is answer to function name.
456 **************************************************************************/
457 bool is_building_replaced(const struct city *pcity,
458 struct impr_type *pimprove,
459 const enum req_problem_type prob_type)
461 struct effect_list *plist;
462 struct universal source = {
463 .kind = VUT_IMPROVEMENT,
464 .value = {.building = pimprove}
467 plist = get_req_source_effects(&source);
469 /* A building with no effects and no flags is always redundant! */
470 if (!plist) {
471 return TRUE;
474 effect_list_iterate(plist, peffect) {
475 /* We use TARGET_BUILDING as the lowest common denominator. Note that
476 * the building is its own target - but whether this is actually
477 * checked depends on the range of the effect. */
478 /* Prob_type is not reversed here. disabled is equal to replaced, not
479 * reverse */
480 if (!is_effect_prevented(city_owner(pcity), NULL, pcity,
481 pimprove,
482 NULL, NULL, NULL, NULL, NULL,
483 peffect, prob_type)) {
484 return FALSE;
486 } effect_list_iterate_end;
487 return TRUE;
490 /**************************************************************************
491 Returns the effect bonus of a given type for any target.
493 target gives the type of the target
494 (player,city,building,tile) give the exact target
495 effect_type gives the effect type to be considered
497 Returns the effect sources of this type _currently active_.
499 The returned vector must be freed (building_vector_free) when the caller
500 is done with it.
501 **************************************************************************/
502 int get_target_bonus_effects(struct effect_list *plist,
503 const struct player *target_player,
504 const struct player *other_player,
505 const struct city *target_city,
506 const struct impr_type *target_building,
507 const struct tile *target_tile,
508 const struct unit *target_unit,
509 const struct unit_type *target_unittype,
510 const struct output_type *target_output,
511 const struct specialist *target_specialist,
512 enum effect_type effect_type)
514 int bonus = 0;
516 /* Loop over all effects of this type. */
517 effect_list_iterate(get_effects(effect_type), peffect) {
518 /* For each effect, see if it is active. */
519 if (are_reqs_active(target_player, other_player, target_city,
520 target_building, target_tile,
521 target_unit, target_unittype,
522 target_output, target_specialist,
523 &peffect->reqs, RPT_CERTAIN)) {
524 /* This code will add value of effect. If there's multiplier for
525 * effect and target_player aren't null, then value is multiplied
526 * by player's multiplier factor. */
527 if (peffect->multiplier) {
528 if (target_player) {
529 bonus += (peffect->value
530 * player_multiplier_effect_value(target_player,
531 peffect->multiplier)) / 100;
533 } else {
534 bonus += peffect->value;
537 if (plist) {
538 effect_list_append(plist, peffect);
541 } effect_list_iterate_end;
543 return bonus;
546 /**************************************************************************
547 Returns the effect bonus for the whole world.
548 **************************************************************************/
549 int get_world_bonus(enum effect_type effect_type)
551 if (!initialized) {
552 return 0;
555 return get_target_bonus_effects(NULL,
556 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
557 NULL, NULL,
558 effect_type);
561 /**************************************************************************
562 Returns the effect bonus for a player.
563 **************************************************************************/
564 int get_player_bonus(const struct player *pplayer,
565 enum effect_type effect_type)
567 if (!initialized) {
568 return 0;
571 return get_target_bonus_effects(NULL,
572 pplayer, NULL, NULL, NULL,
573 NULL, NULL, NULL, NULL,
574 NULL, effect_type);
577 /**************************************************************************
578 Returns the effect bonus at a city.
579 **************************************************************************/
580 int get_city_bonus(const struct city *pcity, enum effect_type effect_type)
582 if (!initialized) {
583 return 0;
586 return get_target_bonus_effects(NULL,
587 city_owner(pcity), NULL, pcity, NULL,
588 city_tile(pcity), NULL, NULL, NULL,
589 NULL, effect_type);
592 /**************************************************************************
593 Returns the effect bonus of a specialist in a city.
594 **************************************************************************/
595 int get_city_specialist_output_bonus(const struct city *pcity,
596 const struct specialist *pspecialist,
597 const struct output_type *poutput,
598 enum effect_type effect_type)
600 fc_assert_ret_val(pcity != NULL, 0);
601 fc_assert_ret_val(pspecialist != NULL, 0);
602 fc_assert_ret_val(poutput != NULL, 0);
603 return get_target_bonus_effects(NULL,
604 city_owner(pcity), NULL, pcity, NULL,
605 NULL, NULL, NULL, poutput, pspecialist,
606 effect_type);
609 /**************************************************************************
610 Returns the effect bonus at a city tile.
612 FIXME: this is now used both for tile bonuses, tile-output bonuses,
613 and city-output bonuses. Thus ptile or poutput may be NULL for
614 certain callers. This could be changed by adding 2 new functions to
615 the interface but they'd be almost identical and their likely names
616 would conflict with functions already in city.c.
617 **************************************************************************/
618 int get_city_tile_output_bonus(const struct city *pcity,
619 const struct tile *ptile,
620 const struct output_type *poutput,
621 enum effect_type effect_type)
623 fc_assert_ret_val(pcity != NULL, 0);
624 return get_target_bonus_effects(NULL,
625 city_owner(pcity), NULL, pcity, NULL,
626 ptile, NULL, NULL, poutput, NULL,
627 effect_type);
630 /**************************************************************************
631 Returns the player effect bonus of an output.
632 **************************************************************************/
633 int get_player_output_bonus(const struct player *pplayer,
634 const struct output_type *poutput,
635 enum effect_type effect_type)
637 if (!initialized) {
638 return 0;
641 fc_assert_ret_val(pplayer != NULL, 0);
642 fc_assert_ret_val(poutput != NULL, 0);
643 fc_assert_ret_val(effect_type != EFT_COUNT, 0);
644 return get_target_bonus_effects(NULL, pplayer, NULL, NULL, NULL, NULL,
645 NULL, NULL, poutput, NULL, effect_type);
648 /**************************************************************************
649 Returns the player effect bonus of an output.
650 **************************************************************************/
651 int get_city_output_bonus(const struct city *pcity,
652 const struct output_type *poutput,
653 enum effect_type effect_type)
655 if (!initialized) {
656 return 0;
659 fc_assert_ret_val(pcity != NULL, 0);
660 fc_assert_ret_val(poutput != NULL, 0);
661 fc_assert_ret_val(effect_type != EFT_COUNT, 0);
662 return get_target_bonus_effects(NULL, city_owner(pcity), NULL, pcity,
663 NULL, NULL, NULL, NULL, poutput, NULL,
664 effect_type);
667 /**************************************************************************
668 Returns the effect bonus at a building.
669 **************************************************************************/
670 int get_building_bonus(const struct city *pcity,
671 const struct impr_type *building,
672 enum effect_type effect_type)
674 if (!initialized) {
675 return 0;
678 fc_assert_ret_val(NULL != pcity && NULL != building, 0);
679 return get_target_bonus_effects(NULL,
680 city_owner(pcity), NULL, pcity,
681 building,
682 NULL, NULL, NULL, NULL,
683 NULL, effect_type);
686 /**************************************************************************
687 Returns the effect bonus that applies at a tile for a given unittype.
689 For instance with EFT_DEFEND_BONUS the attacker's unittype and the
690 defending tile should be passed in. Slightly counter-intuitive!
691 See doc/README.effects to see how the unittype applies for each effect
692 here.
693 **************************************************************************/
694 int get_unittype_bonus(const struct player *pplayer,
695 const struct tile *ptile,
696 const struct unit_type *punittype,
697 enum effect_type effect_type)
699 struct city *pcity;
701 if (!initialized) {
702 return 0;
705 fc_assert_ret_val(pplayer != NULL && punittype != NULL, 0);
707 if (ptile != NULL) {
708 pcity = tile_city(ptile);
709 } else {
710 pcity = NULL;
713 return get_target_bonus_effects(NULL,
714 pplayer, NULL, pcity, NULL, ptile,
715 NULL, punittype, NULL,
716 NULL, effect_type);
719 /**************************************************************************
720 Returns the effect bonus at a unit
721 **************************************************************************/
722 int get_unit_bonus(const struct unit *punit, enum effect_type effect_type)
724 if (!initialized) {
725 return 0;
728 fc_assert_ret_val(punit != NULL, 0);
729 return get_target_bonus_effects(NULL,
730 unit_owner(punit),
731 NULL,
732 unit_tile(punit)
733 ? tile_city(unit_tile(punit)) : NULL,
734 NULL, unit_tile(punit),
735 punit, unit_type_get(punit), NULL, NULL,
736 effect_type);
739 /**************************************************************************
740 Returns the effect bonus at a tile
741 **************************************************************************/
742 int get_tile_bonus(const struct tile *ptile, const struct unit *punit,
743 enum effect_type etype)
745 struct player *pplayer = NULL;
746 struct unit_type *utype = NULL;
748 if (!initialized) {
749 return 0;
752 fc_assert_ret_val(ptile != NULL, 0);
754 if (punit != NULL) {
755 pplayer = unit_owner(punit);
756 utype = unit_type_get(punit);
759 return get_target_bonus_effects(NULL,
760 pplayer,
761 NULL,
762 tile_city(ptile),
763 NULL,
764 ptile,
765 punit,
766 utype,
767 NULL, NULL,
768 etype);
771 /**************************************************************************
772 Returns the effect sources of this type _currently active_ at the player.
774 The returned vector must be freed (building_vector_free) when the caller
775 is done with it.
776 **************************************************************************/
777 int get_player_bonus_effects(struct effect_list *plist,
778 const struct player *pplayer,
779 enum effect_type effect_type)
781 if (!initialized) {
782 return 0;
785 fc_assert_ret_val(pplayer != NULL, 0);
786 return get_target_bonus_effects(plist,
787 pplayer, NULL, NULL, NULL,
788 NULL, NULL, NULL, NULL, NULL,
789 effect_type);
792 /**************************************************************************
793 Returns the effect sources of this type _currently active_ at the city.
795 The returned vector must be freed (building_vector_free) when the caller
796 is done with it.
797 **************************************************************************/
798 int get_city_bonus_effects(struct effect_list *plist,
799 const struct city *pcity,
800 const struct output_type *poutput,
801 enum effect_type effect_type)
803 if (!initialized) {
804 return 0;
807 fc_assert_ret_val(pcity != NULL, 0);
808 return get_target_bonus_effects(plist,
809 city_owner(pcity), NULL, pcity, NULL,
810 NULL, NULL, NULL, poutput, NULL,
811 effect_type);
814 /**************************************************************************
815 Returns the effect bonus the currently-in-construction-item will provide.
817 Note this is not called get_current_production_bonus because that would
818 be confused with EFT_PROD_BONUS.
820 Problem type tells if we need to be CERTAIN about bonus before counting
821 it or is POSSIBLE bonus enough.
822 **************************************************************************/
823 int get_current_construction_bonus(const struct city *pcity,
824 enum effect_type effect_type,
825 const enum req_problem_type prob_type)
827 if (!initialized) {
828 return 0;
831 if (VUT_IMPROVEMENT == pcity->production.kind) {
832 return get_potential_improvement_bonus(pcity->production.value.building,
833 pcity, effect_type, prob_type);
835 return 0;
838 /**************************************************************************
839 Returns the effect bonus the improvement would or does provide if present.
841 Problem type tells if we need to be CERTAIN about bonus before counting
842 it or is POSSIBLE bonus enough.
843 **************************************************************************/
844 int get_potential_improvement_bonus(struct impr_type *pimprove,
845 const struct city *pcity,
846 enum effect_type effect_type,
847 const enum req_problem_type prob_type)
849 struct universal source = { .kind = VUT_IMPROVEMENT,
850 .value = {.building = pimprove}};
851 struct effect_list *plist = get_req_source_effects(&source);
854 if (plist) {
855 int power = 0;
857 effect_list_iterate(plist, peffect) {
858 bool present = TRUE;
859 bool useful = TRUE;
861 if (peffect->type != effect_type) {
862 continue;
865 requirement_vector_iterate(&peffect->reqs, preq) {
866 if (VUT_IMPROVEMENT == preq->source.kind
867 && preq->source.value.building == pimprove) {
868 present = preq->present;
869 continue;
872 if (!is_req_active(city_owner(pcity), NULL, pcity, pimprove,
873 NULL, NULL, NULL, NULL, NULL,
874 preq, prob_type)) {
875 useful = FALSE;
876 break;
878 } requirement_vector_iterate_end;
880 if (useful) {
881 if (present) {
882 power += peffect->value;
883 } else {
884 power -= peffect->value;
887 } effect_list_iterate_end;
889 return power;
891 return 0;
894 /**************************************************************************
895 Make user-friendly text for the source. The text is put into a user
896 buffer.
897 **************************************************************************/
898 void get_effect_req_text(const struct effect *peffect,
899 char *buf, size_t buf_len)
901 buf[0] = '\0';
903 if (peffect->multiplier) {
904 fc_strlcat(buf, multiplier_name_translation(peffect->multiplier), buf_len);
907 /* FIXME: should we do something for present==FALSE reqs?
908 * Currently we just ignore them. */
909 requirement_vector_iterate(&peffect->reqs, preq) {
910 if (!preq->present) {
911 continue;
913 if (buf[0] != '\0') {
914 fc_strlcat(buf, Q_("?req-list-separator:+"), buf_len);
917 universal_name_translation(&preq->source,
918 buf + strlen(buf), buf_len - strlen(buf));
919 } requirement_vector_iterate_end;
922 /****************************************************************************
923 Make user-friendly text for an effect list. The text is put into a user
924 astring.
925 ****************************************************************************/
926 void get_effect_list_req_text(const struct effect_list *plist,
927 struct astring *astr)
929 struct strvec *psv = strvec_new();
930 char req_text[512];
932 effect_list_iterate(plist, peffect) {
933 get_effect_req_text(peffect, req_text, sizeof(req_text));
934 strvec_append(psv, req_text);
935 } effect_list_iterate_end;
937 strvec_to_and_list(psv, astr);
938 strvec_destroy(psv);
941 /**************************************************************************
942 Iterate through all the effects in cache, and call callback for each.
943 This is currently not very generic implementation, as we have only one user;
944 ruleset sanity checking. If any callback returns FALSE, there is no
945 further checking and this will return FALSE.
946 **************************************************************************/
947 bool iterate_effect_cache(iec_cb cb, void *data)
949 fc_assert_ret_val(cb != NULL, FALSE);
951 effect_list_iterate(ruleset_cache.tracker, peffect) {
952 if (!cb(peffect, data)) {
953 return FALSE;
955 } effect_list_iterate_end;
957 return TRUE;