Comment fix: OS is not excluded from permissive.
[freeciv.git] / common / requirements.c
blob158212a9c3961bc04b879f3695a5a5846aa24e94
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)
6 any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
13 #ifdef HAVE_CONFIG_H
14 #include <fc_config.h>
15 #endif
17 /* utility */
18 #include "astring.h"
19 #include "fcintl.h"
20 #include "log.h"
21 #include "support.h"
23 /* common */
24 #include "achievements.h"
25 #include "calendar.h"
26 #include "citizens.h"
27 #include "culture.h"
28 #include "game.h"
29 #include "government.h"
30 #include "improvement.h"
31 #include "movement.h"
32 #include "player.h"
33 #include "map.h"
34 #include "research.h"
35 #include "road.h"
36 #include "specialist.h"
37 #include "style.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,
59 const char *value)
61 struct universal source;
63 source.kind = universals_n_by_name(kind, fc_strcasecmp);
64 if (!universals_n_is_valid(source.kind)) {
65 return source;
68 universal_value_from_str(&source, value);
70 return source;
73 /**************************************************************************
74 Parse requirement value strings into a universal
75 structure.
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) {
81 case VUT_NONE:
82 return;
83 case VUT_ADVANCE:
84 source->value.advance = advance_by_rule_name(value);
85 if (source->value.advance != NULL) {
86 return;
88 break;
89 case VUT_TECHFLAG:
90 source->value.techflag
91 = tech_flag_id_by_name(value, fc_strcasecmp);
92 if (tech_flag_id_is_valid(source->value.techflag)) {
93 return;
95 break;
96 case VUT_GOVERNMENT:
97 source->value.govern = government_by_rule_name(value);
98 if (source->value.govern != NULL) {
99 return;
101 break;
102 case VUT_ACHIEVEMENT:
103 source->value.achievement = achievement_by_rule_name(value);
104 if (source->value.achievement != NULL) {
105 return;
107 break;
108 case VUT_STYLE:
109 source->value.style = style_by_rule_name(value);
110 if (source->value.style != NULL) {
111 return;
113 break;
114 case VUT_IMPROVEMENT:
115 source->value.building = improvement_by_rule_name(value);
116 if (source->value.building != NULL) {
117 return;
119 break;
120 case VUT_IMPR_GENUS:
121 source->value.impr_genus = impr_genus_id_by_name(value, fc_strcasecmp);
122 if (impr_genus_id_is_valid(source->value.impr_genus)) {
123 return;
125 break;
126 case VUT_EXTRA:
127 source->value.extra = extra_type_by_rule_name(value);
128 if (source->value.extra != NULL) {
129 return;
131 break;
132 case VUT_GOOD:
133 source->value.good = goods_by_rule_name(value);
134 if (source->value.good != NULL) {
135 return;
137 break;
138 case VUT_TERRAIN:
139 source->value.terrain = terrain_by_rule_name(value);
140 if (source->value.terrain != T_UNKNOWN) {
141 return;
143 break;
144 case VUT_TERRFLAG:
145 source->value.terrainflag
146 = terrain_flag_id_by_name(value, fc_strcasecmp);
147 if (terrain_flag_id_is_valid(source->value.terrainflag)) {
148 return;
150 break;
151 case VUT_NATION:
152 source->value.nation = nation_by_rule_name(value);
153 if (source->value.nation != NO_NATION_SELECTED) {
154 return;
156 break;
157 case VUT_NATIONGROUP:
158 source->value.nationgroup = nation_group_by_rule_name(value);
159 if (source->value.nationgroup != NULL) {
160 return;
162 break;
163 case VUT_NATIONALITY:
164 source->value.nationality = nation_by_rule_name(value);
165 if (source->value.nationality != NO_NATION_SELECTED) {
166 return;
168 break;
169 case VUT_DIPLREL:
170 source->value.diplrel = diplrel_by_rule_name(value);
171 if (source->value.diplrel != diplrel_other_invalid()) {
172 return;
174 break;
175 case VUT_UTYPE:
176 source->value.utype = unit_type_by_rule_name(value);
177 if (source->value.utype) {
178 return;
180 break;
181 case VUT_UTFLAG:
182 source->value.unitflag = unit_type_flag_id_by_name(value, fc_strcasecmp);
183 if (unit_type_flag_id_is_valid(source->value.unitflag)) {
184 return;
186 break;
187 case VUT_UCLASS:
188 source->value.uclass = unit_class_by_rule_name(value);
189 if (source->value.uclass) {
190 return;
192 break;
193 case VUT_UCFLAG:
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)) {
197 return;
199 break;
200 case VUT_MINVETERAN:
201 source->value.minveteran = atoi(value);
202 if (source->value.minveteran > 0) {
203 return;
205 break;
206 case VUT_UNITSTATE:
207 source->value.unit_state = ustate_prop_by_name(value, fc_strcasecmp);
208 if (ustate_prop_is_valid(source->value.unit_state)) {
209 return;
211 break;
212 case VUT_MINMOVES:
213 source->value.minmoves = atoi(value);
214 if (source->value.minmoves > 0) {
215 return;
217 break;
218 case VUT_MINHP:
219 source->value.min_hit_points = atoi(value);
220 if (source->value.min_hit_points > 0) {
221 return;
223 break;
224 case VUT_AGE:
225 source->value.age = atoi(value);
226 if (source->value.age > 0) {
227 return;
229 break;
230 case VUT_MINTECHS:
231 source->value.min_techs = atoi(value);
232 if (source->value.min_techs > 0) {
233 return;
235 case VUT_ACTION:
236 source->value.action = action_by_rule_name(value);
237 if (source->value.action != NULL) {
238 return;
240 break;
241 case VUT_OTYPE:
242 source->value.outputtype = output_type_by_identifier(value);
243 if (source->value.outputtype != O_LAST) {
244 return;
246 break;
247 case VUT_SPECIALIST:
248 source->value.specialist = specialist_by_rule_name(value);
249 if (source->value.specialist) {
250 return;
252 case VUT_MINSIZE:
253 source->value.minsize = atoi(value);
254 if (source->value.minsize > 0) {
255 return;
257 break;
258 case VUT_MINCULTURE:
259 source->value.minculture = atoi(value);
260 if (source->value.minculture > 0) {
261 return;
263 break;
264 case VUT_AI_LEVEL:
265 source->value.ai_level = ai_level_by_name(value, fc_strcasecmp);
266 if (ai_level_is_valid(source->value.ai_level)) {
267 return;
269 break;
270 case VUT_MAXTILEUNITS:
271 source->value.max_tile_units = atoi(value);
272 if (0 <= source->value.max_tile_units) {
273 return;
275 break;
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)) {
280 return;
282 break;
283 case VUT_BASEFLAG:
284 source->value.baseflag = base_flag_id_by_name(value, fc_strcasecmp);
285 if (base_flag_id_is_valid(source->value.baseflag)) {
286 return;
288 break;
289 case VUT_ROADFLAG:
290 source->value.roadflag = road_flag_id_by_name(value, fc_strcasecmp);
291 if (road_flag_id_is_valid(source->value.roadflag)) {
292 return;
294 break;
295 case VUT_EXTRAFLAG:
296 source->value.extraflag = extra_flag_id_by_name(value, fc_strcasecmp);
297 if (extra_flag_id_is_valid(source->value.extraflag)) {
298 return;
300 break;
301 case VUT_MINYEAR:
302 source->value.minyear = atoi(value);
303 return;
304 case VUT_MINCALFRAG:
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() */
309 return;
311 case VUT_TOPO:
312 source->value.topo_property = topo_flag_by_name(value, fc_strcasecmp);
313 if (topo_flag_is_valid(source->value.topo_property)) {
314 return;
316 break;
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)) {
321 return;
323 break;
324 case VUT_CITYTILE:
325 source->value.citytile = citytile_type_by_name(value, fc_strcasecmp);
326 if (source->value.citytile != CITYT_LAST) {
327 return;
329 break;
330 case VUT_COUNT:
331 break;
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,
344 const int value)
346 struct universal source;
348 source.kind = kind;
350 switch (source.kind) {
351 case VUT_NONE:
352 /* Avoid compiler warning about unitialized source.value */
353 source.value.advance = NULL;
355 return source;
356 case VUT_ADVANCE:
357 source.value.advance = advance_by_number(value);
358 if (source.value.advance != NULL) {
359 return source;
361 break;
362 case VUT_TECHFLAG:
363 source.value.techflag = value;
364 return source;
365 case VUT_GOVERNMENT:
366 source.value.govern = government_by_number(value);
367 if (source.value.govern != NULL) {
368 return source;
370 break;
371 case VUT_ACHIEVEMENT:
372 source.value.achievement = achievement_by_number(value);
373 if (source.value.achievement != NULL) {
374 return source;
376 break;
377 case VUT_STYLE:
378 source.value.style = style_by_number(value);
379 if (source.value.style != NULL) {
380 return source;
382 break;
383 case VUT_IMPROVEMENT:
384 source.value.building = improvement_by_number(value);
385 if (source.value.building != NULL) {
386 return source;
388 break;
389 case VUT_IMPR_GENUS:
390 source.value.impr_genus = value;
391 return source;
392 case VUT_EXTRA:
393 source.value.extra = extra_by_number(value);
394 return source;
395 case VUT_GOOD:
396 source.value.good = goods_by_number(value);
397 return source;
398 case VUT_TERRAIN:
399 source.value.terrain = terrain_by_number(value);
400 if (source.value.terrain != NULL) {
401 return source;
403 break;
404 case VUT_TERRFLAG:
405 source.value.terrainflag = value;
406 return source;
407 case VUT_NATION:
408 source.value.nation = nation_by_number(value);
409 if (source.value.nation != NULL) {
410 return source;
412 break;
413 case VUT_NATIONGROUP:
414 source.value.nationgroup = nation_group_by_number(value);
415 if (source.value.nationgroup != NULL) {
416 return source;
418 break;
419 case VUT_DIPLREL:
420 source.value.diplrel = value;
421 if (source.value.diplrel != diplrel_other_invalid()) {
422 return source;
424 break;
425 case VUT_NATIONALITY:
426 source.value.nationality = nation_by_number(value);
427 if (source.value.nationality != NULL) {
428 return source;
430 break;
431 case VUT_UTYPE:
432 source.value.utype = utype_by_number(value);
433 if (source.value.utype != NULL) {
434 return source;
436 break;
437 case VUT_UTFLAG:
438 source.value.unitflag = value;
439 return source;
440 case VUT_UCLASS:
441 source.value.uclass = uclass_by_number(value);
442 if (source.value.uclass != NULL) {
443 return source;
445 break;
446 case VUT_UCFLAG:
447 source.value.unitclassflag = value;
448 return source;
449 case VUT_MINVETERAN:
450 source.value.minveteran = value;
451 return source;
452 case VUT_UNITSTATE:
453 source.value.unit_state = value;
454 return source;
455 case VUT_MINMOVES:
456 source.value.minmoves = value;
457 return source;
458 case VUT_MINHP:
459 source.value.min_hit_points = value;
460 return source;
461 case VUT_AGE:
462 source.value.age = value;
463 return source;
464 case VUT_MINTECHS:
465 source.value.min_techs = value;
466 return source;
467 case VUT_ACTION:
468 source.value.action = action_by_number(value);
469 if (source.value.action != NULL) {
470 return source;
472 break;
473 case VUT_OTYPE:
474 source.value.outputtype = value;
475 return source;
476 case VUT_SPECIALIST:
477 source.value.specialist = specialist_by_number(value);
478 return source;
479 case VUT_MINSIZE:
480 source.value.minsize = value;
481 return source;
482 case VUT_MINCULTURE:
483 source.value.minculture = value;
484 return source;
485 case VUT_AI_LEVEL:
486 source.value.ai_level = value;
487 return source;
488 case VUT_MAXTILEUNITS:
489 source.value.max_tile_units = value;
490 return source;
491 case VUT_TERRAINCLASS:
492 source.value.terrainclass = value;
493 return source;
494 case VUT_BASEFLAG:
495 source.value.baseflag = value;
496 return source;
497 case VUT_ROADFLAG:
498 source.value.roadflag = value;
499 return source;
500 case VUT_EXTRAFLAG:
501 source.value.extraflag = value;
502 return source;
503 case VUT_MINYEAR:
504 source.value.minyear = value;
505 return source;
506 case VUT_MINCALFRAG:
507 source.value.mincalfrag = value;
508 return source;
509 case VUT_TOPO:
510 source.value.topo_property = value;
511 return source;
512 case VUT_TERRAINALTER:
513 source.value.terrainalter = value;
514 return source;
515 case VUT_CITYTILE:
516 source.value.citytile = value;
517 return source;
518 case VUT_COUNT:
519 break;
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;
527 return source;
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) {
547 case VUT_NONE:
548 return 0;
549 case VUT_ADVANCE:
550 return advance_number(source->value.advance);
551 case VUT_TECHFLAG:
552 return source->value.techflag;
553 case VUT_GOVERNMENT:
554 return government_number(source->value.govern);
555 case VUT_ACHIEVEMENT:
556 return achievement_number(source->value.achievement);
557 case VUT_STYLE:
558 return style_number(source->value.style);
559 case VUT_IMPROVEMENT:
560 return improvement_number(source->value.building);
561 case VUT_IMPR_GENUS:
562 return source->value.impr_genus;
563 case VUT_EXTRA:
564 return extra_number(source->value.extra);
565 case VUT_GOOD:
566 return goods_number(source->value.good);
567 case VUT_TERRAIN:
568 return terrain_number(source->value.terrain);
569 case VUT_TERRFLAG:
570 return source->value.terrainflag;
571 case VUT_NATION:
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);
577 case VUT_DIPLREL:
578 return source->value.diplrel;
579 case VUT_UTYPE:
580 return utype_number(source->value.utype);
581 case VUT_UTFLAG:
582 return source->value.unitflag;
583 case VUT_UCLASS:
584 return uclass_number(source->value.uclass);
585 case VUT_UCFLAG:
586 return source->value.unitclassflag;
587 case VUT_MINVETERAN:
588 return source->value.minveteran;
589 case VUT_UNITSTATE:
590 return source->value.unit_state;
591 case VUT_MINMOVES:
592 return source->value.minmoves;
593 case VUT_MINHP:
594 return source->value.min_hit_points;
595 case VUT_AGE:
596 return source->value.age;
597 case VUT_MINTECHS:
598 return source->value.min_techs;
599 case VUT_ACTION:
600 return action_number(source->value.action);
601 case VUT_OTYPE:
602 return source->value.outputtype;
603 case VUT_SPECIALIST:
604 return specialist_number(source->value.specialist);
605 case VUT_MINSIZE:
606 return source->value.minsize;
607 case VUT_MINCULTURE:
608 return source->value.minculture;
609 case VUT_AI_LEVEL:
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;
615 case VUT_BASEFLAG:
616 return source->value.baseflag;
617 case VUT_ROADFLAG:
618 return source->value.roadflag;
619 case VUT_EXTRAFLAG:
620 return source->value.extraflag;
621 case VUT_MINYEAR:
622 return source->value.minyear;
623 case VUT_MINCALFRAG:
624 return source->value.mincalfrag;
625 case VUT_TOPO:
626 return source->value.topo_property;
627 case VUT_TERRAINALTER:
628 return source->value.terrainalter;
629 case VUT_CITYTILE:
630 return source->value.citytile;
631 case VUT_COUNT:
632 break;
635 /* If we reach here there's been an error. */
636 fc_assert_msg(FALSE, "universal_number(): invalid source kind %d.",
637 source->kind);
638 return 0;
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,
669 const char *value)
671 struct requirement req;
672 bool invalid;
673 const char *error = NULL;
675 req.source = universal_by_rule_name(type, value);
677 invalid = !universals_n_is_valid(req.source.kind);
678 if (invalid) {
679 error = "bad type or name";
680 } else {
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) {
686 case VUT_NONE:
687 case VUT_COUNT:
688 break;
689 case VUT_IMPROVEMENT:
690 case VUT_IMPR_GENUS:
691 case VUT_EXTRA:
692 case VUT_GOOD:
693 case VUT_TERRAIN:
694 case VUT_TERRFLAG:
695 case VUT_UTYPE:
696 case VUT_UTFLAG:
697 case VUT_UCLASS:
698 case VUT_UCFLAG:
699 case VUT_MINVETERAN:
700 case VUT_UNITSTATE:
701 case VUT_MINMOVES:
702 case VUT_MINHP:
703 case VUT_AGE:
704 case VUT_ACTION:
705 case VUT_OTYPE:
706 case VUT_SPECIALIST:
707 case VUT_TERRAINCLASS:
708 case VUT_BASEFLAG:
709 case VUT_ROADFLAG:
710 case VUT_EXTRAFLAG:
711 case VUT_TERRAINALTER:
712 case VUT_CITYTILE:
713 case VUT_MAXTILEUNITS:
714 req.range = REQ_RANGE_LOCAL;
715 break;
716 case VUT_MINSIZE:
717 case VUT_MINCULTURE:
718 case VUT_NATIONALITY:
719 req.range = REQ_RANGE_CITY;
720 break;
721 case VUT_GOVERNMENT:
722 case VUT_ACHIEVEMENT:
723 case VUT_STYLE:
724 case VUT_ADVANCE:
725 case VUT_TECHFLAG:
726 case VUT_NATION:
727 case VUT_NATIONGROUP:
728 case VUT_DIPLREL:
729 case VUT_AI_LEVEL:
730 req.range = REQ_RANGE_PLAYER;
731 break;
732 case VUT_MINYEAR:
733 case VUT_MINCALFRAG:
734 case VUT_TOPO:
735 case VUT_MINTECHS:
736 req.range = REQ_RANGE_WORLD;
737 break;
741 req.survives = survives;
742 req.present = present;
743 req.quiet = quiet;
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) {
750 case VUT_TERRAIN:
751 case VUT_EXTRA:
752 case VUT_TERRAINCLASS:
753 case VUT_TERRFLAG:
754 case VUT_BASEFLAG:
755 case VUT_ROADFLAG:
756 case VUT_EXTRAFLAG:
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);
762 break;
763 case VUT_ADVANCE:
764 case VUT_TECHFLAG:
765 case VUT_ACHIEVEMENT:
766 case VUT_MINTECHS:
767 invalid = (req.range < REQ_RANGE_PLAYER);
768 break;
769 case VUT_GOVERNMENT:
770 case VUT_AI_LEVEL:
771 case VUT_STYLE:
772 invalid = (req.range != REQ_RANGE_PLAYER);
773 break;
774 case VUT_MINSIZE:
775 case VUT_NATIONALITY:
776 case VUT_GOOD:
777 invalid = (req.range != REQ_RANGE_CITY
778 && req.range != REQ_RANGE_TRADEROUTE);
779 break;
780 case VUT_MINCULTURE:
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);
787 break;
788 case VUT_DIPLREL:
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);
797 break;
798 case VUT_NATION:
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);
804 break;
805 case VUT_UTYPE:
806 case VUT_UTFLAG:
807 case VUT_UCLASS:
808 case VUT_UCFLAG:
809 case VUT_MINVETERAN:
810 case VUT_UNITSTATE:
811 case VUT_MINMOVES:
812 case VUT_MINHP:
813 case VUT_ACTION:
814 case VUT_OTYPE:
815 case VUT_SPECIALIST:
816 case VUT_TERRAINALTER: /* XXX could in principle support C/ADJACENT */
817 invalid = (req.range != REQ_RANGE_LOCAL);
818 break;
819 case VUT_CITYTILE:
820 case VUT_MAXTILEUNITS:
821 invalid = (req.range != REQ_RANGE_LOCAL
822 && req.range != REQ_RANGE_CADJACENT
823 && req.range != REQ_RANGE_ADJACENT);
824 break;
825 case VUT_MINYEAR:
826 case VUT_MINCALFRAG:
827 case VUT_TOPO:
828 invalid = (req.range != REQ_RANGE_WORLD);
829 break;
830 case VUT_AGE:
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);
835 break;
836 case VUT_IMPR_GENUS:
837 /* TODO: Support other ranges too. */
838 invalid = req.range != REQ_RANGE_LOCAL;
839 break;
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(). */
845 case VUT_NONE:
846 invalid = FALSE;
847 break;
848 case VUT_COUNT:
849 break;
851 if (invalid) {
852 error = "bad range";
856 if (!invalid) {
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;
862 break;
863 case VUT_NATION:
864 case VUT_ADVANCE:
865 invalid = survives && req.range != REQ_RANGE_WORLD;
866 break;
867 case VUT_IMPR_GENUS:
868 case VUT_GOVERNMENT:
869 case VUT_TERRAIN:
870 case VUT_UTYPE:
871 case VUT_UTFLAG:
872 case VUT_UCLASS:
873 case VUT_UCFLAG:
874 case VUT_MINVETERAN:
875 case VUT_UNITSTATE:
876 case VUT_MINMOVES:
877 case VUT_MINHP:
878 case VUT_AGE:
879 case VUT_ACTION:
880 case VUT_OTYPE:
881 case VUT_SPECIALIST:
882 case VUT_MINSIZE:
883 case VUT_MINCULTURE:
884 case VUT_AI_LEVEL:
885 case VUT_TERRAINCLASS:
886 case VUT_MINYEAR:
887 case VUT_MINCALFRAG:
888 case VUT_TOPO:
889 case VUT_TERRAINALTER:
890 case VUT_CITYTILE:
891 case VUT_TERRFLAG:
892 case VUT_NATIONALITY:
893 case VUT_BASEFLAG:
894 case VUT_ROADFLAG:
895 case VUT_EXTRAFLAG:
896 case VUT_EXTRA:
897 case VUT_GOOD:
898 case VUT_TECHFLAG:
899 case VUT_ACHIEVEMENT:
900 case VUT_NATIONGROUP:
901 case VUT_STYLE:
902 case VUT_DIPLREL:
903 case VUT_MAXTILEUNITS:
904 case VUT_MINTECHS:
905 /* Most requirements don't support 'survives'. */
906 invalid = survives;
907 break;
908 case VUT_NONE:
909 case VUT_COUNT:
910 break;
912 if (invalid) {
913 error = "bad 'survives'";
917 if (invalid) {
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();
924 return req;
927 /****************************************************************************
928 Set the values of a req from serializable integers. This is the opposite
929 of req_get_values.
930 ****************************************************************************/
931 struct requirement req_from_values(int type, int range,
932 bool survives, bool present, bool quiet,
933 int value)
935 struct requirement req;
937 req.source = universal_by_number(type, value);
938 req.range = range;
939 req.survives = survives;
940 req.present = present;
941 req.quiet = quiet;
943 return req;
946 /****************************************************************************
947 Return the value of a req as a serializable integer. This is the opposite
948 of req_set_value.
949 ****************************************************************************/
950 void req_get_values(const struct requirement *req,
951 int *type, int *range,
952 bool *survives, bool *present, bool *quiet,
953 int *value)
955 universal_extraction(&req->source, type, value);
956 *range = req->range;
957 *survives = req->survives;
958 *present = req->present;
959 *quiet = req->quiet;
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. */
1016 return FALSE;
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. */
1042 return FALSE;
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. */
1057 return TRUE;
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. */
1067 return FALSE;
1068 break;
1069 case VUT_IMPR_GENUS:
1070 if (req2->source.kind == VUT_IMPROVEMENT) {
1071 return impr_contra_genus(req2, req1);
1074 /* No special knowledge. */
1075 return FALSE;
1076 break;
1077 case VUT_DIPLREL:
1078 if (req2->source.kind != VUT_DIPLREL) {
1079 /* Finding contradictions across requirement kinds aren't supported
1080 * for DiplRel requirements. */
1081 return FALSE;
1082 } else {
1083 /* Use the special knowledge about DiplRel requirements to find
1084 * contradictions. */
1086 bv_diplrel_all_reqs req1_contra;
1087 int req2_pos;
1089 req1_contra = diplrel_req_contradicts(req1);
1090 req2_pos = requirement_diplrel_ereq(req2->source.value.diplrel,
1091 req2->range,
1092 req2->present);
1094 return BV_ISSET(req1_contra, req2_pos);
1096 break;
1097 case VUT_MINMOVES:
1098 if (req2->source.kind != VUT_MINMOVES) {
1099 /* Finding contradictions across requirement kinds aren't supported
1100 * for MinMoveFrags requirements. */
1101 return FALSE;
1102 } else if (req1->present == req2->present) {
1103 /* No contradiction possible. */
1104 return FALSE;
1105 } else {
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;
1112 } else {
1113 return req1->source.value.minmoves <= req2->source.value.minmoves;
1116 break;
1117 case VUT_NATION:
1118 if (req2->source.kind == VUT_NATIONGROUP) {
1119 return nation_contra_group(req1, req2);
1122 /* No special knowledge. */
1123 return FALSE;
1124 break;
1125 case VUT_NATIONGROUP:
1126 if (req2->source.kind == VUT_NATION) {
1127 return nation_contra_group(req2, req1);
1130 /* No special knowledge. */
1131 return FALSE;
1132 break;
1133 default:
1134 /* No special knowledge exists. The requirements aren't the exact
1135 * opposite of each other per the initial check. */
1136 return FALSE;
1137 break;
1141 /**************************************************************************
1142 Returns TRUE if the given requirement contradicts the given requirement
1143 vector.
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)) {
1152 return TRUE;
1154 } requirement_vector_iterate_end;
1156 /* Not a singe requirement in the requirement vector is contradicted be
1157 * the specified requirement. */
1158 return FALSE;
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)
1170 int i;
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)) {
1176 return i;
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)
1192 int conflict;
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)
1206 switch (range) {
1207 case REQ_RANGE_WORLD:
1208 return TRUE;
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:
1222 break;
1225 fc_assert_msg(FALSE, "Invalid range %d.", range);
1226 return FALSE;
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);
1238 } else {
1239 log_error("World-ranged requirements are only supported for wonders.");
1240 return 0;
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);
1251 } else {
1252 log_error("World-ranged requirements are only supported for wonders.");
1253 return 0;
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
1266 exact number.
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);
1274 } else {
1275 log_error("Player-ranged requirements are only supported for wonders.");
1276 return FALSE;
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);
1288 } else {
1289 log_error("Player-ranged requirements are only supported for wonders.");
1290 return 0;
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,
1298 int continent,
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) {
1306 return 1;
1308 } else {
1309 log_error("Island-ranged requirements are only supported for wonders.");
1311 return 0;
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
1325 obsolete?
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,
1343 bool survives,
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)) {
1349 return TRI_NO;
1352 if (survives) {
1354 /* Check whether condition has ever held, using cached information. */
1355 switch (range) {
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) {
1361 return TRI_MAYBE;
1363 players_iterate_alive(plr2) {
1364 if (players_in_same_range(target_player, plr2, range)
1365 && player_has_ever_built(plr2, source)) {
1366 return TRI_YES;
1368 } players_iterate_alive_end;
1369 return TRI_NO;
1370 case REQ_RANGE_PLAYER:
1371 if (target_player == NULL) {
1372 return TRI_MAYBE;
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.");
1384 return TRI_NO;
1385 case REQ_RANGE_COUNT:
1386 break;
1389 } else {
1391 /* Non-surviving requirement. */
1392 switch (range) {
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) {
1398 return TRI_MAYBE;
1400 players_iterate_alive(plr2) {
1401 if (players_in_same_range(target_player, plr2, range)
1402 && num_player_buildings(plr2, source) > 0) {
1403 return TRI_YES;
1405 } players_iterate_alive_end;
1406 return TRI_NO;
1407 case REQ_RANGE_PLAYER:
1408 if (target_player == NULL) {
1409 return TRI_MAYBE;
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);
1419 } else {
1420 return TRI_MAYBE;
1422 case REQ_RANGE_TRADEROUTE:
1423 if (target_city) {
1424 if (num_city_buildings(target_city, source) > 0) {
1425 return TRI_YES;
1426 } else {
1427 trade_partners_iterate(target_city, trade_partner) {
1428 if (num_city_buildings(trade_partner, source) > 0) {
1429 return TRI_YES;
1431 } trade_partners_iterate_end;
1433 return TRI_NO;
1434 } else {
1435 return TRI_MAYBE;
1437 case REQ_RANGE_CITY:
1438 if (target_city) {
1439 return BOOL_TO_TRISTATE(num_city_buildings(target_city, source) > 0);
1440 } else {
1441 return TRI_MAYBE;
1443 case REQ_RANGE_LOCAL:
1444 if (target_building) {
1445 if (target_building == source) {
1446 return TRI_YES;
1447 } else {
1448 return TRI_NO;
1450 } else {
1451 /* TODO: other local targets */
1452 return TRI_MAYBE;
1454 case REQ_RANGE_CADJACENT:
1455 case REQ_RANGE_ADJACENT:
1456 return TRI_NO;
1457 case REQ_RANGE_COUNT:
1458 break;
1463 fc_assert_msg(FALSE, "Invalid range %d.", range);
1464 return TRI_NO;
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,
1472 Tech_type_id tech)
1474 if (survives) {
1475 fc_assert(range == REQ_RANGE_WORLD);
1476 return BOOL_TO_TRISTATE(game.info.global_advances[tech]);
1479 /* Not a 'surviving' requirement. */
1480 switch (range) {
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));
1485 } else {
1486 return TRI_MAYBE;
1488 case REQ_RANGE_TEAM:
1489 case REQ_RANGE_ALLIANCE:
1490 case REQ_RANGE_WORLD:
1491 if (NULL == target_player) {
1492 return TRI_MAYBE;
1494 players_iterate_alive(plr2) {
1495 if (players_in_same_range(target_player, plr2, range)) {
1496 if (research_invention_state(research_get(plr2), tech)
1497 == TECH_KNOWN) {
1498 return TRI_YES;
1501 } players_iterate_alive_end;
1503 return TRI_NO;
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:
1511 break;
1514 fc_assert_msg(FALSE, "Invalid range %d.", range);
1516 return TRI_MAYBE;
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)
1526 switch (range) {
1527 case REQ_RANGE_PLAYER:
1528 if (NULL != target_player) {
1529 return BOOL_TO_TRISTATE(player_knows_techs_with_flag(target_player, techflag));
1530 } else {
1531 return TRI_MAYBE;
1533 break;
1534 case REQ_RANGE_TEAM:
1535 case REQ_RANGE_ALLIANCE:
1536 if (NULL == target_player) {
1537 return TRI_MAYBE;
1539 players_iterate_alive(plr2) {
1540 if (players_in_same_range(target_player, plr2, range)
1541 && player_knows_techs_with_flag(plr2, techflag)) {
1542 return TRI_YES;
1544 } players_iterate_alive_end;
1545 return TRI_NO;
1546 case REQ_RANGE_WORLD:
1547 players_iterate(pplayer) {
1548 if (player_knows_techs_with_flag(pplayer, techflag)) {
1549 return TRI_YES;
1551 } players_iterate_end;
1553 return TRI_NO;
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:
1561 break;
1564 fc_assert_msg(FALSE, "Invalid range %d.", range);
1566 return TRI_MAYBE;
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,
1575 int minculture)
1577 switch (range) {
1578 case REQ_RANGE_CITY:
1579 if (!target_city) {
1580 return TRI_MAYBE;
1582 return BOOL_TO_TRISTATE(city_culture(target_city) >= minculture);
1583 case REQ_RANGE_TRADEROUTE:
1584 if (!target_city) {
1585 return TRI_MAYBE;
1587 if (city_culture(target_city) >= minculture) {
1588 return TRI_YES;
1589 } else {
1590 trade_partners_iterate(target_city, trade_partner) {
1591 if (city_culture(trade_partner) >= minculture) {
1592 return TRI_YES;
1594 } trade_partners_iterate_end;
1595 return TRI_MAYBE;
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) {
1602 return TRI_MAYBE;
1604 players_iterate_alive(plr2) {
1605 if (players_in_same_range(target_player, plr2, range)) {
1606 if (player_culture(plr2) >= minculture) {
1607 return TRI_YES;
1610 } players_iterate_alive_end;
1611 return TRI_NO;
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:
1617 break;
1620 fc_assert_msg(FALSE, "Invalid range %d.", range);
1622 return TRI_MAYBE;
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,
1630 int maxUnits)
1632 /* TODO: if can't see V_INVIS -> TRI_MAYBE */
1633 switch (range) {
1634 case REQ_RANGE_LOCAL:
1635 if (!target_tile) {
1636 return TRI_MAYBE;
1638 return BOOL_TO_TRISTATE(unit_list_size(target_tile->units) <= maxUnits);
1639 case REQ_RANGE_CADJACENT:
1640 if (!target_tile) {
1641 return TRI_MAYBE;
1643 if (unit_list_size(target_tile->units) <= maxUnits) {
1644 return TRI_YES;
1646 cardinal_adjc_iterate(&(wld.map), target_tile, adjc_tile) {
1647 if (unit_list_size(adjc_tile->units) <= maxUnits) {
1648 return TRI_YES;
1650 } cardinal_adjc_iterate_end;
1651 return TRI_NO;
1652 case REQ_RANGE_ADJACENT:
1653 if (!target_tile) {
1654 return TRI_MAYBE;
1656 if (unit_list_size(target_tile->units) <= maxUnits) {
1657 return TRI_YES;
1659 adjc_iterate(&(wld.map), target_tile, adjc_tile) {
1660 if (unit_list_size(adjc_tile->units) <= maxUnits) {
1661 return TRI_YES;
1663 } adjc_iterate_end;
1664 return TRI_NO;
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:
1673 break;
1676 fc_assert_msg(FALSE, "Invalid range %d.", range);
1678 return TRI_MAYBE;
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)
1689 switch (range) {
1690 case REQ_RANGE_LOCAL:
1691 /* The requirement is filled if the tile has extra of requested type. */
1692 if (!target_tile) {
1693 return TRI_MAYBE;
1695 return BOOL_TO_TRISTATE(tile_has_extra(target_tile, pextra));
1696 case REQ_RANGE_CADJACENT:
1697 if (!target_tile) {
1698 return TRI_MAYBE;
1700 return BOOL_TO_TRISTATE(tile_has_extra(target_tile, pextra)
1701 || is_extra_card_near(target_tile, pextra));
1702 case REQ_RANGE_ADJACENT:
1703 if (!target_tile) {
1704 return TRI_MAYBE;
1706 return BOOL_TO_TRISTATE(tile_has_extra(target_tile, pextra)
1707 || is_extra_near_tile(target_tile, pextra));
1708 case REQ_RANGE_CITY:
1709 if (!target_city) {
1710 return TRI_MAYBE;
1712 city_tile_iterate(city_map_radius_sq_get(target_city),
1713 city_tile(target_city), ptile) {
1714 if (tile_has_extra(ptile, pextra)) {
1715 return TRI_YES;
1717 } city_tile_iterate_end;
1719 return TRI_NO;
1721 case REQ_RANGE_TRADEROUTE:
1722 if (!target_city) {
1723 return TRI_MAYBE;
1725 city_tile_iterate(city_map_radius_sq_get(target_city),
1726 city_tile(target_city), ptile) {
1727 if (tile_has_extra(ptile, pextra)) {
1728 return TRI_YES;
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)) {
1735 return TRI_YES;
1737 } city_tile_iterate_end;
1738 } trade_partners_iterate_end;
1740 return TRI_NO;
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:
1748 break;
1751 fc_assert_msg(FALSE, "Invalid range %d.", range);
1753 return TRI_MAYBE;
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)
1764 switch (range) {
1765 case REQ_RANGE_LOCAL:
1766 case REQ_RANGE_CITY:
1767 /* The requirement is filled if the tile has extra of requested type. */
1768 if (!target_city) {
1769 return TRI_MAYBE;
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:
1781 break;
1784 fc_assert_msg(FALSE, "Invalid range %d.", range);
1786 return TRI_MAYBE;
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)
1797 switch (range) {
1798 case REQ_RANGE_LOCAL:
1799 /* The requirement is filled if the tile has the terrain. */
1800 if (!target_tile) {
1801 return TRI_MAYBE;
1803 return pterrain && tile_terrain(target_tile) == pterrain;
1804 case REQ_RANGE_CADJACENT:
1805 if (!target_tile) {
1806 return TRI_MAYBE;
1808 return BOOL_TO_TRISTATE(pterrain && is_terrain_card_near(target_tile, pterrain, TRUE));
1809 case REQ_RANGE_ADJACENT:
1810 if (!target_tile) {
1811 return TRI_MAYBE;
1813 return BOOL_TO_TRISTATE(pterrain && is_terrain_near_tile(target_tile, pterrain, TRUE));
1814 case REQ_RANGE_CITY:
1815 if (!target_city) {
1816 return TRI_MAYBE;
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) {
1822 return TRI_YES;
1824 } city_tile_iterate_end;
1826 return TRI_NO;
1827 case REQ_RANGE_TRADEROUTE:
1828 if (!target_city) {
1829 return TRI_MAYBE;
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) {
1835 return TRI_YES;
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) {
1842 return TRI_YES;
1844 } city_tile_iterate_end;
1845 } trade_partners_iterate_end;
1847 return TRI_NO;
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:
1854 break;
1857 fc_assert_msg(FALSE, "Invalid range %d.", range);
1859 return TRI_MAYBE;
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)
1870 switch (range) {
1871 case REQ_RANGE_LOCAL:
1872 /* The requirement is filled if the tile has the terrain of correct class. */
1873 if (!target_tile) {
1874 return TRI_MAYBE;
1876 return BOOL_TO_TRISTATE(terrain_type_terrain_class(tile_terrain(target_tile)) == pclass);
1877 case REQ_RANGE_CADJACENT:
1878 if (!target_tile) {
1879 return TRI_MAYBE;
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:
1884 if (!target_tile) {
1885 return TRI_MAYBE;
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:
1890 if (!target_city) {
1891 return TRI_MAYBE;
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) {
1898 return TRI_YES;
1900 } city_tile_iterate_end;
1902 return TRI_NO;
1903 case REQ_RANGE_TRADEROUTE:
1904 if (!target_city) {
1905 return TRI_MAYBE;
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) {
1912 return TRI_YES;
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) {
1922 return TRI_YES;
1924 } city_tile_iterate_end;
1925 } trade_partners_iterate_end;
1927 return TRI_NO;
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:
1934 break;
1937 fc_assert_msg(FALSE, "Invalid range %d.", range);
1939 return TRI_MAYBE;
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)
1950 switch (range) {
1951 case REQ_RANGE_LOCAL:
1952 /* The requirement is fulfilled if the tile has a terrain with
1953 * correct flag. */
1954 if (!target_tile) {
1955 return TRI_MAYBE;
1957 return BOOL_TO_TRISTATE(terrain_has_flag(tile_terrain(target_tile),
1958 terrflag));
1959 case REQ_RANGE_CADJACENT:
1960 if (!target_tile) {
1961 return TRI_MAYBE;
1963 return BOOL_TO_TRISTATE(terrain_has_flag(tile_terrain(target_tile),
1964 terrflag)
1965 || is_terrain_flag_card_near(target_tile,
1966 terrflag));
1967 case REQ_RANGE_ADJACENT:
1968 if (!target_tile) {
1969 return TRI_MAYBE;
1971 return BOOL_TO_TRISTATE(terrain_has_flag(tile_terrain(target_tile),
1972 terrflag)
1973 || is_terrain_flag_near_tile(target_tile,
1974 terrflag));
1975 case REQ_RANGE_CITY:
1976 if (!target_city) {
1977 return TRI_MAYBE;
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)) {
1984 return TRI_YES;
1986 } city_tile_iterate_end;
1988 return TRI_NO;
1989 case REQ_RANGE_TRADEROUTE:
1990 if (!target_city) {
1991 return TRI_MAYBE;
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)) {
1998 return TRI_YES;
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)) {
2008 return TRI_YES;
2010 } city_tile_iterate_end;
2011 } trade_partners_iterate_end;
2013 return TRI_NO;
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:
2020 break;
2023 fc_assert_msg(FALSE, "Invalid range %d.", range);
2025 return TRI_MAYBE;
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)
2036 switch (range) {
2037 case REQ_RANGE_LOCAL:
2038 /* The requirement is filled if the tile has a base with correct flag. */
2039 if (!target_tile) {
2040 return TRI_MAYBE;
2042 return BOOL_TO_TRISTATE(tile_has_base_flag(target_tile, baseflag));
2043 case REQ_RANGE_CADJACENT:
2044 if (!target_tile) {
2045 return TRI_MAYBE;
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:
2050 if (!target_tile) {
2051 return TRI_MAYBE;
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:
2056 if (!target_city) {
2057 return TRI_MAYBE;
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)) {
2062 return TRI_YES;
2064 } city_tile_iterate_end;
2066 return TRI_NO;
2067 case REQ_RANGE_TRADEROUTE:
2068 if (!target_city) {
2069 return TRI_MAYBE;
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)) {
2074 return TRI_YES;
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)) {
2082 return TRI_YES;
2084 } city_tile_iterate_end;
2085 } trade_partners_iterate_end;
2087 return TRI_NO;
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:
2094 break;
2097 fc_assert_msg(FALSE, "Invalid range %d.", range);
2099 return TRI_MAYBE;
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)
2110 switch (range) {
2111 case REQ_RANGE_LOCAL:
2112 /* The requirement is filled if the tile has a road with correct flag. */
2113 if (!target_tile) {
2114 return TRI_MAYBE;
2116 return BOOL_TO_TRISTATE(tile_has_road_flag(target_tile, roadflag));
2117 case REQ_RANGE_CADJACENT:
2118 if (!target_tile) {
2119 return TRI_MAYBE;
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:
2124 if (!target_tile) {
2125 return TRI_MAYBE;
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:
2130 if (!target_city) {
2131 return TRI_MAYBE;
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)) {
2136 return TRI_YES;
2138 } city_tile_iterate_end;
2140 return TRI_NO;
2141 case REQ_RANGE_TRADEROUTE:
2142 if (!target_city) {
2143 return TRI_MAYBE;
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)) {
2148 return TRI_YES;
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)) {
2156 return TRI_YES;
2158 } city_tile_iterate_end;
2159 } trade_partners_iterate_end;
2161 return TRI_NO;
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:
2168 break;
2171 fc_assert_msg(FALSE, "Invalid range %d.", range);
2173 return TRI_MAYBE;
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)
2184 switch (range) {
2185 case REQ_RANGE_LOCAL:
2186 /* The requirement is filled if the tile has an extra with correct flag. */
2187 if (!target_tile) {
2188 return TRI_MAYBE;
2190 return BOOL_TO_TRISTATE(tile_has_extra_flag(target_tile, extraflag));
2191 case REQ_RANGE_CADJACENT:
2192 if (!target_tile) {
2193 return TRI_MAYBE;
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:
2198 if (!target_tile) {
2199 return TRI_MAYBE;
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:
2204 if (!target_city) {
2205 return TRI_MAYBE;
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)) {
2210 return TRI_YES;
2212 } city_tile_iterate_end;
2214 return TRI_NO;
2215 case REQ_RANGE_TRADEROUTE:
2216 if (!target_city) {
2217 return TRI_MAYBE;
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)) {
2222 return TRI_YES;
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)) {
2230 return TRI_YES;
2232 } city_tile_iterate_end;
2233 } trade_partners_iterate_end;
2235 return TRI_NO;
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:
2242 break;
2245 fc_assert_msg(FALSE, "Invalid range %d.", range);
2247 return TRI_MAYBE;
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,
2256 bool survives,
2257 enum terrain_alteration alteration)
2259 if (!target_tile) {
2260 return TRI_MAYBE;
2263 switch (range) {
2264 case REQ_RANGE_LOCAL:
2265 return BOOL_TO_TRISTATE(terrain_can_support_alteration(tile_terrain(target_tile),
2266 alteration));
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:
2277 break;
2280 fc_assert_msg(FALSE, "Invalid range %d.", range);
2282 return TRI_MAYBE;
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)
2292 switch (range) {
2293 case REQ_RANGE_PLAYER:
2294 if (target_player == NULL) {
2295 return TRI_MAYBE;
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) {
2301 return TRI_MAYBE;
2303 players_iterate_alive(plr2) {
2304 if (players_in_same_range(target_player, plr2, range)) {
2305 if (nation_of_player(plr2) == nation) {
2306 return TRI_YES;
2309 } players_iterate_alive_end;
2310 return TRI_NO;
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:
2325 break;
2328 fc_assert_msg(FALSE, "Invalid range %d.", range);
2330 return TRI_MAYBE;
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)
2341 switch (range) {
2342 case REQ_RANGE_PLAYER:
2343 if (target_player == NULL) {
2344 return TRI_MAYBE;
2346 return BOOL_TO_TRISTATE(nation_is_in_group(nation_of_player(target_player),
2347 ngroup));
2348 case REQ_RANGE_TEAM:
2349 case REQ_RANGE_ALLIANCE:
2350 case REQ_RANGE_WORLD:
2351 if (target_player == NULL) {
2352 return TRI_MAYBE;
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)) {
2357 return TRI_YES;
2360 } players_iterate_alive_end;
2361 return TRI_NO;
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:
2369 break;
2372 fc_assert_msg(FALSE, "Invalid range %d.", range);
2374 return TRI_MAYBE;
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)
2384 switch (range) {
2385 case REQ_RANGE_CITY:
2386 if (target_city == NULL) {
2387 return TRI_MAYBE;
2389 citizens_iterate(target_city, slot, count) {
2390 if (player_slot_get_player(slot)->nation == nationality) {
2391 return TRI_YES;
2393 } citizens_iterate_end;
2395 return TRI_NO;
2396 case REQ_RANGE_TRADEROUTE:
2397 if (target_city == NULL) {
2398 return TRI_MAYBE;
2400 citizens_iterate(target_city, slot, count) {
2401 if (player_slot_get_player(slot)->nation == nationality) {
2402 return TRI_YES;
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) {
2409 return TRI_YES;
2411 } citizens_iterate_end;
2412 } trade_partners_iterate_end;
2414 return TRI_NO;
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:
2424 break;
2427 fc_assert_msg(FALSE, "Invalid range %d.", range);
2429 return TRI_MAYBE;
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,
2438 int diplrel)
2440 switch (range) {
2441 case REQ_RANGE_PLAYER:
2442 if (target_player == NULL) {
2443 return TRI_MAYBE;
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) {
2450 return TRI_MAYBE;
2452 players_iterate_alive(plr2) {
2453 if (players_in_same_range(target_player, plr2, range)) {
2454 if (is_diplrel_to_other(plr2, diplrel)) {
2455 return TRI_YES;
2458 } players_iterate_alive_end;
2459 return TRI_NO;
2460 case REQ_RANGE_LOCAL:
2461 if (target_player == NULL || other_player == NULL) {
2462 return TRI_MAYBE;
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:
2471 break;
2474 fc_assert_msg(FALSE, "Invalid range %d.", range);
2476 return TRI_MAYBE;
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) {
2505 return TRI_NO;
2507 if (!target_unittype) {
2508 return TRI_MAYBE;
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,
2549 bool survives,
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) {
2559 return TRI_MAYBE;
2562 switch (uprop) {
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)));
2569 break;
2570 case USP_DOMESTIC_TILE:
2571 return BOOL_TO_TRISTATE(
2572 tile_owner(unit_tile(target_unit)) == unit_owner(target_unit));
2573 break;
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)));
2581 break;
2582 case USP_COUNT:
2583 fc_assert_msg(uprop != USP_COUNT, "Invalid unit state property.");
2584 /* Invalid property is unknowable. */
2585 return TRI_NO;
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;
2602 } else {
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)
2615 if (target_tile) {
2616 if (citytile == CITYT_CENTER) {
2617 switch (range) {
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)) {
2622 return TRI_YES;
2624 cardinal_adjc_iterate(&(wld.map), target_tile, adjc_tile) {
2625 if (is_city_in_tile(adjc_tile, target_city)) {
2626 return TRI_YES;
2628 } cardinal_adjc_iterate_end;
2630 return TRI_NO;
2631 case REQ_RANGE_ADJACENT:
2632 if (is_city_in_tile(target_tile, target_city)) {
2633 return TRI_YES;
2635 adjc_iterate(&(wld.map), target_tile, adjc_tile) {
2636 if (is_city_in_tile(adjc_tile, target_city)) {
2637 return TRI_YES;
2639 } adjc_iterate_end;
2641 return TRI_NO;
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:
2650 break;
2653 fc_assert_msg(FALSE, "Invalid range %d for citytile.", range);
2655 return TRI_MAYBE;
2656 } else if (citytile == CITYT_CLAIMED) {
2657 switch (range) {
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) {
2662 return TRI_YES;
2664 cardinal_adjc_iterate(&(wld.map), target_tile, adjc_tile) {
2665 if (adjc_tile->owner != NULL) {
2666 return TRI_YES;
2668 } cardinal_adjc_iterate_end;
2670 return TRI_NO;
2671 case REQ_RANGE_ADJACENT:
2672 if (target_tile->owner != NULL) {
2673 return TRI_YES;
2675 adjc_iterate(&(wld.map), target_tile, adjc_tile) {
2676 if (adjc_tile->owner != NULL) {
2677 return TRI_YES;
2679 } adjc_iterate_end;
2681 return TRI_NO;
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:
2690 break;
2693 fc_assert_msg(FALSE, "Invalid range %d for citytile.", range);
2695 return TRI_MAYBE;
2696 } else {
2697 /* Not implemented */
2698 log_error("is_req_active(): citytile %d not supported.",
2699 citytile);
2700 return TRI_MAYBE;
2702 } else {
2703 return TRI_MAYBE;
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) {
2718 return TRI_MAYBE;
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)) {
2723 return TRI_YES;
2725 } players_iterate_alive_end;
2726 return TRI_NO;
2727 } else if (range == REQ_RANGE_PLAYER) {
2728 if (achievement_player_has(achievement, target_player)) {
2729 return TRI_YES;
2730 } else {
2731 return TRI_NO;
2733 } else {
2734 fc_assert_ret_val_msg(FALSE, TRI_MAYBE,
2735 "Illegal range %d for achievement requirement.",
2736 range);
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) {
2776 case VUT_NONE:
2777 eval = TRI_YES;
2778 break;
2779 case VUT_ADVANCE:
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));
2783 break;
2784 case VUT_TECHFLAG:
2785 eval = is_techflag_in_range(target_player, req->range,
2786 req->source.value.techflag);
2787 break;
2788 case VUT_GOVERNMENT:
2789 /* The requirement is filled if the player is using the government. */
2790 if (target_player == NULL) {
2791 eval = TRI_MAYBE;
2792 } else {
2793 eval = BOOL_TO_TRISTATE(government_of_player(target_player) == req->source.value.govern);
2795 break;
2796 case VUT_ACHIEVEMENT:
2797 eval = is_achievement_in_range(target_player, req->range,
2798 req->source.value.achievement);
2799 break;
2800 case VUT_STYLE:
2801 if (target_player == NULL) {
2802 eval = TRI_MAYBE;
2803 } else {
2804 eval = BOOL_TO_TRISTATE(target_player->style == req->source.value.style);
2806 break;
2807 case VUT_IMPROVEMENT:
2808 eval = is_building_in_range(target_player, target_city,
2809 target_building,
2810 req->range, req->survives,
2811 req->source.value.building);
2812 break;
2813 case VUT_IMPR_GENUS:
2814 eval = (target_building ? BOOL_TO_TRISTATE(
2815 target_building->genus
2816 == req->source.value.impr_genus)
2817 : TRI_MAYBE);
2818 break;
2819 case VUT_EXTRA:
2820 eval = is_extra_type_in_range(target_tile, target_city,
2821 req->range, req->survives,
2822 req->source.value.extra);
2823 break;
2824 case VUT_GOOD:
2825 eval = is_goods_type_in_range(target_tile, target_city,
2826 req->range, req->survives,
2827 req->source.value.good);
2828 break;
2829 case VUT_TERRAIN:
2830 eval = is_terrain_in_range(target_tile, target_city,
2831 req->range, req->survives,
2832 req->source.value.terrain);
2833 break;
2834 case VUT_TERRFLAG:
2835 eval = is_terrainflag_in_range(target_tile, target_city,
2836 req->range, req->survives,
2837 req->source.value.terrainflag);
2838 break;
2839 case VUT_NATION:
2840 eval = is_nation_in_range(target_player, req->range, req->survives,
2841 req->source.value.nation);
2842 break;
2843 case VUT_NATIONGROUP:
2844 eval = is_nation_group_in_range(target_player, req->range, req->survives,
2845 req->source.value.nationgroup);
2846 break;
2847 case VUT_NATIONALITY:
2848 eval = is_nationality_in_range(target_city, req->range,
2849 req->source.value.nationality);
2850 break;
2851 case VUT_DIPLREL:
2852 eval = is_diplrel_in_range(target_player, other_player, req->range,
2853 req->source.value.diplrel);
2854 break;
2855 case VUT_UTYPE:
2856 if (target_unittype == NULL) {
2857 eval = TRI_MAYBE;
2858 } else {
2859 eval = is_unittype_in_range(target_unittype,
2860 req->range, req->survives,
2861 req->source.value.utype);
2863 break;
2864 case VUT_UTFLAG:
2865 eval = is_unitflag_in_range(target_unittype,
2866 req->range, req->survives,
2867 req->source.value.unitflag);
2868 break;
2869 case VUT_UCLASS:
2870 if (target_unittype == NULL) {
2871 eval = TRI_MAYBE;
2872 } else {
2873 eval = is_unitclass_in_range(target_unittype,
2874 req->range, req->survives,
2875 req->source.value.uclass);
2877 break;
2878 case VUT_UCFLAG:
2879 if (target_unittype == NULL) {
2880 eval = TRI_MAYBE;
2881 } else {
2882 eval = is_unitclassflag_in_range(target_unittype,
2883 req->range, req->survives,
2884 req->source.value.unitclassflag);
2886 break;
2887 case VUT_MINVETERAN:
2888 if (target_unit == NULL) {
2889 eval = TRI_MAYBE;
2890 } else {
2891 eval =
2892 BOOL_TO_TRISTATE(target_unit->veteran >= req->source.value.minveteran);
2894 break;
2895 case VUT_UNITSTATE:
2896 if (target_unit == NULL) {
2897 eval = TRI_MAYBE;
2898 } else {
2899 eval = is_unit_state(target_unit,
2900 req->range, req->survives,
2901 req->source.value.unit_state);
2903 break;
2904 case VUT_MINMOVES:
2905 if (target_unit == NULL) {
2906 eval = TRI_MAYBE;
2907 } else {
2908 eval = BOOL_TO_TRISTATE(
2909 req->source.value.minmoves <= target_unit->moves_left);
2911 break;
2912 case VUT_MINHP:
2913 if (target_unit == NULL) {
2914 eval = TRI_MAYBE;
2915 } else {
2916 eval = BOOL_TO_TRISTATE(
2917 req->source.value.min_hit_points <= target_unit->hp);
2919 break;
2920 case VUT_AGE:
2921 switch (req->range) {
2922 case REQ_RANGE_LOCAL:
2923 if (target_unit == NULL || !is_server()) {
2924 eval = TRI_MAYBE;
2925 } else {
2926 eval = BOOL_TO_TRISTATE(
2927 req->source.value.age <=
2928 game.info.turn - target_unit->server.birth_turn);
2930 break;
2931 case REQ_RANGE_CITY:
2932 if (target_city == NULL) {
2933 eval = TRI_MAYBE;
2934 } else {
2935 eval = BOOL_TO_TRISTATE(
2936 req->source.value.age <=
2937 game.info.turn - target_city->turn_founded);
2939 break;
2940 case REQ_RANGE_PLAYER:
2941 if (target_player == NULL) {
2942 eval = TRI_MAYBE;
2943 } else {
2944 eval =
2945 BOOL_TO_TRISTATE(req->source.value.age <= player_age(target_player));
2947 break;
2948 default:
2949 eval = TRI_MAYBE;
2950 break;
2952 break;
2953 case VUT_MINTECHS:
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);
2958 break;
2959 case REQ_RANGE_PLAYER:
2960 if (target_player == NULL) {
2961 eval = TRI_MAYBE;
2962 } else {
2963 /* "None" does not count */
2964 eval = ((research_get(target_player)->techs_researched - 1) >= req->source.value.min_techs);
2966 break;
2967 default:
2968 eval = TRI_MAYBE;
2970 break;
2971 case VUT_ACTION:
2972 eval = BOOL_TO_TRISTATE(target_action
2973 && action_number(target_action)
2974 == action_number(req->source.value.action));
2975 break;
2976 case VUT_OTYPE:
2977 eval = BOOL_TO_TRISTATE(target_output
2978 && target_output->index == req->source.value.outputtype);
2979 break;
2980 case VUT_SPECIALIST:
2981 eval = BOOL_TO_TRISTATE(target_specialist
2982 && target_specialist == req->source.value.specialist);
2983 break;
2984 case VUT_MINSIZE:
2985 if (target_city == NULL) {
2986 eval = TRI_MAYBE;
2987 } else {
2988 if (req->range == REQ_RANGE_TRADEROUTE) {
2989 bool found = FALSE;
2991 if (city_size_get(target_city) >= req->source.value.minsize) {
2992 eval = TRI_YES;
2993 break;
2995 trade_partners_iterate(target_city, trade_partner) {
2996 if (city_size_get(trade_partner) >= req->source.value.minsize) {
2997 found = TRUE;
2998 break;
3000 } trade_partners_iterate_end;
3001 eval = BOOL_TO_TRISTATE(found);
3002 } else {
3003 eval = BOOL_TO_TRISTATE(city_size_get(target_city) >= req->source.value.minsize);
3006 break;
3007 case VUT_MINCULTURE:
3008 eval = is_minculture_in_range(target_city, target_player, req->range,
3009 req->source.value.minculture);
3010 break;
3011 case VUT_AI_LEVEL:
3012 if (target_player == NULL) {
3013 eval = TRI_MAYBE;
3014 } else {
3015 eval = BOOL_TO_TRISTATE(is_ai(target_player)
3016 && target_player->ai_common.skill_level == req->source.value.ai_level);
3018 break;
3019 case VUT_MAXTILEUNITS:
3020 eval = is_tile_units_in_range(target_tile, req->range,
3021 req->source.value.max_tile_units);
3022 break;
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);
3027 break;
3028 case VUT_BASEFLAG:
3029 eval = is_baseflag_in_range(target_tile, target_city,
3030 req->range, req->survives,
3031 req->source.value.baseflag);
3032 break;
3033 case VUT_ROADFLAG:
3034 eval = is_roadflag_in_range(target_tile, target_city,
3035 req->range, req->survives,
3036 req->source.value.roadflag);
3037 break;
3038 case VUT_EXTRAFLAG:
3039 eval = is_extraflag_in_range(target_tile, target_city,
3040 req->range, req->survives,
3041 req->source.value.extraflag);
3042 break;
3043 case VUT_MINYEAR:
3044 eval = BOOL_TO_TRISTATE(game.info.year >= req->source.value.minyear);
3045 break;
3046 case VUT_MINCALFRAG:
3047 eval = BOOL_TO_TRISTATE(game.info.fragment_count >= req->source.value.mincalfrag);
3048 break;
3049 case VUT_TOPO:
3050 eval = BOOL_TO_TRISTATE(current_topo_has_flag(req->source.value.topo_property));
3051 break;
3052 case VUT_TERRAINALTER:
3053 if (target_tile == NULL) {
3054 eval = TRI_MAYBE;
3055 } else {
3056 eval = is_terrain_alter_possible_in_range(target_tile,
3057 req->range, req->survives,
3058 req->source.value.terrainalter);
3060 break;
3061 case VUT_CITYTILE:
3062 if (target_tile == NULL) {
3063 eval = TRI_MAYBE;
3064 } else {
3065 eval = is_citytile_in_range(target_tile, target_city,
3066 req->range,
3067 req->source.value.citytile);
3069 break;
3070 case VUT_COUNT:
3071 log_error("is_req_active(): invalid source kind %d.", req->source.kind);
3072 return FALSE;
3075 if (eval == TRI_MAYBE) {
3076 if (prob_type == RPT_POSSIBLE) {
3077 return TRUE;
3078 } else {
3079 return FALSE;
3082 if (req->present) {
3083 return (eval == TRI_YES);
3084 } else {
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,
3120 preq, prob_type)) {
3121 return FALSE;
3123 } requirement_vector_iterate_end;
3124 return TRUE;
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)
3135 it may be wrong.
3136 *****************************************************************************/
3137 bool is_req_unchanging(const struct requirement *req)
3139 switch (req->source.kind) {
3140 case VUT_NONE:
3141 case VUT_ACTION:
3142 case VUT_OTYPE:
3143 case VUT_SPECIALIST: /* Only so long as it's at local range only */
3144 case VUT_AI_LEVEL:
3145 case VUT_CITYTILE:
3146 case VUT_STYLE:
3147 case VUT_TOPO:
3148 return TRUE;
3149 case VUT_NATION:
3150 case VUT_NATIONGROUP:
3151 return (req->range != REQ_RANGE_ALLIANCE);
3152 case VUT_ADVANCE:
3153 case VUT_TECHFLAG:
3154 case VUT_GOVERNMENT:
3155 case VUT_ACHIEVEMENT:
3156 case VUT_IMPROVEMENT:
3157 case VUT_IMPR_GENUS:
3158 case VUT_MINSIZE:
3159 case VUT_MINCULTURE:
3160 case VUT_MINTECHS:
3161 case VUT_NATIONALITY:
3162 case VUT_DIPLREL:
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:
3169 case VUT_UNITSTATE:
3170 case VUT_MINMOVES:
3171 case VUT_MINHP:
3172 case VUT_AGE:
3173 case VUT_ROADFLAG:
3174 case VUT_EXTRAFLAG:
3175 case VUT_MINCALFRAG: /* cyclically available */
3176 return FALSE;
3177 case VUT_TERRAIN:
3178 case VUT_EXTRA:
3179 case VUT_GOOD:
3180 case VUT_TERRAINCLASS:
3181 case VUT_TERRFLAG:
3182 case VUT_TERRAINALTER:
3183 case VUT_BASEFLAG:
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). */
3188 return TRUE;
3189 case VUT_MINYEAR:
3190 /* Once year is reached, it does not change again */
3191 return req->source.value.minyear > game.info.year;
3192 case VUT_COUNT:
3193 break;
3195 fc_assert_msg(FALSE, "Invalid source kind %d.", req->source.kind);
3196 return TRUE;
3199 /*************************************************************************
3200 Returns TRUE iff the requirement vector vec contains the requirement
3201 req.
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)) {
3208 return TRUE;
3210 } requirement_vector_iterate_end;
3212 return FALSE;
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) {
3223 return FALSE;
3225 switch (psource1->kind) {
3226 case VUT_NONE:
3227 return TRUE;
3228 case VUT_ADVANCE:
3229 return psource1->value.advance == psource2->value.advance;
3230 case VUT_TECHFLAG:
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;
3236 case VUT_STYLE:
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;
3242 case VUT_EXTRA:
3243 return psource1->value.extra == psource2->value.extra;
3244 case VUT_GOOD:
3245 return psource1->value.good == psource2->value.good;
3246 case VUT_TERRAIN:
3247 return psource1->value.terrain == psource2->value.terrain;
3248 case VUT_TERRFLAG:
3249 return psource1->value.terrainflag == psource2->value.terrainflag;
3250 case VUT_NATION:
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;
3256 case VUT_DIPLREL:
3257 return psource1->value.diplrel == psource2->value.diplrel;
3258 case VUT_UTYPE:
3259 return psource1->value.utype == psource2->value.utype;
3260 case VUT_UTFLAG:
3261 return psource1->value.unitflag == psource2->value.unitflag;
3262 case VUT_UCLASS:
3263 return psource1->value.uclass == psource2->value.uclass;
3264 case VUT_UCFLAG:
3265 return psource1->value.unitclassflag == psource2->value.unitclassflag;
3266 case VUT_MINVETERAN:
3267 return psource1->value.minveteran == psource2->value.minveteran;
3268 case VUT_UNITSTATE:
3269 return psource1->value.unit_state == psource2->value.unit_state;
3270 case VUT_MINMOVES:
3271 return psource1->value.minmoves == psource2->value.minmoves;
3272 case VUT_MINHP:
3273 return psource1->value.min_hit_points == psource2->value.min_hit_points;
3274 case VUT_AGE:
3275 return psource1->value.age == psource2->value.age;
3276 case VUT_MINTECHS:
3277 return psource1->value.min_techs == psource2->value.min_techs;
3278 case VUT_ACTION:
3279 return (action_number(psource1->value.action)
3280 == action_number(psource2->value.action));
3281 case VUT_OTYPE:
3282 return psource1->value.outputtype == psource2->value.outputtype;
3283 case VUT_SPECIALIST:
3284 return psource1->value.specialist == psource2->value.specialist;
3285 case VUT_MINSIZE:
3286 return psource1->value.minsize == psource2->value.minsize;
3287 case VUT_MINCULTURE:
3288 return psource1->value.minculture == psource2->value.minculture;
3289 case VUT_AI_LEVEL:
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;
3295 case VUT_BASEFLAG:
3296 return psource1->value.baseflag == psource2->value.baseflag;
3297 case VUT_ROADFLAG:
3298 return psource1->value.roadflag == psource2->value.roadflag;
3299 case VUT_EXTRAFLAG:
3300 return psource1->value.extraflag == psource2->value.extraflag;
3301 case VUT_MINYEAR:
3302 return psource1->value.minyear == psource2->value.minyear;
3303 case VUT_MINCALFRAG:
3304 return psource1->value.mincalfrag == psource2->value.mincalfrag;
3305 case VUT_TOPO:
3306 return psource1->value.topo_property == psource2->value.topo_property;
3307 case VUT_TERRAINALTER:
3308 return psource1->value.terrainalter == psource2->value.terrainalter;
3309 case VUT_CITYTILE:
3310 return psource1->value.citytile == psource2->value.citytile;
3311 case VUT_COUNT:
3312 break;
3315 fc_assert_msg(FALSE, "Invalid source kind %d.", psource1->kind);
3316 return FALSE;
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) {
3328 case VUT_NONE:
3329 return "(none)";
3330 case VUT_CITYTILE:
3331 return citytile_type_name(psource->value.citytile);
3332 case VUT_MINYEAR:
3333 fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.minyear);
3335 return buffer;
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);
3340 return buffer;
3341 case VUT_TOPO:
3342 return topo_flag_name(psource->value.topo_property);
3343 case VUT_ADVANCE:
3344 return advance_rule_name(psource->value.advance);
3345 case VUT_TECHFLAG:
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);
3351 case VUT_STYLE:
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);
3357 case VUT_EXTRA:
3358 return extra_rule_name(psource->value.extra);
3359 case VUT_GOOD:
3360 return goods_rule_name(psource->value.good);
3361 case VUT_TERRAIN:
3362 return terrain_rule_name(psource->value.terrain);
3363 case VUT_TERRFLAG:
3364 return terrain_flag_id_name(psource->value.terrainflag);
3365 case VUT_NATION:
3366 return nation_rule_name(psource->value.nation);
3367 case VUT_NATIONGROUP:
3368 return nation_group_rule_name(psource->value.nationgroup);
3369 case VUT_DIPLREL:
3370 return diplrel_rule_name(psource->value.diplrel);
3371 case VUT_NATIONALITY:
3372 return nation_rule_name(psource->value.nationality);
3373 case VUT_UTYPE:
3374 return utype_rule_name(psource->value.utype);
3375 case VUT_UTFLAG:
3376 return unit_type_flag_id_name(psource->value.unitflag);
3377 case VUT_UCLASS:
3378 return uclass_rule_name(psource->value.uclass);
3379 case VUT_UCFLAG:
3380 return unit_class_flag_id_name(psource->value.unitclassflag);
3381 case VUT_MINVETERAN:
3382 fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.minveteran);
3384 return buffer;
3385 case VUT_UNITSTATE:
3386 return ustate_prop_name(psource->value.unit_state);
3387 case VUT_MINMOVES:
3388 fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.minmoves);
3390 return buffer;
3391 case VUT_MINHP:
3392 fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.min_hit_points);
3394 return buffer;
3395 case VUT_AGE:
3396 fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.age);
3398 return buffer;
3399 case VUT_MINTECHS:
3400 fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.min_techs);
3402 return buffer;
3403 case VUT_ACTION:
3404 return action_rule_name(psource->value.action);
3405 case VUT_OTYPE:
3406 return get_output_name(psource->value.outputtype);
3407 case VUT_SPECIALIST:
3408 return specialist_rule_name(psource->value.specialist);
3409 case VUT_MINSIZE:
3410 fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.minsize);
3412 return buffer;
3413 case VUT_MINCULTURE:
3414 fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.minculture);
3416 return buffer;
3417 case VUT_AI_LEVEL:
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);
3421 return buffer;
3422 case VUT_TERRAINCLASS:
3423 return terrain_class_name(psource->value.terrainclass);
3424 case VUT_BASEFLAG:
3425 return base_flag_id_name(psource->value.baseflag);
3426 case VUT_ROADFLAG:
3427 return road_flag_id_name(psource->value.roadflag);
3428 case VUT_EXTRAFLAG:
3429 return extra_flag_id_name(psource->value.extraflag);
3430 case VUT_TERRAINALTER:
3431 return terrain_alteration_name(psource->value.terrainalter);
3432 case VUT_COUNT:
3433 break;
3436 fc_assert_msg(FALSE, "Invalid source kind %d.", psource->kind);
3437 return NULL;
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) {
3453 case VUT_NONE:
3454 /* TRANS: missing value */
3455 fc_strlcat(buf, _("(none)"), bufsz);
3456 return buf;
3457 case VUT_ADVANCE:
3458 fc_strlcat(buf, advance_name_translation(psource->value.advance), bufsz);
3459 return buf;
3460 case VUT_TECHFLAG:
3461 cat_snprintf(buf, bufsz, _("\"%s\" tech"),
3462 tech_flag_id_translated_name(psource->value.techflag));
3463 return buf;
3464 case VUT_GOVERNMENT:
3465 fc_strlcat(buf, government_name_translation(psource->value.govern),
3466 bufsz);
3467 return buf;
3468 case VUT_ACHIEVEMENT:
3469 fc_strlcat(buf, achievement_name_translation(psource->value.achievement),
3470 bufsz);
3471 return buf;
3472 case VUT_STYLE:
3473 fc_strlcat(buf, style_name_translation(psource->value.style),
3474 bufsz);
3475 return buf;
3476 case VUT_IMPROVEMENT:
3477 fc_strlcat(buf, improvement_name_translation(psource->value.building),
3478 bufsz);
3479 return buf;
3480 case VUT_IMPR_GENUS:
3481 fc_strlcat(buf,
3482 impr_genus_id_translated_name(psource->value.impr_genus),
3483 bufsz);
3484 return buf;
3485 case VUT_EXTRA:
3486 fc_strlcat(buf, extra_name_translation(psource->value.extra), bufsz);
3487 return buf;
3488 case VUT_GOOD:
3489 fc_strlcat(buf, goods_name_translation(psource->value.good), bufsz);
3490 return buf;
3491 case VUT_TERRAIN:
3492 fc_strlcat(buf, terrain_name_translation(psource->value.terrain), bufsz);
3493 return buf;
3494 case VUT_NATION:
3495 fc_strlcat(buf, nation_adjective_translation(psource->value.nation),
3496 bufsz);
3497 return buf;
3498 case VUT_NATIONGROUP:
3499 fc_strlcat(buf, nation_group_name_translation(psource->value.nationgroup),
3500 bufsz);
3501 return buf;
3502 case VUT_NATIONALITY:
3503 cat_snprintf(buf, bufsz, _("%s citizens"),
3504 nation_adjective_translation(psource->value.nationality));
3505 return buf;
3506 case VUT_DIPLREL:
3507 fc_strlcat(buf, diplrel_name_translation(psource->value.diplrel),
3508 bufsz);
3509 return buf;
3510 case VUT_UTYPE:
3511 fc_strlcat(buf, utype_name_translation(psource->value.utype), bufsz);
3512 return buf;
3513 case VUT_UTFLAG:
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));
3519 return buf;
3520 case VUT_UCLASS:
3521 cat_snprintf(buf, bufsz,
3522 /* TRANS: Unit class */
3523 _("%s units"),
3524 uclass_name_translation(psource->value.uclass));
3525 return buf;
3526 case VUT_UCFLAG:
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));
3532 return buf;
3533 case VUT_MINVETERAN:
3534 /* FIXME */
3535 cat_snprintf(buf, bufsz, _("Veteran level >=%d"),
3536 psource->value.minveteran);
3537 return buf;
3538 case VUT_UNITSTATE:
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"));
3543 break;
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"));
3549 break;
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"));
3555 break;
3556 case USP_TRANSPORTING:
3557 /* TRANS: unit state. (appears in strings like "Missile+Transported") */
3558 cat_snprintf(buf, bufsz, _("Transporting"));
3559 break;
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"));
3563 break;
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"));
3569 break;
3570 case USP_COUNT:
3571 fc_assert_msg(psource->value.unit_state != USP_COUNT,
3572 "Invalid unit state property.");
3573 break;
3575 return buf;
3576 case VUT_MINMOVES:
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));
3581 return buf;
3582 case VUT_MINHP:
3583 /* TRANS: HP = hit points */
3584 cat_snprintf(buf, bufsz, _("%d HP"),
3585 psource->value.min_hit_points);
3586 return buf;
3587 case VUT_AGE:
3588 cat_snprintf(buf, bufsz, _("Age %d"),
3589 psource->value.age);
3590 return buf;
3591 case VUT_MINTECHS:
3592 cat_snprintf(buf, bufsz, _("%d Techs"),
3593 psource->value.min_techs);
3594 return buf;
3595 case VUT_ACTION:
3596 fc_strlcat(buf, action_name_translation(psource->value.action),
3597 bufsz);
3598 return buf;
3599 case VUT_OTYPE:
3600 /* FIXME */
3601 fc_strlcat(buf, get_output_name(psource->value.outputtype), bufsz);
3602 return buf;
3603 case VUT_SPECIALIST:
3604 fc_strlcat(buf, specialist_plural_translation(psource->value.specialist),
3605 bufsz);
3606 return buf;
3607 case VUT_MINSIZE:
3608 cat_snprintf(buf, bufsz, _("Size %d"),
3609 psource->value.minsize);
3610 return buf;
3611 case VUT_MINCULTURE:
3612 cat_snprintf(buf, bufsz, _("Culture %d"),
3613 psource->value.minculture);
3614 return buf;
3615 case VUT_AI_LEVEL:
3616 /* TRANS: "Hard AI" */
3617 cat_snprintf(buf, bufsz, _("%s AI"),
3618 ai_level_translated_name(psource->value.ai_level)); /* FIXME */
3619 return buf;
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);
3625 return buf;
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));
3630 return buf;
3631 case VUT_TERRFLAG:
3632 cat_snprintf(buf, bufsz,
3633 /* TRANS: Terrain flag */
3634 Q_("?terrflag:\"%s\" terrain"),
3635 terrain_flag_id_translated_name(
3636 psource->value.terrainflag));
3637 return buf;
3638 case VUT_BASEFLAG:
3639 cat_snprintf(buf, bufsz,
3640 /* TRANS: Base flag */
3641 Q_("?baseflag:\"%s\" base"),
3642 base_flag_id_translated_name(psource->value.baseflag));
3643 return buf;
3644 case VUT_ROADFLAG:
3645 cat_snprintf(buf, bufsz,
3646 /* TRANS: Road flag */
3647 Q_("?roadflag:\"%s\" road"),
3648 road_flag_id_translated_name(psource->value.roadflag));
3649 return buf;
3650 case VUT_EXTRAFLAG:
3651 cat_snprintf(buf, bufsz,
3652 /* TRANS: Extra flag */
3653 Q_("?extraflag:\"%s\" extra"),
3654 extra_flag_id_translated_name(psource->value.extraflag));
3655 return buf;
3656 case VUT_MINYEAR:
3657 cat_snprintf(buf, bufsz, _("After %s"),
3658 textyear(psource->value.minyear));
3659 return buf;
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));
3665 return buf;
3666 case VUT_TOPO:
3667 cat_snprintf(buf, bufsz, _("%s map"),
3668 _(topo_flag_name(psource->value.topo_property)));
3669 return buf;
3670 case VUT_TERRAINALTER:
3671 /* TRANS: "Irrigation possible" */
3672 cat_snprintf(buf, bufsz, _("%s possible"),
3673 Q_(terrain_alteration_name(psource->value.terrainalter)));
3674 return buf;
3675 case VUT_CITYTILE:
3676 fc_strlcat(buf, _("City center"), bufsz);
3677 return buf;
3678 case VUT_COUNT:
3679 break;
3682 fc_assert_msg(FALSE, "Invalid source kind %d.", psource->kind);
3683 return buf;
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);
3702 case VUT_UTYPE:
3703 return utype_build_shield_cost(target->value.utype);
3704 default:
3705 break;
3707 return FC_INFINITY;
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:
3724 continue;
3725 case ITF_NO:
3726 if (preq->present) {
3727 return FALSE;
3729 break;
3730 case ITF_YES:
3731 if (preq->present) {
3732 necessary = TRUE;
3733 } else {
3734 return FALSE;
3736 break;
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:
3754 return FALSE;
3755 case ITF_NO:
3756 case ITF_YES:
3757 return TRUE;
3760 log_error("Unhandled item_found value");
3761 return FALSE;
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) {
3773 case VUT_NATION:
3774 return preq->source.value.nation == source->value.nation ? ITF_YES
3775 : ITF_NO;
3776 case VUT_NATIONGROUP:
3777 return nation_is_in_group(source->value.nation,
3778 preq->source.value.nationgroup) ? ITF_YES
3779 : ITF_NO;
3780 default:
3781 break;
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
3797 : ITF_NO;
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) {
3819 return ITF_YES;
3821 break;
3822 case VUT_IMPR_GENUS:
3823 if (source->value.building->genus == preq->source.value.impr_genus) {
3824 return ITF_YES;
3826 break;
3827 default:
3828 break;
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) {
3843 case VUT_UCLASS:
3844 return source->value.uclass == preq->source.value.uclass ? ITF_YES
3845 : ITF_NO;
3846 case VUT_UCFLAG:
3847 return uclass_has_flag(source->value.uclass,
3848 preq->source.value.unitclassflag) ? ITF_YES
3849 : ITF_NO;
3851 default:
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) {
3866 case VUT_UTYPE:
3867 return source->value.utype == preq->source.value.utype ? ITF_YES : ITF_NO;
3868 case VUT_UCLASS:
3869 return utype_class(source->value.utype) == preq->source.value.uclass
3870 ? ITF_YES : ITF_NO;
3871 case VUT_UTFLAG:
3872 return utype_has_flag(source->value.utype,
3873 preq->source.value.unitflag) ? ITF_YES : ITF_NO;
3874 case VUT_UCFLAG:
3875 return uclass_has_flag(utype_class(source->value.utype),
3876 preq->source.value.unitclassflag) ? ITF_YES
3877 : ITF_NO;
3878 default:
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) {
3893 case VUT_TERRAIN:
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
3897 ? ITF_YES : ITF_NO;
3898 case VUT_TERRFLAG:
3899 return terrain_has_flag(source->value.terrain,
3900 preq->source.value.terrainflag) ? ITF_YES : ITF_NO;
3901 default:
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
3926 appears.
3927 **************************************************************************/
3928 int requirement_kind_ereq(const int value,
3929 const enum req_range range,
3930 const bool present,
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;