Find "best" transport from correct tile for transport dialog.
[freeciv.git] / common / extras.c
blob6a0039f0ecfd60d3ebcc12edd7f10af75d4458e4
1 /****************************************************************************
2 Freeciv - Copyright (C) 2004 - The Freeciv 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 /* utility */
19 #include "rand.h"
20 #include "string_vector.h"
22 /* common */
23 #include "base.h"
24 #include "game.h"
25 #include "map.h"
26 #include "road.h"
28 #include "extras.h"
30 static struct extra_type extras[MAX_EXTRA_TYPES];
32 static struct extra_type_list *category_extra[ECAT_COUNT];
33 static struct extra_type_list *caused_by[EC_LAST];
34 static struct extra_type_list *removed_by[ERM_COUNT];
36 /****************************************************************************
37 Initialize extras structures.
38 ****************************************************************************/
39 void extras_init(void)
41 int i;
43 for (i = 0; i < EC_LAST; i++) {
44 caused_by[i] = extra_type_list_new();
46 for (i = 0; i < ERM_COUNT; i++) {
47 removed_by[i] = extra_type_list_new();
49 for (i = 0; i < ECAT_COUNT; i++) {
50 category_extra[i] = extra_type_list_new();
53 for (i = 0; i < MAX_EXTRA_TYPES; i++) {
54 requirement_vector_init(&(extras[i].reqs));
55 requirement_vector_init(&(extras[i].rmreqs));
56 extras[i].id = i;
57 extras[i].hiders = NULL;
58 extras[i].data.special_idx = -1;
59 extras[i].data.base = NULL;
60 extras[i].data.road = NULL;
61 extras[i].causes = 0;
62 extras[i].rmcauses = 0;
63 extras[i].helptext = NULL;
67 /****************************************************************************
68 Free the memory associated with extras
69 ****************************************************************************/
70 void extras_free(void)
72 int i;
74 base_types_free();
75 road_types_free();
77 for (i = 0; i < game.control.num_extra_types; i++) {
78 if (extras[i].data.base != NULL) {
79 FC_FREE(extras[i].data.base);
80 extras[i].data.base = NULL;
82 if (extras[i].data.road != NULL) {
83 FC_FREE(extras[i].data.road);
84 extras[i].data.road = NULL;
88 for (i = 0; i < EC_LAST; i++) {
89 extra_type_list_destroy(caused_by[i]);
90 caused_by[i] = NULL;
93 for (i = 0; i < ERM_COUNT; i++) {
94 extra_type_list_destroy(removed_by[i]);
95 removed_by[i] = NULL;
98 for (i = 0; i < ECAT_COUNT; i++) {
99 extra_type_list_destroy(category_extra[i]);
100 category_extra[i] = NULL;
103 for (i = 0; i < MAX_EXTRA_TYPES; i++) {
104 requirement_vector_free(&(extras[i].reqs));
105 requirement_vector_free(&(extras[i].rmreqs));
107 if (NULL != extras[i].helptext) {
108 strvec_destroy(extras[i].helptext);
109 extras[i].helptext = NULL;
113 extra_type_iterate(pextra) {
114 if (pextra->hiders != NULL) {
115 extra_type_list_destroy(pextra->hiders);
116 pextra->hiders = NULL;
118 } extra_type_iterate_end;
121 /**************************************************************************
122 Return the number of extra_types.
123 **************************************************************************/
124 int extra_count(void)
126 return game.control.num_extra_types;
129 /**************************************************************************
130 Return the extra id.
131 **************************************************************************/
132 int extra_number(const struct extra_type *pextra)
134 fc_assert_ret_val(NULL != pextra, -1);
136 return pextra->id;
139 #ifndef extra_index
140 /**************************************************************************
141 Return the extra index.
142 **************************************************************************/
143 int extra_index(const struct extra_type *pextra)
145 fc_assert_ret_val(NULL != pextra, -1);
147 return pextra - extras;
149 #endif /* extra_index */
151 /****************************************************************************
152 Return extras type of given id.
153 ****************************************************************************/
154 struct extra_type *extra_by_number(int id)
156 fc_assert_ret_val(id >= 0 && id < MAX_EXTRA_TYPES, NULL);
158 return &extras[id];
161 /****************************************************************************
162 Get extra of the given special
163 ****************************************************************************/
164 struct extra_type *special_extra_get(int spe)
166 struct extra_type_list *elist = extra_type_list_by_cause(EC_SPECIAL);
168 if (spe < extra_type_list_size(elist)) {
169 return extra_type_list_get(elist, spe);
172 return NULL;
175 /**************************************************************************
176 Return the (translated) name of the extra type.
177 You don't have to free the return pointer.
178 **************************************************************************/
179 const char *extra_name_translation(const struct extra_type *pextra)
181 return name_translation_get(&pextra->name);
184 /**************************************************************************
185 Return the (untranslated) rule name of the extra type.
186 You don't have to free the return pointer.
187 **************************************************************************/
188 const char *extra_rule_name(const struct extra_type *pextra)
190 return rule_name_get(&pextra->name);
193 /**************************************************************************
194 Returns extra type matching rule name or NULL if there is no extra type
195 with such name.
196 **************************************************************************/
197 struct extra_type *extra_type_by_rule_name(const char *name)
199 const char *qs;
201 if (name == NULL) {
202 return NULL;
205 qs = Qn_(name);
207 extra_type_iterate(pextra) {
208 if (!fc_strcasecmp(extra_rule_name(pextra), qs)) {
209 return pextra;
211 } extra_type_iterate_end;
213 return NULL;
216 /**************************************************************************
217 Returns extra type matching the translated name, or NULL if there is no
218 extra type with that name.
219 **************************************************************************/
220 struct extra_type *extra_type_by_translated_name(const char *name)
222 extra_type_iterate(pextra) {
223 if (0 == strcmp(extra_name_translation(pextra), name)) {
224 return pextra;
226 } extra_type_iterate_end;
228 return NULL;
231 /**************************************************************************
232 Returns extra type for given cause.
233 **************************************************************************/
234 struct extra_type_list *extra_type_list_by_cause(enum extra_cause cause)
236 fc_assert(cause < EC_LAST);
238 return caused_by[cause];
241 /**************************************************************************
242 Returns extra types of the category.
243 **************************************************************************/
244 struct extra_type_list *extra_type_list_for_category(enum extra_category cat)
246 fc_assert(cat < ECAT_LAST);
248 return category_extra[cat];
251 /**************************************************************************
252 Return random extra type for given cause that is native to the tile.
253 **************************************************************************/
254 struct extra_type *rand_extra_for_tile(struct tile *ptile, enum extra_cause cause)
256 struct extra_type_list *full_list = extra_type_list_by_cause(cause);
257 struct extra_type_list *potential = extra_type_list_new();
258 int options;
259 struct extra_type *selected = NULL;
261 extra_type_list_iterate(full_list, pextra) {
262 if (is_native_tile_to_extra(pextra, ptile)) {
263 extra_type_list_append(potential, pextra);
265 } extra_type_list_iterate_end;
267 options = extra_type_list_size(potential);
269 if (options > 0) {
270 selected = extra_type_list_get(potential, fc_rand(options));
273 extra_type_list_destroy(potential);
275 return selected;
278 /**************************************************************************
279 Add extra type to list of extra caused by given cause.
280 **************************************************************************/
281 void extra_to_caused_by_list(struct extra_type *pextra, enum extra_cause cause)
283 fc_assert(cause < EC_LAST);
285 extra_type_list_append(caused_by[cause], pextra);
288 /**************************************************************************
289 Add extra type to list of extras of a category
290 **************************************************************************/
291 void extra_to_category_list(struct extra_type *pextra, enum extra_category cat)
293 fc_assert(cat < ECAT_LAST);
295 extra_type_list_append(category_extra[cat], pextra);
298 /**************************************************************************
299 Returns extra type for given rmcause.
300 **************************************************************************/
301 struct extra_type_list *extra_type_list_by_rmcause(enum extra_rmcause rmcause)
303 fc_assert(rmcause < ERM_COUNT);
305 return removed_by[rmcause];
308 /**************************************************************************
309 Add extra type to list of extra removed by given cause.
310 **************************************************************************/
311 void extra_to_removed_by_list(struct extra_type *pextra,
312 enum extra_rmcause rmcause)
314 fc_assert(rmcause < ERM_COUNT);
316 extra_type_list_append(removed_by[rmcause], pextra);
319 /**************************************************************************
320 Is given cause one of the removal causes for given extra?
321 **************************************************************************/
322 bool is_extra_removed_by(const struct extra_type *pextra,
323 enum extra_rmcause rmcause)
325 return (pextra->rmcauses & (1 << rmcause));
328 /****************************************************************************
329 Is there extra of the given type cardinally near tile?
330 (Does not check ptile itself.)
331 ****************************************************************************/
332 bool is_extra_card_near(const struct tile *ptile, const struct extra_type *pextra)
334 cardinal_adjc_iterate(ptile, adjc_tile) {
335 if (tile_has_extra(adjc_tile, pextra)) {
336 return TRUE;
338 } cardinal_adjc_iterate_end;
340 return FALSE;
343 /****************************************************************************
344 Is there extra of the given type near tile?
345 (Does not check ptile itself.)
346 ****************************************************************************/
347 bool is_extra_near_tile(const struct tile *ptile, const struct extra_type *pextra)
349 adjc_iterate(ptile, adjc_tile) {
350 if (tile_has_extra(adjc_tile, pextra)) {
351 return TRUE;
353 } adjc_iterate_end;
355 return FALSE;
358 /****************************************************************************
359 Tells if extra can build to tile if all other requirements are met.
360 ****************************************************************************/
361 bool extra_can_be_built(const struct extra_type *pextra,
362 const struct tile *ptile)
364 if (!pextra->buildable) {
365 /* Extra type not buildable */
366 return FALSE;
369 if (tile_has_extra(ptile, pextra)) {
370 /* Extra exist already */
371 return FALSE;
374 return TRUE;
377 /****************************************************************************
378 Tells if player can build extra to tile with suitable unit.
379 ****************************************************************************/
380 static bool can_build_extra_base(const struct extra_type *pextra,
381 const struct player *pplayer,
382 const struct tile *ptile)
384 if (is_extra_caused_by(pextra, EC_BASE)
385 && !base_can_be_built(extra_base_get(pextra), ptile)) {
386 return FALSE;
389 if (is_extra_caused_by(pextra, EC_ROAD)
390 && !can_build_road_base(extra_road_get(pextra), pplayer, ptile)) {
391 return FALSE;
394 if (!extra_can_be_built(pextra, ptile)) {
395 return FALSE;
398 return TRUE;
401 /****************************************************************************
402 Tells if player can build extra to tile with suitable unit.
403 ****************************************************************************/
404 bool player_can_build_extra(const struct extra_type *pextra,
405 const struct player *pplayer,
406 const struct tile *ptile)
408 if (!can_build_extra_base(pextra, pplayer, ptile)) {
409 return FALSE;
412 return are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile,
413 NULL, NULL, NULL, NULL, &pextra->reqs,
414 RPT_POSSIBLE);
417 /****************************************************************************
418 Tells if unit can build extra on tile.
419 ****************************************************************************/
420 bool can_build_extra(struct extra_type *pextra,
421 const struct unit *punit,
422 const struct tile *ptile)
424 struct player *pplayer = unit_owner(punit);
426 if (!can_build_extra_base(pextra, pplayer, ptile)) {
427 return FALSE;
430 return are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile,
431 punit, unit_type_get(punit), NULL, NULL, &pextra->reqs,
432 RPT_CERTAIN);
435 /****************************************************************************
436 Is it possible at all to remove this extra now
437 ****************************************************************************/
438 static bool can_extra_be_removed(const struct extra_type *pextra,
439 const struct tile *ptile)
441 struct city *pcity = tile_city(ptile);
443 /* Cannot remove EF_ALWAYS_ON_CITY_CENTER extras from city center. */
444 if (pcity != NULL) {
445 if (extra_has_flag(pextra, EF_ALWAYS_ON_CITY_CENTER)) {
446 return FALSE;
448 if (extra_has_flag(pextra, EF_AUTO_ON_CITY_CENTER)) {
449 struct tile *vtile = tile_virtual_new(ptile);
451 /* Would extra get rebuilt if removed */
452 tile_remove_extra(vtile, pextra);
453 if (player_can_build_extra(pextra, city_owner(pcity), vtile)) {
454 /* No need to worry about conflicting extras - extra would had
455 * not been here if conflicting one is. */
456 tile_virtual_destroy(vtile);
458 return FALSE;
461 tile_virtual_destroy(vtile);
465 return TRUE;
468 /****************************************************************************
469 Tells if player can remove extra from tile with suitable unit.
470 ****************************************************************************/
471 bool player_can_remove_extra(const struct extra_type *pextra,
472 const struct player *pplayer,
473 const struct tile *ptile)
475 if (!can_extra_be_removed(pextra, ptile)) {
476 return FALSE;
479 return are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile,
480 NULL, NULL, NULL, NULL, &pextra->rmreqs,
481 RPT_POSSIBLE);
484 /****************************************************************************
485 Tells if unit can remove extra from tile.
486 ****************************************************************************/
487 bool can_remove_extra(struct extra_type *pextra,
488 const struct unit *punit,
489 const struct tile *ptile)
491 struct player *pplayer;
493 if (!can_extra_be_removed(pextra, ptile)) {
494 return FALSE;
497 pplayer = unit_owner(punit);
499 return are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile,
500 punit, unit_type_get(punit), NULL, NULL,
501 &pextra->rmreqs, RPT_CERTAIN);
504 /****************************************************************************
505 Is tile native to extra?
506 ****************************************************************************/
507 bool is_native_tile_to_extra(const struct extra_type *pextra,
508 const struct tile *ptile)
510 struct terrain *pterr = tile_terrain(ptile);
512 if (is_extra_caused_by(pextra, EC_IRRIGATION)
513 && pterr->irrigation_result != pterr) {
514 return FALSE;
517 if (is_extra_caused_by(pextra, EC_MINE)
518 && pterr->mining_result != pterr) {
519 return FALSE;
522 if (is_extra_caused_by(pextra, EC_BASE)) {
523 if (pterr->base_time == 0) {
524 return FALSE;
526 if (tile_city(ptile) != NULL && extra_base_get(pextra)->border_sq >= 0) {
527 return FALSE;
531 if (is_extra_caused_by(pextra, EC_ROAD)) {
532 struct road_type *proad = extra_road_get(pextra);
534 if (road_has_flag(proad, RF_RIVER)) {
535 if (!terrain_has_flag(pterr, TER_CAN_HAVE_RIVER)) {
536 return FALSE;
538 } else if (pterr->road_time == 0) {
539 return FALSE;
543 return are_reqs_active(NULL, NULL, NULL, NULL, ptile,
544 NULL, NULL, NULL, NULL,
545 &pextra->reqs, RPT_POSSIBLE);
548 /****************************************************************************
549 Returns next extra by cause that unit or player can build to tile.
550 ****************************************************************************/
551 struct extra_type *next_extra_for_tile(const struct tile *ptile, enum extra_cause cause,
552 const struct player *pplayer,
553 const struct unit *punit)
555 if (cause == EC_IRRIGATION) {
556 struct terrain *pterrain = tile_terrain(ptile);
558 if (pterrain->irrigation_result != pterrain) {
559 /* No extra can be created by irrigation the tile */
560 return NULL;
563 if (cause == EC_MINE) {
564 struct terrain *pterrain = tile_terrain(ptile);
566 if (pterrain->mining_result != pterrain) {
567 /* No extra can be created by mining the tile */
568 return NULL;
572 extra_type_by_cause_iterate(cause, pextra) {
573 if (!tile_has_extra(ptile, pextra)) {
574 if (punit != NULL) {
575 if (can_build_extra(pextra, punit, ptile)) {
576 return pextra;
578 } else {
579 /* punit is certainly NULL, pplayer can be too */
580 if (player_can_build_extra(pextra, pplayer, ptile)) {
581 return pextra;
585 } extra_type_by_cause_iterate_end;
587 return NULL;
590 /****************************************************************************
591 Returns prev extra by cause that unit or player can remove from tile.
592 ****************************************************************************/
593 struct extra_type *prev_extra_in_tile(const struct tile *ptile,
594 enum extra_rmcause rmcause,
595 const struct player *pplayer,
596 const struct unit *punit)
598 fc_assert(punit != NULL || pplayer != NULL);
600 extra_type_by_rmcause_iterate(rmcause, pextra) {
601 if (tile_has_extra(ptile, pextra)) {
602 if (punit != NULL) {
603 if (can_remove_extra(pextra, punit, ptile)) {
604 return pextra;
606 } else {
607 if (player_can_remove_extra(pextra, pplayer, ptile)) {
608 return pextra;
612 } extra_type_by_rmcause_iterate_end;
614 return NULL;
617 /****************************************************************************
618 Is extra native to unit class?
619 ****************************************************************************/
620 bool is_native_extra_to_uclass(const struct extra_type *pextra,
621 const struct unit_class *pclass)
623 return BV_ISSET(pextra->native_to, uclass_index(pclass));
626 /****************************************************************************
627 Is extra native to unit type?
628 ****************************************************************************/
629 bool is_native_extra_to_utype(const struct extra_type *pextra,
630 const struct unit_type *punittype)
632 return is_native_extra_to_uclass(pextra, utype_class(punittype));
635 /****************************************************************************
636 Check if extra has given flag
637 ****************************************************************************/
638 bool extra_has_flag(const struct extra_type *pextra, enum extra_flag_id flag)
640 return BV_ISSET(pextra->flags, flag);
643 /****************************************************************************
644 Returns TRUE iff any cardinally adjacent tile contains an extra with
645 the given flag (does not check ptile itself).
646 ****************************************************************************/
647 bool is_extra_flag_card_near(const struct tile *ptile, enum extra_flag_id flag)
649 extra_type_iterate(pextra) {
650 if (extra_has_flag(pextra, flag)) {
651 cardinal_adjc_iterate(ptile, adjc_tile) {
652 if (tile_has_extra(adjc_tile, pextra)) {
653 return TRUE;
655 } cardinal_adjc_iterate_end;
657 } extra_type_iterate_end;
659 return FALSE;
662 /****************************************************************************
663 Returns TRUE iff any adjacent tile contains an extra with the given flag
664 (does not check ptile itself).
665 ****************************************************************************/
666 bool is_extra_flag_near_tile(const struct tile *ptile, enum extra_flag_id flag)
668 extra_type_iterate(pextra) {
669 if (extra_has_flag(pextra, flag)) {
670 adjc_iterate(ptile, adjc_tile) {
671 if (tile_has_extra(adjc_tile, pextra)) {
672 return TRUE;
674 } adjc_iterate_end;
676 } extra_type_iterate_end;
678 return FALSE;
681 /**************************************************************************
682 Can two extras coexist in same tile?
683 **************************************************************************/
684 bool can_extras_coexist(const struct extra_type *pextra1,
685 const struct extra_type *pextra2)
687 if (pextra1 == pextra2) {
688 return TRUE;
691 return !BV_ISSET(pextra1->conflicts, extra_index(pextra2));
694 /**************************************************************************
695 Does the extra count toward environment upset?
696 **************************************************************************/
697 bool extra_causes_env_upset(struct extra_type *pextra,
698 enum environment_upset_type upset)
700 switch (upset) {
701 case EUT_GLOBAL_WARMING:
702 return extra_has_flag(pextra, EF_GLOBAL_WARMING);
703 case EUT_NUCLEAR_WINTER:
704 return extra_has_flag(pextra, EF_NUCLEAR_WINTER);
707 return FALSE;
710 /**************************************************************************
711 Is given cause one of the causes for given extra?
712 **************************************************************************/
713 bool is_extra_caused_by(const struct extra_type *pextra, enum extra_cause cause)
715 /* There's some extra cause lists above EC_COUNT that do not have equivalent
716 * bit in pextra->causes */
717 fc_assert(cause < EC_COUNT);
719 return (pextra->causes & (1 << cause));
722 /**************************************************************************
723 Is the extra caused by some kind of worker action?
724 **************************************************************************/
725 bool is_extra_caused_by_worker_action(const struct extra_type *pextra)
727 /* Is any of the worker build action bits set? */
728 return (pextra->causes
729 & (1 << EC_IRRIGATION
730 | 1 << EC_MINE
731 | 1 << EC_BASE
732 | 1 << EC_ROAD));
735 /**************************************************************************
736 Is the extra removed by some kind of worker action?
737 **************************************************************************/
738 bool is_extra_removed_by_worker_action(const struct extra_type *pextra)
740 /* Is any of the worker remove action bits set? */
741 return (pextra->rmcauses
742 & (1 << ERM_CLEANPOLLUTION
743 | 1 << ERM_CLEANFALLOUT
744 | 1 << ERM_PILLAGE));
747 /**************************************************************************
748 Is the extra caused by specific worker action?
749 **************************************************************************/
750 bool is_extra_caused_by_action(const struct extra_type *pextra,
751 enum unit_activity act)
753 return is_extra_caused_by(pextra, activity_to_extra_cause(act));
756 /**************************************************************************
757 Is the extra removed by specific worker action?
758 **************************************************************************/
759 bool is_extra_removed_by_action(const struct extra_type *pextra,
760 enum unit_activity act)
762 return is_extra_removed_by(pextra, activity_to_extra_rmcause(act));
765 /**************************************************************************
766 What extra cause activity is considered to be?
767 **************************************************************************/
768 enum extra_cause activity_to_extra_cause(enum unit_activity act)
770 switch(act) {
771 case ACTIVITY_IRRIGATE:
772 return EC_IRRIGATION;
773 case ACTIVITY_MINE:
774 return EC_MINE;
775 case ACTIVITY_BASE:
776 return EC_BASE;
777 case ACTIVITY_GEN_ROAD:
778 return EC_ROAD;
779 default:
780 break;
783 return EC_NONE;
786 /**************************************************************************
787 What extra rmcause activity is considered to be?
788 **************************************************************************/
789 enum extra_rmcause activity_to_extra_rmcause(enum unit_activity act)
791 switch(act) {
792 case ACTIVITY_PILLAGE:
793 return ERM_PILLAGE;
794 case ACTIVITY_POLLUTION:
795 return ERM_CLEANPOLLUTION;
796 case ACTIVITY_FALLOUT:
797 return ERM_CLEANFALLOUT;
798 default:
799 break;
802 return ERM_NONE;
805 /**************************************************************************
806 Who owns extras on tile
807 **************************************************************************/
808 struct player *extra_owner(const struct tile *ptile)
810 return ptile->extras_owner;