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)
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 ****************************************************************************/
15 #include <fc_config.h>
20 #include "string_vector.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)
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
));
57 extras
[i
].hiders
= NULL
;
58 extras
[i
].data
.special_idx
= -1;
59 extras
[i
].data
.base
= NULL
;
60 extras
[i
].data
.road
= NULL
;
62 extras
[i
].rmcauses
= 0;
63 extras
[i
].helptext
= NULL
;
67 /****************************************************************************
68 Free the memory associated with extras
69 ****************************************************************************/
70 void extras_free(void)
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
]);
93 for (i
= 0; i
< ERM_COUNT
; i
++) {
94 extra_type_list_destroy(removed_by
[i
]);
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 /**************************************************************************
131 **************************************************************************/
132 int extra_number(const struct extra_type
*pextra
)
134 fc_assert_ret_val(NULL
!= pextra
, -1);
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
);
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
);
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
196 **************************************************************************/
197 struct extra_type
*extra_type_by_rule_name(const char *name
)
207 extra_type_iterate(pextra
) {
208 if (!fc_strcasecmp(extra_rule_name(pextra
), qs
)) {
211 } extra_type_iterate_end
;
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
)) {
226 } extra_type_iterate_end
;
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();
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
);
270 selected
= extra_type_list_get(potential
, fc_rand(options
));
273 extra_type_list_destroy(potential
);
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
)) {
338 } cardinal_adjc_iterate_end
;
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
)) {
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 */
369 if (tile_has_extra(ptile
, pextra
)) {
370 /* Extra exist already */
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
)) {
389 if (is_extra_caused_by(pextra
, EC_ROAD
)
390 && !can_build_road_base(extra_road_get(pextra
), pplayer
, ptile
)) {
394 if (!extra_can_be_built(pextra
, ptile
)) {
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
)) {
412 return are_reqs_active(pplayer
, tile_owner(ptile
), NULL
, NULL
, ptile
,
413 NULL
, NULL
, NULL
, NULL
, &pextra
->reqs
,
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
)) {
430 return are_reqs_active(pplayer
, tile_owner(ptile
), NULL
, NULL
, ptile
,
431 punit
, unit_type_get(punit
), NULL
, NULL
, &pextra
->reqs
,
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. */
445 if (extra_has_flag(pextra
, EF_ALWAYS_ON_CITY_CENTER
)) {
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
);
461 tile_virtual_destroy(vtile
);
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
)) {
479 return are_reqs_active(pplayer
, tile_owner(ptile
), NULL
, NULL
, ptile
,
480 NULL
, NULL
, NULL
, NULL
, &pextra
->rmreqs
,
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
)) {
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
) {
517 if (is_extra_caused_by(pextra
, EC_MINE
)
518 && pterr
->mining_result
!= pterr
) {
522 if (is_extra_caused_by(pextra
, EC_BASE
)) {
523 if (pterr
->base_time
== 0) {
526 if (tile_city(ptile
) != NULL
&& extra_base_get(pextra
)->border_sq
>= 0) {
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
)) {
538 } else if (pterr
->road_time
== 0) {
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 */
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 */
572 extra_type_by_cause_iterate(cause
, pextra
) {
573 if (!tile_has_extra(ptile
, pextra
)) {
575 if (can_build_extra(pextra
, punit
, ptile
)) {
579 /* punit is certainly NULL, pplayer can be too */
580 if (player_can_build_extra(pextra
, pplayer
, ptile
)) {
585 } extra_type_by_cause_iterate_end
;
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
)) {
603 if (can_remove_extra(pextra
, punit
, ptile
)) {
607 if (player_can_remove_extra(pextra
, pplayer
, ptile
)) {
612 } extra_type_by_rmcause_iterate_end
;
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
)) {
655 } cardinal_adjc_iterate_end
;
657 } extra_type_iterate_end
;
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
)) {
676 } extra_type_iterate_end
;
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
) {
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
)
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
);
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
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
)
771 case ACTIVITY_IRRIGATE
:
772 return EC_IRRIGATION
;
777 case ACTIVITY_GEN_ROAD
:
786 /**************************************************************************
787 What extra rmcause activity is considered to be?
788 **************************************************************************/
789 enum extra_rmcause
activity_to_extra_rmcause(enum unit_activity act
)
792 case ACTIVITY_PILLAGE
:
794 case ACTIVITY_POLLUTION
:
795 return ERM_CLEANPOLLUTION
;
796 case ACTIVITY_FALLOUT
:
797 return ERM_CLEANFALLOUT
;
805 /**************************************************************************
806 Who owns extras on tile
807 **************************************************************************/
808 struct player
*extra_owner(const struct tile
*ptile
)
810 return ptile
->extras_owner
;