1 /**********************************************************************
2 Freeciv - Copyright (C) 1996-2013 - Freeciv Development Team
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
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 ***********************************************************************/
15 #include <fc_config.h>
19 #include "diptreaty.h"
22 #include "metaknowledge.h"
24 #include "traderoutes.h"
26 /**************************************************************************
27 Returns TRUE iff the target_tile it self and all tiles cardinally
28 adjacent to it are seen by pow_player.
29 **************************************************************************/
30 static bool is_tile_seen_cadj(const struct player
*pow_player
,
31 const struct tile
*target_tile
)
33 /* The tile it self is unseen. */
34 if (!tile_is_seen(target_tile
, pow_player
)) {
38 /* A cardinally adjacent tile is unseen. */
39 cardinal_adjc_iterate(&(wld
.map
), target_tile
, ptile
) {
40 if (!tile_is_seen(ptile
, pow_player
)) {
43 } cardinal_adjc_iterate_end
;
45 /* They are all seen. */
49 /**************************************************************************
50 Returns TRUE iff the target_tile it self and all tiles adjacent to it
51 are seen by pow_player.
52 **************************************************************************/
53 static bool is_tile_seen_adj(const struct player
*pow_player
,
54 const struct tile
*target_tile
)
56 /* The tile it self is unseen. */
57 if (!tile_is_seen(target_tile
, pow_player
)) {
61 /* An adjacent tile is unseen. */
62 adjc_iterate(&(wld
.map
), target_tile
, ptile
) {
63 if (!tile_is_seen(ptile
, pow_player
)) {
68 /* They are all seen. */
72 /**************************************************************************
73 Returns TRUE iff all tiles of a city are seen by pow_player.
74 **************************************************************************/
75 static bool is_tile_seen_city(const struct player
*pow_player
,
76 const struct city
*target_city
)
78 /* Don't know the city radius. */
79 if (!can_player_see_city_internals(pow_player
, target_city
)) {
83 /* A tile of the city is unseen */
84 city_tile_iterate(city_map_radius_sq_get(target_city
),
85 city_tile(target_city
), ptile
) {
86 if (!tile_is_seen(ptile
, pow_player
)) {
89 } city_tile_iterate_end
;
91 /* They are all seen. */
95 /**************************************************************************
96 Returns TRUE iff all the tiles of a city and all the tiles of its trade
97 partners are seen by pow_player.
98 **************************************************************************/
99 static bool is_tile_seen_traderoute(const struct player
*pow_player
,
100 const struct city
*target_city
)
102 /* Don't know who the trade routes will go to. */
103 if (!can_player_see_city_internals(pow_player
, target_city
)) {
107 /* A tile of the city is unseen */
108 if (!is_tile_seen_city(pow_player
, target_city
)) {
112 /* A tile of a trade parter is unseen */
113 trade_partners_iterate(target_city
, trade_partner
) {
114 if (!is_tile_seen_city(pow_player
, trade_partner
)) {
117 } trade_partners_iterate_end
;
119 /* They are all seen. */
123 /**************************************************************************
124 Returns TRUE iff pplayer can see all the symmetric diplomatic
125 relationships of tplayer.
126 **************************************************************************/
127 static bool can_plr_see_all_sym_diplrels_of(const struct player
*pplayer
,
128 const struct player
*tplayer
)
130 if (pplayer
== tplayer
) {
131 /* Can see own relationships. */
135 if (player_has_embassy(pplayer
, tplayer
)) {
136 /* Gets reports from the embassy. */
140 if (player_diplstate_get(pplayer
, tplayer
)->contact_turns_left
> 0) {
141 /* Can see relationships during contact turns. */
148 /**************************************************************************
149 Is an evalutaion of the requirement accurate when pow_player evaluates
152 TODO: Move the data to a data file. That will
153 - let non programmers help complete it and/or fix what is wrong
154 - let clients not written in C use the data
155 **************************************************************************/
156 static bool is_req_knowable(const struct player
*pow_player
,
157 const struct player
*target_player
,
158 const struct player
*other_player
,
159 const struct city
*target_city
,
160 const struct impr_type
*target_building
,
161 const struct tile
*target_tile
,
162 const struct unit
*target_unit
,
163 const struct output_type
*target_output
,
164 const struct specialist
*target_specialist
,
165 const struct requirement
*req
,
166 const enum req_problem_type prob_type
)
168 fc_assert_ret_val_msg(NULL
!= pow_player
, false, "No point of view");
170 if (req
->source
.kind
== VUT_UTFLAG
171 || req
->source
.kind
== VUT_UTYPE
172 || req
->source
.kind
== VUT_UCLASS
173 || req
->source
.kind
== VUT_UCFLAG
174 || req
->source
.kind
== VUT_MINVETERAN
175 || req
->source
.kind
== VUT_MINHP
) {
176 switch (req
->range
) {
177 case REQ_RANGE_LOCAL
:
178 if (target_unit
== NULL
) {
179 /* The unit may exist but not be passed when the problem type is
181 return prob_type
== RPT_CERTAIN
;
184 return target_unit
&& can_player_see_unit(pow_player
, target_unit
);
185 case REQ_RANGE_CADJACENT
:
186 case REQ_RANGE_ADJACENT
:
187 case REQ_RANGE_CONTINENT
:
189 case REQ_RANGE_TRADEROUTE
:
190 case REQ_RANGE_PLAYER
:
192 case REQ_RANGE_ALLIANCE
:
193 case REQ_RANGE_WORLD
:
194 case REQ_RANGE_COUNT
:
199 if (req
->source
.kind
== VUT_UNITSTATE
) {
200 fc_assert_ret_val_msg(req
->range
== REQ_RANGE_LOCAL
, FALSE
, "Wrong range");
202 if (target_unit
== NULL
) {
203 /* The unit may exist but not be passed when the problem type is
205 return prob_type
== RPT_CERTAIN
;
208 switch (req
->source
.value
.unit_state
) {
209 case USP_TRANSPORTED
:
210 case USP_LIVABLE_TILE
:
211 case USP_DOMESTIC_TILE
:
212 case USP_TRANSPORTING
:
213 case USP_NATIVE_TILE
:
214 /* Known if the unit is seen by the player. */
215 return target_unit
&& can_player_see_unit(pow_player
, target_unit
);
216 case USP_HAS_HOME_CITY
:
217 return target_unit
&& unit_owner(target_unit
) == pow_player
;
219 fc_assert_msg(req
->source
.value
.unit_state
!= USP_COUNT
,
220 "Invalid unit state property.");
221 /* Invalid property is unknowable. */
226 if (req
->source
.kind
== VUT_MINMOVES
) {
227 fc_assert_ret_val_msg(req
->range
== REQ_RANGE_LOCAL
, FALSE
, "Wrong range");
229 if (target_unit
== NULL
) {
230 /* The unit may exist but not be passed when the problem type is
232 return prob_type
== RPT_CERTAIN
;
235 switch (req
->range
) {
236 case REQ_RANGE_LOCAL
:
237 /* The owner can see if his unit has move fragments left. */
238 return unit_owner(target_unit
) == pow_player
;
239 case REQ_RANGE_CADJACENT
:
240 case REQ_RANGE_ADJACENT
:
242 case REQ_RANGE_TRADEROUTE
:
243 case REQ_RANGE_CONTINENT
:
244 case REQ_RANGE_PLAYER
:
246 case REQ_RANGE_ALLIANCE
:
247 case REQ_RANGE_WORLD
:
248 case REQ_RANGE_COUNT
:
254 if (req
->source
.kind
== VUT_DIPLREL
) {
255 switch (req
->range
) {
256 case REQ_RANGE_LOCAL
:
257 if (other_player
== NULL
258 || target_player
== NULL
) {
259 /* The two players may exist but not be passed when the problem
260 * type is RPT_POSSIBLE. */
261 return prob_type
== RPT_CERTAIN
;
264 if (pow_player
== target_player
265 || pow_player
== other_player
) {
269 if (can_plr_see_all_sym_diplrels_of(pow_player
, target_player
)
270 || can_plr_see_all_sym_diplrels_of(pow_player
, other_player
)) {
274 /* TODO: Non symmetric diplomatic relationships. */
276 case REQ_RANGE_PLAYER
:
277 if (target_player
== NULL
) {
278 /* The target player may exist but not be passed when the problem
279 * type is RPT_POSSIBLE. */
280 return prob_type
== RPT_CERTAIN
;
283 if (pow_player
== target_player
) {
287 if (can_plr_see_all_sym_diplrels_of(pow_player
, target_player
)) {
291 /* TODO: Non symmetric diplomatic relationships. */
296 case REQ_RANGE_ALLIANCE
:
299 case REQ_RANGE_WORLD
:
302 case REQ_RANGE_CADJACENT
:
303 case REQ_RANGE_ADJACENT
:
305 case REQ_RANGE_TRADEROUTE
:
306 case REQ_RANGE_CONTINENT
:
307 case REQ_RANGE_COUNT
:
314 if (req
->source
.kind
== VUT_MINSIZE
) {
315 if (target_city
== NULL
) {
316 /* The city may exist but not be passed when the problem type is
318 return prob_type
== RPT_CERTAIN
;
321 if (player_can_see_city_externals(pow_player
, target_city
)) {
326 if (req
->source
.kind
== VUT_CITYTILE
) {
329 if (target_tile
== NULL
) {
330 /* The tile may exist but not be passed when the problem type is
332 return prob_type
== RPT_CERTAIN
;
335 switch (req
->range
) {
336 case REQ_RANGE_LOCAL
:
337 /* Known because the tile is seen */
338 if (tile_is_seen(target_tile
, pow_player
)) {
342 /* The player knows its city even if he can't see it */
343 pcity
= tile_city(target_tile
);
344 return pcity
&& city_owner(pcity
) == pow_player
;
345 case REQ_RANGE_CADJACENT
:
346 /* Known because the tile is seen */
347 if (is_tile_seen_cadj(pow_player
, target_tile
)) {
351 /* The player knows its city even if he can't see it */
352 cardinal_adjc_iterate(&(wld
.map
), target_tile
, ptile
) {
353 pcity
= tile_city(ptile
);
354 if (pcity
&& city_owner(pcity
) == pow_player
) {
357 } cardinal_adjc_iterate_end
;
361 case REQ_RANGE_ADJACENT
:
362 /* Known because the tile is seen */
363 if (is_tile_seen_adj(pow_player
, target_tile
)) {
367 /* The player knows its city even if he can't see it */
368 adjc_iterate(&(wld
.map
), target_tile
, ptile
) {
369 pcity
= tile_city(ptile
);
370 if (pcity
&& city_owner(pcity
) == pow_player
) {
378 case REQ_RANGE_TRADEROUTE
:
379 case REQ_RANGE_CONTINENT
:
380 case REQ_RANGE_PLAYER
:
382 case REQ_RANGE_ALLIANCE
:
383 case REQ_RANGE_WORLD
:
384 case REQ_RANGE_COUNT
:
390 if (req
->source
.kind
== VUT_IMPR_GENUS
) {
391 /* The only legal range when this was written was local. */
392 fc_assert(req
->range
== REQ_RANGE_LOCAL
);
395 /* RPT_CERTAIN: Can't be. No city to contain it.
396 * RPT_POSSIBLE: A city like that may exist but not be passed. */
397 return prob_type
== RPT_CERTAIN
;
400 /* Local BuildingGenus could be about city production. */
401 return can_player_see_city_internals(pow_player
, target_city
);
404 if (req
->source
.kind
== VUT_IMPROVEMENT
) {
405 switch (req
->range
) {
406 case REQ_RANGE_WORLD
:
407 case REQ_RANGE_ALLIANCE
:
409 case REQ_RANGE_PLAYER
:
410 case REQ_RANGE_CONTINENT
:
411 /* Only wonders (great or small) can be required in those ranges.
412 * Wonders are always visible. */
414 case REQ_RANGE_TRADEROUTE
:
415 /* Could be known for trade routes to cities owned by pow_player as
416 * long as the requirement is present. Not present requirements would
417 * require knowledge that no trade routes to another foreign city
418 * exists (since all possible trade routes are to a city owned by
419 * pow_player). Not worth the complexity, IMHO. */
422 case REQ_RANGE_LOCAL
:
424 /* RPT_CERTAIN: Can't be. No city to contain it.
425 * RPT_POSSIBLE: A city like that may exist but not be passed. */
426 return prob_type
== RPT_CERTAIN
;
429 if (can_player_see_city_internals(pow_player
, target_city
)) {
430 /* Anyone that can see city internals (like the owner) known all
431 * its improvements. */
435 if (is_improvement_visible(req
->source
.value
.building
)
436 && player_can_see_city_externals(pow_player
, target_city
)) {
437 /* Can see visible improvements when the outside of the city is
442 /* No way to know if a city has an improvement */
444 case REQ_RANGE_CADJACENT
:
445 case REQ_RANGE_ADJACENT
:
446 case REQ_RANGE_COUNT
:
447 /* Not supported by the requirement type. */
452 if (req
->source
.kind
== VUT_NATION
453 || req
->source
.kind
== VUT_NATIONGROUP
) {
455 && (req
->range
== REQ_RANGE_PLAYER
456 || req
->range
== REQ_RANGE_TEAM
457 || req
->range
== REQ_RANGE_ALLIANCE
)) {
458 /* The player (that can have a nationality or be alllied to someone
459 * with the nationality) may exist but not be passed when the problem
460 * type is RPT_POSSIBLE. */
461 return prob_type
== RPT_CERTAIN
;
467 if (req
->source
.kind
== VUT_ADVANCE
|| req
->source
.kind
== VUT_TECHFLAG
) {
468 if (req
->range
== REQ_RANGE_PLAYER
) {
469 if (!target_player
) {
470 /* The player (that may or may not possess the tech) may exist but
471 * not be passed when the problem type is RPT_POSSIBLE. */
472 return prob_type
== RPT_CERTAIN
;
475 return can_see_techs_of_target(pow_player
, target_player
);
479 if (req
->source
.kind
== VUT_GOVERNMENT
) {
480 if (req
->range
== REQ_RANGE_PLAYER
) {
481 if (!target_player
) {
482 /* The player (that may or may not possess the tech) may exist but
483 * not be passed when the problem type is RPT_POSSIBLE. */
484 return prob_type
== RPT_CERTAIN
;
487 return (pow_player
== target_player
488 || could_intel_with_player(pow_player
, target_player
));
492 if (req
->source
.kind
== VUT_MAXTILEUNITS
) {
493 if (target_tile
== NULL
) {
494 /* The tile may exist but not be passed when the problem type is
496 return prob_type
== RPT_CERTAIN
;
499 switch (req
->range
) {
500 case REQ_RANGE_LOCAL
:
501 return can_player_see_hypotetic_units_at(pow_player
, target_tile
);
502 case REQ_RANGE_CADJACENT
:
503 if (!can_player_see_hypotetic_units_at(pow_player
, target_tile
)) {
506 cardinal_adjc_iterate(&(wld
.map
), target_tile
, adjc_tile
) {
507 if (!can_player_see_hypotetic_units_at(pow_player
, adjc_tile
)) {
510 } cardinal_adjc_iterate_end
;
513 case REQ_RANGE_ADJACENT
:
514 if (!can_player_see_hypotetic_units_at(pow_player
, target_tile
)) {
517 adjc_iterate(&(wld
.map
), target_tile
, adjc_tile
) {
518 if (!can_player_see_hypotetic_units_at(pow_player
, adjc_tile
)) {
524 case REQ_RANGE_CONTINENT
:
526 case REQ_RANGE_TRADEROUTE
:
527 case REQ_RANGE_PLAYER
:
529 case REQ_RANGE_ALLIANCE
:
530 case REQ_RANGE_WORLD
:
531 case REQ_RANGE_COUNT
:
537 if (req
->source
.kind
== VUT_TERRAIN
538 || req
->source
.kind
== VUT_TERRFLAG
539 || req
->source
.kind
== VUT_TERRAINCLASS
540 || req
->source
.kind
== VUT_EXTRA
541 || req
->source
.kind
== VUT_EXTRAFLAG
542 || req
->source
.kind
== VUT_BASEFLAG
543 || req
->source
.kind
== VUT_BASEFLAG
) {
544 if (target_tile
== NULL
) {
545 /* The tile may exist but not be passed when the problem type is
547 return prob_type
== RPT_CERTAIN
;
550 switch (req
->range
) {
551 case REQ_RANGE_LOCAL
:
552 return tile_is_seen(target_tile
, pow_player
);
553 case REQ_RANGE_CADJACENT
:
554 /* TODO: The answer is known when the universal is located on a seen
555 * tile. Is returning TRUE in those cases worth the added complexity
556 * and the extra work for the computer? */
557 return is_tile_seen_cadj(pow_player
, target_tile
);
558 case REQ_RANGE_ADJACENT
:
559 /* TODO: The answer is known when the universal is located on a seen
560 * tile. Is returning TRUE in those cases worth the added complexity
561 * and the extra work for the computer? */
562 return is_tile_seen_adj(pow_player
, target_tile
);
564 /* TODO: The answer is known when the universal is located on a seen
565 * tile. Is returning TRUE in those cases worth the added complexity
566 * and the extra work for the computer? */
567 return is_tile_seen_city(pow_player
, target_city
);
568 case REQ_RANGE_TRADEROUTE
:
569 /* TODO: The answer is known when the universal is located on a seen
570 * tile. Is returning TRUE in those cases worth the added complexity
571 * and the extra work for the computer? */
572 return is_tile_seen_traderoute(pow_player
, target_city
);
573 case REQ_RANGE_CONTINENT
:
574 case REQ_RANGE_PLAYER
:
575 case REQ_RANGE_ALLIANCE
:
577 case REQ_RANGE_WORLD
:
578 case REQ_RANGE_COUNT
:
579 /* Non existing range for requirement types. */
584 if (req
->source
.kind
== VUT_ACTION
585 || req
->source
.kind
== VUT_OTYPE
) {
586 /* This requirement type is intended to specify the situation. */
590 /* Uncertain or no support added yet. */
594 /**************************************************************************
595 Evaluate a single requirement given pow_player's knowledge.
597 Note: Assumed to use pow_player's data.
598 **************************************************************************/
600 mke_eval_req(const struct player
*pow_player
,
601 const struct player
*target_player
,
602 const struct player
*other_player
,
603 const struct city
*target_city
,
604 const struct impr_type
*target_building
,
605 const struct tile
*target_tile
,
606 const struct unit
*target_unit
,
607 const struct output_type
*target_output
,
608 const struct specialist
*target_specialist
,
609 const struct requirement
*req
,
610 const enum req_problem_type prob_type
)
612 const struct unit_type
*target_unittype
;
614 if (!is_req_knowable(pow_player
, target_player
, other_player
,
615 target_city
, target_building
, target_tile
,
616 target_unit
, target_output
,
617 target_specialist
, req
, prob_type
)) {
622 target_unittype
= unit_type_get(target_unit
);
624 target_unittype
= NULL
;
627 if (is_req_active(target_player
, other_player
, target_city
,
628 target_building
, target_tile
, target_unit
, target_unittype
,
629 target_output
, target_specialist
, NULL
, req
, prob_type
)) {
636 /**************************************************************************
637 Evaluate a requirement vector given pow_player's knowledge.
639 Note: Assumed to use pow_player's data.
640 **************************************************************************/
642 mke_eval_reqs(const struct player
*pow_player
,
643 const struct player
*target_player
,
644 const struct player
*other_player
,
645 const struct city
*target_city
,
646 const struct impr_type
*target_building
,
647 const struct tile
*target_tile
,
648 const struct unit
*target_unit
,
649 const struct output_type
*target_output
,
650 const struct specialist
*target_specialist
,
651 const struct requirement_vector
*reqs
,
652 const enum req_problem_type prob_type
)
654 enum fc_tristate current
;
655 enum fc_tristate result
;
658 requirement_vector_iterate(reqs
, preq
) {
659 current
= mke_eval_req(pow_player
, target_player
, other_player
,
660 target_city
, target_building
, target_tile
,
661 target_unit
, target_output
,
662 target_specialist
, preq
, prob_type
);
663 if (current
== TRI_NO
) {
665 } else if (current
== TRI_MAYBE
) {
668 } requirement_vector_iterate_end
;
673 /**************************************************************************
674 Can pow_player see the techs of target player?
675 **************************************************************************/
676 bool can_see_techs_of_target(const struct player
*pow_player
,
677 const struct player
*target_player
)
679 return pow_player
== target_player
680 || player_has_embassy(pow_player
, target_player
);