1 /***********************************************************************
2 Freeciv - Copyright (C) 1996-2004 - The Freeciv Project
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)
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 ***********************************************************************/
14 #include <fc_config.h>
24 #include "achievements.h"
29 #include "government.h"
30 #include "improvement.h"
36 #include "specialist.h"
39 #include "requirements.h"
41 /* The item contradicts, fulfills or is irrelevant to the requirement */
42 enum item_found
{ITF_NO
, ITF_YES
, ITF_NOT_APPLICABLE
};
44 /************************************************************************
45 Container for item_found functions
46 ************************************************************************/
47 typedef enum item_found (*universal_found
)(const struct requirement
*,
48 const struct universal
*);
49 static universal_found universal_found_function
[VUT_COUNT
] = {NULL
};
51 /**************************************************************************
52 Parse requirement type (kind) and value strings into a universal
53 structure. Passing in a NULL type is considered VUT_NONE (not an error).
55 Pass this some values like "Building", "Factory".
56 FIXME: ensure that every caller checks error return!
57 **************************************************************************/
58 struct universal
universal_by_rule_name(const char *kind
,
61 struct universal source
;
63 source
.kind
= universals_n_by_name(kind
, fc_strcasecmp
);
64 if (!universals_n_is_valid(source
.kind
)) {
68 universal_value_from_str(&source
, value
);
73 /**************************************************************************
74 Parse requirement value strings into a universal
76 **************************************************************************/
77 void universal_value_from_str(struct universal
*source
, const char *value
)
79 /* Finally scan the value string based on the type of the source. */
80 switch (source
->kind
) {
84 source
->value
.advance
= advance_by_rule_name(value
);
85 if (source
->value
.advance
!= NULL
) {
90 source
->value
.techflag
91 = tech_flag_id_by_name(value
, fc_strcasecmp
);
92 if (tech_flag_id_is_valid(source
->value
.techflag
)) {
97 source
->value
.govern
= government_by_rule_name(value
);
98 if (source
->value
.govern
!= NULL
) {
102 case VUT_ACHIEVEMENT
:
103 source
->value
.achievement
= achievement_by_rule_name(value
);
104 if (source
->value
.achievement
!= NULL
) {
109 source
->value
.style
= style_by_rule_name(value
);
110 if (source
->value
.style
!= NULL
) {
114 case VUT_IMPROVEMENT
:
115 source
->value
.building
= improvement_by_rule_name(value
);
116 if (source
->value
.building
!= NULL
) {
121 source
->value
.impr_genus
= impr_genus_id_by_name(value
, fc_strcasecmp
);
122 if (impr_genus_id_is_valid(source
->value
.impr_genus
)) {
127 source
->value
.extra
= extra_type_by_rule_name(value
);
128 if (source
->value
.extra
!= NULL
) {
133 source
->value
.good
= goods_by_rule_name(value
);
134 if (source
->value
.good
!= NULL
) {
139 source
->value
.terrain
= terrain_by_rule_name(value
);
140 if (source
->value
.terrain
!= T_UNKNOWN
) {
145 source
->value
.terrainflag
146 = terrain_flag_id_by_name(value
, fc_strcasecmp
);
147 if (terrain_flag_id_is_valid(source
->value
.terrainflag
)) {
152 source
->value
.nation
= nation_by_rule_name(value
);
153 if (source
->value
.nation
!= NO_NATION_SELECTED
) {
157 case VUT_NATIONGROUP
:
158 source
->value
.nationgroup
= nation_group_by_rule_name(value
);
159 if (source
->value
.nationgroup
!= NULL
) {
163 case VUT_NATIONALITY
:
164 source
->value
.nationality
= nation_by_rule_name(value
);
165 if (source
->value
.nationality
!= NO_NATION_SELECTED
) {
170 source
->value
.diplrel
= diplrel_by_rule_name(value
);
171 if (source
->value
.diplrel
!= diplrel_other_invalid()) {
176 source
->value
.utype
= unit_type_by_rule_name(value
);
177 if (source
->value
.utype
) {
182 source
->value
.unitflag
= unit_type_flag_id_by_name(value
, fc_strcasecmp
);
183 if (unit_type_flag_id_is_valid(source
->value
.unitflag
)) {
188 source
->value
.uclass
= unit_class_by_rule_name(value
);
189 if (source
->value
.uclass
) {
194 source
->value
.unitclassflag
195 = unit_class_flag_id_by_name(value
, fc_strcasecmp
);
196 if (unit_class_flag_id_is_valid(source
->value
.unitclassflag
)) {
201 source
->value
.minveteran
= atoi(value
);
202 if (source
->value
.minveteran
> 0) {
207 source
->value
.unit_state
= ustate_prop_by_name(value
, fc_strcasecmp
);
208 if (ustate_prop_is_valid(source
->value
.unit_state
)) {
213 source
->value
.minmoves
= atoi(value
);
214 if (source
->value
.minmoves
> 0) {
219 source
->value
.min_hit_points
= atoi(value
);
220 if (source
->value
.min_hit_points
> 0) {
225 source
->value
.age
= atoi(value
);
226 if (source
->value
.age
> 0) {
231 source
->value
.min_techs
= atoi(value
);
232 if (source
->value
.min_techs
> 0) {
236 source
->value
.action
= action_by_rule_name(value
);
237 if (source
->value
.action
!= NULL
) {
242 source
->value
.outputtype
= output_type_by_identifier(value
);
243 if (source
->value
.outputtype
!= O_LAST
) {
248 source
->value
.specialist
= specialist_by_rule_name(value
);
249 if (source
->value
.specialist
) {
253 source
->value
.minsize
= atoi(value
);
254 if (source
->value
.minsize
> 0) {
259 source
->value
.minculture
= atoi(value
);
260 if (source
->value
.minculture
> 0) {
265 source
->value
.ai_level
= ai_level_by_name(value
, fc_strcasecmp
);
266 if (ai_level_is_valid(source
->value
.ai_level
)) {
270 case VUT_MAXTILEUNITS
:
271 source
->value
.max_tile_units
= atoi(value
);
272 if (0 <= source
->value
.max_tile_units
) {
276 case VUT_TERRAINCLASS
:
277 source
->value
.terrainclass
278 = terrain_class_by_name(value
, fc_strcasecmp
);
279 if (terrain_class_is_valid(source
->value
.terrainclass
)) {
284 source
->value
.baseflag
= base_flag_id_by_name(value
, fc_strcasecmp
);
285 if (base_flag_id_is_valid(source
->value
.baseflag
)) {
290 source
->value
.roadflag
= road_flag_id_by_name(value
, fc_strcasecmp
);
291 if (road_flag_id_is_valid(source
->value
.roadflag
)) {
296 source
->value
.extraflag
= extra_flag_id_by_name(value
, fc_strcasecmp
);
297 if (extra_flag_id_is_valid(source
->value
.extraflag
)) {
302 source
->value
.minyear
= atoi(value
);
305 /* Rule names are 0-based numbers, not pretty names from ruleset */
306 source
->value
.mincalfrag
= atoi(value
);
307 if (source
->value
.mincalfrag
>= 0) {
308 /* More range checking done later, in sanity_check_req_individual() */
312 source
->value
.topo_property
= topo_flag_by_name(value
, fc_strcasecmp
);
313 if (topo_flag_is_valid(source
->value
.topo_property
)) {
317 case VUT_TERRAINALTER
:
318 source
->value
.terrainalter
319 = terrain_alteration_by_name(value
, fc_strcasecmp
);
320 if (terrain_alteration_is_valid(source
->value
.terrainalter
)) {
325 source
->value
.citytile
= citytile_type_by_name(value
, fc_strcasecmp
);
326 if (source
->value
.citytile
!= CITYT_LAST
) {
334 /* If we reach here there's been an error. */
335 source
->kind
= universals_n_invalid();
338 /**************************************************************************
339 Combine values into a universal structure. This is for serialization
340 and is the opposite of universal_extraction().
341 FIXME: ensure that every caller checks error return!
342 **************************************************************************/
343 struct universal
universal_by_number(const enum universals_n kind
,
346 struct universal source
;
350 switch (source
.kind
) {
352 /* Avoid compiler warning about unitialized source.value */
353 source
.value
.advance
= NULL
;
357 source
.value
.advance
= advance_by_number(value
);
358 if (source
.value
.advance
!= NULL
) {
363 source
.value
.techflag
= value
;
366 source
.value
.govern
= government_by_number(value
);
367 if (source
.value
.govern
!= NULL
) {
371 case VUT_ACHIEVEMENT
:
372 source
.value
.achievement
= achievement_by_number(value
);
373 if (source
.value
.achievement
!= NULL
) {
378 source
.value
.style
= style_by_number(value
);
379 if (source
.value
.style
!= NULL
) {
383 case VUT_IMPROVEMENT
:
384 source
.value
.building
= improvement_by_number(value
);
385 if (source
.value
.building
!= NULL
) {
390 source
.value
.impr_genus
= value
;
393 source
.value
.extra
= extra_by_number(value
);
396 source
.value
.good
= goods_by_number(value
);
399 source
.value
.terrain
= terrain_by_number(value
);
400 if (source
.value
.terrain
!= NULL
) {
405 source
.value
.terrainflag
= value
;
408 source
.value
.nation
= nation_by_number(value
);
409 if (source
.value
.nation
!= NULL
) {
413 case VUT_NATIONGROUP
:
414 source
.value
.nationgroup
= nation_group_by_number(value
);
415 if (source
.value
.nationgroup
!= NULL
) {
420 source
.value
.diplrel
= value
;
421 if (source
.value
.diplrel
!= diplrel_other_invalid()) {
425 case VUT_NATIONALITY
:
426 source
.value
.nationality
= nation_by_number(value
);
427 if (source
.value
.nationality
!= NULL
) {
432 source
.value
.utype
= utype_by_number(value
);
433 if (source
.value
.utype
!= NULL
) {
438 source
.value
.unitflag
= value
;
441 source
.value
.uclass
= uclass_by_number(value
);
442 if (source
.value
.uclass
!= NULL
) {
447 source
.value
.unitclassflag
= value
;
450 source
.value
.minveteran
= value
;
453 source
.value
.unit_state
= value
;
456 source
.value
.minmoves
= value
;
459 source
.value
.min_hit_points
= value
;
462 source
.value
.age
= value
;
465 source
.value
.min_techs
= value
;
468 source
.value
.action
= action_by_number(value
);
469 if (source
.value
.action
!= NULL
) {
474 source
.value
.outputtype
= value
;
477 source
.value
.specialist
= specialist_by_number(value
);
480 source
.value
.minsize
= value
;
483 source
.value
.minculture
= value
;
486 source
.value
.ai_level
= value
;
488 case VUT_MAXTILEUNITS
:
489 source
.value
.max_tile_units
= value
;
491 case VUT_TERRAINCLASS
:
492 source
.value
.terrainclass
= value
;
495 source
.value
.baseflag
= value
;
498 source
.value
.roadflag
= value
;
501 source
.value
.extraflag
= value
;
504 source
.value
.minyear
= value
;
507 source
.value
.mincalfrag
= value
;
510 source
.value
.topo_property
= value
;
512 case VUT_TERRAINALTER
:
513 source
.value
.terrainalter
= value
;
516 source
.value
.citytile
= value
;
522 /* If we reach here there's been an error. */
523 source
.kind
= universals_n_invalid();
524 /* Avoid compiler warning about unitialized source.value */
525 source
.value
.advance
= NULL
;
530 /**************************************************************************
531 Extract universal structure into its components for serialization;
532 the opposite of universal_by_number().
533 **************************************************************************/
534 void universal_extraction(const struct universal
*source
,
535 int *kind
, int *value
)
537 *kind
= source
->kind
;
538 *value
= universal_number(source
);
541 /**************************************************************************
542 Return the universal number of the constituent.
543 **************************************************************************/
544 int universal_number(const struct universal
*source
)
546 switch (source
->kind
) {
550 return advance_number(source
->value
.advance
);
552 return source
->value
.techflag
;
554 return government_number(source
->value
.govern
);
555 case VUT_ACHIEVEMENT
:
556 return achievement_number(source
->value
.achievement
);
558 return style_number(source
->value
.style
);
559 case VUT_IMPROVEMENT
:
560 return improvement_number(source
->value
.building
);
562 return source
->value
.impr_genus
;
564 return extra_number(source
->value
.extra
);
566 return goods_number(source
->value
.good
);
568 return terrain_number(source
->value
.terrain
);
570 return source
->value
.terrainflag
;
572 return nation_number(source
->value
.nation
);
573 case VUT_NATIONGROUP
:
574 return nation_group_number(source
->value
.nationgroup
);
575 case VUT_NATIONALITY
:
576 return nation_number(source
->value
.nationality
);
578 return source
->value
.diplrel
;
580 return utype_number(source
->value
.utype
);
582 return source
->value
.unitflag
;
584 return uclass_number(source
->value
.uclass
);
586 return source
->value
.unitclassflag
;
588 return source
->value
.minveteran
;
590 return source
->value
.unit_state
;
592 return source
->value
.minmoves
;
594 return source
->value
.min_hit_points
;
596 return source
->value
.age
;
598 return source
->value
.min_techs
;
600 return action_number(source
->value
.action
);
602 return source
->value
.outputtype
;
604 return specialist_number(source
->value
.specialist
);
606 return source
->value
.minsize
;
608 return source
->value
.minculture
;
610 return source
->value
.ai_level
;
611 case VUT_MAXTILEUNITS
:
612 return source
->value
.max_tile_units
;
613 case VUT_TERRAINCLASS
:
614 return source
->value
.terrainclass
;
616 return source
->value
.baseflag
;
618 return source
->value
.roadflag
;
620 return source
->value
.extraflag
;
622 return source
->value
.minyear
;
624 return source
->value
.mincalfrag
;
626 return source
->value
.topo_property
;
627 case VUT_TERRAINALTER
:
628 return source
->value
.terrainalter
;
630 return source
->value
.citytile
;
635 /* If we reach here there's been an error. */
636 fc_assert_msg(FALSE
, "universal_number(): invalid source kind %d.",
642 /****************************************************************************
643 Returns the given requirement as a formatted string ready for printing.
644 Does not care about the 'quiet' property.
645 ****************************************************************************/
646 const char *req_to_fstring(const struct requirement
*req
)
648 struct astring printable_req
= ASTRING_INIT
;
650 astr_set(&printable_req
, "%s%s %s %s%s",
651 req
->survives
? "surviving " : "",
652 req_range_name(req
->range
),
653 universal_type_rule_name(&req
->source
),
654 req
->present
? "" : "!",
655 universal_rule_name(&req
->source
));
657 return astr_str(&printable_req
);
660 /****************************************************************************
661 Parse a requirement type and value string into a requirement structure.
662 Returns the invalid element for enum universal_n on error. Passing in a
663 NULL type is considered VUT_NONE (not an error).
665 Pass this some values like "Building", "Factory".
666 ****************************************************************************/
667 struct requirement
req_from_str(const char *type
, const char *range
,
668 bool survives
, bool present
, bool quiet
,
671 struct requirement req
;
673 const char *error
= NULL
;
675 req
.source
= universal_by_rule_name(type
, value
);
677 invalid
= !universals_n_is_valid(req
.source
.kind
);
679 error
= "bad type or name";
681 /* Scan the range string to find the range. If no range is given a
682 * default fallback is used rather than giving an error. */
683 req
.range
= req_range_by_name(range
, fc_strcasecmp
);
684 if (!req_range_is_valid(req
.range
)) {
685 switch (req
.source
.kind
) {
689 case VUT_IMPROVEMENT
:
707 case VUT_TERRAINCLASS
:
711 case VUT_TERRAINALTER
:
713 case VUT_MAXTILEUNITS
:
714 req
.range
= REQ_RANGE_LOCAL
;
718 case VUT_NATIONALITY
:
719 req
.range
= REQ_RANGE_CITY
;
722 case VUT_ACHIEVEMENT
:
727 case VUT_NATIONGROUP
:
730 req
.range
= REQ_RANGE_PLAYER
;
736 req
.range
= REQ_RANGE_WORLD
;
741 req
.survives
= survives
;
742 req
.present
= present
;
745 /* These checks match what combinations are supported inside
746 * is_req_active(). However, it's only possible to do basic checks,
747 * not anything that might depend on the rest of the ruleset which
748 * might not have been loaded yet. */
749 switch (req
.source
.kind
) {
752 case VUT_TERRAINCLASS
:
757 invalid
= (req
.range
!= REQ_RANGE_LOCAL
758 && req
.range
!= REQ_RANGE_CADJACENT
759 && req
.range
!= REQ_RANGE_ADJACENT
760 && req
.range
!= REQ_RANGE_CITY
761 && req
.range
!= REQ_RANGE_TRADEROUTE
);
765 case VUT_ACHIEVEMENT
:
767 invalid
= (req
.range
< REQ_RANGE_PLAYER
);
772 invalid
= (req
.range
!= REQ_RANGE_PLAYER
);
775 case VUT_NATIONALITY
:
777 invalid
= (req
.range
!= REQ_RANGE_CITY
778 && req
.range
!= REQ_RANGE_TRADEROUTE
);
781 invalid
= (req
.range
!= REQ_RANGE_CITY
782 && req
.range
!= REQ_RANGE_TRADEROUTE
783 && req
.range
!= REQ_RANGE_PLAYER
784 && req
.range
!= REQ_RANGE_TEAM
785 && req
.range
!= REQ_RANGE_ALLIANCE
786 && req
.range
!= REQ_RANGE_WORLD
);
789 invalid
= (req
.range
!= REQ_RANGE_LOCAL
790 && req
.range
!= REQ_RANGE_PLAYER
791 && req
.range
!= REQ_RANGE_TEAM
792 && req
.range
!= REQ_RANGE_ALLIANCE
793 && req
.range
!= REQ_RANGE_WORLD
)
794 /* Non local foreign makes no sense. */
795 || (req
.source
.value
.diplrel
== DRO_FOREIGN
796 && req
.range
!= REQ_RANGE_LOCAL
);
799 case VUT_NATIONGROUP
:
800 invalid
= (req
.range
!= REQ_RANGE_PLAYER
801 && req
.range
!= REQ_RANGE_TEAM
802 && req
.range
!= REQ_RANGE_ALLIANCE
803 && req
.range
!= REQ_RANGE_WORLD
);
816 case VUT_TERRAINALTER
: /* XXX could in principle support C/ADJACENT */
817 invalid
= (req
.range
!= REQ_RANGE_LOCAL
);
820 case VUT_MAXTILEUNITS
:
821 invalid
= (req
.range
!= REQ_RANGE_LOCAL
822 && req
.range
!= REQ_RANGE_CADJACENT
823 && req
.range
!= REQ_RANGE_ADJACENT
);
828 invalid
= (req
.range
!= REQ_RANGE_WORLD
);
831 /* FIXME: could support TRADEROUTE, TEAM, etc */
832 invalid
= (req
.range
!= REQ_RANGE_LOCAL
833 && req
.range
!= REQ_RANGE_CITY
834 && req
.range
!= REQ_RANGE_PLAYER
);
837 /* TODO: Support other ranges too. */
838 invalid
= req
.range
!= REQ_RANGE_LOCAL
;
840 case VUT_IMPROVEMENT
:
841 /* Valid ranges depend on the building genus (wonder/improvement),
842 * which might not have been loaded from the ruleset yet.
843 * So we allow anything here, and do a proper check once ruleset
844 * loading is complete, in sanity_check_req_individual(). */
857 /* Check 'survives'. */
858 switch (req
.source
.kind
) {
859 case VUT_IMPROVEMENT
:
860 /* See buildings_in_range(). */
861 invalid
= survives
&& req
.range
<= REQ_RANGE_CONTINENT
;
865 invalid
= survives
&& req
.range
!= REQ_RANGE_WORLD
;
885 case VUT_TERRAINCLASS
:
889 case VUT_TERRAINALTER
:
892 case VUT_NATIONALITY
:
899 case VUT_ACHIEVEMENT
:
900 case VUT_NATIONGROUP
:
903 case VUT_MAXTILEUNITS
:
905 /* Most requirements don't support 'survives'. */
913 error
= "bad 'survives'";
918 log_error("Invalid requirement %s | %s | %s | %s | %s: %s",
919 type
, range
, survives
? "survives" : "",
920 present
? "present" : "", value
, error
);
921 req
.source
.kind
= universals_n_invalid();
927 /****************************************************************************
928 Set the values of a req from serializable integers. This is the opposite
930 ****************************************************************************/
931 struct requirement
req_from_values(int type
, int range
,
932 bool survives
, bool present
, bool quiet
,
935 struct requirement req
;
937 req
.source
= universal_by_number(type
, value
);
939 req
.survives
= survives
;
940 req
.present
= present
;
946 /****************************************************************************
947 Return the value of a req as a serializable integer. This is the opposite
949 ****************************************************************************/
950 void req_get_values(const struct requirement
*req
,
951 int *type
, int *range
,
952 bool *survives
, bool *present
, bool *quiet
,
955 universal_extraction(&req
->source
, type
, value
);
957 *survives
= req
->survives
;
958 *present
= req
->present
;
962 /****************************************************************************
963 Returns TRUE if req1 and req2 are equal.
964 Does not care if one is quiet and the other not.
965 ****************************************************************************/
966 bool are_requirements_equal(const struct requirement
*req1
,
967 const struct requirement
*req2
)
969 return (are_universals_equal(&req1
->source
, &req2
->source
)
970 && req1
->range
== req2
->range
971 && req1
->survives
== req2
->survives
972 && req1
->present
== req2
->present
);
975 /****************************************************************************
976 Returns TRUE if req1 and req2 directly negate each other.
977 ****************************************************************************/
978 static bool are_requirements_opposites(const struct requirement
*req1
,
979 const struct requirement
*req2
)
981 return (are_universals_equal(&req1
->source
, &req2
->source
)
982 && req1
->range
== req2
->range
983 && req1
->survives
== req2
->survives
984 && req1
->present
!= req2
->present
);
987 /**************************************************************************
988 Returns TRUE if the specified building requirement contradicts the
989 specified building genus requirement.
990 **************************************************************************/
991 static bool impr_contra_genus(const struct requirement
*impr_req
,
992 const struct requirement
*genus_req
)
994 /* The input is sane. */
995 fc_assert_ret_val(impr_req
->source
.kind
== VUT_IMPROVEMENT
, FALSE
);
996 fc_assert_ret_val(genus_req
->source
.kind
== VUT_IMPR_GENUS
, FALSE
);
998 if (impr_req
->range
== REQ_RANGE_LOCAL
999 && genus_req
->range
== REQ_RANGE_LOCAL
) {
1000 /* Applies to the same target building. */
1002 if (impr_req
->present
&& !genus_req
->present
) {
1003 /* The target building can't not have the genus it has. */
1004 return (impr_req
->source
.value
.building
->genus
1005 == genus_req
->source
.value
.impr_genus
);
1008 if (impr_req
->present
&& genus_req
->present
) {
1009 /* The target building can't have another genus than it has. */
1010 return (impr_req
->source
.value
.building
->genus
1011 != genus_req
->source
.value
.impr_genus
);
1015 /* No special knowledge. */
1019 /**************************************************************************
1020 Returns TRUE if the specified nation requirement contradicts the
1021 specified nation group requirement.
1022 **************************************************************************/
1023 static bool nation_contra_group(const struct requirement
*nation_req
,
1024 const struct requirement
*group_req
)
1026 /* The input is sane. */
1027 fc_assert_ret_val(nation_req
->source
.kind
== VUT_NATION
, FALSE
);
1028 fc_assert_ret_val(group_req
->source
.kind
== VUT_NATIONGROUP
, FALSE
);
1030 if (nation_req
->range
== REQ_RANGE_PLAYER
1031 && group_req
->range
== REQ_RANGE_PLAYER
) {
1032 /* Applies to the same target building. */
1034 if (nation_req
->present
&& !group_req
->present
) {
1035 /* The target nation can't be in the group. */
1036 return nation_is_in_group(nation_req
->source
.value
.nation
,
1037 group_req
->source
.value
.nationgroup
);
1041 /* No special knowledge. */
1045 /**************************************************************************
1046 Returns TRUE if req1 and req2 contradicts each other.
1048 TODO: If information about what entity each requirement type will be
1049 evaluated against is passed it will become possible to detect stuff like
1050 that an unclaimed tile contradicts all DiplRel requirements against it.
1051 **************************************************************************/
1052 bool are_requirements_contradictions(const struct requirement
*req1
,
1053 const struct requirement
*req2
)
1055 if (are_requirements_opposites(req1
, req2
)) {
1056 /* The exact opposite. */
1060 switch (req1
->source
.kind
) {
1061 case VUT_IMPROVEMENT
:
1062 if (req2
->source
.kind
== VUT_IMPR_GENUS
) {
1063 return impr_contra_genus(req1
, req2
);
1066 /* No special knowledge. */
1069 case VUT_IMPR_GENUS
:
1070 if (req2
->source
.kind
== VUT_IMPROVEMENT
) {
1071 return impr_contra_genus(req2
, req1
);
1074 /* No special knowledge. */
1078 if (req2
->source
.kind
!= VUT_DIPLREL
) {
1079 /* Finding contradictions across requirement kinds aren't supported
1080 * for DiplRel requirements. */
1083 /* Use the special knowledge about DiplRel requirements to find
1084 * contradictions. */
1086 bv_diplrel_all_reqs req1_contra
;
1089 req1_contra
= diplrel_req_contradicts(req1
);
1090 req2_pos
= requirement_diplrel_ereq(req2
->source
.value
.diplrel
,
1094 return BV_ISSET(req1_contra
, req2_pos
);
1098 if (req2
->source
.kind
!= VUT_MINMOVES
) {
1099 /* Finding contradictions across requirement kinds aren't supported
1100 * for MinMoveFrags requirements. */
1102 } else if (req1
->present
== req2
->present
) {
1103 /* No contradiction possible. */
1106 /* Number of move fragments left can't be larger than the number
1107 * required to be present and smaller than the number required to not
1108 * be present when the number required to be present is smaller than
1109 * the number required to not be present. */
1110 if (req1
->present
) {
1111 return req1
->source
.value
.minmoves
>= req2
->source
.value
.minmoves
;
1113 return req1
->source
.value
.minmoves
<= req2
->source
.value
.minmoves
;
1118 if (req2
->source
.kind
== VUT_NATIONGROUP
) {
1119 return nation_contra_group(req1
, req2
);
1122 /* No special knowledge. */
1125 case VUT_NATIONGROUP
:
1126 if (req2
->source
.kind
== VUT_NATION
) {
1127 return nation_contra_group(req2
, req1
);
1130 /* No special knowledge. */
1134 /* No special knowledge exists. The requirements aren't the exact
1135 * opposite of each other per the initial check. */
1141 /**************************************************************************
1142 Returns TRUE if the given requirement contradicts the given requirement
1144 **************************************************************************/
1145 bool does_req_contradicts_reqs(const struct requirement
*req
,
1146 const struct requirement_vector
*vec
)
1148 /* If the requirement is contradicted by any requirement in the vector it
1149 * contradicts the entire requirement vector. */
1150 requirement_vector_iterate(vec
, preq
) {
1151 if (are_requirements_contradictions(req
, preq
)) {
1154 } requirement_vector_iterate_end
;
1156 /* Not a singe requirement in the requirement vector is contradicted be
1157 * the specified requirement. */
1161 /* No self contradictions in the requirement vector. */
1162 #define NO_CONTRADICTIONS (-1)
1164 /**************************************************************************
1165 Returns the first requirement in a requirement vector that contradicts
1166 with other requirements in the same requirement vector.
1167 **************************************************************************/
1168 static int first_contradiction(const struct requirement_vector
*vec
)
1172 for (i
= 0; i
< requirement_vector_size(vec
); i
++) {
1173 struct requirement
*preq
= requirement_vector_get(vec
, i
);
1175 if (does_req_contradicts_reqs(preq
, vec
)) {
1180 return NO_CONTRADICTIONS
;
1183 /**************************************************************************
1184 Clean up self contradictions from a requirement vector.
1186 When two requirements conflicts the earliest requirement is removed.
1187 This allows requirement adjustment code to append the new requirement(s)
1188 and leave the contradiction clean up to this function.
1189 **************************************************************************/
1190 void requirement_vector_contradiction_clean(struct requirement_vector
*vec
)
1194 while (NO_CONTRADICTIONS
!= (conflict
= first_contradiction(vec
))) {
1195 requirement_vector_remove(vec
, conflict
);
1199 /****************************************************************************
1200 Returns TRUE if players are in the same requirements range.
1201 ****************************************************************************/
1202 static inline bool players_in_same_range(const struct player
*pplayer1
,
1203 const struct player
*pplayer2
,
1204 enum req_range range
)
1207 case REQ_RANGE_WORLD
:
1209 case REQ_RANGE_ALLIANCE
:
1210 return pplayers_allied(pplayer1
, pplayer2
);
1211 case REQ_RANGE_TEAM
:
1212 return players_on_same_team(pplayer1
, pplayer2
);
1213 case REQ_RANGE_PLAYER
:
1214 return pplayer1
== pplayer2
;
1215 case REQ_RANGE_CONTINENT
:
1216 case REQ_RANGE_TRADEROUTE
:
1217 case REQ_RANGE_CITY
:
1218 case REQ_RANGE_ADJACENT
:
1219 case REQ_RANGE_CADJACENT
:
1220 case REQ_RANGE_LOCAL
:
1221 case REQ_RANGE_COUNT
:
1225 fc_assert_msg(FALSE
, "Invalid range %d.", range
);
1229 /****************************************************************************
1230 Returns the number of total world buildings (this includes buildings
1231 that have been destroyed).
1232 ****************************************************************************/
1233 static int num_world_buildings_total(const struct impr_type
*building
)
1235 if (is_great_wonder(building
)) {
1236 return (great_wonder_is_built(building
)
1237 || great_wonder_is_destroyed(building
) ? 1 : 0);
1239 log_error("World-ranged requirements are only supported for wonders.");
1244 /****************************************************************************
1245 Returns the number of buildings of a certain type in the world.
1246 ****************************************************************************/
1247 static int num_world_buildings(const struct impr_type
*building
)
1249 if (is_great_wonder(building
)) {
1250 return (great_wonder_is_built(building
) ? 1 : 0);
1252 log_error("World-ranged requirements are only supported for wonders.");
1257 /****************************************************************************
1258 Returns whether a building of a certain type has ever been built by
1259 pplayer, even if it has subsequently been destroyed.
1261 Note: the implementation of this is no different in principle from
1262 num_world_buildings_total(), but the semantics are different because
1263 unlike a great wonder, a small wonder could be destroyed and rebuilt
1264 many times, requiring return of values >1, but there's no record kept
1265 to support that. Fortunately, the only current caller doesn't need the
1267 ****************************************************************************/
1268 static bool player_has_ever_built(const struct player
*pplayer
,
1269 const struct impr_type
*building
)
1271 if (is_wonder(building
)) {
1272 return (wonder_is_built(pplayer
, building
)
1273 || wonder_is_lost(pplayer
, building
) ? TRUE
: FALSE
);
1275 log_error("Player-ranged requirements are only supported for wonders.");
1280 /****************************************************************************
1281 Returns the number of buildings of a certain type owned by plr.
1282 ****************************************************************************/
1283 static int num_player_buildings(const struct player
*pplayer
,
1284 const struct impr_type
*building
)
1286 if (is_wonder(building
)) {
1287 return (wonder_is_built(pplayer
, building
) ? 1 : 0);
1289 log_error("Player-ranged requirements are only supported for wonders.");
1294 /****************************************************************************
1295 Returns the number of buildings of a certain type on a continent.
1296 ****************************************************************************/
1297 static int num_continent_buildings(const struct player
*pplayer
,
1299 const struct impr_type
*building
)
1301 if (is_wonder(building
)) {
1302 const struct city
*pcity
;
1304 pcity
= city_from_wonder(pplayer
, building
);
1305 if (pcity
&& pcity
->tile
&& tile_continent(pcity
->tile
) == continent
) {
1309 log_error("Island-ranged requirements are only supported for wonders.");
1314 /****************************************************************************
1315 Returns the number of buildings of a certain type in a city.
1316 ****************************************************************************/
1317 static int num_city_buildings(const struct city
*pcity
,
1318 const struct impr_type
*building
)
1320 return (city_has_building(pcity
, building
) ? 1 : 0);
1323 /****************************************************************************
1324 Are there any source buildings within range of the target that are not
1327 The target gives the type of the target. The exact target is a player,
1328 city, or building specified by the target_xxx arguments.
1330 The range gives the range of the requirement.
1332 "Survives" specifies whether the requirement allows destroyed sources.
1333 If set then all source buildings ever built are counted; if not then only
1334 living buildings are counted.
1336 source gives the building type of the source in question.
1337 ****************************************************************************/
1338 static enum fc_tristate
1339 is_building_in_range(const struct player
*target_player
,
1340 const struct city
*target_city
,
1341 const struct impr_type
*target_building
,
1342 enum req_range range
,
1344 const struct impr_type
*source
)
1346 /* Check if it's certain that the building is obsolete given the
1347 * specification we have */
1348 if (improvement_obsolete(target_player
, source
, target_city
)) {
1354 /* Check whether condition has ever held, using cached information. */
1356 case REQ_RANGE_WORLD
:
1357 return BOOL_TO_TRISTATE(num_world_buildings_total(source
) > 0);
1358 case REQ_RANGE_ALLIANCE
:
1359 case REQ_RANGE_TEAM
:
1360 if (target_player
== NULL
) {
1363 players_iterate_alive(plr2
) {
1364 if (players_in_same_range(target_player
, plr2
, range
)
1365 && player_has_ever_built(plr2
, source
)) {
1368 } players_iterate_alive_end
;
1370 case REQ_RANGE_PLAYER
:
1371 if (target_player
== NULL
) {
1374 return BOOL_TO_TRISTATE(player_has_ever_built(target_player
, source
));
1375 case REQ_RANGE_CONTINENT
:
1376 case REQ_RANGE_TRADEROUTE
:
1377 case REQ_RANGE_CITY
:
1378 case REQ_RANGE_LOCAL
:
1379 case REQ_RANGE_CADJACENT
:
1380 case REQ_RANGE_ADJACENT
:
1381 /* There is no sources cache for this. */
1382 log_error("Surviving requirements are only supported at "
1383 "World/Alliance/Team/Player ranges.");
1385 case REQ_RANGE_COUNT
:
1391 /* Non-surviving requirement. */
1393 case REQ_RANGE_WORLD
:
1394 return BOOL_TO_TRISTATE(num_world_buildings(source
) > 0);
1395 case REQ_RANGE_ALLIANCE
:
1396 case REQ_RANGE_TEAM
:
1397 if (target_player
== NULL
) {
1400 players_iterate_alive(plr2
) {
1401 if (players_in_same_range(target_player
, plr2
, range
)
1402 && num_player_buildings(plr2
, source
) > 0) {
1405 } players_iterate_alive_end
;
1407 case REQ_RANGE_PLAYER
:
1408 if (target_player
== NULL
) {
1411 return BOOL_TO_TRISTATE(num_player_buildings(target_player
, source
) > 0);
1412 case REQ_RANGE_CONTINENT
:
1413 /* At present, "Continent" effects can affect only
1414 * cities and units in cities. */
1415 if (target_player
&& target_city
) {
1416 int continent
= tile_continent(target_city
->tile
);
1417 return BOOL_TO_TRISTATE(num_continent_buildings(target_player
,
1418 continent
, source
) > 0);
1422 case REQ_RANGE_TRADEROUTE
:
1424 if (num_city_buildings(target_city
, source
) > 0) {
1427 trade_partners_iterate(target_city
, trade_partner
) {
1428 if (num_city_buildings(trade_partner
, source
) > 0) {
1431 } trade_partners_iterate_end
;
1437 case REQ_RANGE_CITY
:
1439 return BOOL_TO_TRISTATE(num_city_buildings(target_city
, source
) > 0);
1443 case REQ_RANGE_LOCAL
:
1444 if (target_building
) {
1445 if (target_building
== source
) {
1451 /* TODO: other local targets */
1454 case REQ_RANGE_CADJACENT
:
1455 case REQ_RANGE_ADJACENT
:
1457 case REQ_RANGE_COUNT
:
1463 fc_assert_msg(FALSE
, "Invalid range %d.", range
);
1467 /****************************************************************************
1468 Is there a source tech within range of the target?
1469 ****************************************************************************/
1470 static enum fc_tristate
is_tech_in_range(const struct player
*target_player
,
1471 enum req_range range
, bool survives
,
1475 fc_assert(range
== REQ_RANGE_WORLD
);
1476 return BOOL_TO_TRISTATE(game
.info
.global_advances
[tech
]);
1479 /* Not a 'surviving' requirement. */
1481 case REQ_RANGE_PLAYER
:
1482 if (NULL
!= target_player
) {
1483 return BOOL_TO_TRISTATE(TECH_KNOWN
== research_invention_state
1484 (research_get(target_player
), tech
));
1488 case REQ_RANGE_TEAM
:
1489 case REQ_RANGE_ALLIANCE
:
1490 case REQ_RANGE_WORLD
:
1491 if (NULL
== target_player
) {
1494 players_iterate_alive(plr2
) {
1495 if (players_in_same_range(target_player
, plr2
, range
)) {
1496 if (research_invention_state(research_get(plr2
), tech
)
1501 } players_iterate_alive_end
;
1504 case REQ_RANGE_LOCAL
:
1505 case REQ_RANGE_CADJACENT
:
1506 case REQ_RANGE_ADJACENT
:
1507 case REQ_RANGE_CITY
:
1508 case REQ_RANGE_TRADEROUTE
:
1509 case REQ_RANGE_CONTINENT
:
1510 case REQ_RANGE_COUNT
:
1514 fc_assert_msg(FALSE
, "Invalid range %d.", range
);
1519 /****************************************************************************
1520 Is there a tech with the given flag within range of the target?
1521 ****************************************************************************/
1522 static enum fc_tristate
is_techflag_in_range(const struct player
*target_player
,
1523 enum req_range range
,
1524 enum tech_flag_id techflag
)
1527 case REQ_RANGE_PLAYER
:
1528 if (NULL
!= target_player
) {
1529 return BOOL_TO_TRISTATE(player_knows_techs_with_flag(target_player
, techflag
));
1534 case REQ_RANGE_TEAM
:
1535 case REQ_RANGE_ALLIANCE
:
1536 if (NULL
== target_player
) {
1539 players_iterate_alive(plr2
) {
1540 if (players_in_same_range(target_player
, plr2
, range
)
1541 && player_knows_techs_with_flag(plr2
, techflag
)) {
1544 } players_iterate_alive_end
;
1546 case REQ_RANGE_WORLD
:
1547 players_iterate(pplayer
) {
1548 if (player_knows_techs_with_flag(pplayer
, techflag
)) {
1551 } players_iterate_end
;
1554 case REQ_RANGE_LOCAL
:
1555 case REQ_RANGE_CADJACENT
:
1556 case REQ_RANGE_ADJACENT
:
1557 case REQ_RANGE_CITY
:
1558 case REQ_RANGE_TRADEROUTE
:
1559 case REQ_RANGE_CONTINENT
:
1560 case REQ_RANGE_COUNT
:
1564 fc_assert_msg(FALSE
, "Invalid range %d.", range
);
1569 /****************************************************************************
1570 Is city or player with at least minculture culture in range?
1571 ****************************************************************************/
1572 static enum fc_tristate
is_minculture_in_range(const struct city
*target_city
,
1573 const struct player
*target_player
,
1574 enum req_range range
,
1578 case REQ_RANGE_CITY
:
1582 return BOOL_TO_TRISTATE(city_culture(target_city
) >= minculture
);
1583 case REQ_RANGE_TRADEROUTE
:
1587 if (city_culture(target_city
) >= minculture
) {
1590 trade_partners_iterate(target_city
, trade_partner
) {
1591 if (city_culture(trade_partner
) >= minculture
) {
1594 } trade_partners_iterate_end
;
1597 case REQ_RANGE_PLAYER
:
1598 case REQ_RANGE_TEAM
:
1599 case REQ_RANGE_ALLIANCE
:
1600 case REQ_RANGE_WORLD
:
1601 if (NULL
== target_player
) {
1604 players_iterate_alive(plr2
) {
1605 if (players_in_same_range(target_player
, plr2
, range
)) {
1606 if (player_culture(plr2
) >= minculture
) {
1610 } players_iterate_alive_end
;
1612 case REQ_RANGE_LOCAL
:
1613 case REQ_RANGE_CADJACENT
:
1614 case REQ_RANGE_ADJACENT
:
1615 case REQ_RANGE_CONTINENT
:
1616 case REQ_RANGE_COUNT
:
1620 fc_assert_msg(FALSE
, "Invalid range %d.", range
);
1625 /****************************************************************************
1626 Is there a tile with max X units within range of the target?
1627 ****************************************************************************/
1628 static enum fc_tristate
1629 is_tile_units_in_range(const struct tile
*target_tile
, enum req_range range
,
1632 /* TODO: if can't see V_INVIS -> TRI_MAYBE */
1634 case REQ_RANGE_LOCAL
:
1638 return BOOL_TO_TRISTATE(unit_list_size(target_tile
->units
) <= maxUnits
);
1639 case REQ_RANGE_CADJACENT
:
1643 if (unit_list_size(target_tile
->units
) <= maxUnits
) {
1646 cardinal_adjc_iterate(&(wld
.map
), target_tile
, adjc_tile
) {
1647 if (unit_list_size(adjc_tile
->units
) <= maxUnits
) {
1650 } cardinal_adjc_iterate_end
;
1652 case REQ_RANGE_ADJACENT
:
1656 if (unit_list_size(target_tile
->units
) <= maxUnits
) {
1659 adjc_iterate(&(wld
.map
), target_tile
, adjc_tile
) {
1660 if (unit_list_size(adjc_tile
->units
) <= maxUnits
) {
1665 case REQ_RANGE_CITY
:
1666 case REQ_RANGE_TRADEROUTE
:
1667 case REQ_RANGE_CONTINENT
:
1668 case REQ_RANGE_PLAYER
:
1669 case REQ_RANGE_TEAM
:
1670 case REQ_RANGE_ALLIANCE
:
1671 case REQ_RANGE_WORLD
:
1672 case REQ_RANGE_COUNT
:
1676 fc_assert_msg(FALSE
, "Invalid range %d.", range
);
1681 /****************************************************************************
1682 Is there a source extra type within range of the target?
1683 ****************************************************************************/
1684 static enum fc_tristate
is_extra_type_in_range(const struct tile
*target_tile
,
1685 const struct city
*target_city
,
1686 enum req_range range
, bool survives
,
1687 struct extra_type
*pextra
)
1690 case REQ_RANGE_LOCAL
:
1691 /* The requirement is filled if the tile has extra of requested type. */
1695 return BOOL_TO_TRISTATE(tile_has_extra(target_tile
, pextra
));
1696 case REQ_RANGE_CADJACENT
:
1700 return BOOL_TO_TRISTATE(tile_has_extra(target_tile
, pextra
)
1701 || is_extra_card_near(target_tile
, pextra
));
1702 case REQ_RANGE_ADJACENT
:
1706 return BOOL_TO_TRISTATE(tile_has_extra(target_tile
, pextra
)
1707 || is_extra_near_tile(target_tile
, pextra
));
1708 case REQ_RANGE_CITY
:
1712 city_tile_iterate(city_map_radius_sq_get(target_city
),
1713 city_tile(target_city
), ptile
) {
1714 if (tile_has_extra(ptile
, pextra
)) {
1717 } city_tile_iterate_end
;
1721 case REQ_RANGE_TRADEROUTE
:
1725 city_tile_iterate(city_map_radius_sq_get(target_city
),
1726 city_tile(target_city
), ptile
) {
1727 if (tile_has_extra(ptile
, pextra
)) {
1730 } city_tile_iterate_end
;
1731 trade_partners_iterate(target_city
, trade_partner
) {
1732 city_tile_iterate(city_map_radius_sq_get(trade_partner
),
1733 city_tile(trade_partner
), ptile
) {
1734 if (tile_has_extra(ptile
, pextra
)) {
1737 } city_tile_iterate_end
;
1738 } trade_partners_iterate_end
;
1742 case REQ_RANGE_CONTINENT
:
1743 case REQ_RANGE_PLAYER
:
1744 case REQ_RANGE_TEAM
:
1745 case REQ_RANGE_ALLIANCE
:
1746 case REQ_RANGE_WORLD
:
1747 case REQ_RANGE_COUNT
:
1751 fc_assert_msg(FALSE
, "Invalid range %d.", range
);
1756 /****************************************************************************
1757 Is there a source goods type within range of the target?
1758 ****************************************************************************/
1759 static enum fc_tristate
is_goods_type_in_range(const struct tile
*target_tile
,
1760 const struct city
*target_city
,
1761 enum req_range range
, bool survives
,
1762 struct goods_type
*pgood
)
1765 case REQ_RANGE_LOCAL
:
1766 case REQ_RANGE_CITY
:
1767 /* The requirement is filled if the tile has extra of requested type. */
1771 return BOOL_TO_TRISTATE(city_receives_goods(target_city
, pgood
));
1772 case REQ_RANGE_CADJACENT
:
1773 case REQ_RANGE_ADJACENT
:
1774 case REQ_RANGE_TRADEROUTE
:
1775 case REQ_RANGE_CONTINENT
:
1776 case REQ_RANGE_PLAYER
:
1777 case REQ_RANGE_TEAM
:
1778 case REQ_RANGE_ALLIANCE
:
1779 case REQ_RANGE_WORLD
:
1780 case REQ_RANGE_COUNT
:
1784 fc_assert_msg(FALSE
, "Invalid range %d.", range
);
1789 /****************************************************************************
1790 Is there a source tile within range of the target?
1791 ****************************************************************************/
1792 static enum fc_tristate
is_terrain_in_range(const struct tile
*target_tile
,
1793 const struct city
*target_city
,
1794 enum req_range range
, bool survives
,
1795 const struct terrain
*pterrain
)
1798 case REQ_RANGE_LOCAL
:
1799 /* The requirement is filled if the tile has the terrain. */
1803 return pterrain
&& tile_terrain(target_tile
) == pterrain
;
1804 case REQ_RANGE_CADJACENT
:
1808 return BOOL_TO_TRISTATE(pterrain
&& is_terrain_card_near(target_tile
, pterrain
, TRUE
));
1809 case REQ_RANGE_ADJACENT
:
1813 return BOOL_TO_TRISTATE(pterrain
&& is_terrain_near_tile(target_tile
, pterrain
, TRUE
));
1814 case REQ_RANGE_CITY
:
1818 if (pterrain
!= NULL
) {
1819 city_tile_iterate(city_map_radius_sq_get(target_city
),
1820 city_tile(target_city
), ptile
) {
1821 if (tile_terrain(ptile
) == pterrain
) {
1824 } city_tile_iterate_end
;
1827 case REQ_RANGE_TRADEROUTE
:
1831 if (pterrain
!= NULL
) {
1832 city_tile_iterate(city_map_radius_sq_get(target_city
),
1833 city_tile(target_city
), ptile
) {
1834 if (tile_terrain(ptile
) == pterrain
) {
1837 } city_tile_iterate_end
;
1838 trade_partners_iterate(target_city
, trade_partner
) {
1839 city_tile_iterate(city_map_radius_sq_get(trade_partner
),
1840 city_tile(trade_partner
), ptile
) {
1841 if (tile_terrain(ptile
) == pterrain
) {
1844 } city_tile_iterate_end
;
1845 } trade_partners_iterate_end
;
1848 case REQ_RANGE_CONTINENT
:
1849 case REQ_RANGE_PLAYER
:
1850 case REQ_RANGE_TEAM
:
1851 case REQ_RANGE_ALLIANCE
:
1852 case REQ_RANGE_WORLD
:
1853 case REQ_RANGE_COUNT
:
1857 fc_assert_msg(FALSE
, "Invalid range %d.", range
);
1862 /****************************************************************************
1863 Is there a source terrain class within range of the target?
1864 ****************************************************************************/
1865 static enum fc_tristate
is_terrain_class_in_range(const struct tile
*target_tile
,
1866 const struct city
*target_city
,
1867 enum req_range range
, bool survives
,
1868 enum terrain_class pclass
)
1871 case REQ_RANGE_LOCAL
:
1872 /* The requirement is filled if the tile has the terrain of correct class. */
1876 return BOOL_TO_TRISTATE(terrain_type_terrain_class(tile_terrain(target_tile
)) == pclass
);
1877 case REQ_RANGE_CADJACENT
:
1881 return BOOL_TO_TRISTATE(terrain_type_terrain_class(tile_terrain(target_tile
)) == pclass
1882 || is_terrain_class_card_near(target_tile
, pclass
));
1883 case REQ_RANGE_ADJACENT
:
1887 return BOOL_TO_TRISTATE(terrain_type_terrain_class(tile_terrain(target_tile
)) == pclass
1888 || is_terrain_class_near_tile(target_tile
, pclass
));
1889 case REQ_RANGE_CITY
:
1893 city_tile_iterate(city_map_radius_sq_get(target_city
),
1894 city_tile(target_city
), ptile
) {
1895 const struct terrain
*pterrain
= tile_terrain(ptile
);
1896 if (pterrain
!= T_UNKNOWN
1897 && terrain_type_terrain_class(pterrain
) == pclass
) {
1900 } city_tile_iterate_end
;
1903 case REQ_RANGE_TRADEROUTE
:
1907 city_tile_iterate(city_map_radius_sq_get(target_city
),
1908 city_tile(target_city
), ptile
) {
1909 const struct terrain
*pterrain
= tile_terrain(ptile
);
1910 if (pterrain
!= T_UNKNOWN
1911 && terrain_type_terrain_class(pterrain
) == pclass
) {
1914 } city_tile_iterate_end
;
1916 trade_partners_iterate(target_city
, trade_partner
) {
1917 city_tile_iterate(city_map_radius_sq_get(trade_partner
),
1918 city_tile(trade_partner
), ptile
) {
1919 const struct terrain
*pterrain
= tile_terrain(ptile
);
1920 if (pterrain
!= T_UNKNOWN
1921 && terrain_type_terrain_class(pterrain
) == pclass
) {
1924 } city_tile_iterate_end
;
1925 } trade_partners_iterate_end
;
1928 case REQ_RANGE_CONTINENT
:
1929 case REQ_RANGE_PLAYER
:
1930 case REQ_RANGE_TEAM
:
1931 case REQ_RANGE_ALLIANCE
:
1932 case REQ_RANGE_WORLD
:
1933 case REQ_RANGE_COUNT
:
1937 fc_assert_msg(FALSE
, "Invalid range %d.", range
);
1942 /****************************************************************************
1943 Is there a terrain with the given flag within range of the target?
1944 ****************************************************************************/
1945 static enum fc_tristate
is_terrainflag_in_range(const struct tile
*target_tile
,
1946 const struct city
*target_city
,
1947 enum req_range range
, bool survives
,
1948 enum terrain_flag_id terrflag
)
1951 case REQ_RANGE_LOCAL
:
1952 /* The requirement is fulfilled if the tile has a terrain with
1957 return BOOL_TO_TRISTATE(terrain_has_flag(tile_terrain(target_tile
),
1959 case REQ_RANGE_CADJACENT
:
1963 return BOOL_TO_TRISTATE(terrain_has_flag(tile_terrain(target_tile
),
1965 || is_terrain_flag_card_near(target_tile
,
1967 case REQ_RANGE_ADJACENT
:
1971 return BOOL_TO_TRISTATE(terrain_has_flag(tile_terrain(target_tile
),
1973 || is_terrain_flag_near_tile(target_tile
,
1975 case REQ_RANGE_CITY
:
1979 city_tile_iterate(city_map_radius_sq_get(target_city
),
1980 city_tile(target_city
), ptile
) {
1981 const struct terrain
*pterrain
= tile_terrain(ptile
);
1982 if (pterrain
!= T_UNKNOWN
1983 && terrain_has_flag(pterrain
, terrflag
)) {
1986 } city_tile_iterate_end
;
1989 case REQ_RANGE_TRADEROUTE
:
1993 city_tile_iterate(city_map_radius_sq_get(target_city
),
1994 city_tile(target_city
), ptile
) {
1995 const struct terrain
*pterrain
= tile_terrain(ptile
);
1996 if (pterrain
!= T_UNKNOWN
1997 && terrain_has_flag(pterrain
, terrflag
)) {
2000 } city_tile_iterate_end
;
2002 trade_partners_iterate(target_city
, trade_partner
) {
2003 city_tile_iterate(city_map_radius_sq_get(trade_partner
),
2004 city_tile(trade_partner
), ptile
) {
2005 const struct terrain
*pterrain
= tile_terrain(ptile
);
2006 if (pterrain
!= T_UNKNOWN
2007 && terrain_has_flag(pterrain
, terrflag
)) {
2010 } city_tile_iterate_end
;
2011 } trade_partners_iterate_end
;
2014 case REQ_RANGE_CONTINENT
:
2015 case REQ_RANGE_PLAYER
:
2016 case REQ_RANGE_TEAM
:
2017 case REQ_RANGE_ALLIANCE
:
2018 case REQ_RANGE_WORLD
:
2019 case REQ_RANGE_COUNT
:
2023 fc_assert_msg(FALSE
, "Invalid range %d.", range
);
2028 /****************************************************************************
2029 Is there a base with the given flag within range of the target?
2030 ****************************************************************************/
2031 static enum fc_tristate
is_baseflag_in_range(const struct tile
*target_tile
,
2032 const struct city
*target_city
,
2033 enum req_range range
, bool survives
,
2034 enum base_flag_id baseflag
)
2037 case REQ_RANGE_LOCAL
:
2038 /* The requirement is filled if the tile has a base with correct flag. */
2042 return BOOL_TO_TRISTATE(tile_has_base_flag(target_tile
, baseflag
));
2043 case REQ_RANGE_CADJACENT
:
2047 return BOOL_TO_TRISTATE(tile_has_base_flag(target_tile
, baseflag
)
2048 || is_base_flag_card_near(target_tile
, baseflag
));
2049 case REQ_RANGE_ADJACENT
:
2053 return BOOL_TO_TRISTATE(tile_has_base_flag(target_tile
, baseflag
)
2054 || is_base_flag_near_tile(target_tile
, baseflag
));
2055 case REQ_RANGE_CITY
:
2059 city_tile_iterate(city_map_radius_sq_get(target_city
),
2060 city_tile(target_city
), ptile
) {
2061 if (tile_has_base_flag(ptile
, baseflag
)) {
2064 } city_tile_iterate_end
;
2067 case REQ_RANGE_TRADEROUTE
:
2071 city_tile_iterate(city_map_radius_sq_get(target_city
),
2072 city_tile(target_city
), ptile
) {
2073 if (tile_has_base_flag(ptile
, baseflag
)) {
2076 } city_tile_iterate_end
;
2078 trade_partners_iterate(target_city
, trade_partner
) {
2079 city_tile_iterate(city_map_radius_sq_get(trade_partner
),
2080 city_tile(trade_partner
), ptile
) {
2081 if (tile_has_base_flag(ptile
, baseflag
)) {
2084 } city_tile_iterate_end
;
2085 } trade_partners_iterate_end
;
2088 case REQ_RANGE_CONTINENT
:
2089 case REQ_RANGE_PLAYER
:
2090 case REQ_RANGE_TEAM
:
2091 case REQ_RANGE_ALLIANCE
:
2092 case REQ_RANGE_WORLD
:
2093 case REQ_RANGE_COUNT
:
2097 fc_assert_msg(FALSE
, "Invalid range %d.", range
);
2102 /****************************************************************************
2103 Is there a road with the given flag within range of the target?
2104 ****************************************************************************/
2105 static enum fc_tristate
is_roadflag_in_range(const struct tile
*target_tile
,
2106 const struct city
*target_city
,
2107 enum req_range range
, bool survives
,
2108 enum road_flag_id roadflag
)
2111 case REQ_RANGE_LOCAL
:
2112 /* The requirement is filled if the tile has a road with correct flag. */
2116 return BOOL_TO_TRISTATE(tile_has_road_flag(target_tile
, roadflag
));
2117 case REQ_RANGE_CADJACENT
:
2121 return BOOL_TO_TRISTATE(tile_has_road_flag(target_tile
, roadflag
)
2122 || is_road_flag_card_near(target_tile
, roadflag
));
2123 case REQ_RANGE_ADJACENT
:
2127 return BOOL_TO_TRISTATE(tile_has_road_flag(target_tile
, roadflag
)
2128 || is_road_flag_near_tile(target_tile
, roadflag
));
2129 case REQ_RANGE_CITY
:
2133 city_tile_iterate(city_map_radius_sq_get(target_city
),
2134 city_tile(target_city
), ptile
) {
2135 if (tile_has_road_flag(ptile
, roadflag
)) {
2138 } city_tile_iterate_end
;
2141 case REQ_RANGE_TRADEROUTE
:
2145 city_tile_iterate(city_map_radius_sq_get(target_city
),
2146 city_tile(target_city
), ptile
) {
2147 if (tile_has_road_flag(ptile
, roadflag
)) {
2150 } city_tile_iterate_end
;
2152 trade_partners_iterate(target_city
, trade_partner
) {
2153 city_tile_iterate(city_map_radius_sq_get(trade_partner
),
2154 city_tile(trade_partner
), ptile
) {
2155 if (tile_has_road_flag(ptile
, roadflag
)) {
2158 } city_tile_iterate_end
;
2159 } trade_partners_iterate_end
;
2162 case REQ_RANGE_CONTINENT
:
2163 case REQ_RANGE_PLAYER
:
2164 case REQ_RANGE_TEAM
:
2165 case REQ_RANGE_ALLIANCE
:
2166 case REQ_RANGE_WORLD
:
2167 case REQ_RANGE_COUNT
:
2171 fc_assert_msg(FALSE
, "Invalid range %d.", range
);
2176 /****************************************************************************
2177 Is there an extra with the given flag within range of the target?
2178 ****************************************************************************/
2179 static enum fc_tristate
is_extraflag_in_range(const struct tile
*target_tile
,
2180 const struct city
*target_city
,
2181 enum req_range range
, bool survives
,
2182 enum extra_flag_id extraflag
)
2185 case REQ_RANGE_LOCAL
:
2186 /* The requirement is filled if the tile has an extra with correct flag. */
2190 return BOOL_TO_TRISTATE(tile_has_extra_flag(target_tile
, extraflag
));
2191 case REQ_RANGE_CADJACENT
:
2195 return BOOL_TO_TRISTATE(tile_has_extra_flag(target_tile
, extraflag
)
2196 || is_extra_flag_card_near(target_tile
, extraflag
));
2197 case REQ_RANGE_ADJACENT
:
2201 return BOOL_TO_TRISTATE(tile_has_extra_flag(target_tile
, extraflag
)
2202 || is_extra_flag_near_tile(target_tile
, extraflag
));
2203 case REQ_RANGE_CITY
:
2207 city_tile_iterate(city_map_radius_sq_get(target_city
),
2208 city_tile(target_city
), ptile
) {
2209 if (tile_has_extra_flag(ptile
, extraflag
)) {
2212 } city_tile_iterate_end
;
2215 case REQ_RANGE_TRADEROUTE
:
2219 city_tile_iterate(city_map_radius_sq_get(target_city
),
2220 city_tile(target_city
), ptile
) {
2221 if (tile_has_extra_flag(ptile
, extraflag
)) {
2224 } city_tile_iterate_end
;
2226 trade_partners_iterate(target_city
, trade_partner
) {
2227 city_tile_iterate(city_map_radius_sq_get(trade_partner
),
2228 city_tile(trade_partner
), ptile
) {
2229 if (tile_has_extra_flag(ptile
, extraflag
)) {
2232 } city_tile_iterate_end
;
2233 } trade_partners_iterate_end
;
2236 case REQ_RANGE_CONTINENT
:
2237 case REQ_RANGE_PLAYER
:
2238 case REQ_RANGE_TEAM
:
2239 case REQ_RANGE_ALLIANCE
:
2240 case REQ_RANGE_WORLD
:
2241 case REQ_RANGE_COUNT
:
2245 fc_assert_msg(FALSE
, "Invalid range %d.", range
);
2250 /****************************************************************************
2251 Is there a terrain which can support the specified infrastructure
2252 within range of the target?
2253 ****************************************************************************/
2254 static enum fc_tristate
is_terrain_alter_possible_in_range(const struct tile
*target_tile
,
2255 enum req_range range
,
2257 enum terrain_alteration alteration
)
2264 case REQ_RANGE_LOCAL
:
2265 return BOOL_TO_TRISTATE(terrain_can_support_alteration(tile_terrain(target_tile
),
2267 case REQ_RANGE_CADJACENT
:
2268 case REQ_RANGE_ADJACENT
: /* XXX Could in principle support ADJACENT. */
2269 case REQ_RANGE_CITY
:
2270 case REQ_RANGE_TRADEROUTE
:
2271 case REQ_RANGE_CONTINENT
:
2272 case REQ_RANGE_PLAYER
:
2273 case REQ_RANGE_TEAM
:
2274 case REQ_RANGE_ALLIANCE
:
2275 case REQ_RANGE_WORLD
:
2276 case REQ_RANGE_COUNT
:
2280 fc_assert_msg(FALSE
, "Invalid range %d.", range
);
2285 /****************************************************************************
2286 Is there a nation within range of the target?
2287 ****************************************************************************/
2288 static enum fc_tristate
is_nation_in_range(const struct player
*target_player
,
2289 enum req_range range
, bool survives
,
2290 const struct nation_type
*nation
)
2293 case REQ_RANGE_PLAYER
:
2294 if (target_player
== NULL
) {
2297 return BOOL_TO_TRISTATE(nation_of_player(target_player
) == nation
);
2298 case REQ_RANGE_TEAM
:
2299 case REQ_RANGE_ALLIANCE
:
2300 if (target_player
== NULL
) {
2303 players_iterate_alive(plr2
) {
2304 if (players_in_same_range(target_player
, plr2
, range
)) {
2305 if (nation_of_player(plr2
) == nation
) {
2309 } players_iterate_alive_end
;
2311 case REQ_RANGE_WORLD
:
2312 /* NB: if a player is ever removed outright from the game
2313 * (e.g. via /remove), rather than just dying, this 'survives'
2314 * requirement will stop being true for their nation.
2315 * create_command_newcomer() can also cause this to happen. */
2316 return BOOL_TO_TRISTATE(NULL
!= nation
->player
2317 && (survives
|| nation
->player
->is_alive
));
2318 case REQ_RANGE_LOCAL
:
2319 case REQ_RANGE_CADJACENT
:
2320 case REQ_RANGE_ADJACENT
:
2321 case REQ_RANGE_CITY
:
2322 case REQ_RANGE_TRADEROUTE
:
2323 case REQ_RANGE_CONTINENT
:
2324 case REQ_RANGE_COUNT
:
2328 fc_assert_msg(FALSE
, "Invalid range %d.", range
);
2333 /****************************************************************************
2334 Is there a nation group within range of the target?
2335 ****************************************************************************/
2336 static enum fc_tristate
2337 is_nation_group_in_range(const struct player
*target_player
,
2338 enum req_range range
, bool survives
,
2339 const struct nation_group
*ngroup
)
2342 case REQ_RANGE_PLAYER
:
2343 if (target_player
== NULL
) {
2346 return BOOL_TO_TRISTATE(nation_is_in_group(nation_of_player(target_player
),
2348 case REQ_RANGE_TEAM
:
2349 case REQ_RANGE_ALLIANCE
:
2350 case REQ_RANGE_WORLD
:
2351 if (target_player
== NULL
) {
2354 players_iterate_alive(plr2
) {
2355 if (players_in_same_range(target_player
, plr2
, range
)) {
2356 if (nation_is_in_group(nation_of_player(plr2
), ngroup
)) {
2360 } players_iterate_alive_end
;
2362 case REQ_RANGE_LOCAL
:
2363 case REQ_RANGE_CADJACENT
:
2364 case REQ_RANGE_ADJACENT
:
2365 case REQ_RANGE_CITY
:
2366 case REQ_RANGE_TRADEROUTE
:
2367 case REQ_RANGE_CONTINENT
:
2368 case REQ_RANGE_COUNT
:
2372 fc_assert_msg(FALSE
, "Invalid range %d.", range
);
2377 /****************************************************************************
2378 Is there a nationality within range of the target?
2379 ****************************************************************************/
2380 static enum fc_tristate
is_nationality_in_range(const struct city
*target_city
,
2381 enum req_range range
,
2382 const struct nation_type
*nationality
)
2385 case REQ_RANGE_CITY
:
2386 if (target_city
== NULL
) {
2389 citizens_iterate(target_city
, slot
, count
) {
2390 if (player_slot_get_player(slot
)->nation
== nationality
) {
2393 } citizens_iterate_end
;
2396 case REQ_RANGE_TRADEROUTE
:
2397 if (target_city
== NULL
) {
2400 citizens_iterate(target_city
, slot
, count
) {
2401 if (player_slot_get_player(slot
)->nation
== nationality
) {
2404 } citizens_iterate_end
;
2406 trade_partners_iterate(target_city
, trade_partner
) {
2407 citizens_iterate(trade_partner
, slot
, count
) {
2408 if (player_slot_get_player(slot
)->nation
== nationality
) {
2411 } citizens_iterate_end
;
2412 } trade_partners_iterate_end
;
2415 case REQ_RANGE_PLAYER
:
2416 case REQ_RANGE_TEAM
:
2417 case REQ_RANGE_ALLIANCE
:
2418 case REQ_RANGE_WORLD
:
2419 case REQ_RANGE_LOCAL
:
2420 case REQ_RANGE_CADJACENT
:
2421 case REQ_RANGE_ADJACENT
:
2422 case REQ_RANGE_CONTINENT
:
2423 case REQ_RANGE_COUNT
:
2427 fc_assert_msg(FALSE
, "Invalid range %d.", range
);
2432 /**************************************************************************
2433 Is the diplomatic state within range of the target?
2434 **************************************************************************/
2435 static enum fc_tristate
is_diplrel_in_range(const struct player
*target_player
,
2436 const struct player
*other_player
,
2437 enum req_range range
,
2441 case REQ_RANGE_PLAYER
:
2442 if (target_player
== NULL
) {
2445 return BOOL_TO_TRISTATE(is_diplrel_to_other(target_player
, diplrel
));
2446 case REQ_RANGE_TEAM
:
2447 case REQ_RANGE_ALLIANCE
:
2448 case REQ_RANGE_WORLD
:
2449 if (target_player
== NULL
) {
2452 players_iterate_alive(plr2
) {
2453 if (players_in_same_range(target_player
, plr2
, range
)) {
2454 if (is_diplrel_to_other(plr2
, diplrel
)) {
2458 } players_iterate_alive_end
;
2460 case REQ_RANGE_LOCAL
:
2461 if (target_player
== NULL
|| other_player
== NULL
) {
2464 return BOOL_TO_TRISTATE(is_diplrel_between(target_player
, other_player
, diplrel
));
2465 case REQ_RANGE_CADJACENT
:
2466 case REQ_RANGE_ADJACENT
:
2467 case REQ_RANGE_CITY
:
2468 case REQ_RANGE_TRADEROUTE
:
2469 case REQ_RANGE_CONTINENT
:
2470 case REQ_RANGE_COUNT
:
2474 fc_assert_msg(FALSE
, "Invalid range %d.", range
);
2479 /****************************************************************************
2480 Is there a unit of the given type within range of the target?
2481 ****************************************************************************/
2482 static enum fc_tristate
is_unittype_in_range(const struct unit_type
*target_unittype
,
2483 enum req_range range
, bool survives
,
2484 struct unit_type
*punittype
)
2486 /* If no target_unittype is given, we allow the req to be met. This is
2487 * to allow querying of certain effect types (like the presence of city
2488 * walls) without actually knowing the target unit. */
2489 return BOOL_TO_TRISTATE(range
== REQ_RANGE_LOCAL
2490 && (!target_unittype
2491 || target_unittype
== punittype
));
2494 /****************************************************************************
2495 Is there a unit with the given flag within range of the target?
2496 ****************************************************************************/
2497 static enum fc_tristate
is_unitflag_in_range(const struct unit_type
*target_unittype
,
2498 enum req_range range
, bool survives
,
2499 enum unit_type_flag_id unitflag
)
2501 /* If no target_unittype is given, we allow the req to be met. This is
2502 * to allow querying of certain effect types (like the presence of city
2503 * walls) without actually knowing the target unit. */
2504 if (range
!= REQ_RANGE_LOCAL
) {
2507 if (!target_unittype
) {
2511 return BOOL_TO_TRISTATE(utype_has_flag(target_unittype
, unitflag
));
2514 /****************************************************************************
2515 Is there a unit with the given flag within range of the target?
2516 ****************************************************************************/
2517 static enum fc_tristate
is_unitclass_in_range(const struct unit_type
*target_unittype
,
2518 enum req_range range
, bool survives
,
2519 struct unit_class
*pclass
)
2521 /* If no target_unittype is given, we allow the req to be met. This is
2522 * to allow querying of certain effect types (like the presence of city
2523 * walls) without actually knowing the target unit. */
2524 return BOOL_TO_TRISTATE(range
== REQ_RANGE_LOCAL
2525 && (!target_unittype
2526 || utype_class(target_unittype
) == pclass
));
2529 /****************************************************************************
2530 Is there a unit with the given flag within range of the target?
2531 ****************************************************************************/
2532 static enum fc_tristate
is_unitclassflag_in_range(const struct unit_type
*target_unittype
,
2533 enum req_range range
, bool survives
,
2534 enum unit_class_flag_id ucflag
)
2536 /* If no target_unittype is given, we allow the req to be met. This is
2537 * to allow querying of certain effect types (like the presence of city
2538 * walls) without actually knowing the target unit. */
2539 return BOOL_TO_TRISTATE(range
== REQ_RANGE_LOCAL
2540 && (!target_unittype
2541 || uclass_has_flag(utype_class(target_unittype
), ucflag
)));
2544 /****************************************************************************
2545 Is the given property of the unit state true?
2546 ****************************************************************************/
2547 static enum fc_tristate
is_unit_state(const struct unit
*target_unit
,
2548 enum req_range range
,
2550 enum ustate_prop uprop
)
2552 fc_assert_ret_val_msg(range
== REQ_RANGE_LOCAL
, TRI_NO
,
2553 "Unsupported range \"%s\"",
2554 req_range_name(range
));
2556 /* Could be asked with incomplete data.
2557 * is_req_active() will handle it based on prob_type. */
2558 if (target_unit
== NULL
) {
2563 case USP_TRANSPORTED
:
2564 return BOOL_TO_TRISTATE(target_unit
->transporter
!= NULL
);
2565 case USP_LIVABLE_TILE
:
2566 return BOOL_TO_TRISTATE(
2567 can_unit_exist_at_tile(&(wld
.map
), target_unit
,
2568 unit_tile(target_unit
)));
2570 case USP_DOMESTIC_TILE
:
2571 return BOOL_TO_TRISTATE(
2572 tile_owner(unit_tile(target_unit
)) == unit_owner(target_unit
));
2574 case USP_TRANSPORTING
:
2575 return BOOL_TO_TRISTATE(0 < get_transporter_occupancy(target_unit
));
2576 case USP_HAS_HOME_CITY
:
2577 return BOOL_TO_TRISTATE(target_unit
->homecity
> 0);
2578 case USP_NATIVE_TILE
:
2579 return BOOL_TO_TRISTATE(
2580 is_native_tile(unit_type_get(target_unit
), unit_tile(target_unit
)));
2583 fc_assert_msg(uprop
!= USP_COUNT
, "Invalid unit state property.");
2584 /* Invalid property is unknowable. */
2588 /* Should never be reached */
2589 fc_assert_ret_val_msg(FALSE
, TRI_NO
,
2590 "Unsupported unit property \"%s\"",
2591 ustate_prop_name(uprop
));
2594 /****************************************************************************
2595 Is center of given city in tile. If city is NULL, any city will do.
2596 ****************************************************************************/
2597 static bool is_city_in_tile(const struct tile
*ptile
,
2598 const struct city
*pcity
)
2600 if (pcity
== NULL
) {
2601 return tile_city(ptile
) != NULL
;
2603 return is_city_center(pcity
, ptile
);
2607 /****************************************************************************
2608 Is center of given city in range. If city is NULL, any city will do.
2609 ****************************************************************************/
2610 static enum fc_tristate
is_citytile_in_range(const struct tile
*target_tile
,
2611 const struct city
*target_city
,
2612 enum req_range range
,
2613 enum citytile_type citytile
)
2616 if (citytile
== CITYT_CENTER
) {
2618 case REQ_RANGE_LOCAL
:
2619 return BOOL_TO_TRISTATE(is_city_in_tile(target_tile
, target_city
));
2620 case REQ_RANGE_CADJACENT
:
2621 if (is_city_in_tile(target_tile
, target_city
)) {
2624 cardinal_adjc_iterate(&(wld
.map
), target_tile
, adjc_tile
) {
2625 if (is_city_in_tile(adjc_tile
, target_city
)) {
2628 } cardinal_adjc_iterate_end
;
2631 case REQ_RANGE_ADJACENT
:
2632 if (is_city_in_tile(target_tile
, target_city
)) {
2635 adjc_iterate(&(wld
.map
), target_tile
, adjc_tile
) {
2636 if (is_city_in_tile(adjc_tile
, target_city
)) {
2642 case REQ_RANGE_CITY
:
2643 case REQ_RANGE_TRADEROUTE
:
2644 case REQ_RANGE_CONTINENT
:
2645 case REQ_RANGE_PLAYER
:
2646 case REQ_RANGE_TEAM
:
2647 case REQ_RANGE_ALLIANCE
:
2648 case REQ_RANGE_WORLD
:
2649 case REQ_RANGE_COUNT
:
2653 fc_assert_msg(FALSE
, "Invalid range %d for citytile.", range
);
2656 } else if (citytile
== CITYT_CLAIMED
) {
2658 case REQ_RANGE_LOCAL
:
2659 return BOOL_TO_TRISTATE(target_tile
->owner
!= NULL
);
2660 case REQ_RANGE_CADJACENT
:
2661 if (target_tile
->owner
!= NULL
) {
2664 cardinal_adjc_iterate(&(wld
.map
), target_tile
, adjc_tile
) {
2665 if (adjc_tile
->owner
!= NULL
) {
2668 } cardinal_adjc_iterate_end
;
2671 case REQ_RANGE_ADJACENT
:
2672 if (target_tile
->owner
!= NULL
) {
2675 adjc_iterate(&(wld
.map
), target_tile
, adjc_tile
) {
2676 if (adjc_tile
->owner
!= NULL
) {
2682 case REQ_RANGE_CITY
:
2683 case REQ_RANGE_TRADEROUTE
:
2684 case REQ_RANGE_CONTINENT
:
2685 case REQ_RANGE_PLAYER
:
2686 case REQ_RANGE_TEAM
:
2687 case REQ_RANGE_ALLIANCE
:
2688 case REQ_RANGE_WORLD
:
2689 case REQ_RANGE_COUNT
:
2693 fc_assert_msg(FALSE
, "Invalid range %d for citytile.", range
);
2697 /* Not implemented */
2698 log_error("is_req_active(): citytile %d not supported.",
2707 /****************************************************************************
2708 Has achievement been claimed by someone in range.
2709 ****************************************************************************/
2710 static enum fc_tristate
2711 is_achievement_in_range(const struct player
*target_player
,
2712 enum req_range range
,
2713 const struct achievement
*achievement
)
2715 if (range
== REQ_RANGE_WORLD
) {
2716 return BOOL_TO_TRISTATE(achievement_claimed(achievement
));
2717 } else if (target_player
== NULL
) {
2719 } else if (range
== REQ_RANGE_ALLIANCE
|| range
== REQ_RANGE_TEAM
) {
2720 players_iterate_alive(plr2
) {
2721 if (players_in_same_range(target_player
, plr2
, range
)
2722 && achievement_player_has(achievement
, plr2
)) {
2725 } players_iterate_alive_end
;
2727 } else if (range
== REQ_RANGE_PLAYER
) {
2728 if (achievement_player_has(achievement
, target_player
)) {
2734 fc_assert_ret_val_msg(FALSE
, TRI_MAYBE
,
2735 "Illegal range %d for achievement requirement.",
2740 /****************************************************************************
2741 Checks the requirement to see if it is active on the given target.
2743 target gives the type of the target
2744 (player,city,building,tile) give the exact target
2745 req gives the requirement itself
2747 Make sure you give all aspects of the target when calling this function:
2748 for instance if you have TARGET_CITY pass the city's owner as the target
2749 player as well as the city itself as the target city.
2750 ****************************************************************************/
2751 bool is_req_active(const struct player
*target_player
,
2752 const struct player
*other_player
,
2753 const struct city
*target_city
,
2754 const struct impr_type
*target_building
,
2755 const struct tile
*target_tile
,
2756 const struct unit
*target_unit
,
2757 const struct unit_type
*target_unittype
,
2758 const struct output_type
*target_output
,
2759 const struct specialist
*target_specialist
,
2760 const struct action
*target_action
,
2761 const struct requirement
*req
,
2762 const enum req_problem_type prob_type
)
2764 enum fc_tristate eval
= TRI_NO
;
2766 /* The supplied unit has a type. Use it if the unit type is missing. */
2767 if (target_unittype
== NULL
&& target_unit
!= NULL
) {
2768 target_unittype
= unit_type_get(target_unit
);
2771 /* Note the target may actually not exist. In particular, effects that
2772 * have a VUT_TERRAIN may often be passed
2773 * to this function with a city as their target. In this case the
2774 * requirement is simply not met. */
2775 switch (req
->source
.kind
) {
2780 /* The requirement is filled if the player owns the tech. */
2781 eval
= is_tech_in_range(target_player
, req
->range
, req
->survives
,
2782 advance_number(req
->source
.value
.advance
));
2785 eval
= is_techflag_in_range(target_player
, req
->range
,
2786 req
->source
.value
.techflag
);
2788 case VUT_GOVERNMENT
:
2789 /* The requirement is filled if the player is using the government. */
2790 if (target_player
== NULL
) {
2793 eval
= BOOL_TO_TRISTATE(government_of_player(target_player
) == req
->source
.value
.govern
);
2796 case VUT_ACHIEVEMENT
:
2797 eval
= is_achievement_in_range(target_player
, req
->range
,
2798 req
->source
.value
.achievement
);
2801 if (target_player
== NULL
) {
2804 eval
= BOOL_TO_TRISTATE(target_player
->style
== req
->source
.value
.style
);
2807 case VUT_IMPROVEMENT
:
2808 eval
= is_building_in_range(target_player
, target_city
,
2810 req
->range
, req
->survives
,
2811 req
->source
.value
.building
);
2813 case VUT_IMPR_GENUS
:
2814 eval
= (target_building
? BOOL_TO_TRISTATE(
2815 target_building
->genus
2816 == req
->source
.value
.impr_genus
)
2820 eval
= is_extra_type_in_range(target_tile
, target_city
,
2821 req
->range
, req
->survives
,
2822 req
->source
.value
.extra
);
2825 eval
= is_goods_type_in_range(target_tile
, target_city
,
2826 req
->range
, req
->survives
,
2827 req
->source
.value
.good
);
2830 eval
= is_terrain_in_range(target_tile
, target_city
,
2831 req
->range
, req
->survives
,
2832 req
->source
.value
.terrain
);
2835 eval
= is_terrainflag_in_range(target_tile
, target_city
,
2836 req
->range
, req
->survives
,
2837 req
->source
.value
.terrainflag
);
2840 eval
= is_nation_in_range(target_player
, req
->range
, req
->survives
,
2841 req
->source
.value
.nation
);
2843 case VUT_NATIONGROUP
:
2844 eval
= is_nation_group_in_range(target_player
, req
->range
, req
->survives
,
2845 req
->source
.value
.nationgroup
);
2847 case VUT_NATIONALITY
:
2848 eval
= is_nationality_in_range(target_city
, req
->range
,
2849 req
->source
.value
.nationality
);
2852 eval
= is_diplrel_in_range(target_player
, other_player
, req
->range
,
2853 req
->source
.value
.diplrel
);
2856 if (target_unittype
== NULL
) {
2859 eval
= is_unittype_in_range(target_unittype
,
2860 req
->range
, req
->survives
,
2861 req
->source
.value
.utype
);
2865 eval
= is_unitflag_in_range(target_unittype
,
2866 req
->range
, req
->survives
,
2867 req
->source
.value
.unitflag
);
2870 if (target_unittype
== NULL
) {
2873 eval
= is_unitclass_in_range(target_unittype
,
2874 req
->range
, req
->survives
,
2875 req
->source
.value
.uclass
);
2879 if (target_unittype
== NULL
) {
2882 eval
= is_unitclassflag_in_range(target_unittype
,
2883 req
->range
, req
->survives
,
2884 req
->source
.value
.unitclassflag
);
2887 case VUT_MINVETERAN
:
2888 if (target_unit
== NULL
) {
2892 BOOL_TO_TRISTATE(target_unit
->veteran
>= req
->source
.value
.minveteran
);
2896 if (target_unit
== NULL
) {
2899 eval
= is_unit_state(target_unit
,
2900 req
->range
, req
->survives
,
2901 req
->source
.value
.unit_state
);
2905 if (target_unit
== NULL
) {
2908 eval
= BOOL_TO_TRISTATE(
2909 req
->source
.value
.minmoves
<= target_unit
->moves_left
);
2913 if (target_unit
== NULL
) {
2916 eval
= BOOL_TO_TRISTATE(
2917 req
->source
.value
.min_hit_points
<= target_unit
->hp
);
2921 switch (req
->range
) {
2922 case REQ_RANGE_LOCAL
:
2923 if (target_unit
== NULL
|| !is_server()) {
2926 eval
= BOOL_TO_TRISTATE(
2927 req
->source
.value
.age
<=
2928 game
.info
.turn
- target_unit
->server
.birth_turn
);
2931 case REQ_RANGE_CITY
:
2932 if (target_city
== NULL
) {
2935 eval
= BOOL_TO_TRISTATE(
2936 req
->source
.value
.age
<=
2937 game
.info
.turn
- target_city
->turn_founded
);
2940 case REQ_RANGE_PLAYER
:
2941 if (target_player
== NULL
) {
2945 BOOL_TO_TRISTATE(req
->source
.value
.age
<= player_age(target_player
));
2954 switch (req
->range
) {
2955 case REQ_RANGE_WORLD
:
2956 /* "None" does not count */
2957 eval
= ((game
.info
.global_advance_count
- 1) >= req
->source
.value
.min_techs
);
2959 case REQ_RANGE_PLAYER
:
2960 if (target_player
== NULL
) {
2963 /* "None" does not count */
2964 eval
= ((research_get(target_player
)->techs_researched
- 1) >= req
->source
.value
.min_techs
);
2972 eval
= BOOL_TO_TRISTATE(target_action
2973 && action_number(target_action
)
2974 == action_number(req
->source
.value
.action
));
2977 eval
= BOOL_TO_TRISTATE(target_output
2978 && target_output
->index
== req
->source
.value
.outputtype
);
2980 case VUT_SPECIALIST
:
2981 eval
= BOOL_TO_TRISTATE(target_specialist
2982 && target_specialist
== req
->source
.value
.specialist
);
2985 if (target_city
== NULL
) {
2988 if (req
->range
== REQ_RANGE_TRADEROUTE
) {
2991 if (city_size_get(target_city
) >= req
->source
.value
.minsize
) {
2995 trade_partners_iterate(target_city
, trade_partner
) {
2996 if (city_size_get(trade_partner
) >= req
->source
.value
.minsize
) {
3000 } trade_partners_iterate_end
;
3001 eval
= BOOL_TO_TRISTATE(found
);
3003 eval
= BOOL_TO_TRISTATE(city_size_get(target_city
) >= req
->source
.value
.minsize
);
3007 case VUT_MINCULTURE
:
3008 eval
= is_minculture_in_range(target_city
, target_player
, req
->range
,
3009 req
->source
.value
.minculture
);
3012 if (target_player
== NULL
) {
3015 eval
= BOOL_TO_TRISTATE(is_ai(target_player
)
3016 && target_player
->ai_common
.skill_level
== req
->source
.value
.ai_level
);
3019 case VUT_MAXTILEUNITS
:
3020 eval
= is_tile_units_in_range(target_tile
, req
->range
,
3021 req
->source
.value
.max_tile_units
);
3023 case VUT_TERRAINCLASS
:
3024 eval
= is_terrain_class_in_range(target_tile
, target_city
,
3025 req
->range
, req
->survives
,
3026 req
->source
.value
.terrainclass
);
3029 eval
= is_baseflag_in_range(target_tile
, target_city
,
3030 req
->range
, req
->survives
,
3031 req
->source
.value
.baseflag
);
3034 eval
= is_roadflag_in_range(target_tile
, target_city
,
3035 req
->range
, req
->survives
,
3036 req
->source
.value
.roadflag
);
3039 eval
= is_extraflag_in_range(target_tile
, target_city
,
3040 req
->range
, req
->survives
,
3041 req
->source
.value
.extraflag
);
3044 eval
= BOOL_TO_TRISTATE(game
.info
.year
>= req
->source
.value
.minyear
);
3046 case VUT_MINCALFRAG
:
3047 eval
= BOOL_TO_TRISTATE(game
.info
.fragment_count
>= req
->source
.value
.mincalfrag
);
3050 eval
= BOOL_TO_TRISTATE(current_topo_has_flag(req
->source
.value
.topo_property
));
3052 case VUT_TERRAINALTER
:
3053 if (target_tile
== NULL
) {
3056 eval
= is_terrain_alter_possible_in_range(target_tile
,
3057 req
->range
, req
->survives
,
3058 req
->source
.value
.terrainalter
);
3062 if (target_tile
== NULL
) {
3065 eval
= is_citytile_in_range(target_tile
, target_city
,
3067 req
->source
.value
.citytile
);
3071 log_error("is_req_active(): invalid source kind %d.", req
->source
.kind
);
3075 if (eval
== TRI_MAYBE
) {
3076 if (prob_type
== RPT_POSSIBLE
) {
3083 return (eval
== TRI_YES
);
3085 return (eval
== TRI_NO
);
3089 /****************************************************************************
3090 Checks the requirement(s) to see if they are active on the given target.
3092 target gives the type of the target
3093 (player,city,building,tile) give the exact target
3095 reqs gives the requirement vector.
3096 The function returns TRUE only if all requirements are active.
3098 Make sure you give all aspects of the target when calling this function:
3099 for instance if you have TARGET_CITY pass the city's owner as the target
3100 player as well as the city itself as the target city.
3101 ****************************************************************************/
3102 bool are_reqs_active(const struct player
*target_player
,
3103 const struct player
*other_player
,
3104 const struct city
*target_city
,
3105 const struct impr_type
*target_building
,
3106 const struct tile
*target_tile
,
3107 const struct unit
*target_unit
,
3108 const struct unit_type
*target_unittype
,
3109 const struct output_type
*target_output
,
3110 const struct specialist
*target_specialist
,
3111 const struct action
*target_action
,
3112 const struct requirement_vector
*reqs
,
3113 const enum req_problem_type prob_type
)
3115 requirement_vector_iterate(reqs
, preq
) {
3116 if (!is_req_active(target_player
, other_player
, target_city
,
3117 target_building
, target_tile
,
3118 target_unit
, target_unittype
,
3119 target_output
, target_specialist
, target_action
,
3123 } requirement_vector_iterate_end
;
3127 /****************************************************************************
3128 Return TRUE if this is an "unchanging" requirement. This means that
3129 if a target can't meet the requirement now, it probably won't ever be able
3130 to do so later. This can be used to do requirement filtering when checking
3131 if a target may "eventually" become available.
3133 Note this isn't absolute. Returning TRUE here just means that the
3134 requirement probably can't be met. In some cases (particularly terrains)
3136 *****************************************************************************/
3137 bool is_req_unchanging(const struct requirement
*req
)
3139 switch (req
->source
.kind
) {
3143 case VUT_SPECIALIST
: /* Only so long as it's at local range only */
3150 case VUT_NATIONGROUP
:
3151 return (req
->range
!= REQ_RANGE_ALLIANCE
);
3154 case VUT_GOVERNMENT
:
3155 case VUT_ACHIEVEMENT
:
3156 case VUT_IMPROVEMENT
:
3157 case VUT_IMPR_GENUS
:
3159 case VUT_MINCULTURE
:
3161 case VUT_NATIONALITY
:
3163 case VUT_MAXTILEUNITS
:
3164 case VUT_UTYPE
: /* Not sure about this one */
3165 case VUT_UTFLAG
: /* Not sure about this one */
3166 case VUT_UCLASS
: /* Not sure about this one */
3167 case VUT_UCFLAG
: /* Not sure about this one */
3168 case VUT_MINVETERAN
:
3175 case VUT_MINCALFRAG
: /* cyclically available */
3180 case VUT_TERRAINCLASS
:
3182 case VUT_TERRAINALTER
:
3184 /* Terrains, specials and bases aren't really unchanging; in fact they're
3185 * practically guaranteed to change. We return TRUE here for historical
3186 * reasons and so that the AI doesn't get confused (since the AI
3187 * doesn't know how to meet special and terrain requirements). */
3190 /* Once year is reached, it does not change again */
3191 return req
->source
.value
.minyear
> game
.info
.year
;
3195 fc_assert_msg(FALSE
, "Invalid source kind %d.", req
->source
.kind
);
3199 /*************************************************************************
3200 Returns TRUE iff the requirement vector vec contains the requirement
3202 **************************************************************************/
3203 bool is_req_in_vec(const struct requirement
*req
,
3204 const struct requirement_vector
*vec
)
3206 requirement_vector_iterate(vec
, preq
) {
3207 if (are_requirements_equal(req
, preq
)) {
3210 } requirement_vector_iterate_end
;
3215 /****************************************************************************
3216 Return TRUE iff the two sources are equivalent. Note this isn't the
3217 same as an == or memcmp check.
3218 *****************************************************************************/
3219 bool are_universals_equal(const struct universal
*psource1
,
3220 const struct universal
*psource2
)
3222 if (psource1
->kind
!= psource2
->kind
) {
3225 switch (psource1
->kind
) {
3229 return psource1
->value
.advance
== psource2
->value
.advance
;
3231 return psource1
->value
.techflag
== psource2
->value
.techflag
;
3232 case VUT_GOVERNMENT
:
3233 return psource1
->value
.govern
== psource2
->value
.govern
;
3234 case VUT_ACHIEVEMENT
:
3235 return psource1
->value
.achievement
== psource2
->value
.achievement
;
3237 return psource1
->value
.style
== psource2
->value
.style
;
3238 case VUT_IMPROVEMENT
:
3239 return psource1
->value
.building
== psource2
->value
.building
;
3240 case VUT_IMPR_GENUS
:
3241 return psource1
->value
.impr_genus
== psource2
->value
.impr_genus
;
3243 return psource1
->value
.extra
== psource2
->value
.extra
;
3245 return psource1
->value
.good
== psource2
->value
.good
;
3247 return psource1
->value
.terrain
== psource2
->value
.terrain
;
3249 return psource1
->value
.terrainflag
== psource2
->value
.terrainflag
;
3251 return psource1
->value
.nation
== psource2
->value
.nation
;
3252 case VUT_NATIONGROUP
:
3253 return psource1
->value
.nationgroup
== psource2
->value
.nationgroup
;
3254 case VUT_NATIONALITY
:
3255 return psource1
->value
.nationality
== psource2
->value
.nationality
;
3257 return psource1
->value
.diplrel
== psource2
->value
.diplrel
;
3259 return psource1
->value
.utype
== psource2
->value
.utype
;
3261 return psource1
->value
.unitflag
== psource2
->value
.unitflag
;
3263 return psource1
->value
.uclass
== psource2
->value
.uclass
;
3265 return psource1
->value
.unitclassflag
== psource2
->value
.unitclassflag
;
3266 case VUT_MINVETERAN
:
3267 return psource1
->value
.minveteran
== psource2
->value
.minveteran
;
3269 return psource1
->value
.unit_state
== psource2
->value
.unit_state
;
3271 return psource1
->value
.minmoves
== psource2
->value
.minmoves
;
3273 return psource1
->value
.min_hit_points
== psource2
->value
.min_hit_points
;
3275 return psource1
->value
.age
== psource2
->value
.age
;
3277 return psource1
->value
.min_techs
== psource2
->value
.min_techs
;
3279 return (action_number(psource1
->value
.action
)
3280 == action_number(psource2
->value
.action
));
3282 return psource1
->value
.outputtype
== psource2
->value
.outputtype
;
3283 case VUT_SPECIALIST
:
3284 return psource1
->value
.specialist
== psource2
->value
.specialist
;
3286 return psource1
->value
.minsize
== psource2
->value
.minsize
;
3287 case VUT_MINCULTURE
:
3288 return psource1
->value
.minculture
== psource2
->value
.minculture
;
3290 return psource1
->value
.ai_level
== psource2
->value
.ai_level
;
3291 case VUT_MAXTILEUNITS
:
3292 return psource1
->value
.max_tile_units
== psource2
->value
.max_tile_units
;
3293 case VUT_TERRAINCLASS
:
3294 return psource1
->value
.terrainclass
== psource2
->value
.terrainclass
;
3296 return psource1
->value
.baseflag
== psource2
->value
.baseflag
;
3298 return psource1
->value
.roadflag
== psource2
->value
.roadflag
;
3300 return psource1
->value
.extraflag
== psource2
->value
.extraflag
;
3302 return psource1
->value
.minyear
== psource2
->value
.minyear
;
3303 case VUT_MINCALFRAG
:
3304 return psource1
->value
.mincalfrag
== psource2
->value
.mincalfrag
;
3306 return psource1
->value
.topo_property
== psource2
->value
.topo_property
;
3307 case VUT_TERRAINALTER
:
3308 return psource1
->value
.terrainalter
== psource2
->value
.terrainalter
;
3310 return psource1
->value
.citytile
== psource2
->value
.citytile
;
3315 fc_assert_msg(FALSE
, "Invalid source kind %d.", psource1
->kind
);
3319 /****************************************************************************
3320 Return the (untranslated) rule name of the universal.
3321 You don't have to free the return pointer.
3322 *****************************************************************************/
3323 const char *universal_rule_name(const struct universal
*psource
)
3325 static char buffer
[10];
3327 switch (psource
->kind
) {
3331 return citytile_type_name(psource
->value
.citytile
);
3333 fc_snprintf(buffer
, sizeof(buffer
), "%d", psource
->value
.minyear
);
3336 case VUT_MINCALFRAG
:
3337 /* Rule name is 0-based number, not pretty name from ruleset */
3338 fc_snprintf(buffer
, sizeof(buffer
), "%d", psource
->value
.mincalfrag
);
3342 return topo_flag_name(psource
->value
.topo_property
);
3344 return advance_rule_name(psource
->value
.advance
);
3346 return tech_flag_id_name(psource
->value
.techflag
);
3347 case VUT_GOVERNMENT
:
3348 return government_rule_name(psource
->value
.govern
);
3349 case VUT_ACHIEVEMENT
:
3350 return achievement_rule_name(psource
->value
.achievement
);
3352 return style_rule_name(psource
->value
.style
);
3353 case VUT_IMPROVEMENT
:
3354 return improvement_rule_name(psource
->value
.building
);
3355 case VUT_IMPR_GENUS
:
3356 return impr_genus_id_name(psource
->value
.impr_genus
);
3358 return extra_rule_name(psource
->value
.extra
);
3360 return goods_rule_name(psource
->value
.good
);
3362 return terrain_rule_name(psource
->value
.terrain
);
3364 return terrain_flag_id_name(psource
->value
.terrainflag
);
3366 return nation_rule_name(psource
->value
.nation
);
3367 case VUT_NATIONGROUP
:
3368 return nation_group_rule_name(psource
->value
.nationgroup
);
3370 return diplrel_rule_name(psource
->value
.diplrel
);
3371 case VUT_NATIONALITY
:
3372 return nation_rule_name(psource
->value
.nationality
);
3374 return utype_rule_name(psource
->value
.utype
);
3376 return unit_type_flag_id_name(psource
->value
.unitflag
);
3378 return uclass_rule_name(psource
->value
.uclass
);
3380 return unit_class_flag_id_name(psource
->value
.unitclassflag
);
3381 case VUT_MINVETERAN
:
3382 fc_snprintf(buffer
, sizeof(buffer
), "%d", psource
->value
.minveteran
);
3386 return ustate_prop_name(psource
->value
.unit_state
);
3388 fc_snprintf(buffer
, sizeof(buffer
), "%d", psource
->value
.minmoves
);
3392 fc_snprintf(buffer
, sizeof(buffer
), "%d", psource
->value
.min_hit_points
);
3396 fc_snprintf(buffer
, sizeof(buffer
), "%d", psource
->value
.age
);
3400 fc_snprintf(buffer
, sizeof(buffer
), "%d", psource
->value
.min_techs
);
3404 return action_rule_name(psource
->value
.action
);
3406 return get_output_name(psource
->value
.outputtype
);
3407 case VUT_SPECIALIST
:
3408 return specialist_rule_name(psource
->value
.specialist
);
3410 fc_snprintf(buffer
, sizeof(buffer
), "%d", psource
->value
.minsize
);
3413 case VUT_MINCULTURE
:
3414 fc_snprintf(buffer
, sizeof(buffer
), "%d", psource
->value
.minculture
);
3418 return ai_level_name(psource
->value
.ai_level
);
3419 case VUT_MAXTILEUNITS
:
3420 fc_snprintf(buffer
, sizeof(buffer
), "%d", psource
->value
.max_tile_units
);
3422 case VUT_TERRAINCLASS
:
3423 return terrain_class_name(psource
->value
.terrainclass
);
3425 return base_flag_id_name(psource
->value
.baseflag
);
3427 return road_flag_id_name(psource
->value
.roadflag
);
3429 return extra_flag_id_name(psource
->value
.extraflag
);
3430 case VUT_TERRAINALTER
:
3431 return terrain_alteration_name(psource
->value
.terrainalter
);
3436 fc_assert_msg(FALSE
, "Invalid source kind %d.", psource
->kind
);
3440 /****************************************************************************
3441 Make user-friendly text for the source. The text is put into a user
3442 buffer which is also returned.
3443 This should be short, as it's used in lists like "Aqueduct+Size 8" when
3444 explaining a calculated value. It just needs to be enough to remind the
3445 player of rules they already know, not a complete explanation (use
3446 insert_requirement() for that).
3447 *****************************************************************************/
3448 const char *universal_name_translation(const struct universal
*psource
,
3449 char *buf
, size_t bufsz
)
3451 buf
[0] = '\0'; /* to be safe. */
3452 switch (psource
->kind
) {
3454 /* TRANS: missing value */
3455 fc_strlcat(buf
, _("(none)"), bufsz
);
3458 fc_strlcat(buf
, advance_name_translation(psource
->value
.advance
), bufsz
);
3461 cat_snprintf(buf
, bufsz
, _("\"%s\" tech"),
3462 tech_flag_id_translated_name(psource
->value
.techflag
));
3464 case VUT_GOVERNMENT
:
3465 fc_strlcat(buf
, government_name_translation(psource
->value
.govern
),
3468 case VUT_ACHIEVEMENT
:
3469 fc_strlcat(buf
, achievement_name_translation(psource
->value
.achievement
),
3473 fc_strlcat(buf
, style_name_translation(psource
->value
.style
),
3476 case VUT_IMPROVEMENT
:
3477 fc_strlcat(buf
, improvement_name_translation(psource
->value
.building
),
3480 case VUT_IMPR_GENUS
:
3482 impr_genus_id_translated_name(psource
->value
.impr_genus
),
3486 fc_strlcat(buf
, extra_name_translation(psource
->value
.extra
), bufsz
);
3489 fc_strlcat(buf
, goods_name_translation(psource
->value
.good
), bufsz
);
3492 fc_strlcat(buf
, terrain_name_translation(psource
->value
.terrain
), bufsz
);
3495 fc_strlcat(buf
, nation_adjective_translation(psource
->value
.nation
),
3498 case VUT_NATIONGROUP
:
3499 fc_strlcat(buf
, nation_group_name_translation(psource
->value
.nationgroup
),
3502 case VUT_NATIONALITY
:
3503 cat_snprintf(buf
, bufsz
, _("%s citizens"),
3504 nation_adjective_translation(psource
->value
.nationality
));
3507 fc_strlcat(buf
, diplrel_name_translation(psource
->value
.diplrel
),
3511 fc_strlcat(buf
, utype_name_translation(psource
->value
.utype
), bufsz
);
3514 cat_snprintf(buf
, bufsz
,
3515 /* TRANS: Unit type flag */
3516 Q_("?utflag:\"%s\" units"),
3517 unit_type_flag_id_translated_name(
3518 psource
->value
.unitflag
));
3521 cat_snprintf(buf
, bufsz
,
3522 /* TRANS: Unit class */
3524 uclass_name_translation(psource
->value
.uclass
));
3527 cat_snprintf(buf
, bufsz
,
3528 /* TRANS: Unit class flag */
3529 Q_("?ucflag:\"%s\" units"),
3530 unit_class_flag_id_translated_name(
3531 psource
->value
.unitclassflag
));
3533 case VUT_MINVETERAN
:
3535 cat_snprintf(buf
, bufsz
, _("Veteran level >=%d"),
3536 psource
->value
.minveteran
);
3539 switch (psource
->value
.unit_state
) {
3540 case USP_TRANSPORTED
:
3541 /* TRANS: unit state. (appears in strings like "Missile+Transported") */
3542 cat_snprintf(buf
, bufsz
, _("Transported"));
3544 case USP_LIVABLE_TILE
:
3545 cat_snprintf(buf
, bufsz
,
3546 /* TRANS: unit state. (appears in strings like
3547 * "Missile+On livable tile") */
3548 _("On livable tile"));
3550 case USP_DOMESTIC_TILE
:
3551 cat_snprintf(buf
, bufsz
,
3552 /* TRANS: unit state. (appears in strings like
3553 * "Missile+On domestic tile") */
3554 _("On domestic tile"));
3556 case USP_TRANSPORTING
:
3557 /* TRANS: unit state. (appears in strings like "Missile+Transported") */
3558 cat_snprintf(buf
, bufsz
, _("Transporting"));
3560 case USP_HAS_HOME_CITY
:
3561 /* TRANS: unit state. (appears in strings like "Missile+Has a home city") */
3562 cat_snprintf(buf
, bufsz
, _("Has a home city"));
3564 case USP_NATIVE_TILE
:
3565 cat_snprintf(buf
, bufsz
,
3566 /* TRANS: unit state. (appears in strings like
3567 * "Missile+On native tile") */
3568 _("On native tile"));
3571 fc_assert_msg(psource
->value
.unit_state
!= USP_COUNT
,
3572 "Invalid unit state property.");
3577 /* TRANS: Minimum unit movement points left for requirement to be met
3578 * (%s is a string like "1" or "2 1/3") */
3579 cat_snprintf(buf
, bufsz
, _("%s MP"),
3580 move_points_text(psource
->value
.minmoves
, TRUE
));
3583 /* TRANS: HP = hit points */
3584 cat_snprintf(buf
, bufsz
, _("%d HP"),
3585 psource
->value
.min_hit_points
);
3588 cat_snprintf(buf
, bufsz
, _("Age %d"),
3589 psource
->value
.age
);
3592 cat_snprintf(buf
, bufsz
, _("%d Techs"),
3593 psource
->value
.min_techs
);
3596 fc_strlcat(buf
, action_name_translation(psource
->value
.action
),
3601 fc_strlcat(buf
, get_output_name(psource
->value
.outputtype
), bufsz
);
3603 case VUT_SPECIALIST
:
3604 fc_strlcat(buf
, specialist_plural_translation(psource
->value
.specialist
),
3608 cat_snprintf(buf
, bufsz
, _("Size %d"),
3609 psource
->value
.minsize
);
3611 case VUT_MINCULTURE
:
3612 cat_snprintf(buf
, bufsz
, _("Culture %d"),
3613 psource
->value
.minculture
);
3616 /* TRANS: "Hard AI" */
3617 cat_snprintf(buf
, bufsz
, _("%s AI"),
3618 ai_level_translated_name(psource
->value
.ai_level
)); /* FIXME */
3620 case VUT_MAXTILEUNITS
:
3621 /* TRANS: here <= means 'less than or equal' */
3622 cat_snprintf(buf
, bufsz
, PL_("<=%d unit",
3623 "<=%d units", psource
->value
.max_tile_units
),
3624 psource
->value
.max_tile_units
);
3626 case VUT_TERRAINCLASS
:
3627 /* TRANS: Terrain class: "Land terrain" */
3628 cat_snprintf(buf
, bufsz
, _("%s terrain"),
3629 terrain_class_name_translation(psource
->value
.terrainclass
));
3632 cat_snprintf(buf
, bufsz
,
3633 /* TRANS: Terrain flag */
3634 Q_("?terrflag:\"%s\" terrain"),
3635 terrain_flag_id_translated_name(
3636 psource
->value
.terrainflag
));
3639 cat_snprintf(buf
, bufsz
,
3640 /* TRANS: Base flag */
3641 Q_("?baseflag:\"%s\" base"),
3642 base_flag_id_translated_name(psource
->value
.baseflag
));
3645 cat_snprintf(buf
, bufsz
,
3646 /* TRANS: Road flag */
3647 Q_("?roadflag:\"%s\" road"),
3648 road_flag_id_translated_name(psource
->value
.roadflag
));
3651 cat_snprintf(buf
, bufsz
,
3652 /* TRANS: Extra flag */
3653 Q_("?extraflag:\"%s\" extra"),
3654 extra_flag_id_translated_name(psource
->value
.extraflag
));
3657 cat_snprintf(buf
, bufsz
, _("After %s"),
3658 textyear(psource
->value
.minyear
));
3660 case VUT_MINCALFRAG
:
3661 /* TRANS: here >= means 'greater than or equal'.
3662 * %s identifies a calendar fragment (may be bare number). */
3663 cat_snprintf(buf
, bufsz
, _(">=%s"),
3664 textcalfrag(psource
->value
.mincalfrag
));
3667 cat_snprintf(buf
, bufsz
, _("%s map"),
3668 _(topo_flag_name(psource
->value
.topo_property
)));
3670 case VUT_TERRAINALTER
:
3671 /* TRANS: "Irrigation possible" */
3672 cat_snprintf(buf
, bufsz
, _("%s possible"),
3673 Q_(terrain_alteration_name(psource
->value
.terrainalter
)));
3676 fc_strlcat(buf
, _("City center"), bufsz
);
3682 fc_assert_msg(FALSE
, "Invalid source kind %d.", psource
->kind
);
3686 /****************************************************************************
3687 Return untranslated name of the universal source name.
3688 *****************************************************************************/
3689 const char *universal_type_rule_name(const struct universal
*psource
)
3691 return universals_n_name(psource
->kind
);
3694 /**************************************************************************
3695 Return the number of shields it takes to build this universal.
3696 **************************************************************************/
3697 int universal_build_shield_cost(const struct universal
*target
)
3699 switch (target
->kind
) {
3700 case VUT_IMPROVEMENT
:
3701 return impr_build_shield_cost(target
->value
.building
);
3703 return utype_build_shield_cost(target
->value
.utype
);
3710 /*************************************************************************
3711 Will the specified universal fulfill the requirements in the list?
3712 **************************************************************************/
3713 bool universal_fulfills_requirement(bool check_necessary
,
3714 const struct requirement_vector
*reqs
,
3715 const struct universal
*source
)
3717 bool necessary
= FALSE
;
3719 fc_assert(universal_found_function
[source
->kind
]);
3721 requirement_vector_iterate(reqs
, preq
) {
3722 switch ((*universal_found_function
[source
->kind
])(preq
, source
)) {
3723 case ITF_NOT_APPLICABLE
:
3726 if (preq
->present
) {
3731 if (preq
->present
) {
3738 } requirement_vector_iterate_end
;
3740 return (!check_necessary
|| necessary
);
3743 /*************************************************************************
3744 Returns TRUE iff the specified universal is relevant to fulfilling the
3745 specified requirement.
3746 **************************************************************************/
3747 bool universal_is_relevant_to_requirement(const struct requirement
*req
,
3748 const struct universal
*source
)
3750 fc_assert(universal_found_function
[source
->kind
]);
3752 switch ((*universal_found_function
[source
->kind
])(req
, source
)) {
3753 case ITF_NOT_APPLICABLE
:
3760 log_error("Unhandled item_found value");
3764 /*************************************************************************
3765 Find if a nation fulfills a requirement
3766 **************************************************************************/
3767 static enum item_found
nation_found(const struct requirement
*preq
,
3768 const struct universal
*source
)
3770 fc_assert(source
->value
.nation
);
3772 switch (preq
->source
.kind
) {
3774 return preq
->source
.value
.nation
== source
->value
.nation
? ITF_YES
3776 case VUT_NATIONGROUP
:
3777 return nation_is_in_group(source
->value
.nation
,
3778 preq
->source
.value
.nationgroup
) ? ITF_YES
3784 return ITF_NOT_APPLICABLE
;
3787 /*************************************************************************
3788 Find if a government fulfills a requirement
3789 **************************************************************************/
3790 static enum item_found
government_found(const struct requirement
*preq
,
3791 const struct universal
*source
)
3793 fc_assert(source
->value
.govern
);
3795 if (preq
->source
.kind
== VUT_GOVERNMENT
) {
3796 return preq
->source
.value
.govern
== source
->value
.govern
? ITF_YES
3800 return ITF_NOT_APPLICABLE
;
3803 /*************************************************************************
3804 Find if an improvement fulfills a requirement
3805 **************************************************************************/
3806 static enum item_found
improvement_found(const struct requirement
*preq
,
3807 const struct universal
*source
)
3809 fc_assert(source
->value
.building
);
3811 /* We only ever return ITF_YES, because requiring a different
3812 * improvement does not mean that the improvement under consideration
3813 * cannot fulfill the requirements. This is necessary to allow
3814 * requirement vectors to specify multiple required improvements. */
3816 switch (preq
->source
.kind
) {
3817 case VUT_IMPROVEMENT
:
3818 if (source
->value
.building
== preq
->source
.value
.building
) {
3822 case VUT_IMPR_GENUS
:
3823 if (source
->value
.building
->genus
== preq
->source
.value
.impr_genus
) {
3831 return ITF_NOT_APPLICABLE
;
3834 /*************************************************************************
3835 Find if a unit class fulfills a requirement
3836 **************************************************************************/
3837 static enum item_found
unit_class_found(const struct requirement
*preq
,
3838 const struct universal
*source
)
3840 fc_assert(source
->value
.uclass
);
3842 switch (preq
->source
.kind
) {
3844 return source
->value
.uclass
== preq
->source
.value
.uclass
? ITF_YES
3847 return uclass_has_flag(source
->value
.uclass
,
3848 preq
->source
.value
.unitclassflag
) ? ITF_YES
3852 /* Not found and not relevant. */
3853 return ITF_NOT_APPLICABLE
;
3857 /*************************************************************************
3858 Find if a unit type fulfills a requirement
3859 **************************************************************************/
3860 static enum item_found
unit_type_found(const struct requirement
*preq
,
3861 const struct universal
*source
)
3863 fc_assert(source
->value
.utype
);
3865 switch (preq
->source
.kind
) {
3867 return source
->value
.utype
== preq
->source
.value
.utype
? ITF_YES
: ITF_NO
;
3869 return utype_class(source
->value
.utype
) == preq
->source
.value
.uclass
3872 return utype_has_flag(source
->value
.utype
,
3873 preq
->source
.value
.unitflag
) ? ITF_YES
: ITF_NO
;
3875 return uclass_has_flag(utype_class(source
->value
.utype
),
3876 preq
->source
.value
.unitclassflag
) ? ITF_YES
3879 /* Not found and not relevant. */
3880 return ITF_NOT_APPLICABLE
;
3884 /*************************************************************************
3885 Find if a terrain type fulfills a requirement
3886 **************************************************************************/
3887 static enum item_found
terrain_type_found(const struct requirement
*preq
,
3888 const struct universal
*source
)
3890 fc_assert(source
->value
.terrain
);
3892 switch (preq
->source
.kind
) {
3894 return source
->value
.terrain
== preq
->source
.value
.terrain
? ITF_YES
: ITF_NO
;
3895 case VUT_TERRAINCLASS
:
3896 return terrain_type_terrain_class(source
->value
.terrain
) == preq
->source
.value
.terrainclass
3899 return terrain_has_flag(source
->value
.terrain
,
3900 preq
->source
.value
.terrainflag
) ? ITF_YES
: ITF_NO
;
3902 /* Not found and not relevant. */
3903 return ITF_NOT_APPLICABLE
;
3907 /************************************************************************
3908 Initialise universal_found_callbacks array.
3909 *************************************************************************/
3910 void universal_found_functions_init(void)
3912 universal_found_function
[VUT_GOVERNMENT
] = &government_found
;
3913 universal_found_function
[VUT_NATION
] = &nation_found
;
3914 universal_found_function
[VUT_IMPROVEMENT
] = &improvement_found
;
3915 universal_found_function
[VUT_UCLASS
] = &unit_class_found
;
3916 universal_found_function
[VUT_UTYPE
] = &unit_type_found
;
3917 universal_found_function
[VUT_TERRAIN
] = &terrain_type_found
;
3920 /**************************************************************************
3921 Returns (the position of) the given requirement's enumerator in the
3922 enumeration of all possible requirements of its requirement kind.
3924 Note: Since this isn't used for any requirement type that supports
3925 surviving requirements those aren't supported. Add support if a user
3927 **************************************************************************/
3928 int requirement_kind_ereq(const int value
,
3929 const enum req_range range
,
3931 const int max_value
)
3933 /* The enumerators in each range starts with present for every possible
3934 * value followed by !present for every possible value. */
3935 const int pres_start
= (present
? 0 : max_value
);
3937 /* The enumerators for every range follows all the positions of the
3938 * previous range(s). */
3939 const int range_start
= ((max_value
- 1) * 2) * range
;
3941 return range_start
+ pres_start
+ value
;