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.
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 /* utility */
19 #include "rand.h"
20 #include "string_vector.h"
21
22 /* common */
23 #include "base.h"
24 #include "game.h"
25 #include "map.h"
26 #include "road.h"
27
28 #include "extras.h"
29
30 static struct extra_type extras[MAX_EXTRA_TYPES];
31
32 static struct extra_type_list *caused_by[EC_LAST];
33 static struct extra_type_list *removed_by[ERM_COUNT];
34
35 /****************************************************************************
36 Initialize extras structures.
37 ****************************************************************************/
extras_init(void)38 void extras_init(void)
39 {
40 int i;
41
42 for (i = 0; i < EC_LAST; i++) {
43 caused_by[i] = extra_type_list_new();
44 }
45 for (i = 0; i < ERM_COUNT; i++) {
46 removed_by[i] = extra_type_list_new();
47 }
48
49 for (i = 0; i < MAX_EXTRA_TYPES; i++) {
50 requirement_vector_init(&(extras[i].reqs));
51 requirement_vector_init(&(extras[i].rmreqs));
52 extras[i].id = i;
53 extras[i].hiders = NULL;
54 extras[i].data.special_idx = -1;
55 extras[i].data.base = NULL;
56 extras[i].data.road = NULL;
57 extras[i].causes = 0;
58 extras[i].rmcauses = 0;
59 extras[i].helptext = NULL;
60 }
61 }
62
63 /****************************************************************************
64 Free the memory associated with extras
65 ****************************************************************************/
extras_free(void)66 void extras_free(void)
67 {
68 int i;
69
70 base_types_free();
71 road_types_free();
72
73 for (i = 0; i < game.control.num_extra_types; i++) {
74 if (extras[i].data.base != NULL) {
75 FC_FREE(extras[i].data.base);
76 extras[i].data.base = NULL;
77 }
78 if (extras[i].data.road != NULL) {
79 FC_FREE(extras[i].data.road);
80 extras[i].data.road = NULL;
81 }
82 }
83
84 for (i = 0; i < EC_LAST; i++) {
85 extra_type_list_destroy(caused_by[i]);
86 caused_by[i] = NULL;
87 }
88
89 for (i = 0; i < ERM_COUNT; i++) {
90 extra_type_list_destroy(removed_by[i]);
91 removed_by[i] = NULL;
92 }
93
94 for (i = 0; i < MAX_EXTRA_TYPES; i++) {
95 requirement_vector_free(&(extras[i].reqs));
96 requirement_vector_free(&(extras[i].rmreqs));
97
98 if (NULL != extras[i].helptext) {
99 strvec_destroy(extras[i].helptext);
100 extras[i].helptext = NULL;
101 }
102 }
103
104 extra_type_iterate(pextra) {
105 if (pextra->hiders != NULL) {
106 extra_type_list_destroy(pextra->hiders);
107 pextra->hiders = NULL;
108 }
109 } extra_type_iterate_end;
110 }
111
112 /**************************************************************************
113 Return the number of extra_types.
114 **************************************************************************/
extra_count(void)115 int extra_count(void)
116 {
117 return game.control.num_extra_types;
118 }
119
120 /**************************************************************************
121 Return the extra id.
122 **************************************************************************/
extra_number(const struct extra_type * pextra)123 int extra_number(const struct extra_type *pextra)
124 {
125 fc_assert_ret_val(NULL != pextra, -1);
126
127 return pextra->id;
128 }
129
130 #ifndef extra_index
131 /**************************************************************************
132 Return the extra index.
133 **************************************************************************/
extra_index(const struct extra_type * pextra)134 int extra_index(const struct extra_type *pextra)
135 {
136 fc_assert_ret_val(NULL != pextra, -1);
137
138 return pextra - extras;
139 }
140 #endif /* extra_index */
141
142 /****************************************************************************
143 Return extras type of given id.
144 ****************************************************************************/
extra_by_number(int id)145 struct extra_type *extra_by_number(int id)
146 {
147 fc_assert_ret_val(id >= 0 && id < MAX_EXTRA_TYPES, NULL);
148
149 return &extras[id];
150 }
151
152 /****************************************************************************
153 Get extra of the given special
154 ****************************************************************************/
special_extra_get(int spe)155 struct extra_type *special_extra_get(int spe)
156 {
157 struct extra_type_list *elist = extra_type_list_by_cause(EC_SPECIAL);
158
159 if (spe < extra_type_list_size(elist)) {
160 return extra_type_list_get(elist, spe);
161 }
162
163 return NULL;
164 }
165
166 /**************************************************************************
167 Return the (translated) name of the extra type.
168 You don't have to free the return pointer.
169 **************************************************************************/
extra_name_translation(const struct extra_type * pextra)170 const char *extra_name_translation(const struct extra_type *pextra)
171 {
172 return name_translation_get(&pextra->name);
173 }
174
175 /**************************************************************************
176 Return the (untranslated) rule name of the extra type.
177 You don't have to free the return pointer.
178 **************************************************************************/
extra_rule_name(const struct extra_type * pextra)179 const char *extra_rule_name(const struct extra_type *pextra)
180 {
181 return rule_name_get(&pextra->name);
182 }
183
184 /**************************************************************************
185 Returns extra type matching rule name or NULL if there is no extra type
186 with such name.
187 **************************************************************************/
extra_type_by_rule_name(const char * name)188 struct extra_type *extra_type_by_rule_name(const char *name)
189 {
190 const char *qs;
191
192 if (name == NULL) {
193 return NULL;
194 }
195
196 qs = Qn_(name);
197
198 extra_type_iterate(pextra) {
199 if (!fc_strcasecmp(extra_rule_name(pextra), qs)) {
200 return pextra;
201 }
202 } extra_type_iterate_end;
203
204 return NULL;
205 }
206
207 /**************************************************************************
208 Returns extra type matching the translated name, or NULL if there is no
209 extra type with that name.
210 **************************************************************************/
extra_type_by_translated_name(const char * name)211 struct extra_type *extra_type_by_translated_name(const char *name)
212 {
213 extra_type_iterate(pextra) {
214 if (0 == strcmp(extra_name_translation(pextra), name)) {
215 return pextra;
216 }
217 } extra_type_iterate_end;
218
219 return NULL;
220 }
221
222 /**************************************************************************
223 Returns extra type for given cause.
224 **************************************************************************/
extra_type_list_by_cause(enum extra_cause cause)225 struct extra_type_list *extra_type_list_by_cause(enum extra_cause cause)
226 {
227 fc_assert(cause < EC_LAST);
228
229 return caused_by[cause];
230 }
231
232 /**************************************************************************
233 Return random extra type for given cause that is native to the tile.
234 **************************************************************************/
rand_extra_for_tile(struct tile * ptile,enum extra_cause cause)235 struct extra_type *rand_extra_for_tile(struct tile *ptile, enum extra_cause cause)
236 {
237 struct extra_type_list *full_list = extra_type_list_by_cause(cause);
238 struct extra_type_list *potential = extra_type_list_new();
239 int options;
240 struct extra_type *selected = NULL;
241
242 extra_type_list_iterate(full_list, pextra) {
243 if (is_native_tile_to_extra(pextra, ptile)) {
244 extra_type_list_append(potential, pextra);
245 }
246 } extra_type_list_iterate_end;
247
248 options = extra_type_list_size(potential);
249
250 if (options > 0) {
251 selected = extra_type_list_get(potential, fc_rand(options));
252 }
253
254 extra_type_list_destroy(potential);
255
256 return selected;
257 }
258
259 /**************************************************************************
260 Add extra type to list of extra caused by given cause.
261 **************************************************************************/
extra_to_caused_by_list(struct extra_type * pextra,enum extra_cause cause)262 void extra_to_caused_by_list(struct extra_type *pextra, enum extra_cause cause)
263 {
264 fc_assert(cause < EC_LAST);
265
266 extra_type_list_append(caused_by[cause], pextra);
267 }
268
269 /**************************************************************************
270 Returns extra type for given rmcause.
271 **************************************************************************/
extra_type_list_by_rmcause(enum extra_rmcause rmcause)272 struct extra_type_list *extra_type_list_by_rmcause(enum extra_rmcause rmcause)
273 {
274 fc_assert(rmcause < ERM_COUNT);
275
276 return removed_by[rmcause];
277 }
278
279 /**************************************************************************
280 Add extra type to list of extra removed by given cause.
281 **************************************************************************/
extra_to_removed_by_list(struct extra_type * pextra,enum extra_rmcause rmcause)282 void extra_to_removed_by_list(struct extra_type *pextra,
283 enum extra_rmcause rmcause)
284 {
285 fc_assert(rmcause < ERM_COUNT);
286
287 extra_type_list_append(removed_by[rmcause], pextra);
288 }
289
290 /**************************************************************************
291 Is given cause one of the removal causes for the given extra?
292 **************************************************************************/
is_extra_removed_by(const struct extra_type * pextra,enum extra_rmcause rmcause)293 bool is_extra_removed_by(const struct extra_type *pextra,
294 enum extra_rmcause rmcause)
295 {
296 return (pextra->rmcauses & (1 << rmcause));
297 }
298
299 /****************************************************************************
300 Is there extra of the given type cardinally near tile?
301 (Does not check ptile itself.)
302 ****************************************************************************/
is_extra_card_near(const struct tile * ptile,const struct extra_type * pextra)303 bool is_extra_card_near(const struct tile *ptile, const struct extra_type *pextra)
304 {
305 cardinal_adjc_iterate(ptile, adjc_tile) {
306 if (tile_has_extra(adjc_tile, pextra)) {
307 return TRUE;
308 }
309 } cardinal_adjc_iterate_end;
310
311 return FALSE;
312 }
313
314 /****************************************************************************
315 Is there extra of the given type near tile?
316 (Does not check ptile itself.)
317 ****************************************************************************/
is_extra_near_tile(const struct tile * ptile,const struct extra_type * pextra)318 bool is_extra_near_tile(const struct tile *ptile, const struct extra_type *pextra)
319 {
320 adjc_iterate(ptile, adjc_tile) {
321 if (tile_has_extra(adjc_tile, pextra)) {
322 return TRUE;
323 }
324 } adjc_iterate_end;
325
326 return FALSE;
327 }
328
329 /****************************************************************************
330 Tells if extra can build to tile if all other requirements are met.
331 ****************************************************************************/
extra_can_be_built(const struct extra_type * pextra,const struct tile * ptile)332 bool extra_can_be_built(const struct extra_type *pextra,
333 const struct tile *ptile)
334 {
335 if (!pextra->buildable) {
336 /* Extra type not buildable */
337 return FALSE;
338 }
339
340 if (tile_has_extra(ptile, pextra)) {
341 /* Extra exist already */
342 return FALSE;
343 }
344
345 return TRUE;
346 }
347
348 /****************************************************************************
349 Tells if player can build extra to tile with suitable unit.
350 ****************************************************************************/
can_build_extra_base(const struct extra_type * pextra,const struct player * pplayer,const struct tile * ptile)351 static bool can_build_extra_base(const struct extra_type *pextra,
352 const struct player *pplayer,
353 const struct tile *ptile)
354 {
355 if (is_extra_caused_by(pextra, EC_BASE)
356 && !base_can_be_built(extra_base_get(pextra), ptile)) {
357 return FALSE;
358 }
359
360 if (is_extra_caused_by(pextra, EC_ROAD)
361 && !can_build_road_base(extra_road_get(pextra), pplayer, ptile)) {
362 return FALSE;
363 }
364
365 if (!extra_can_be_built(pextra, ptile)) {
366 return FALSE;
367 }
368
369 return TRUE;
370 }
371
372 /****************************************************************************
373 Tells if player can build extra to tile with suitable unit.
374 ****************************************************************************/
player_can_build_extra(const struct extra_type * pextra,const struct player * pplayer,const struct tile * ptile)375 bool player_can_build_extra(const struct extra_type *pextra,
376 const struct player *pplayer,
377 const struct tile *ptile)
378 {
379 if (!can_build_extra_base(pextra, pplayer, ptile)) {
380 return FALSE;
381 }
382
383 return are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile,
384 NULL, NULL, NULL, NULL, &pextra->reqs,
385 RPT_POSSIBLE);
386 }
387
388 /****************************************************************************
389 Tells if unit can build extra on tile.
390 ****************************************************************************/
can_build_extra(const struct extra_type * pextra,const struct unit * punit,const struct tile * ptile)391 bool can_build_extra(const struct extra_type *pextra,
392 const struct unit *punit,
393 const struct tile *ptile)
394 {
395 struct player *pplayer = unit_owner(punit);
396
397 if (!can_build_extra_base(pextra, pplayer, ptile)) {
398 return FALSE;
399 }
400
401 return are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile,
402 punit, unit_type_get(punit), NULL, NULL, &pextra->reqs,
403 RPT_CERTAIN);
404 }
405
406 /****************************************************************************
407 Is it possible at all to remove this extra now
408 ****************************************************************************/
can_extra_be_removed(const struct extra_type * pextra,const struct tile * ptile)409 static bool can_extra_be_removed(const struct extra_type *pextra,
410 const struct tile *ptile)
411 {
412 struct city *pcity = tile_city(ptile);
413
414 /* Cannot remove EF_ALWAYS_ON_CITY_CENTER extras from city center. */
415 if (pcity != NULL) {
416 if (extra_has_flag(pextra, EF_ALWAYS_ON_CITY_CENTER)) {
417 return FALSE;
418 }
419 if (extra_has_flag(pextra, EF_AUTO_ON_CITY_CENTER)) {
420 struct tile *vtile = tile_virtual_new(ptile);
421
422 /* Would extra get rebuilt if removed */
423 tile_remove_extra(vtile, pextra);
424 if (player_can_build_extra(pextra, city_owner(pcity), vtile)) {
425 /* No need to worry about conflicting extras - extra would had
426 * not been here if conflicting one is. */
427 tile_virtual_destroy(vtile);
428
429 return FALSE;
430 }
431
432 tile_virtual_destroy(vtile);
433 }
434 }
435
436 return TRUE;
437 }
438
439 /****************************************************************************
440 Tells if player can remove extra from tile with suitable unit.
441 ****************************************************************************/
player_can_remove_extra(const struct extra_type * pextra,const struct player * pplayer,const struct tile * ptile)442 bool player_can_remove_extra(const struct extra_type *pextra,
443 const struct player *pplayer,
444 const struct tile *ptile)
445 {
446 if (!can_extra_be_removed(pextra, ptile)) {
447 return FALSE;
448 }
449
450 return are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile,
451 NULL, NULL, NULL, NULL, &pextra->rmreqs,
452 RPT_POSSIBLE);
453 }
454
455 /****************************************************************************
456 Tells if unit can remove extra from tile.
457 ****************************************************************************/
can_remove_extra(const struct extra_type * pextra,const struct unit * punit,const struct tile * ptile)458 bool can_remove_extra(const struct extra_type *pextra,
459 const struct unit *punit,
460 const struct tile *ptile)
461 {
462 struct player *pplayer;
463
464 if (!can_extra_be_removed(pextra, ptile)) {
465 return FALSE;
466 }
467
468 pplayer = unit_owner(punit);
469
470 return are_reqs_active(pplayer, tile_owner(ptile), NULL, NULL, ptile,
471 punit, unit_type_get(punit), NULL, NULL,
472 &pextra->rmreqs, RPT_CERTAIN);
473 }
474
475 /****************************************************************************
476 Is tile native to extra?
477 ****************************************************************************/
is_native_tile_to_extra(const struct extra_type * pextra,const struct tile * ptile)478 bool is_native_tile_to_extra(const struct extra_type *pextra,
479 const struct tile *ptile)
480 {
481 struct terrain *pterr = tile_terrain(ptile);
482
483 if (is_extra_caused_by(pextra, EC_IRRIGATION)
484 && pterr->irrigation_result != pterr) {
485 return FALSE;
486 }
487
488 if (is_extra_caused_by(pextra, EC_MINE)
489 && pterr->mining_result != pterr) {
490 return FALSE;
491 }
492
493 if (is_extra_caused_by(pextra, EC_BASE)) {
494 if (pterr->base_time == 0) {
495 return FALSE;
496 }
497 if (tile_city(ptile) != NULL && extra_base_get(pextra)->border_sq >= 0) {
498 return FALSE;
499 }
500 }
501
502 if (is_extra_caused_by(pextra, EC_ROAD)) {
503 struct road_type *proad = extra_road_get(pextra);
504
505 if (road_has_flag(proad, RF_RIVER)) {
506 if (!terrain_has_flag(pterr, TER_CAN_HAVE_RIVER)) {
507 return FALSE;
508 }
509 } else if (pterr->road_time == 0) {
510 return FALSE;
511 }
512 }
513
514 return are_reqs_active(NULL, NULL, NULL, NULL, ptile,
515 NULL, NULL, NULL, NULL,
516 &pextra->reqs, RPT_POSSIBLE);
517 }
518
519 /****************************************************************************
520 Returns next extra by cause that unit or player can build to tile.
521 ****************************************************************************/
next_extra_for_tile(const struct tile * ptile,enum extra_cause cause,const struct player * pplayer,const struct unit * punit)522 struct extra_type *next_extra_for_tile(const struct tile *ptile, enum extra_cause cause,
523 const struct player *pplayer,
524 const struct unit *punit)
525 {
526 if (cause == EC_IRRIGATION) {
527 struct terrain *pterrain = tile_terrain(ptile);
528
529 if (pterrain->irrigation_result != pterrain) {
530 /* No extra can be created by irrigation the tile */
531 return NULL;
532 }
533 }
534 if (cause == EC_MINE) {
535 struct terrain *pterrain = tile_terrain(ptile);
536
537 if (pterrain->mining_result != pterrain) {
538 /* No extra can be created by mining the tile */
539 return NULL;
540 }
541 }
542
543 extra_type_by_cause_iterate(cause, pextra) {
544 if (!tile_has_extra(ptile, pextra)) {
545 if (punit != NULL) {
546 if (can_build_extra(pextra, punit, ptile)) {
547 return pextra;
548 }
549 } else {
550 /* punit is certainly NULL, pplayer can be too */
551 if (player_can_build_extra(pextra, pplayer, ptile)) {
552 return pextra;
553 }
554 }
555 }
556 } extra_type_by_cause_iterate_end;
557
558 return NULL;
559 }
560
561 /****************************************************************************
562 Returns prev extra by cause that unit or player can remove from tile.
563 ****************************************************************************/
prev_extra_in_tile(const struct tile * ptile,enum extra_rmcause rmcause,const struct player * pplayer,const struct unit * punit)564 struct extra_type *prev_extra_in_tile(const struct tile *ptile,
565 enum extra_rmcause rmcause,
566 const struct player *pplayer,
567 const struct unit *punit)
568 {
569 fc_assert(punit != NULL || pplayer != NULL);
570
571 extra_type_by_rmcause_iterate(rmcause, pextra) {
572 if (tile_has_extra(ptile, pextra)) {
573 if (punit != NULL) {
574 if (can_remove_extra(pextra, punit, ptile)) {
575 return pextra;
576 }
577 } else {
578 if (player_can_remove_extra(pextra, pplayer, ptile)) {
579 return pextra;
580 }
581 }
582 }
583 } extra_type_by_rmcause_iterate_end;
584
585 return NULL;
586 }
587
588 /****************************************************************************
589 Is extra native to unit class?
590 ****************************************************************************/
is_native_extra_to_uclass(const struct extra_type * pextra,const struct unit_class * pclass)591 bool is_native_extra_to_uclass(const struct extra_type *pextra,
592 const struct unit_class *pclass)
593 {
594 return BV_ISSET(pextra->native_to, uclass_index(pclass));
595 }
596
597 /****************************************************************************
598 Is extra native to unit type?
599 ****************************************************************************/
is_native_extra_to_utype(const struct extra_type * pextra,const struct unit_type * punittype)600 bool is_native_extra_to_utype(const struct extra_type *pextra,
601 const struct unit_type *punittype)
602 {
603 return is_native_extra_to_uclass(pextra, utype_class(punittype));
604 }
605
606 /****************************************************************************
607 Check if extra has given flag
608 ****************************************************************************/
extra_has_flag(const struct extra_type * pextra,enum extra_flag_id flag)609 bool extra_has_flag(const struct extra_type *pextra, enum extra_flag_id flag)
610 {
611 return BV_ISSET(pextra->flags, flag);
612 }
613
614 /****************************************************************************
615 Returns TRUE iff any cardinally adjacent tile contains an extra with
616 the given flag (does not check ptile itself).
617 ****************************************************************************/
is_extra_flag_card_near(const struct tile * ptile,enum extra_flag_id flag)618 bool is_extra_flag_card_near(const struct tile *ptile, enum extra_flag_id flag)
619 {
620 extra_type_iterate(pextra) {
621 if (extra_has_flag(pextra, flag)) {
622 cardinal_adjc_iterate(ptile, adjc_tile) {
623 if (tile_has_extra(adjc_tile, pextra)) {
624 return TRUE;
625 }
626 } cardinal_adjc_iterate_end;
627 }
628 } extra_type_iterate_end;
629
630 return FALSE;
631 }
632
633 /****************************************************************************
634 Returns TRUE iff any adjacent tile contains an extra with the given flag
635 (does not check ptile itself).
636 ****************************************************************************/
is_extra_flag_near_tile(const struct tile * ptile,enum extra_flag_id flag)637 bool is_extra_flag_near_tile(const struct tile *ptile, enum extra_flag_id flag)
638 {
639 extra_type_iterate(pextra) {
640 if (extra_has_flag(pextra, flag)) {
641 adjc_iterate(ptile, adjc_tile) {
642 if (tile_has_extra(adjc_tile, pextra)) {
643 return TRUE;
644 }
645 } adjc_iterate_end;
646 }
647 } extra_type_iterate_end;
648
649 return FALSE;
650 }
651
652 /**************************************************************************
653 Can two extras coexist in same tile?
654 **************************************************************************/
can_extras_coexist(const struct extra_type * pextra1,const struct extra_type * pextra2)655 bool can_extras_coexist(const struct extra_type *pextra1,
656 const struct extra_type *pextra2)
657 {
658 if (pextra1 == pextra2) {
659 return TRUE;
660 }
661
662 return !BV_ISSET(pextra1->conflicts, extra_index(pextra2));
663 }
664
665 /**************************************************************************
666 Does the extra count toward environment upset?
667 **************************************************************************/
extra_causes_env_upset(struct extra_type * pextra,enum environment_upset_type upset)668 bool extra_causes_env_upset(struct extra_type *pextra,
669 enum environment_upset_type upset)
670 {
671 switch (upset) {
672 case EUT_GLOBAL_WARMING:
673 return extra_has_flag(pextra, EF_GLOBAL_WARMING);
674 case EUT_NUCLEAR_WINTER:
675 return extra_has_flag(pextra, EF_NUCLEAR_WINTER);
676 }
677
678 return FALSE;
679 }
680
681 /**************************************************************************
682 Is the extra caused by some kind of worker action?
683 **************************************************************************/
is_extra_caused_by_worker_action(const struct extra_type * pextra)684 bool is_extra_caused_by_worker_action(const struct extra_type *pextra)
685 {
686 /* Is any of the worker build action bits set? */
687 return (pextra->causes
688 & (1 << EC_IRRIGATION
689 | 1 << EC_MINE
690 | 1 << EC_BASE
691 | 1 << EC_ROAD));
692 }
693
694 /**************************************************************************
695 Is the extra removed by some kind of worker action?
696 **************************************************************************/
is_extra_removed_by_worker_action(const struct extra_type * pextra)697 bool is_extra_removed_by_worker_action(const struct extra_type *pextra)
698 {
699 /* Is any of the worker remove action bits set? */
700 return (pextra->rmcauses
701 & (1 << ERM_CLEANPOLLUTION
702 | 1 << ERM_CLEANFALLOUT
703 | 1 << ERM_PILLAGE));
704 }
705
706 /**************************************************************************
707 Is the extra caused by specific worker action?
708 **************************************************************************/
is_extra_caused_by_action(const struct extra_type * pextra,enum unit_activity act)709 bool is_extra_caused_by_action(const struct extra_type *pextra,
710 enum unit_activity act)
711 {
712 return is_extra_caused_by(pextra, activity_to_extra_cause(act));
713 }
714
715 /**************************************************************************
716 Is the extra removed by specific worker action?
717 **************************************************************************/
is_extra_removed_by_action(const struct extra_type * pextra,enum unit_activity act)718 bool is_extra_removed_by_action(const struct extra_type *pextra,
719 enum unit_activity act)
720 {
721 return is_extra_removed_by(pextra, activity_to_extra_rmcause(act));
722 }
723
724 /**************************************************************************
725 What extra cause activity is considered to be?
726 **************************************************************************/
activity_to_extra_cause(enum unit_activity act)727 enum extra_cause activity_to_extra_cause(enum unit_activity act)
728 {
729 switch(act) {
730 case ACTIVITY_IRRIGATE:
731 return EC_IRRIGATION;
732 case ACTIVITY_MINE:
733 return EC_MINE;
734 case ACTIVITY_BASE:
735 return EC_BASE;
736 case ACTIVITY_GEN_ROAD:
737 return EC_ROAD;
738 default:
739 break;
740 }
741
742 return EC_NONE;
743 }
744
745 /**************************************************************************
746 What extra rmcause activity is considered to be?
747 **************************************************************************/
activity_to_extra_rmcause(enum unit_activity act)748 enum extra_rmcause activity_to_extra_rmcause(enum unit_activity act)
749 {
750 switch(act) {
751 case ACTIVITY_PILLAGE:
752 return ERM_PILLAGE;
753 case ACTIVITY_POLLUTION:
754 return ERM_CLEANPOLLUTION;
755 case ACTIVITY_FALLOUT:
756 return ERM_CLEANFALLOUT;
757 default:
758 break;
759 }
760
761 return ERM_NONE;
762 }
763
764 /**************************************************************************
765 Who owns extras on tile
766 **************************************************************************/
extra_owner(const struct tile * ptile)767 struct player *extra_owner(const struct tile *ptile)
768 {
769 return ptile->extras_owner;
770 }
771