Removed silencing of gtk warning logs from gtk3.22-client.
[freeciv.git] / common / metaknowledge.c
blob18aa6a6a8bddda904a3b600065d234da006066fb
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 An AND function for fc_tristate.
28 **************************************************************************/
29 enum fc_tristate tri_and(enum fc_tristate one,
30 enum fc_tristate two)
32 if (TRI_NO == one || TRI_NO == two) {
33 return TRI_NO;
36 if (TRI_MAYBE == one || TRI_MAYBE == two) {
37 return TRI_MAYBE;
40 return TRI_YES;
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)) {
61 return FALSE;
64 /* A cardinally adjacent tile is unseen. */
65 cardinal_adjc_iterate(target_tile, ptile) {
66 if (!is_tile_seen(pow_player, ptile)) {
67 return FALSE;
69 } cardinal_adjc_iterate_end;
71 /* They are all seen. */
72 return TRUE;
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)) {
84 return FALSE;
87 /* An adjacent tile is unseen. */
88 adjc_iterate(target_tile, ptile) {
89 if (!is_tile_seen(pow_player, ptile)) {
90 return FALSE;
92 } adjc_iterate_end;
94 /* They are all seen. */
95 return TRUE;
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)) {
106 return FALSE;
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)) {
113 return FALSE;
115 } city_tile_iterate_end;
117 /* They are all seen. */
118 return TRUE;
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)) {
130 return FALSE;
133 /* A tile of the city is unseen */
134 if (!is_tile_seen_city(pow_player, target_city)) {
135 return FALSE;
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)) {
141 return FALSE;
143 } trade_routes_iterate_end;
145 /* They are all seen. */
146 return TRUE;
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. */
158 return TRUE;
161 if (player_has_embassy(pplayer, tplayer)) {
162 /* Gets reports from the embassy. */
163 return TRUE;
166 if (player_diplstate_get(pplayer, tplayer)->contact_turns_left > 0) {
167 /* Can see relationships during contact turns. */
168 return TRUE;
171 return FALSE;
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
206 * RPT_POSSIBLE. */
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:
214 case REQ_RANGE_CITY:
215 case REQ_RANGE_TRADEROUTE:
216 case REQ_RANGE_PLAYER:
217 case REQ_RANGE_TEAM:
218 case REQ_RANGE_ALLIANCE:
219 case REQ_RANGE_WORLD:
220 case REQ_RANGE_COUNT:
221 return FALSE;
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
230 * RPT_POSSIBLE. */
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);
239 case USP_COUNT:
240 fc_assert_msg(req->source.value.unit_state != USP_COUNT,
241 "Invalid unit state property.");
242 /* Invalid property is unknowable. */
243 return FALSE;
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
252 * RPT_POSSIBLE. */
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:
262 case REQ_RANGE_CITY:
263 case REQ_RANGE_TRADEROUTE:
264 case REQ_RANGE_CONTINENT:
265 case REQ_RANGE_PLAYER:
266 case REQ_RANGE_TEAM:
267 case REQ_RANGE_ALLIANCE:
268 case REQ_RANGE_WORLD:
269 case REQ_RANGE_COUNT:
270 /* Invalid range */
271 return FALSE;
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) {
287 return TRUE;
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)) {
292 return TRUE;
295 /* TODO: Non symmetric diplomatic relationships. */
296 break;
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) {
305 return TRUE;
308 if (can_plr_see_all_sym_diplrels_of(pow_player, target_player)) {
309 return TRUE;
312 /* TODO: Non symmetric diplomatic relationships. */
313 break;
314 case REQ_RANGE_TEAM:
315 /* TODO */
316 break;
317 case REQ_RANGE_ALLIANCE:
318 /* TODO */
319 break;
320 case REQ_RANGE_WORLD:
321 /* TODO */
322 break;
323 case REQ_RANGE_CADJACENT:
324 case REQ_RANGE_ADJACENT:
325 case REQ_RANGE_CITY:
326 case REQ_RANGE_TRADEROUTE:
327 case REQ_RANGE_CONTINENT:
328 case REQ_RANGE_COUNT:
329 /* Invalid range */
330 return FALSE;
331 break;
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
338 * RPT_POSSIBLE. */
339 return prob_type == RPT_CERTAIN;
342 if (mke_can_see_city_externals(pow_player, target_city)) {
343 return TRUE;
347 if (req->source.kind == VUT_CITYTILE) {
348 struct city *pcity;
350 if (target_tile == NULL) {
351 /* The tile may exist but not be passed when the problem type is
352 * RPT_POSSIBLE. */
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)) {
360 return TRUE;
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)) {
369 return TRUE;
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) {
376 return TRUE;
378 } cardinal_adjc_iterate_end;
380 /* Unknown */
381 return FALSE;
382 case REQ_RANGE_ADJACENT:
383 /* Known because the tile is seen */
384 if (is_tile_seen_adj(pow_player, target_tile)) {
385 return TRUE;
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) {
392 return TRUE;
394 } adjc_iterate_end;
396 /* Unknown */
397 return FALSE;
398 case REQ_RANGE_CITY:
399 case REQ_RANGE_TRADEROUTE:
400 case REQ_RANGE_CONTINENT:
401 case REQ_RANGE_PLAYER:
402 case REQ_RANGE_TEAM:
403 case REQ_RANGE_ALLIANCE:
404 case REQ_RANGE_WORLD:
405 case REQ_RANGE_COUNT:
406 /* Invalid range */
407 return FALSE;
411 if (req->source.kind == VUT_IMPROVEMENT) {
412 switch (req->range) {
413 case REQ_RANGE_WORLD:
414 case REQ_RANGE_ALLIANCE:
415 case REQ_RANGE_TEAM:
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. */
420 return TRUE;
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. */
427 return FALSE;
428 case REQ_RANGE_CITY:
429 case REQ_RANGE_LOCAL:
430 if (!target_city) {
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. */
439 return TRUE;
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
445 * seen. */
446 return TRUE;
449 /* No way to know if a city has an improvement */
450 return FALSE;
451 case REQ_RANGE_CADJACENT:
452 case REQ_RANGE_ADJACENT:
453 case REQ_RANGE_COUNT:
454 /* Not supported by the requirement type. */
455 return FALSE;
459 if (req->source.kind == VUT_NATION
460 || req->source.kind == VUT_NATIONGROUP) {
461 if (!target_player
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;
471 return TRUE;
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
502 * RPT_POSSIBLE. */
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)) {
511 return FALSE;
513 cardinal_adjc_iterate(target_tile, adjc_tile) {
514 if (!can_player_see_hypotetic_units_at(pow_player, adjc_tile)) {
515 return FALSE;
517 } cardinal_adjc_iterate_end;
519 return TRUE;
520 case REQ_RANGE_ADJACENT:
521 if (!can_player_see_hypotetic_units_at(pow_player, target_tile)) {
522 return FALSE;
524 adjc_iterate(target_tile, adjc_tile) {
525 if (!can_player_see_hypotetic_units_at(pow_player, adjc_tile)) {
526 return FALSE;
528 } adjc_iterate_end;
530 return TRUE;
531 case REQ_RANGE_CONTINENT:
532 case REQ_RANGE_CITY:
533 case REQ_RANGE_TRADEROUTE:
534 case REQ_RANGE_PLAYER:
535 case REQ_RANGE_TEAM:
536 case REQ_RANGE_ALLIANCE:
537 case REQ_RANGE_WORLD:
538 case REQ_RANGE_COUNT:
539 /* Non existing. */
540 return FALSE;
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
554 * RPT_POSSIBLE. */
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);
571 case REQ_RANGE_CITY:
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:
584 case REQ_RANGE_TEAM:
585 case REQ_RANGE_WORLD:
586 case REQ_RANGE_COUNT:
587 /* Non existing range for requirement types. */
588 return FALSE;
592 if (req->source.kind == VUT_OTYPE) {
593 /* This requirement type is intended to specify the situation. */
594 return TRUE;
597 /* Uncertain or no support added yet. */
598 return FALSE;
601 /**************************************************************************
602 Evaluate a single requirement given pow_player's knowledge.
604 Note: Assumed to use pow_player's data.
605 **************************************************************************/
606 enum fc_tristate
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)) {
625 return TRI_MAYBE;
628 if (target_unit) {
629 target_unittype = unit_type_get(target_unit);
630 } else {
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)) {
637 return TRI_YES;
638 } else {
639 return TRI_NO;
643 /**************************************************************************
644 Evaluate a requirement vector given pow_player's knowledge.
646 Note: Assumed to use pow_player's data.
647 **************************************************************************/
648 enum fc_tristate
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;
664 result = TRI_YES;
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) {
671 return TRI_NO;
672 } else if (current == TRI_MAYBE) {
673 result = TRI_MAYBE;
675 } requirement_vector_iterate_end;
677 return result;
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
692 target_city.
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. */
704 return TRUE;
707 if (is_tile_seen(pow_player, city_tile(target_city))) {
708 /* The tile is being observed. */
709 return TRUE;
712 trade_routes_iterate(target_city, trade_city) {
713 if (city_owner(trade_city) == pow_player) {
714 /* Revealed because of the trade route. */
715 return TRUE;
717 } trade_routes_iterate_end;
719 return FALSE;