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.
7 
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 
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17 
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"
25 
26 /**************************************************************************
27   Returns TRUE iff the target_tile it self and all tiles cardinally
28   adjacent to it are seen by pow_player.
29 **************************************************************************/
is_tile_seen_cadj(const struct player * pow_player,const struct tile * target_tile)30 static bool is_tile_seen_cadj(const struct player *pow_player,
31                               const struct tile *target_tile)
32 {
33   /* The tile it self is unseen. */
34   if (!tile_is_seen(target_tile, pow_player)) {
35     return FALSE;
36   }
37 
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;
42     }
43   } cardinal_adjc_iterate_end;
44 
45   /* They are all seen. */
46   return TRUE;
47 }
48 
49 /**************************************************************************
50   Returns TRUE iff the target_tile it self and all tiles adjacent to it
51   are seen by pow_player.
52 **************************************************************************/
is_tile_seen_adj(const struct player * pow_player,const struct tile * target_tile)53 static bool is_tile_seen_adj(const struct player *pow_player,
54                              const struct tile *target_tile)
55 {
56   /* The tile it self is unseen. */
57   if (!tile_is_seen(target_tile, pow_player)) {
58     return FALSE;
59   }
60 
61   /* An adjacent tile is unseen. */
62   adjc_iterate(target_tile, ptile) {
63     if (!tile_is_seen(ptile, pow_player)) {
64       return FALSE;
65     }
66   } adjc_iterate_end;
67 
68   /* They are all seen. */
69   return TRUE;
70 }
71 
72 /**************************************************************************
73   Returns TRUE iff all tiles of a city are seen by pow_player.
74 **************************************************************************/
is_tile_seen_city(const struct player * pow_player,const struct city * target_city)75 static bool is_tile_seen_city(const struct player *pow_player,
76                               const struct city *target_city)
77 {
78   /* Don't know the city radius. */
79   if (!can_player_see_city_internals(pow_player, target_city)) {
80     return FALSE;
81   }
82 
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;
88     }
89   } city_tile_iterate_end;
90 
91   /* They are all seen. */
92   return TRUE;
93 }
94 
95 /**************************************************************************
96   Returns TRUE iff all tiles of a city an all tiles of its trade partners
97   are seen by pow_player.
98 **************************************************************************/
is_tile_seen_traderoute(const struct player * pow_player,const struct city * target_city)99 static bool is_tile_seen_traderoute(const struct player *pow_player,
100                                     const struct city *target_city)
101 {
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;
105   }
106 
107   /* A tile of the city is unseen */
108   if (!is_tile_seen_city(pow_player, target_city)) {
109     return FALSE;
110   }
111 
112   /* A tile of a trade parter is unseen */
113   trade_routes_iterate(target_city, trade_partner) {
114     if (!is_tile_seen_city(pow_player, trade_partner)) {
115       return FALSE;
116     }
117   } trade_routes_iterate_end;
118 
119   /* They are all seen. */
120   return TRUE;
121 }
122 
123 /**************************************************************************
124   Returns TRUE iff pplayer can see all the symmetric diplomatic
125   relationships of tplayer.
126 **************************************************************************/
can_plr_see_all_sym_diplrels_of(const struct player * pplayer,const struct player * tplayer)127 static bool can_plr_see_all_sym_diplrels_of(const struct player *pplayer,
128                                             const struct player *tplayer)
129 {
130   if (pplayer == tplayer) {
131     /* Can see own relationships. */
132     return TRUE;
133   }
134 
135   if (player_has_embassy(pplayer, tplayer)) {
136     /* Gets reports from the embassy. */
137     return TRUE;
138   }
139 
140   if (player_diplstate_get(pplayer, tplayer)->contact_turns_left > 0) {
141     /* Can see relationships during contact turns. */
142     return TRUE;
143   }
144 
145   return FALSE;
146 }
147 
148 /**************************************************************************
149   Is an evaluation of the requirement accurate when pow_player evaluates
150   it?
151 
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 **************************************************************************/
is_req_knowable(const struct player * pow_player,const struct player * target_player,const struct player * other_player,const struct city * target_city,const struct impr_type * target_building,const struct tile * target_tile,const struct unit * target_unit,const struct output_type * target_output,const struct specialist * target_specialist,const struct requirement * req,const enum req_problem_type prob_type)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)
167 {
168   fc_assert_ret_val_msg(NULL != pow_player, false, "No point of view");
169 
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;
182       }
183 
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;
196     }
197   }
198 
199   if (req->source.kind == VUT_UNITSTATE) {
200     fc_assert_ret_val_msg(req->range == REQ_RANGE_LOCAL, FALSE, "Wrong range");
201 
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;
206     }
207 
208     switch (req->source.value.unit_state) {
209     case USP_TRANSPORTED:
210     case USP_LIVABLE_TILE:
211       /* Known if the unit is seen by the player. */
212       return target_unit && can_player_see_unit(pow_player, target_unit);
213     case USP_COUNT:
214       fc_assert_msg(req->source.value.unit_state != USP_COUNT,
215                     "Invalid unit state property.");
216       /* Invalid property is unknowable. */
217       return FALSE;
218     }
219   }
220 
221   if (req->source.kind == VUT_MINMOVES) {
222     fc_assert_ret_val_msg(req->range == REQ_RANGE_LOCAL, FALSE, "Wrong range");
223 
224     if (target_unit == NULL) {
225       /* The unit may exist but not be passed when the problem type is
226        * RPT_POSSIBLE. */
227       return prob_type == RPT_CERTAIN;
228     }
229 
230     switch (req->range) {
231     case REQ_RANGE_LOCAL:
232       /* The owner can see if his unit has move fragments left. */
233       return unit_owner(target_unit) == pow_player;
234     case REQ_RANGE_CADJACENT:
235     case REQ_RANGE_ADJACENT:
236     case REQ_RANGE_CITY:
237     case REQ_RANGE_TRADEROUTE:
238     case REQ_RANGE_CONTINENT:
239     case REQ_RANGE_PLAYER:
240     case REQ_RANGE_TEAM:
241     case REQ_RANGE_ALLIANCE:
242     case REQ_RANGE_WORLD:
243     case REQ_RANGE_COUNT:
244       /* Invalid range */
245       return FALSE;
246     }
247   }
248 
249   if (req->source.kind == VUT_DIPLREL) {
250     switch (req->range) {
251     case REQ_RANGE_LOCAL:
252       if (other_player == NULL
253           || target_player == NULL) {
254         /* The two players may exist but not be passed when the problem
255          * type is RPT_POSSIBLE. */
256         return prob_type == RPT_CERTAIN;
257       }
258 
259       if (pow_player == target_player
260           || pow_player == other_player)  {
261         return TRUE;
262       }
263 
264       if (can_plr_see_all_sym_diplrels_of(pow_player, target_player)
265           || can_plr_see_all_sym_diplrels_of(pow_player, other_player)) {
266         return TRUE;
267       }
268 
269       /* TODO: Non symmetric diplomatic relationships. */
270       break;
271     case REQ_RANGE_PLAYER:
272       if (target_player == NULL) {
273         /* The target player may exist but not be passed when the problem
274          * type is RPT_POSSIBLE. */
275         return prob_type == RPT_CERTAIN;
276       }
277 
278       if (pow_player == target_player) {
279         return TRUE;
280       }
281 
282       if (can_plr_see_all_sym_diplrels_of(pow_player, target_player)) {
283         return TRUE;
284       }
285 
286       /* TODO: Non symmetric diplomatic relationships. */
287       break;
288     case REQ_RANGE_TEAM:
289       /* TODO */
290       break;
291     case REQ_RANGE_ALLIANCE:
292       /* TODO */
293       break;
294     case REQ_RANGE_WORLD:
295       /* TODO */
296       break;
297     case REQ_RANGE_CADJACENT:
298     case REQ_RANGE_ADJACENT:
299     case REQ_RANGE_CITY:
300     case REQ_RANGE_TRADEROUTE:
301     case REQ_RANGE_CONTINENT:
302     case REQ_RANGE_COUNT:
303       /* Invalid range */
304       return FALSE;
305       break;
306     }
307   }
308 
309   if (req->source.kind == VUT_MINSIZE) {
310     if (target_city == NULL) {
311       /* The city may exist but not be passed when the problem type is
312        * RPT_POSSIBLE. */
313       return prob_type == RPT_CERTAIN;
314     }
315 
316     if (player_can_see_city_externals(pow_player, target_city)) {
317       return TRUE;
318     }
319   }
320 
321   if (req->source.kind == VUT_CITYTILE) {
322     struct city *pcity;
323 
324     if (target_tile == NULL) {
325       /* The tile may exist but not be passed when the problem type is
326        * RPT_POSSIBLE. */
327       return prob_type == RPT_CERTAIN;
328     }
329 
330     switch (req->range) {
331     case REQ_RANGE_LOCAL:
332       /* Known because the tile is seen */
333       if (tile_is_seen(target_tile, pow_player)) {
334         return TRUE;
335       }
336 
337       /* The player knows its city even if he can't see it */
338       pcity = tile_city(target_tile);
339       return pcity && city_owner(pcity) == pow_player;
340     case REQ_RANGE_CADJACENT:
341       /* Known because the tile is seen */
342       if (is_tile_seen_cadj(pow_player, target_tile)) {
343         return TRUE;
344       }
345 
346       /* The player knows its city even if he can't see it */
347       cardinal_adjc_iterate(target_tile, ptile) {
348         pcity = tile_city(ptile);
349         if (pcity && city_owner(pcity) == pow_player) {
350           return TRUE;
351         }
352       } cardinal_adjc_iterate_end;
353 
354       /* Unknown */
355       return FALSE;
356     case REQ_RANGE_ADJACENT:
357       /* Known because the tile is seen */
358       if (is_tile_seen_adj(pow_player, target_tile)) {
359         return TRUE;
360       }
361 
362       /* The player knows its city even if he can't see it */
363       adjc_iterate(target_tile, ptile) {
364         pcity = tile_city(ptile);
365         if (pcity && city_owner(pcity) == pow_player) {
366           return TRUE;
367         }
368       } adjc_iterate_end;
369 
370       /* Unknown */
371       return FALSE;
372     case REQ_RANGE_CITY:
373     case REQ_RANGE_TRADEROUTE:
374     case REQ_RANGE_CONTINENT:
375     case REQ_RANGE_PLAYER:
376     case REQ_RANGE_TEAM:
377     case REQ_RANGE_ALLIANCE:
378     case REQ_RANGE_WORLD:
379     case REQ_RANGE_COUNT:
380       /* Invalid range */
381       return FALSE;
382     }
383   }
384 
385   if (req->source.kind == VUT_IMPROVEMENT) {
386     switch (req->range) {
387     case REQ_RANGE_WORLD:
388     case REQ_RANGE_ALLIANCE:
389     case REQ_RANGE_TEAM:
390     case REQ_RANGE_PLAYER:
391     case REQ_RANGE_CONTINENT:
392       /* Only wonders (great or small) can be required in those ranges.
393        * Wonders are always visible. */
394       return TRUE;
395     case REQ_RANGE_TRADEROUTE:
396       /* Could be known for trade routes to cities owned by pow_player as
397        * long as the requirement is present. Not present requirements would
398        * require knowledge that no trade routes to another foreign city
399        * exists (since all possible trade routes are to a city owned by
400        * pow_player). Not worth the complexity, IMHO. */
401       return FALSE;
402     case REQ_RANGE_CITY:
403     case REQ_RANGE_LOCAL:
404       if (!target_city) {
405         /* RPT_CERTAIN: Can't be. No city to contain it.
406          * RPT_POSSIBLE: A city like that may exist but not be passed. */
407         return prob_type == RPT_CERTAIN;
408       }
409 
410       if (can_player_see_city_internals(pow_player, target_city)) {
411         /* Anyone that can see city internals (like the owner) known all
412          * its improvements. */
413         return TRUE;
414       }
415 
416       if (is_improvement_visible(req->source.value.building)
417           && player_can_see_city_externals(pow_player, target_city)) {
418         /* Can see visible improvements when the outside of the city is
419          * seen. */
420         return TRUE;
421       }
422 
423       /* No way to know if a city has an improvement */
424       return FALSE;
425     case REQ_RANGE_CADJACENT:
426     case REQ_RANGE_ADJACENT:
427     case REQ_RANGE_COUNT:
428       /* Not supported by the requirement type. */
429       return FALSE;
430     }
431   }
432 
433   if (req->source.kind == VUT_NATION
434       || req->source.kind == VUT_NATIONGROUP) {
435     if (!target_player
436         && (req->range == REQ_RANGE_PLAYER
437             || req->range == REQ_RANGE_TEAM
438             || req->range == REQ_RANGE_ALLIANCE)) {
439       /* The player (that can have a nationality or be alllied to someone
440        * with the nationality) may exist but not be passed when the problem
441        * type is RPT_POSSIBLE. */
442       return prob_type == RPT_CERTAIN;
443     }
444 
445     return TRUE;
446   }
447 
448   if (req->source.kind == VUT_ADVANCE || req->source.kind == VUT_TECHFLAG) {
449     if (req->range == REQ_RANGE_PLAYER) {
450       if (!target_player) {
451         /* The player (that may or may not possess the tech) may exist but
452          * not be passed when the problem type is RPT_POSSIBLE. */
453         return prob_type == RPT_CERTAIN;
454       }
455 
456       return can_see_techs_of_target(pow_player, target_player);
457     } else if (req->range == REQ_RANGE_WORLD && req->survives) {
458       /* game.info.global_advances is sent to each player */
459       return TRUE;
460     }
461   }
462 
463   if (req->source.kind == VUT_GOVERNMENT) {
464     if (req->range == REQ_RANGE_PLAYER) {
465       if (!target_player) {
466         /* The player (that may or may not possess the tech) may exist but
467          * not be passed when the problem type is RPT_POSSIBLE. */
468         return prob_type == RPT_CERTAIN;
469       }
470 
471       return (pow_player == target_player
472               || could_intel_with_player(pow_player, target_player));
473     }
474   }
475 
476   if (req->source.kind == VUT_MAXTILEUNITS) {
477     if (target_tile == NULL) {
478       /* The tile may exist but not be passed when the problem type is
479        * RPT_POSSIBLE. */
480       return prob_type == RPT_CERTAIN;
481     }
482 
483     switch (req->range) {
484     case REQ_RANGE_LOCAL:
485       return can_player_see_hypotetic_units_at(pow_player, target_tile);
486     case REQ_RANGE_CADJACENT:
487       if (!can_player_see_hypotetic_units_at(pow_player, target_tile)) {
488         return FALSE;
489       }
490       cardinal_adjc_iterate(target_tile, adjc_tile) {
491         if (!can_player_see_hypotetic_units_at(pow_player, adjc_tile)) {
492           return FALSE;
493         }
494       } cardinal_adjc_iterate_end;
495 
496       return TRUE;
497     case REQ_RANGE_ADJACENT:
498       if (!can_player_see_hypotetic_units_at(pow_player, target_tile)) {
499         return FALSE;
500       }
501       adjc_iterate(target_tile, adjc_tile) {
502         if (!can_player_see_hypotetic_units_at(pow_player, adjc_tile)) {
503           return FALSE;
504         }
505       } adjc_iterate_end;
506 
507       return TRUE;
508     case REQ_RANGE_CONTINENT:
509     case REQ_RANGE_CITY:
510     case REQ_RANGE_TRADEROUTE:
511     case REQ_RANGE_PLAYER:
512     case REQ_RANGE_TEAM:
513     case REQ_RANGE_ALLIANCE:
514     case REQ_RANGE_WORLD:
515     case REQ_RANGE_COUNT:
516       /* Non existing. */
517       return FALSE;
518     }
519   }
520 
521   if (req->source.kind == VUT_TERRAIN
522       || req->source.kind == VUT_TERRFLAG
523       || req->source.kind == VUT_TERRAINCLASS
524       || req->source.kind == VUT_TERRAINALTER
525       || req->source.kind == VUT_RESOURCE
526       || req->source.kind == VUT_EXTRA
527       || req->source.kind == VUT_EXTRAFLAG
528       || req->source.kind == VUT_BASEFLAG
529       || req->source.kind == VUT_ROADFLAG) {
530     if (target_tile == NULL) {
531       /* The tile may exist but not be passed when the problem type is
532        * RPT_POSSIBLE. */
533       return prob_type == RPT_CERTAIN;
534     }
535 
536     switch (req->range) {
537     case REQ_RANGE_LOCAL:
538       return tile_is_seen(target_tile, pow_player);
539     case REQ_RANGE_CADJACENT:
540       /* TODO: The answer is known when the universal is located on a seen
541        * tile. Is returning TRUE in those cases worth the added complexity
542        * and the extra work for the computer? */
543       return is_tile_seen_cadj(pow_player, target_tile);
544     case REQ_RANGE_ADJACENT:
545       /* TODO: The answer is known when the universal is located on a seen
546        * tile. Is returning TRUE in those cases worth the added complexity
547        * and the extra work for the computer? */
548       return is_tile_seen_adj(pow_player, target_tile);
549     case REQ_RANGE_CITY:
550       /* TODO: The answer is known when the universal is located on a seen
551        * tile. Is returning TRUE in those cases worth the added complexity
552        * and the extra work for the computer? */
553       return is_tile_seen_city(pow_player, target_city);
554     case REQ_RANGE_TRADEROUTE:
555       /* TODO: The answer is known when the universal is located on a seen
556        * tile. Is returning TRUE in those cases worth the added complexity
557        * and the extra work for the computer? */
558       return is_tile_seen_traderoute(pow_player, target_city);
559     case REQ_RANGE_CONTINENT:
560     case REQ_RANGE_PLAYER:
561     case REQ_RANGE_ALLIANCE:
562     case REQ_RANGE_TEAM:
563     case REQ_RANGE_WORLD:
564     case REQ_RANGE_COUNT:
565       /* Non existing range for requirement types. */
566       return FALSE;
567     }
568   }
569 
570   if (req->source.kind == VUT_OTYPE) {
571     /* This requirement type is intended to specify the situation. */
572     return TRUE;
573   }
574 
575   /* Uncertain or no support added yet. */
576   return FALSE;
577 }
578 
579 /**************************************************************************
580   Evaluate a single requirement given pow_player's knowledge.
581 
582   Note: Assumed to use pow_player's data.
583 **************************************************************************/
584 enum fc_tristate
mke_eval_req(const struct player * pow_player,const struct player * target_player,const struct player * other_player,const struct city * target_city,const struct impr_type * target_building,const struct tile * target_tile,const struct unit * target_unit,const struct output_type * target_output,const struct specialist * target_specialist,const struct requirement * req,const enum req_problem_type prob_type)585 mke_eval_req(const struct player *pow_player,
586              const struct player *target_player,
587              const struct player *other_player,
588              const struct city *target_city,
589              const struct impr_type *target_building,
590              const struct tile *target_tile,
591              const struct unit *target_unit,
592              const struct output_type *target_output,
593              const struct specialist *target_specialist,
594              const struct requirement *req,
595              const enum   req_problem_type prob_type)
596 {
597   const struct unit_type *target_unittype;
598 
599   if (!is_req_knowable(pow_player, target_player, other_player,
600                        target_city, target_building, target_tile,
601                        target_unit, target_output,
602                        target_specialist, req, prob_type)) {
603     return TRI_MAYBE;
604   }
605 
606   if (target_unit) {
607     target_unittype = unit_type_get(target_unit);
608   } else {
609     target_unittype = NULL;
610   }
611 
612   if (is_req_active(target_player, other_player, target_city,
613                     target_building, target_tile, target_unit, target_unittype,
614                     target_output, target_specialist, req, prob_type)) {
615     return TRI_YES;
616   } else {
617     return TRI_NO;
618   }
619 }
620 
621 /**************************************************************************
622   Evaluate a requirement vector given pow_player's knowledge.
623 
624   Note: Assumed to use pow_player's data.
625 **************************************************************************/
626 enum fc_tristate
mke_eval_reqs(const struct player * pow_player,const struct player * target_player,const struct player * other_player,const struct city * target_city,const struct impr_type * target_building,const struct tile * target_tile,const struct unit * target_unit,const struct output_type * target_output,const struct specialist * target_specialist,const struct requirement_vector * reqs,const enum req_problem_type prob_type)627 mke_eval_reqs(const struct player *pow_player,
628               const struct player *target_player,
629               const struct player *other_player,
630               const struct city *target_city,
631               const struct impr_type *target_building,
632               const struct tile *target_tile,
633               const struct unit *target_unit,
634               const struct output_type *target_output,
635               const struct specialist *target_specialist,
636               const struct requirement_vector *reqs,
637               const enum   req_problem_type prob_type)
638 {
639   enum fc_tristate current;
640   enum fc_tristate result;
641 
642   result = TRI_YES;
643   requirement_vector_iterate(reqs, preq) {
644     current = mke_eval_req(pow_player, target_player, other_player,
645                            target_city, target_building, target_tile,
646                            target_unit, target_output,
647                            target_specialist, preq, prob_type);
648     if (current == TRI_NO) {
649       return TRI_NO;
650     } else if (current == TRI_MAYBE) {
651       result = TRI_MAYBE;
652     }
653   } requirement_vector_iterate_end;
654 
655   return result;
656 }
657 
658 /**************************************************************************
659   Can pow_player see the techs of target player?
660 **************************************************************************/
can_see_techs_of_target(const struct player * pow_player,const struct player * target_player)661 bool can_see_techs_of_target(const struct player *pow_player,
662                              const struct player *target_player)
663 {
664   return pow_player == target_player
665       || player_has_embassy(pow_player, target_player);
666 }
667