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