webperimental: killstack decides stack protects.
[freeciv.git] / common / extras.c
blob7e9401d088c0a364ed666d122d67cde841a5639f
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 "research.h"
27 #include "road.h"
29 #include "extras.h"
31 static struct extra_type extras[MAX_EXTRA_TYPES];
33 static struct user_flag user_extra_flags[MAX_NUM_USER_EXTRA_FLAGS];
35 static struct extra_type_list *category_extra[ECAT_COUNT];
36 static struct extra_type_list *caused_by[EC_LAST];
37 static struct extra_type_list *removed_by[ERM_COUNT];
38 static struct extra_type_list *unit_hidden;
40 /****************************************************************************
41 Initialize extras structures.
42 ****************************************************************************/
43 void extras_init(void)
45 int i;
47 for (i = 0; i < EC_LAST; i++) {
48 caused_by[i] = extra_type_list_new();
50 for (i = 0; i < ERM_COUNT; i++) {
51 removed_by[i] = extra_type_list_new();
53 for (i = 0; i < ECAT_COUNT; i++) {
54 category_extra[i] = extra_type_list_new();
56 unit_hidden = extra_type_list_new();
58 for (i = 0; i < MAX_EXTRA_TYPES; i++) {
59 requirement_vector_init(&(extras[i].reqs));
60 requirement_vector_init(&(extras[i].rmreqs));
61 requirement_vector_init(&(extras[i].appearance_reqs));
62 requirement_vector_init(&(extras[i].disappearance_reqs));
63 extras[i].id = i;
64 extras[i].hiders = NULL;
65 extras[i].data.special_idx = -1;
66 extras[i].data.base = NULL;
67 extras[i].data.road = NULL;
68 extras[i].data.resource = NULL;
69 extras[i].causes = 0;
70 extras[i].rmcauses = 0;
71 extras[i].helptext = NULL;
72 extras[i].disabled = FALSE;
73 extras[i].visibility_req = A_NONE;
77 /****************************************************************************
78 Free the memory associated with extras
79 ****************************************************************************/
80 void extras_free(void)
82 int i;
84 base_types_free();
85 road_types_free();
86 resource_types_free();
88 for (i = 0; i < game.control.num_extra_types; i++) {
89 if (extras[i].data.base != NULL) {
90 FC_FREE(extras[i].data.base);
91 extras[i].data.base = NULL;
93 if (extras[i].data.road != NULL) {
94 FC_FREE(extras[i].data.road);
95 extras[i].data.road = NULL;
97 if (extras[i].data.resource != NULL) {
98 FC_FREE(extras[i].data.resource);
99 extras[i].data.resource = NULL;
103 for (i = 0; i < EC_LAST; i++) {
104 extra_type_list_destroy(caused_by[i]);
105 caused_by[i] = NULL;
108 for (i = 0; i < ERM_COUNT; i++) {
109 extra_type_list_destroy(removed_by[i]);
110 removed_by[i] = NULL;
113 for (i = 0; i < ECAT_COUNT; i++) {
114 extra_type_list_destroy(category_extra[i]);
115 category_extra[i] = NULL;
118 extra_type_list_destroy(unit_hidden);
119 unit_hidden = NULL;
121 for (i = 0; i < MAX_EXTRA_TYPES; i++) {
122 requirement_vector_free(&(extras[i].reqs));
123 requirement_vector_free(&(extras[i].rmreqs));
124 requirement_vector_free(&(extras[i].appearance_reqs));
125 requirement_vector_free(&(extras[i].disappearance_reqs));
127 if (NULL != extras[i].helptext) {
128 strvec_destroy(extras[i].helptext);
129 extras[i].helptext = NULL;
133 extra_type_iterate(pextra) {
134 if (pextra->hiders != NULL) {
135 extra_type_list_destroy(pextra->hiders);
136 pextra->hiders = NULL;
138 } extra_type_iterate_end;
141 /**************************************************************************
142 Return the number of extra_types.
143 **************************************************************************/
144 int extra_count(void)
146 return game.control.num_extra_types;
149 /**************************************************************************
150 Return the extra id.
151 **************************************************************************/
152 int extra_number(const struct extra_type *pextra)
154 fc_assert_ret_val(NULL != pextra, -1);
156 return pextra->id;
159 #ifndef extra_index
160 /**************************************************************************
161 Return the extra index.
162 **************************************************************************/
163 int extra_index(const struct extra_type *pextra)
165 fc_assert_ret_val(NULL != pextra, -1);
167 return pextra - extras;
169 #endif /* extra_index */
171 /****************************************************************************
172 Return extras type of given id.
173 ****************************************************************************/
174 struct extra_type *extra_by_number(int id)
176 fc_assert_ret_val(id >= 0 && id < MAX_EXTRA_TYPES, NULL);
178 return &extras[id];
181 /**************************************************************************
182 Return the (translated) name of the extra type.
183 You don't have to free the return pointer.
184 **************************************************************************/
185 const char *extra_name_translation(const struct extra_type *pextra)
187 return name_translation_get(&pextra->name);
190 /**************************************************************************
191 Return the (untranslated) rule name of the extra type.
192 You don't have to free the return pointer.
193 **************************************************************************/
194 const char *extra_rule_name(const struct extra_type *pextra)
196 return rule_name_get(&pextra->name);
199 /**************************************************************************
200 Returns extra type matching rule name or NULL if there is no extra type
201 with such name.
202 **************************************************************************/
203 struct extra_type *extra_type_by_rule_name(const char *name)
205 const char *qs;
207 if (name == NULL) {
208 return NULL;
211 qs = Qn_(name);
213 extra_type_iterate(pextra) {
214 if (!fc_strcasecmp(extra_rule_name(pextra), qs)) {
215 return pextra;
217 } extra_type_iterate_end;
219 return NULL;
222 /**************************************************************************
223 Returns extra type matching the translated name, or NULL if there is no
224 extra type with that name.
225 **************************************************************************/
226 struct extra_type *extra_type_by_translated_name(const char *name)
228 extra_type_iterate(pextra) {
229 if (0 == strcmp(extra_name_translation(pextra), name)) {
230 return pextra;
232 } extra_type_iterate_end;
234 return NULL;
237 /**************************************************************************
238 Returns extra type for given cause.
239 **************************************************************************/
240 struct extra_type_list *extra_type_list_by_cause(enum extra_cause cause)
242 fc_assert(cause < EC_LAST);
244 return caused_by[cause];
247 /**************************************************************************
248 Returns extra types of the category.
249 **************************************************************************/
250 struct extra_type_list *extra_type_list_for_category(enum extra_category cat)
252 fc_assert(cat < ECAT_LAST);
254 return category_extra[cat];
257 /**************************************************************************
258 Returns extra types that hide units.
259 **************************************************************************/
260 struct extra_type_list *extra_type_list_of_unit_hiders(void)
262 return unit_hidden;
265 /**************************************************************************
266 Return random extra type for given cause that is native to the tile.
267 **************************************************************************/
268 struct extra_type *rand_extra_for_tile(struct tile *ptile, enum extra_cause cause)
270 struct extra_type_list *full_list = extra_type_list_by_cause(cause);
271 struct extra_type_list *potential = extra_type_list_new();
272 int options;
273 struct extra_type *selected = NULL;
275 extra_type_list_iterate(full_list, pextra) {
276 if (is_native_tile_to_extra(pextra, ptile)) {
277 extra_type_list_append(potential, pextra);
279 } extra_type_list_iterate_end;
281 options = extra_type_list_size(potential);
283 if (options > 0) {
284 selected = extra_type_list_get(potential, fc_rand(options));
287 extra_type_list_destroy(potential);
289 return selected;
292 /**************************************************************************
293 Add extra type to list of extra caused by given cause.
294 **************************************************************************/
295 void extra_to_caused_by_list(struct extra_type *pextra, enum extra_cause cause)
297 fc_assert(cause < EC_LAST);
299 extra_type_list_append(caused_by[cause], pextra);
302 /**************************************************************************
303 Add extra type to list of extras of a category
304 **************************************************************************/
305 void extra_to_category_list(struct extra_type *pextra, enum extra_category cat)
307 fc_assert(cat < ECAT_LAST);
309 extra_type_list_append(category_extra[cat], pextra);
312 /**************************************************************************
313 Returns extra type for given rmcause.
314 **************************************************************************/
315 struct extra_type_list *extra_type_list_by_rmcause(enum extra_rmcause rmcause)
317 fc_assert(rmcause < ERM_COUNT);
319 return removed_by[rmcause];
322 /**************************************************************************
323 Add extra type to list of extra removed by given cause.
324 **************************************************************************/
325 void extra_to_removed_by_list(struct extra_type *pextra,
326 enum extra_rmcause rmcause)
328 fc_assert(rmcause < ERM_COUNT);
330 extra_type_list_append(removed_by[rmcause], pextra);
333 /**************************************************************************
334 Is given cause one of the removal causes for given extra?
335 **************************************************************************/
336 bool is_extra_removed_by(const struct extra_type *pextra,
337 enum extra_rmcause rmcause)
339 return (pextra->rmcauses & (1 << rmcause));
342 /****************************************************************************
343 Is there extra of the given type cardinally near tile?
344 (Does not check ptile itself.)
345 ****************************************************************************/
346 bool is_extra_card_near(const struct tile *ptile, const struct extra_type *pextra)
348 cardinal_adjc_iterate(&(wld.map), ptile, adjc_tile) {
349 if (tile_has_extra(adjc_tile, pextra)) {
350 return TRUE;
352 } cardinal_adjc_iterate_end;
354 return FALSE;
357 /****************************************************************************
358 Is there extra of the given type near tile?
359 (Does not check ptile itself.)
360 ****************************************************************************/
361 bool is_extra_near_tile(const struct tile *ptile, const struct extra_type *pextra)
363 adjc_iterate(&(wld.map), ptile, adjc_tile) {
364 if (tile_has_extra(adjc_tile, pextra)) {
365 return TRUE;
367 } adjc_iterate_end;
369 return FALSE;
372 /****************************************************************************
373 Tells if extra can build to tile if all other requirements are met.
374 ****************************************************************************/
375 bool extra_can_be_built(const struct extra_type *pextra,
376 const struct tile *ptile)
378 if (!pextra->buildable) {
379 /* Extra type not buildable */
380 return FALSE;
383 if (tile_has_extra(ptile, pextra)) {
384 /* Extra exist already */
385 return FALSE;
388 return TRUE;
391 /****************************************************************************
392 Tells if player can build extra to tile with suitable unit.
393 ****************************************************************************/
394 static bool can_build_extra_base(const struct extra_type *pextra,
395 const struct player *pplayer,
396 const struct tile *ptile)
398 if (is_extra_caused_by(pextra, EC_BASE)
399 && !base_can_be_built(extra_base_get(pextra), ptile)) {
400 return FALSE;
403 if (is_extra_caused_by(pextra, EC_ROAD)
404 && !can_build_road_base(extra_road_get(pextra), pplayer, ptile)) {
405 return FALSE;
408 if (!extra_can_be_built(pextra, ptile)) {
409 return FALSE;
412 return TRUE;
415 /****************************************************************************
416 Tells if player can build extra to tile with suitable unit.
417 ****************************************************************************/
418 bool player_can_build_extra(const struct extra_type *pextra,
419 const struct player *pplayer,
420 const struct tile *ptile)
422 if (!can_build_extra_base(pextra, pplayer, ptile)) {
423 return FALSE;
426 return are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile,
427 NULL, NULL, NULL, NULL, NULL, &pextra->reqs,
428 RPT_POSSIBLE);
431 /****************************************************************************
432 Tells if unit can build extra on tile.
433 ****************************************************************************/
434 bool can_build_extra(struct extra_type *pextra,
435 const struct unit *punit,
436 const struct tile *ptile)
438 struct player *pplayer = unit_owner(punit);
440 if (!can_build_extra_base(pextra, pplayer, ptile)) {
441 return FALSE;
444 return are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile,
445 punit, unit_type_get(punit), NULL, NULL, NULL, &pextra->reqs,
446 RPT_CERTAIN);
449 /****************************************************************************
450 Is it possible at all to remove this extra now
451 ****************************************************************************/
452 static bool can_extra_be_removed(const struct extra_type *pextra,
453 const struct tile *ptile)
455 struct city *pcity = tile_city(ptile);
457 /* Cannot remove EF_ALWAYS_ON_CITY_CENTER extras from city center. */
458 if (pcity != NULL) {
459 if (extra_has_flag(pextra, EF_ALWAYS_ON_CITY_CENTER)) {
460 return FALSE;
462 if (extra_has_flag(pextra, EF_AUTO_ON_CITY_CENTER)) {
463 struct tile *vtile = tile_virtual_new(ptile);
465 /* Would extra get rebuilt if removed */
466 tile_remove_extra(vtile, pextra);
467 if (player_can_build_extra(pextra, city_owner(pcity), vtile)) {
468 /* No need to worry about conflicting extras - extra would had
469 * not been here if conflicting one is. */
470 tile_virtual_destroy(vtile);
472 return FALSE;
475 tile_virtual_destroy(vtile);
479 return TRUE;
482 /****************************************************************************
483 Tells if player can remove extra from tile with suitable unit.
484 ****************************************************************************/
485 bool player_can_remove_extra(const struct extra_type *pextra,
486 const struct player *pplayer,
487 const struct tile *ptile)
489 if (!can_extra_be_removed(pextra, ptile)) {
490 return FALSE;
493 return are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile,
494 NULL, NULL, NULL, NULL, NULL, &pextra->rmreqs,
495 RPT_POSSIBLE);
498 /****************************************************************************
499 Tells if unit can remove extra from tile.
500 ****************************************************************************/
501 bool can_remove_extra(struct extra_type *pextra,
502 const struct unit *punit,
503 const struct tile *ptile)
505 struct player *pplayer;
507 if (!can_extra_be_removed(pextra, ptile)) {
508 return FALSE;
511 pplayer = unit_owner(punit);
513 return are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile,
514 punit, unit_type_get(punit), NULL, NULL, NULL,
515 &pextra->rmreqs, RPT_CERTAIN);
518 /****************************************************************************
519 Is tile native to extra?
520 ****************************************************************************/
521 bool is_native_tile_to_extra(const struct extra_type *pextra,
522 const struct tile *ptile)
524 struct terrain *pterr = tile_terrain(ptile);
526 if (terrain_has_resource(pterr, pextra)) {
527 return TRUE;
530 if (is_extra_caused_by(pextra, EC_IRRIGATION)
531 && pterr->irrigation_result != pterr) {
532 return FALSE;
535 if (is_extra_caused_by(pextra, EC_MINE)
536 && pterr->mining_result != pterr) {
537 return FALSE;
540 if (is_extra_caused_by(pextra, EC_BASE)) {
541 if (pterr->base_time == 0) {
542 return FALSE;
544 if (tile_city(ptile) != NULL && extra_base_get(pextra)->border_sq >= 0) {
545 return FALSE;
549 if (is_extra_caused_by(pextra, EC_ROAD)) {
550 struct road_type *proad = extra_road_get(pextra);
552 if (road_has_flag(proad, RF_RIVER)) {
553 if (!terrain_has_flag(pterr, TER_CAN_HAVE_RIVER)) {
554 return FALSE;
556 } else if (pterr->road_time == 0) {
557 return FALSE;
561 return are_reqs_active(NULL, NULL, NULL, NULL, ptile,
562 NULL, NULL, NULL, NULL, NULL,
563 &pextra->reqs, RPT_POSSIBLE);
566 /****************************************************************************
567 Returns TRUE iff an extra that conflicts with pextra exists at ptile.
568 ****************************************************************************/
569 bool extra_conflicting_on_tile(const struct extra_type *pextra,
570 const struct tile *ptile)
572 extra_type_iterate(old_extra) {
573 if (tile_has_extra(ptile, old_extra)
574 && !can_extras_coexist(old_extra, pextra)) {
575 return TRUE;
577 } extra_type_iterate_end;
579 return FALSE;
582 /****************************************************************************
583 Returns next extra by cause that unit or player can build to tile.
584 ****************************************************************************/
585 struct extra_type *next_extra_for_tile(const struct tile *ptile, enum extra_cause cause,
586 const struct player *pplayer,
587 const struct unit *punit)
589 if (cause == EC_IRRIGATION) {
590 struct terrain *pterrain = tile_terrain(ptile);
592 if (pterrain->irrigation_result != pterrain) {
593 /* No extra can be created by irrigation the tile */
594 return NULL;
597 if (cause == EC_MINE) {
598 struct terrain *pterrain = tile_terrain(ptile);
600 if (pterrain->mining_result != pterrain) {
601 /* No extra can be created by mining the tile */
602 return NULL;
606 extra_type_by_cause_iterate(cause, pextra) {
607 if (!tile_has_extra(ptile, pextra)) {
608 if (punit != NULL) {
609 if (can_build_extra(pextra, punit, ptile)) {
610 return pextra;
612 } else {
613 /* punit is certainly NULL, pplayer can be too */
614 if (player_can_build_extra(pextra, pplayer, ptile)) {
615 return pextra;
619 } extra_type_by_cause_iterate_end;
621 return NULL;
624 /****************************************************************************
625 Returns prev extra by cause that unit or player can remove from tile.
626 ****************************************************************************/
627 struct extra_type *prev_extra_in_tile(const struct tile *ptile,
628 enum extra_rmcause rmcause,
629 const struct player *pplayer,
630 const struct unit *punit)
632 fc_assert(punit != NULL || pplayer != NULL);
634 extra_type_by_rmcause_iterate(rmcause, pextra) {
635 if (tile_has_extra(ptile, pextra)) {
636 if (punit != NULL) {
637 if (can_remove_extra(pextra, punit, ptile)) {
638 return pextra;
640 } else {
641 if (player_can_remove_extra(pextra, pplayer, ptile)) {
642 return pextra;
646 } extra_type_by_rmcause_iterate_end;
648 return NULL;
651 /****************************************************************************
652 Is extra native to unit class?
653 ****************************************************************************/
654 bool is_native_extra_to_uclass(const struct extra_type *pextra,
655 const struct unit_class *pclass)
657 return BV_ISSET(pextra->native_to, uclass_index(pclass));
660 /****************************************************************************
661 Is extra native to unit type?
662 ****************************************************************************/
663 bool is_native_extra_to_utype(const struct extra_type *pextra,
664 const struct unit_type *punittype)
666 return is_native_extra_to_uclass(pextra, utype_class(punittype));
669 /****************************************************************************
670 Check if extra has given flag
671 ****************************************************************************/
672 bool extra_has_flag(const struct extra_type *pextra, enum extra_flag_id flag)
674 return BV_ISSET(pextra->flags, flag);
677 /****************************************************************************
678 Returns TRUE iff any cardinally adjacent tile contains an extra with
679 the given flag (does not check ptile itself).
680 ****************************************************************************/
681 bool is_extra_flag_card_near(const struct tile *ptile, enum extra_flag_id flag)
683 extra_type_iterate(pextra) {
684 if (extra_has_flag(pextra, flag)) {
685 cardinal_adjc_iterate(&(wld.map), ptile, adjc_tile) {
686 if (tile_has_extra(adjc_tile, pextra)) {
687 return TRUE;
689 } cardinal_adjc_iterate_end;
691 } extra_type_iterate_end;
693 return FALSE;
696 /****************************************************************************
697 Returns TRUE iff any adjacent tile contains an extra with the given flag
698 (does not check ptile itself).
699 ****************************************************************************/
700 bool is_extra_flag_near_tile(const struct tile *ptile, enum extra_flag_id flag)
702 extra_type_iterate(pextra) {
703 if (extra_has_flag(pextra, flag)) {
704 adjc_iterate(&(wld.map), ptile, adjc_tile) {
705 if (tile_has_extra(adjc_tile, pextra)) {
706 return TRUE;
708 } adjc_iterate_end;
710 } extra_type_iterate_end;
712 return FALSE;
715 /**************************************************************************
716 Initialize user extra flags.
717 **************************************************************************/
718 void user_extra_flags_init(void)
720 int i;
722 for (i = 0; i < MAX_NUM_USER_EXTRA_FLAGS; i++) {
723 user_flag_init(&user_extra_flags[i]);
727 /***************************************************************
728 Frees the memory associated with all extra flags
729 ***************************************************************/
730 void extra_flags_free(void)
732 int i;
734 for (i = 0; i < MAX_NUM_USER_EXTRA_FLAGS; i++) {
735 user_flag_free(&user_extra_flags[i]);
739 /**************************************************************************
740 Sets user defined name for extra flag.
741 **************************************************************************/
742 void set_user_extra_flag_name(enum extra_flag_id id, const char *name,
743 const char *helptxt)
745 int efid = id - EF_USER_FLAG_1;
747 fc_assert_ret(id >= EF_USER_FLAG_1 && id <= EF_LAST_USER_FLAG);
749 if (user_extra_flags[efid].name != NULL) {
750 FC_FREE(user_extra_flags[efid].name);
751 user_extra_flags[efid].name = NULL;
754 if (name && name[0] != '\0') {
755 user_extra_flags[efid].name = fc_strdup(name);
758 if (user_extra_flags[efid].helptxt != NULL) {
759 free(user_extra_flags[efid].helptxt);
760 user_extra_flags[efid].helptxt = NULL;
763 if (helptxt && helptxt[0] != '\0') {
764 user_extra_flags[efid].helptxt = fc_strdup(helptxt);
768 /**************************************************************************
769 Extra flag name callback, called from specenum code.
770 **************************************************************************/
771 const char *extra_flag_id_name_cb(enum extra_flag_id flag)
773 if (flag < EF_USER_FLAG_1 || flag > EF_LAST_USER_FLAG) {
774 return NULL;
777 return user_extra_flags[flag - EF_USER_FLAG_1].name;
780 /**************************************************************************
781 Return the (untranslated) help text of the user extra flag.
782 **************************************************************************/
783 const char *extra_flag_helptxt(enum extra_flag_id id)
785 fc_assert(id >= EF_USER_FLAG_1 && id <= EF_LAST_USER_FLAG);
787 return user_extra_flags[id - EF_USER_FLAG_1].helptxt;
790 /**************************************************************************
791 Can two extras coexist in same tile?
792 **************************************************************************/
793 bool can_extras_coexist(const struct extra_type *pextra1,
794 const struct extra_type *pextra2)
796 if (pextra1 == pextra2) {
797 return TRUE;
800 return !BV_ISSET(pextra1->conflicts, extra_index(pextra2));
803 /**************************************************************************
804 Does the extra count toward environment upset?
805 **************************************************************************/
806 bool extra_causes_env_upset(struct extra_type *pextra,
807 enum environment_upset_type upset)
809 switch (upset) {
810 case EUT_GLOBAL_WARMING:
811 return extra_has_flag(pextra, EF_GLOBAL_WARMING);
812 case EUT_NUCLEAR_WINTER:
813 return extra_has_flag(pextra, EF_NUCLEAR_WINTER);
816 return FALSE;
819 /**************************************************************************
820 Is given cause one of the causes for given extra?
821 **************************************************************************/
822 bool is_extra_caused_by(const struct extra_type *pextra, enum extra_cause cause)
824 /* There's some extra cause lists above EC_COUNT that do not have equivalent
825 * bit in pextra->causes */
826 fc_assert(cause < EC_COUNT);
828 return (pextra->causes & (1 << cause));
831 /**************************************************************************
832 Is the extra caused by some kind of worker action?
833 **************************************************************************/
834 bool is_extra_caused_by_worker_action(const struct extra_type *pextra)
836 /* Is any of the worker build action bits set? */
837 return (pextra->causes
838 & (1 << EC_IRRIGATION
839 | 1 << EC_MINE
840 | 1 << EC_BASE
841 | 1 << EC_ROAD));
844 /**************************************************************************
845 Is the extra removed by some kind of worker action?
846 **************************************************************************/
847 bool is_extra_removed_by_worker_action(const struct extra_type *pextra)
849 /* Is any of the worker remove action bits set? */
850 return (pextra->rmcauses
851 & (1 << ERM_CLEANPOLLUTION
852 | 1 << ERM_CLEANFALLOUT
853 | 1 << ERM_PILLAGE));
856 /**************************************************************************
857 Is the extra caused by specific worker action?
858 **************************************************************************/
859 bool is_extra_caused_by_action(const struct extra_type *pextra,
860 enum unit_activity act)
862 return is_extra_caused_by(pextra, activity_to_extra_cause(act));
865 /**************************************************************************
866 Is the extra removed by specific worker action?
867 **************************************************************************/
868 bool is_extra_removed_by_action(const struct extra_type *pextra,
869 enum unit_activity act)
871 return is_extra_removed_by(pextra, activity_to_extra_rmcause(act));
874 /**************************************************************************
875 What extra cause activity is considered to be?
876 **************************************************************************/
877 enum extra_cause activity_to_extra_cause(enum unit_activity act)
879 switch(act) {
880 case ACTIVITY_IRRIGATE:
881 return EC_IRRIGATION;
882 case ACTIVITY_MINE:
883 return EC_MINE;
884 case ACTIVITY_BASE:
885 return EC_BASE;
886 case ACTIVITY_GEN_ROAD:
887 return EC_ROAD;
888 default:
889 break;
892 return EC_NONE;
895 /**************************************************************************
896 What extra rmcause activity is considered to be?
897 **************************************************************************/
898 enum extra_rmcause activity_to_extra_rmcause(enum unit_activity act)
900 switch(act) {
901 case ACTIVITY_PILLAGE:
902 return ERM_PILLAGE;
903 case ACTIVITY_POLLUTION:
904 return ERM_CLEANPOLLUTION;
905 case ACTIVITY_FALLOUT:
906 return ERM_CLEANFALLOUT;
907 default:
908 break;
911 return ERM_NONE;
914 /**************************************************************************
915 Who owns extras on tile
916 **************************************************************************/
917 struct player *extra_owner(const struct tile *ptile)
919 return ptile->extras_owner;
922 /**************************************************************************
923 Are all the requirements for extra to appear on tile fulfilled.
924 **************************************************************************/
925 bool can_extra_appear(const struct extra_type *pextra, const struct tile *ptile)
927 return !tile_has_extra(ptile, pextra)
928 && is_extra_caused_by(pextra, EC_APPEARANCE)
929 && is_native_tile_to_extra(pextra, ptile)
930 && !extra_conflicting_on_tile(pextra, ptile)
931 && are_reqs_active(NULL, tile_owner(ptile), NULL, NULL, ptile,
932 NULL, NULL, NULL, NULL, NULL,
933 &pextra->appearance_reqs, RPT_CERTAIN);
936 /**************************************************************************
937 Are all the requirements for extra to disappear from tile fulfilled.
938 **************************************************************************/
939 bool can_extra_disappear(const struct extra_type *pextra, const struct tile *ptile)
941 return tile_has_extra(ptile, pextra)
942 && is_extra_removed_by(pextra, ERM_DISAPPEARANCE)
943 && can_extra_be_removed(pextra, ptile)
944 && are_reqs_active(NULL, tile_owner(ptile), NULL, NULL, ptile,
945 NULL, NULL, NULL, NULL, NULL,
946 &pextra->disappearance_reqs, RPT_CERTAIN);
949 /**************************************************************************
950 Extra is not hidden from the user.
951 **************************************************************************/
952 bool player_knows_extra_exist(const struct player *pplayer,
953 const struct extra_type *pextra,
954 const struct tile *ptile)
956 if (!tile_has_extra(ptile, pextra)) {
957 return FALSE;
960 return research_invention_state(research_get(pplayer),
961 pextra->visibility_req) == TECH_KNOWN;