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 An AND function for fc_tristate.
28 **************************************************************************/
29 enum fc_tristate
tri_and(enum fc_tristate one
,
32 if (TRI_NO
== one
|| TRI_NO
== two
) {
36 if (TRI_MAYBE
== one
|| TRI_MAYBE
== two
) {
43 /**************************************************************************
44 Returns TRUE iff the target_tile is seen by pow_player.
45 **************************************************************************/
46 static bool is_tile_seen(const struct player
*pow_player
,
47 const struct tile
*target_tile
)
49 return tile_get_known(target_tile
, pow_player
) == TILE_KNOWN_SEEN
;
52 /**************************************************************************
53 Returns TRUE iff the target_tile it self and all tiles cardinally
54 adjacent to it are seen by pow_player.
55 **************************************************************************/
56 static bool is_tile_seen_cadj(const struct player
*pow_player
,
57 const struct tile
*target_tile
)
59 /* The tile it self is unseen. */
60 if (!is_tile_seen(pow_player
, target_tile
)) {
64 /* A cardinally adjacent tile is unseen. */
65 cardinal_adjc_iterate(target_tile
, ptile
) {
66 if (!is_tile_seen(pow_player
, ptile
)) {
69 } cardinal_adjc_iterate_end
;
71 /* They are all seen. */
75 /**************************************************************************
76 Returns TRUE iff the target_tile it self and all tiles adjacent to it
77 are seen by pow_player.
78 **************************************************************************/
79 static bool is_tile_seen_adj(const struct player
*pow_player
,
80 const struct tile
*target_tile
)
82 /* The tile it self is unseen. */
83 if (!is_tile_seen(pow_player
, target_tile
)) {
87 /* An adjacent tile is unseen. */
88 adjc_iterate(target_tile
, ptile
) {
89 if (!is_tile_seen(pow_player
, ptile
)) {
94 /* They are all seen. */
98 /**************************************************************************
99 Returns TRUE iff all tiles of a city are seen by pow_player.
100 **************************************************************************/
101 static bool is_tile_seen_city(const struct player
*pow_player
,
102 const struct city
*target_city
)
104 /* Don't know the city radius. */
105 if (!can_player_see_city_internals(pow_player
, target_city
)) {
109 /* A tile of the city is unseen */
110 city_tile_iterate(city_map_radius_sq_get(target_city
),
111 city_tile(target_city
), ptile
) {
112 if (!is_tile_seen(pow_player
, ptile
)) {
115 } city_tile_iterate_end
;
117 /* They are all seen. */
121 /**************************************************************************
122 Returns TRUE iff all tiles of a city an all tiles of its trade partners
123 are seen by pow_player.
124 **************************************************************************/
125 static bool is_tile_seen_traderoute(const struct player
*pow_player
,
126 const struct city
*target_city
)
128 /* Don't know who the trade routes will go to. */
129 if (!can_player_see_city_internals(pow_player
, target_city
)) {
133 /* A tile of the city is unseen */
134 if (!is_tile_seen_city(pow_player
, target_city
)) {
138 /* A tile of a trade parter is unseen */
139 trade_routes_iterate(target_city
, trade_partner
) {
140 if (!is_tile_seen_city(pow_player
, trade_partner
)) {
143 } trade_routes_iterate_end
;
145 /* They are all seen. */
149 /**************************************************************************
150 Returns TRUE iff pplayer can see all the symmetric diplomatic
151 relationships of tplayer.
152 **************************************************************************/
153 static bool can_plr_see_all_sym_diplrels_of(const struct player
*pplayer
,
154 const struct player
*tplayer
)
156 if (pplayer
== tplayer
) {
157 /* Can see own relationships. */
161 if (player_has_embassy(pplayer
, tplayer
)) {
162 /* Gets reports from the embassy. */
166 if (player_diplstate_get(pplayer
, tplayer
)->contact_turns_left
> 0) {
167 /* Can see relationships during contact turns. */
174 /**************************************************************************
175 Is an evalutaion of the requirement accurate when pow_player evaluates
178 TODO: Move the data to a data file. That will
179 - let non programmers help complete it and/or fix what is wrong
180 - let clients not written in C use the data
181 **************************************************************************/
182 static bool is_req_knowable(const struct player
*pow_player
,
183 const struct player
*target_player
,
184 const struct player
*other_player
,
185 const struct city
*target_city
,
186 const struct impr_type
*target_building
,
187 const struct tile
*target_tile
,
188 const struct unit
*target_unit
,
189 const struct output_type
*target_output
,
190 const struct specialist
*target_specialist
,
191 const struct requirement
*req
,
192 const enum req_problem_type prob_type
)
194 fc_assert_ret_val_msg(NULL
!= pow_player
, false, "No point of view");
196 if (req
->source
.kind
== VUT_UTFLAG
197 || req
->source
.kind
== VUT_UTYPE
198 || req
->source
.kind
== VUT_UCLASS
199 || req
->source
.kind
== VUT_UCFLAG
200 || req
->source
.kind
== VUT_MINVETERAN
201 || req
->source
.kind
== VUT_MINHP
) {
202 switch (req
->range
) {
203 case REQ_RANGE_LOCAL
:
204 if (target_unit
== NULL
) {
205 /* The unit may exist but not be passed when the problem type is
207 return prob_type
== RPT_CERTAIN
;
210 return target_unit
&& can_player_see_unit(pow_player
, target_unit
);
211 case REQ_RANGE_CADJACENT
:
212 case REQ_RANGE_ADJACENT
:
213 case REQ_RANGE_CONTINENT
:
215 case REQ_RANGE_TRADEROUTE
:
216 case REQ_RANGE_PLAYER
:
218 case REQ_RANGE_ALLIANCE
:
219 case REQ_RANGE_WORLD
:
220 case REQ_RANGE_COUNT
:
225 if (req
->source
.kind
== VUT_UNITSTATE
) {
226 fc_assert_ret_val_msg(req
->range
== REQ_RANGE_LOCAL
, FALSE
, "Wrong range");
228 if (target_unit
== NULL
) {
229 /* The unit may exist but not be passed when the problem type is
231 return prob_type
== RPT_CERTAIN
;
234 switch (req
->source
.value
.unit_state
) {
235 case USP_TRANSPORTED
:
236 case USP_LIVABLE_TILE
:
237 /* Known if the unit is seen by the player. */
238 return target_unit
&& can_player_see_unit(pow_player
, target_unit
);
240 fc_assert_msg(req
->source
.value
.unit_state
!= USP_COUNT
,
241 "Invalid unit state property.");
242 /* Invalid property is unknowable. */
247 if (req
->source
.kind
== VUT_MINMOVES
) {
248 fc_assert_ret_val_msg(req
->range
== REQ_RANGE_LOCAL
, FALSE
, "Wrong range");
250 if (target_unit
== NULL
) {
251 /* The unit may exist but not be passed when the problem type is
253 return prob_type
== RPT_CERTAIN
;
256 switch (req
->range
) {
257 case REQ_RANGE_LOCAL
:
258 /* The owner can see if his unit has move fragments left. */
259 return unit_owner(target_unit
) == pow_player
;
260 case REQ_RANGE_CADJACENT
:
261 case REQ_RANGE_ADJACENT
:
263 case REQ_RANGE_TRADEROUTE
:
264 case REQ_RANGE_CONTINENT
:
265 case REQ_RANGE_PLAYER
:
267 case REQ_RANGE_ALLIANCE
:
268 case REQ_RANGE_WORLD
:
269 case REQ_RANGE_COUNT
:
275 if (req
->source
.kind
== VUT_DIPLREL
) {
276 switch (req
->range
) {
277 case REQ_RANGE_LOCAL
:
278 if (other_player
== NULL
279 || target_player
== NULL
) {
280 /* The two players may exist but not be passed when the problem
281 * type is RPT_POSSIBLE. */
282 return prob_type
== RPT_CERTAIN
;
285 if (pow_player
== target_player
286 || pow_player
== other_player
) {
290 if (can_plr_see_all_sym_diplrels_of(pow_player
, target_player
)
291 || can_plr_see_all_sym_diplrels_of(pow_player
, other_player
)) {
295 /* TODO: Non symmetric diplomatic relationships. */
297 case REQ_RANGE_PLAYER
:
298 if (target_player
== NULL
) {
299 /* The target player may exist but not be passed when the problem
300 * type is RPT_POSSIBLE. */
301 return prob_type
== RPT_CERTAIN
;
304 if (pow_player
== target_player
) {
308 if (can_plr_see_all_sym_diplrels_of(pow_player
, target_player
)) {
312 /* TODO: Non symmetric diplomatic relationships. */
317 case REQ_RANGE_ALLIANCE
:
320 case REQ_RANGE_WORLD
:
323 case REQ_RANGE_CADJACENT
:
324 case REQ_RANGE_ADJACENT
:
326 case REQ_RANGE_TRADEROUTE
:
327 case REQ_RANGE_CONTINENT
:
328 case REQ_RANGE_COUNT
:
335 if (req
->source
.kind
== VUT_MINSIZE
) {
336 if (target_city
== NULL
) {
337 /* The city may exist but not be passed when the problem type is
339 return prob_type
== RPT_CERTAIN
;
342 if (mke_can_see_city_externals(pow_player
, target_city
)) {
347 if (req
->source
.kind
== VUT_CITYTILE
) {
350 if (target_tile
== NULL
) {
351 /* The tile may exist but not be passed when the problem type is
353 return prob_type
== RPT_CERTAIN
;
356 switch (req
->range
) {
357 case REQ_RANGE_LOCAL
:
358 /* Known because the tile is seen */
359 if (is_tile_seen(pow_player
, target_tile
)) {
363 /* The player knows its city even if he can't see it */
364 pcity
= tile_city(target_tile
);
365 return pcity
&& city_owner(pcity
) == pow_player
;
366 case REQ_RANGE_CADJACENT
:
367 /* Known because the tile is seen */
368 if (is_tile_seen_cadj(pow_player
, target_tile
)) {
372 /* The player knows its city even if he can't see it */
373 cardinal_adjc_iterate(target_tile
, ptile
) {
374 pcity
= tile_city(ptile
);
375 if (pcity
&& city_owner(pcity
) == pow_player
) {
378 } cardinal_adjc_iterate_end
;
382 case REQ_RANGE_ADJACENT
:
383 /* Known because the tile is seen */
384 if (is_tile_seen_adj(pow_player
, target_tile
)) {
388 /* The player knows its city even if he can't see it */
389 adjc_iterate(target_tile
, ptile
) {
390 pcity
= tile_city(ptile
);
391 if (pcity
&& city_owner(pcity
) == pow_player
) {
399 case REQ_RANGE_TRADEROUTE
:
400 case REQ_RANGE_CONTINENT
:
401 case REQ_RANGE_PLAYER
:
403 case REQ_RANGE_ALLIANCE
:
404 case REQ_RANGE_WORLD
:
405 case REQ_RANGE_COUNT
:
411 if (req
->source
.kind
== VUT_IMPROVEMENT
) {
412 switch (req
->range
) {
413 case REQ_RANGE_WORLD
:
414 case REQ_RANGE_ALLIANCE
:
416 case REQ_RANGE_PLAYER
:
417 case REQ_RANGE_CONTINENT
:
418 /* Only wonders (great or small) can be required in those ranges.
419 * Wonders are always visible. */
421 case REQ_RANGE_TRADEROUTE
:
422 /* Could be known for trade routes to cities owned by pow_player as
423 * long as the requirement is present. Not present requirements would
424 * require knowledge that no trade routes to another foreign city
425 * exists (since all possible trade routes are to a city owned by
426 * pow_player). Not worth the complexity, IMHO. */
429 case REQ_RANGE_LOCAL
:
431 /* RPT_CERTAIN: Can't be. No city to contain it.
432 * RPT_POSSIBLE: A city like that may exist but not be passed. */
433 return prob_type
== RPT_CERTAIN
;
436 if (can_player_see_city_internals(pow_player
, target_city
)) {
437 /* Anyone that can see city internals (like the owner) known all
438 * its improvements. */
442 if (is_improvement_visible(req
->source
.value
.building
)
443 && mke_can_see_city_externals(pow_player
, target_city
)) {
444 /* Can see visible improvements when the outside of the city is
449 /* No way to know if a city has an improvement */
451 case REQ_RANGE_CADJACENT
:
452 case REQ_RANGE_ADJACENT
:
453 case REQ_RANGE_COUNT
:
454 /* Not supported by the requirement type. */
459 if (req
->source
.kind
== VUT_NATION
460 || req
->source
.kind
== VUT_NATIONGROUP
) {
462 && (req
->range
== REQ_RANGE_PLAYER
463 || req
->range
== REQ_RANGE_TEAM
464 || req
->range
== REQ_RANGE_ALLIANCE
)) {
465 /* The player (that can have a nationality or be alllied to someone
466 * with the nationality) may exist but not be passed when the problem
467 * type is RPT_POSSIBLE. */
468 return prob_type
== RPT_CERTAIN
;
474 if (req
->source
.kind
== VUT_ADVANCE
|| req
->source
.kind
== VUT_TECHFLAG
) {
475 if (req
->range
== REQ_RANGE_PLAYER
) {
476 if (!target_player
) {
477 /* The player (that may or may not possess the tech) may exist but
478 * not be passed when the problem type is RPT_POSSIBLE. */
479 return prob_type
== RPT_CERTAIN
;
482 return can_see_techs_of_target(pow_player
, target_player
);
486 if (req
->source
.kind
== VUT_GOVERNMENT
) {
487 if (req
->range
== REQ_RANGE_PLAYER
) {
488 if (!target_player
) {
489 /* The player (that may or may not possess the tech) may exist but
490 * not be passed when the problem type is RPT_POSSIBLE. */
491 return prob_type
== RPT_CERTAIN
;
494 return (pow_player
== target_player
495 || could_intel_with_player(pow_player
, target_player
));
499 if (req
->source
.kind
== VUT_MAXTILEUNITS
) {
500 if (target_tile
== NULL
) {
501 /* The tile may exist but not be passed when the problem type is
503 return prob_type
== RPT_CERTAIN
;
506 switch (req
->range
) {
507 case REQ_RANGE_LOCAL
:
508 return can_player_see_hypotetic_units_at(pow_player
, target_tile
);
509 case REQ_RANGE_CADJACENT
:
510 if (!can_player_see_hypotetic_units_at(pow_player
, target_tile
)) {
513 cardinal_adjc_iterate(target_tile
, adjc_tile
) {
514 if (!can_player_see_hypotetic_units_at(pow_player
, adjc_tile
)) {
517 } cardinal_adjc_iterate_end
;
520 case REQ_RANGE_ADJACENT
:
521 if (!can_player_see_hypotetic_units_at(pow_player
, target_tile
)) {
524 adjc_iterate(target_tile
, adjc_tile
) {
525 if (!can_player_see_hypotetic_units_at(pow_player
, adjc_tile
)) {
531 case REQ_RANGE_CONTINENT
:
533 case REQ_RANGE_TRADEROUTE
:
534 case REQ_RANGE_PLAYER
:
536 case REQ_RANGE_ALLIANCE
:
537 case REQ_RANGE_WORLD
:
538 case REQ_RANGE_COUNT
:
544 if (req
->source
.kind
== VUT_TERRAIN
545 || req
->source
.kind
== VUT_TERRFLAG
546 || req
->source
.kind
== VUT_TERRAINCLASS
547 || req
->source
.kind
== VUT_RESOURCE
548 || req
->source
.kind
== VUT_EXTRA
549 || req
->source
.kind
== VUT_EXTRAFLAG
550 || req
->source
.kind
== VUT_BASEFLAG
551 || req
->source
.kind
== VUT_BASEFLAG
) {
552 if (target_tile
== NULL
) {
553 /* The tile may exist but not be passed when the problem type is
555 return prob_type
== RPT_CERTAIN
;
558 switch (req
->range
) {
559 case REQ_RANGE_LOCAL
:
560 return is_tile_seen(pow_player
, target_tile
);
561 case REQ_RANGE_CADJACENT
:
562 /* TODO: The answer is known when the universal is located on a seen
563 * tile. Is returning TRUE in those cases worth the added complexity
564 * and the extra work for the computer? */
565 return is_tile_seen_cadj(pow_player
, target_tile
);
566 case REQ_RANGE_ADJACENT
:
567 /* TODO: The answer is known when the universal is located on a seen
568 * tile. Is returning TRUE in those cases worth the added complexity
569 * and the extra work for the computer? */
570 return is_tile_seen_adj(pow_player
, target_tile
);
572 /* TODO: The answer is known when the universal is located on a seen
573 * tile. Is returning TRUE in those cases worth the added complexity
574 * and the extra work for the computer? */
575 return is_tile_seen_city(pow_player
, target_city
);
576 case REQ_RANGE_TRADEROUTE
:
577 /* TODO: The answer is known when the universal is located on a seen
578 * tile. Is returning TRUE in those cases worth the added complexity
579 * and the extra work for the computer? */
580 return is_tile_seen_traderoute(pow_player
, target_city
);
581 case REQ_RANGE_CONTINENT
:
582 case REQ_RANGE_PLAYER
:
583 case REQ_RANGE_ALLIANCE
:
585 case REQ_RANGE_WORLD
:
586 case REQ_RANGE_COUNT
:
587 /* Non existing range for requirement types. */
592 if (req
->source
.kind
== VUT_OTYPE
) {
593 /* This requirement type is intended to specify the situation. */
597 /* Uncertain or no support added yet. */
601 /**************************************************************************
602 Evaluate a single requirement given pow_player's knowledge.
604 Note: Assumed to use pow_player's data.
605 **************************************************************************/
607 mke_eval_req(const struct player
*pow_player
,
608 const struct player
*target_player
,
609 const struct player
*other_player
,
610 const struct city
*target_city
,
611 const struct impr_type
*target_building
,
612 const struct tile
*target_tile
,
613 const struct unit
*target_unit
,
614 const struct output_type
*target_output
,
615 const struct specialist
*target_specialist
,
616 const struct requirement
*req
,
617 const enum req_problem_type prob_type
)
619 const struct unit_type
*target_unittype
;
621 if (!is_req_knowable(pow_player
, target_player
, other_player
,
622 target_city
, target_building
, target_tile
,
623 target_unit
, target_output
,
624 target_specialist
, req
, prob_type
)) {
629 target_unittype
= unit_type_get(target_unit
);
631 target_unittype
= NULL
;
634 if (is_req_active(target_player
, other_player
, target_city
,
635 target_building
, target_tile
, target_unit
, target_unittype
,
636 target_output
, target_specialist
, req
, prob_type
)) {
643 /**************************************************************************
644 Evaluate a requirement vector given pow_player's knowledge.
646 Note: Assumed to use pow_player's data.
647 **************************************************************************/
649 mke_eval_reqs(const struct player
*pow_player
,
650 const struct player
*target_player
,
651 const struct player
*other_player
,
652 const struct city
*target_city
,
653 const struct impr_type
*target_building
,
654 const struct tile
*target_tile
,
655 const struct unit
*target_unit
,
656 const struct output_type
*target_output
,
657 const struct specialist
*target_specialist
,
658 const struct requirement_vector
*reqs
,
659 const enum req_problem_type prob_type
)
661 enum fc_tristate current
;
662 enum fc_tristate result
;
665 requirement_vector_iterate(reqs
, preq
) {
666 current
= mke_eval_req(pow_player
, target_player
, other_player
,
667 target_city
, target_building
, target_tile
,
668 target_unit
, target_output
,
669 target_specialist
, preq
, prob_type
);
670 if (current
== TRI_NO
) {
672 } else if (current
== TRI_MAYBE
) {
675 } requirement_vector_iterate_end
;
680 /**************************************************************************
681 Can pow_player see the techs of target player?
682 **************************************************************************/
683 bool can_see_techs_of_target(const struct player
*pow_player
,
684 const struct player
*target_player
)
686 return pow_player
== target_player
687 || player_has_embassy(pow_player
, target_player
);
690 /**************************************************************************
691 Returns TRUE iff pow_player can see externally visible features of
694 Those are visible to its owner, to players that currently sees its city
695 tile and to players that has it as a trade partner.
696 **************************************************************************/
697 bool mke_can_see_city_externals(const struct player
*pow_player
,
698 const struct city
*target_city
) {
699 fc_assert_ret_val(target_city
, FALSE
);
700 fc_assert_ret_val(pow_player
, FALSE
);
702 if (can_player_see_city_internals(pow_player
, target_city
)) {
703 /* City internals includes city externals. */
707 if (is_tile_seen(pow_player
, city_tile(target_city
))) {
708 /* The tile is being observed. */
712 trade_routes_iterate(target_city
, trade_city
) {
713 if (city_owner(trade_city
) == pow_player
) {
714 /* Revealed because of the trade route. */
717 } trade_routes_iterate_end
;