Stop sharing requirement_unit_state_ereq().
[freeciv.git] / common / metaknowledge.c
blob42d8eab79088711abec8737e1e5c61b9ea73d012
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)
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 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 /* common */
19 #include "diptreaty.h"
20 #include "game.h"
21 #include "map.h"
22 #include "metaknowledge.h"
23 #include "tile.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)) {
35 return FALSE;
38 /* A cardinally adjacent tile is unseen. */
39 cardinal_adjc_iterate(target_tile, ptile) {
40 if (!tile_is_seen(ptile, pow_player)) {
41 return FALSE;
43 } cardinal_adjc_iterate_end;
45 /* They are all seen. */
46 return TRUE;
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)) {
58 return FALSE;
61 /* An adjacent tile is unseen. */
62 adjc_iterate(target_tile, ptile) {
63 if (!tile_is_seen(ptile, pow_player)) {
64 return FALSE;
66 } adjc_iterate_end;
68 /* They are all seen. */
69 return TRUE;
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)) {
80 return FALSE;
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)) {
87 return FALSE;
89 } city_tile_iterate_end;
91 /* They are all seen. */
92 return TRUE;
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)) {
104 return FALSE;
107 /* A tile of the city is unseen */
108 if (!is_tile_seen_city(pow_player, target_city)) {
109 return FALSE;
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)) {
115 return FALSE;
117 } trade_partners_iterate_end;
119 /* They are all seen. */
120 return TRUE;
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. */
132 return TRUE;
135 if (player_has_embassy(pplayer, tplayer)) {
136 /* Gets reports from the embassy. */
137 return TRUE;
140 if (player_diplstate_get(pplayer, tplayer)->contact_turns_left > 0) {
141 /* Can see relationships during contact turns. */
142 return TRUE;
145 return FALSE;
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
180 * RPT_POSSIBLE. */
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:
188 case REQ_RANGE_CITY:
189 case REQ_RANGE_TRADEROUTE:
190 case REQ_RANGE_PLAYER:
191 case REQ_RANGE_TEAM:
192 case REQ_RANGE_ALLIANCE:
193 case REQ_RANGE_WORLD:
194 case REQ_RANGE_COUNT:
195 return FALSE;
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
204 * RPT_POSSIBLE. */
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;
218 case USP_COUNT:
219 fc_assert_msg(req->source.value.unit_state != USP_COUNT,
220 "Invalid unit state property.");
221 /* Invalid property is unknowable. */
222 return FALSE;
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
231 * RPT_POSSIBLE. */
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:
241 case REQ_RANGE_CITY:
242 case REQ_RANGE_TRADEROUTE:
243 case REQ_RANGE_CONTINENT:
244 case REQ_RANGE_PLAYER:
245 case REQ_RANGE_TEAM:
246 case REQ_RANGE_ALLIANCE:
247 case REQ_RANGE_WORLD:
248 case REQ_RANGE_COUNT:
249 /* Invalid range */
250 return FALSE;
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) {
266 return TRUE;
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)) {
271 return TRUE;
274 /* TODO: Non symmetric diplomatic relationships. */
275 break;
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) {
284 return TRUE;
287 if (can_plr_see_all_sym_diplrels_of(pow_player, target_player)) {
288 return TRUE;
291 /* TODO: Non symmetric diplomatic relationships. */
292 break;
293 case REQ_RANGE_TEAM:
294 /* TODO */
295 break;
296 case REQ_RANGE_ALLIANCE:
297 /* TODO */
298 break;
299 case REQ_RANGE_WORLD:
300 /* TODO */
301 break;
302 case REQ_RANGE_CADJACENT:
303 case REQ_RANGE_ADJACENT:
304 case REQ_RANGE_CITY:
305 case REQ_RANGE_TRADEROUTE:
306 case REQ_RANGE_CONTINENT:
307 case REQ_RANGE_COUNT:
308 /* Invalid range */
309 return FALSE;
310 break;
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
317 * RPT_POSSIBLE. */
318 return prob_type == RPT_CERTAIN;
321 if (player_can_see_city_externals(pow_player, target_city)) {
322 return TRUE;
326 if (req->source.kind == VUT_CITYTILE) {
327 struct city *pcity;
329 if (target_tile == NULL) {
330 /* The tile may exist but not be passed when the problem type is
331 * RPT_POSSIBLE. */
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)) {
339 return TRUE;
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)) {
348 return TRUE;
351 /* The player knows its city even if he can't see it */
352 cardinal_adjc_iterate(target_tile, ptile) {
353 pcity = tile_city(ptile);
354 if (pcity && city_owner(pcity) == pow_player) {
355 return TRUE;
357 } cardinal_adjc_iterate_end;
359 /* Unknown */
360 return FALSE;
361 case REQ_RANGE_ADJACENT:
362 /* Known because the tile is seen */
363 if (is_tile_seen_adj(pow_player, target_tile)) {
364 return TRUE;
367 /* The player knows its city even if he can't see it */
368 adjc_iterate(target_tile, ptile) {
369 pcity = tile_city(ptile);
370 if (pcity && city_owner(pcity) == pow_player) {
371 return TRUE;
373 } adjc_iterate_end;
375 /* Unknown */
376 return FALSE;
377 case REQ_RANGE_CITY:
378 case REQ_RANGE_TRADEROUTE:
379 case REQ_RANGE_CONTINENT:
380 case REQ_RANGE_PLAYER:
381 case REQ_RANGE_TEAM:
382 case REQ_RANGE_ALLIANCE:
383 case REQ_RANGE_WORLD:
384 case REQ_RANGE_COUNT:
385 /* Invalid range */
386 return FALSE;
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);
394 if (!target_city) {
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:
408 case REQ_RANGE_TEAM:
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. */
413 return TRUE;
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. */
420 return FALSE;
421 case REQ_RANGE_CITY:
422 case REQ_RANGE_LOCAL:
423 if (!target_city) {
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. */
432 return TRUE;
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
438 * seen. */
439 return TRUE;
442 /* No way to know if a city has an improvement */
443 return FALSE;
444 case REQ_RANGE_CADJACENT:
445 case REQ_RANGE_ADJACENT:
446 case REQ_RANGE_COUNT:
447 /* Not supported by the requirement type. */
448 return FALSE;
452 if (req->source.kind == VUT_NATION
453 || req->source.kind == VUT_NATIONGROUP) {
454 if (!target_player
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;
464 return TRUE;
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
495 * RPT_POSSIBLE. */
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)) {
504 return FALSE;
506 cardinal_adjc_iterate(target_tile, adjc_tile) {
507 if (!can_player_see_hypotetic_units_at(pow_player, adjc_tile)) {
508 return FALSE;
510 } cardinal_adjc_iterate_end;
512 return TRUE;
513 case REQ_RANGE_ADJACENT:
514 if (!can_player_see_hypotetic_units_at(pow_player, target_tile)) {
515 return FALSE;
517 adjc_iterate(target_tile, adjc_tile) {
518 if (!can_player_see_hypotetic_units_at(pow_player, adjc_tile)) {
519 return FALSE;
521 } adjc_iterate_end;
523 return TRUE;
524 case REQ_RANGE_CONTINENT:
525 case REQ_RANGE_CITY:
526 case REQ_RANGE_TRADEROUTE:
527 case REQ_RANGE_PLAYER:
528 case REQ_RANGE_TEAM:
529 case REQ_RANGE_ALLIANCE:
530 case REQ_RANGE_WORLD:
531 case REQ_RANGE_COUNT:
532 /* Non existing. */
533 return FALSE;
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
546 * RPT_POSSIBLE. */
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);
563 case REQ_RANGE_CITY:
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:
576 case REQ_RANGE_TEAM:
577 case REQ_RANGE_WORLD:
578 case REQ_RANGE_COUNT:
579 /* Non existing range for requirement types. */
580 return FALSE;
584 if (req->source.kind == VUT_ACTION
585 || req->source.kind == VUT_OTYPE) {
586 /* This requirement type is intended to specify the situation. */
587 return TRUE;
590 /* Uncertain or no support added yet. */
591 return FALSE;
594 /**************************************************************************
595 Evaluate a single requirement given pow_player's knowledge.
597 Note: Assumed to use pow_player's data.
598 **************************************************************************/
599 enum fc_tristate
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)) {
618 return TRI_MAYBE;
621 if (target_unit) {
622 target_unittype = unit_type_get(target_unit);
623 } else {
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)) {
630 return TRI_YES;
631 } else {
632 return TRI_NO;
636 /**************************************************************************
637 Evaluate a requirement vector given pow_player's knowledge.
639 Note: Assumed to use pow_player's data.
640 **************************************************************************/
641 enum fc_tristate
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;
657 result = TRI_YES;
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) {
664 return TRI_NO;
665 } else if (current == TRI_MAYBE) {
666 result = TRI_MAYBE;
668 } requirement_vector_iterate_end;
670 return result;
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);