Rulesave saves trade.type and trade.bonus correctly.
[freeciv.git] / common / terrain.c
blobb621d4425c6e22485cf6aa04cc65b918f23c5ba3
1 /***********************************************************************
2 Freeciv - Copyright (C) 2003 - The Freeciv Project
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 "fcintl.h"
20 #include "log.h" /* fc_assert */
21 #include "mem.h" /* free */
22 #include "rand.h"
23 #include "shared.h"
24 #include "string_vector.h"
25 #include "support.h"
27 /* common */
28 #include "extras.h"
29 #include "game.h"
30 #include "map.h"
31 #include "rgbcolor.h"
32 #include "road.h"
34 #include "terrain.h"
36 static struct terrain civ_terrains[MAX_NUM_TERRAINS];
37 static struct resource civ_resources[MAX_NUM_RESOURCES];
38 static struct user_flag user_terrain_flags[MAX_NUM_USER_TER_FLAGS];
40 /****************************************************************************
41 Initialize terrain and resource structures.
42 ****************************************************************************/
43 void terrains_init(void)
45 int i;
47 for (i = 0; i < ARRAY_SIZE(civ_terrains); i++) {
48 /* Can't use terrain_by_number here because it does a bounds check. */
49 civ_terrains[i].item_number = i;
50 civ_terrains[i].rgb = NULL;
51 civ_terrains[i].animal = NULL;
53 for (i = 0; i < ARRAY_SIZE(civ_resources); i++) {
54 civ_resources[i].item_number = i;
58 /****************************************************************************
59 Free memory which is associated with terrain types.
60 ****************************************************************************/
61 void terrains_free(void)
63 terrain_type_iterate(pterrain) {
64 if (NULL != pterrain->helptext) {
65 strvec_destroy(pterrain->helptext);
66 pterrain->helptext = NULL;
68 if (pterrain->resources != NULL) {
69 /* Server allocates this on ruleset loading, client when
70 * ruleset packet is received. */
71 free(pterrain->resources);
72 pterrain->resources = NULL;
74 if (pterrain->rgb != NULL) {
75 /* Server allocates this on ruleset loading, client when
76 * ruleset packet is received. */
77 rgbcolor_destroy(pterrain->rgb);
78 pterrain->rgb = NULL;
80 } terrain_type_iterate_end;
83 /**************************************************************************
84 Return the first item of terrains.
85 **************************************************************************/
86 struct terrain *terrain_array_first(void)
88 if (game.control.terrain_count > 0) {
89 return civ_terrains;
91 return NULL;
94 /**************************************************************************
95 Return the last item of terrains.
96 **************************************************************************/
97 const struct terrain *terrain_array_last(void)
99 if (game.control.terrain_count > 0) {
100 return &civ_terrains[game.control.terrain_count - 1];
102 return NULL;
105 /**************************************************************************
106 Return the number of terrains.
107 **************************************************************************/
108 Terrain_type_id terrain_count(void)
110 return game.control.terrain_count;
113 /**************************************************************************
114 Return the terrain identifier.
115 **************************************************************************/
116 char terrain_identifier(const struct terrain *pterrain)
118 fc_assert_ret_val(pterrain, '\0');
119 return pterrain->identifier;
122 /**************************************************************************
123 Return the terrain index.
125 Currently same as terrain_number(), paired with terrain_count()
126 indicates use as an array index.
127 **************************************************************************/
128 Terrain_type_id terrain_index(const struct terrain *pterrain)
130 fc_assert_ret_val(pterrain, -1);
131 return pterrain - civ_terrains;
134 /**************************************************************************
135 Return the terrain index.
136 **************************************************************************/
137 Terrain_type_id terrain_number(const struct terrain *pterrain)
139 fc_assert_ret_val(pterrain, -1);
140 return pterrain->item_number;
143 /****************************************************************************
144 Return the terrain for the given terrain index.
145 ****************************************************************************/
146 struct terrain *terrain_by_number(const Terrain_type_id type)
148 if (type < 0 || type >= game.control.terrain_count) {
149 /* This isn't an error; some T_UNKNOWN callers depend on it. */
150 return NULL;
152 return &civ_terrains[type];
155 /****************************************************************************
156 Return the terrain type matching the identifier, or T_UNKNOWN if none matches.
157 ****************************************************************************/
158 struct terrain *terrain_by_identifier(const char identifier)
160 if (TERRAIN_UNKNOWN_IDENTIFIER == identifier) {
161 return T_UNKNOWN;
163 terrain_type_iterate(pterrain) {
164 if (pterrain->identifier == identifier) {
165 return pterrain;
167 } terrain_type_iterate_end;
169 return T_UNKNOWN;
172 /****************************************************************************
173 Return the terrain type matching the name, or T_UNKNOWN if none matches.
174 ****************************************************************************/
175 struct terrain *terrain_by_rule_name(const char *name)
177 const char *qname = Qn_(name);
179 terrain_type_iterate(pterrain) {
180 if (0 == fc_strcasecmp(terrain_rule_name(pterrain), qname)) {
181 return pterrain;
183 } terrain_type_iterate_end;
185 return T_UNKNOWN;
188 /****************************************************************************
189 Return the terrain type matching the name, or T_UNKNOWN if none matches.
190 ****************************************************************************/
191 struct terrain *terrain_by_translated_name(const char *name)
193 terrain_type_iterate(pterrain) {
194 if (0 == strcmp(terrain_name_translation(pterrain), name)) {
195 return pterrain;
197 } terrain_type_iterate_end;
199 return T_UNKNOWN;
202 /****************************************************************************
203 Return terrain having the flag. If several terrains have the flag,
204 random one is returned.
205 ****************************************************************************/
206 struct terrain *rand_terrain_by_flag(enum terrain_flag_id flag)
208 int num = 0;
209 struct terrain *terr = NULL;
211 terrain_type_iterate(pterr) {
212 if (terrain_has_flag(pterr, flag)) {
213 num++;
214 if (fc_rand(num) == 1) {
215 terr = pterr;
218 } terrain_type_iterate_end;
220 return terr;
223 /****************************************************************************
224 Return the (translated) name of the terrain.
225 You don't have to free the return pointer.
226 ****************************************************************************/
227 const char *terrain_name_translation(const struct terrain *pterrain)
229 return name_translation_get(&pterrain->name);
232 /**************************************************************************
233 Return the (untranslated) rule name of the terrain.
234 You don't have to free the return pointer.
235 **************************************************************************/
236 const char *terrain_rule_name(const struct terrain *pterrain)
238 return rule_name_get(&pterrain->name);
241 /****************************************************************************
242 Check for resource in terrain resources list.
243 ****************************************************************************/
244 bool terrain_has_resource(const struct terrain *pterrain,
245 const struct resource *presource)
247 struct resource **r = pterrain->resources;
249 while (NULL != *r) {
250 if (*r == presource) {
251 return TRUE;
253 r++;
255 return FALSE;
258 /**************************************************************************
259 Return the first item of resources.
260 **************************************************************************/
261 struct resource *resource_array_first(void)
263 if (game.control.resource_count > 0) {
264 return civ_resources;
266 return NULL;
269 /**************************************************************************
270 Return the last item of resources.
271 **************************************************************************/
272 const struct resource *resource_array_last(void)
274 if (game.control.resource_count > 0) {
275 return &civ_resources[game.control.resource_count - 1];
277 return NULL;
280 /**************************************************************************
281 Return the resource count.
282 **************************************************************************/
283 Resource_type_id resource_count(void)
285 return game.control.resource_count;
288 /**************************************************************************
289 Return the resource index.
291 Currently same as resource_number(), paired with resource_count()
292 indicates use as an array index.
293 **************************************************************************/
294 Resource_type_id resource_index(const struct resource *presource)
296 fc_assert_ret_val(NULL != presource, -1);
297 return presource - civ_resources;
300 /**************************************************************************
301 Return the resource index.
302 **************************************************************************/
303 Resource_type_id resource_number(const struct resource *presource)
305 fc_assert_ret_val(NULL != presource, -1);
306 return presource->item_number;
309 /****************************************************************************
310 Return the resource for the given resource index.
311 ****************************************************************************/
312 struct resource *resource_by_number(const Resource_type_id type)
314 if (type < 0 || type >= game.control.resource_count) {
315 /* This isn't an error; some callers depend on it. */
316 return NULL;
318 return &civ_resources[type];
321 /****************************************************************************
322 Return the resource type matching the identifier, or NULL when none matches.
323 ****************************************************************************/
324 struct resource *resource_by_identifier(const char identifier)
326 resource_type_iterate(presource) {
327 if (presource->identifier == identifier) {
328 return presource;
330 } resource_type_iterate_end;
332 return NULL;
335 /****************************************************************************
336 Return the resource type matching the name, or NULL when none matches.
337 ****************************************************************************/
338 struct resource *resource_by_rule_name(const char *name)
340 const char *qname = Qn_(name);
342 resource_type_iterate(presource) {
343 if (0 == fc_strcasecmp(resource_rule_name(presource), qname)) {
344 return presource;
346 } resource_type_iterate_end;
348 return NULL;
351 /****************************************************************************
352 Return the (translated) name of the resource.
353 You don't have to free the return pointer.
354 ****************************************************************************/
355 const char *resource_name_translation(const struct resource *presource)
357 return name_translation_get(&presource->name);
360 /**************************************************************************
361 Return the (untranslated) rule name of the resource.
362 You don't have to free the return pointer.
363 **************************************************************************/
364 const char *resource_rule_name(const struct resource *presource)
366 return rule_name_get(&presource->name);
369 /****************************************************************************
370 This iterator behaves like adjc_iterate or cardinal_adjc_iterate depending
371 on the value of card_only.
372 ****************************************************************************/
373 #define variable_adjc_iterate(center_tile, _tile, card_only) \
375 enum direction8 *_tile##_list; \
376 int _tile##_count; \
378 if (card_only) { \
379 _tile##_list = game.map.cardinal_dirs; \
380 _tile##_count = game.map.num_cardinal_dirs; \
381 } else { \
382 _tile##_list = game.map.valid_dirs; \
383 _tile##_count = game.map.num_valid_dirs; \
385 adjc_dirlist_iterate(center_tile, _tile, _tile##_dir, \
386 _tile##_list, _tile##_count) {
388 #define variable_adjc_iterate_end \
389 } adjc_dirlist_iterate_end; \
392 /****************************************************************************
393 Returns TRUE iff any cardinally adjacent tile contains the given terrain.
394 ****************************************************************************/
395 bool is_terrain_card_near(const struct tile *ptile,
396 const struct terrain *pterrain,
397 bool check_self)
399 if (!pterrain) {
400 return FALSE;
403 cardinal_adjc_iterate(ptile, adjc_tile) {
404 if (tile_terrain(adjc_tile) == pterrain) {
405 return TRUE;
407 } cardinal_adjc_iterate_end;
409 return check_self && ptile->terrain == pterrain;
412 /****************************************************************************
413 Returns TRUE iff any adjacent tile contains the given terrain.
414 ****************************************************************************/
415 bool is_terrain_near_tile(const struct tile *ptile,
416 const struct terrain *pterrain,
417 bool check_self)
419 if (!pterrain) {
420 return FALSE;
423 adjc_iterate(ptile, adjc_tile) {
424 if (tile_terrain(adjc_tile) == pterrain) {
425 return TRUE;
427 } adjc_iterate_end;
429 return check_self && ptile->terrain == pterrain;
432 /****************************************************************************
433 Return the number of adjacent tiles that have the given terrain.
434 ****************************************************************************/
435 int count_terrain_near_tile(const struct tile *ptile,
436 bool cardinal_only, bool percentage,
437 const struct terrain *pterrain)
439 int count = 0, total = 0;
441 variable_adjc_iterate(ptile, adjc_tile, cardinal_only) {
442 if (pterrain && tile_terrain(adjc_tile) == pterrain) {
443 count++;
445 total++;
446 } variable_adjc_iterate_end;
448 if (percentage) {
449 count = count * 100 / total;
451 return count;
454 /****************************************************************************
455 Return the number of adjacent tiles that have the given terrain property.
456 ****************************************************************************/
457 int count_terrain_property_near_tile(const struct tile *ptile,
458 bool cardinal_only, bool percentage,
459 enum mapgen_terrain_property prop)
461 int count = 0, total = 0;
463 variable_adjc_iterate(ptile, adjc_tile, cardinal_only) {
464 struct terrain *pterrain = tile_terrain(adjc_tile);
465 if (pterrain->property[prop] > 0) {
466 count++;
468 total++;
469 } variable_adjc_iterate_end;
471 if (percentage) {
472 count = count * 100 / total;
474 return count;
477 /****************************************************************************
478 Returns TRUE iff any cardinally adjacent tile contains the given resource.
479 ****************************************************************************/
480 bool is_resource_card_near(const struct tile *ptile,
481 const struct resource *pres,
482 bool check_self)
484 if (!pres) {
485 return FALSE;
488 cardinal_adjc_iterate(ptile, adjc_tile) {
489 if (tile_resource(adjc_tile) == pres) {
490 return TRUE;
492 } cardinal_adjc_iterate_end;
494 return check_self && tile_resource(ptile) == pres;
497 /****************************************************************************
498 Returns TRUE iff any adjacent tile contains the given resource.
499 ****************************************************************************/
500 bool is_resource_near_tile(const struct tile *ptile,
501 const struct resource *pres,
502 bool check_self)
504 if (!pres) {
505 return FALSE;
508 adjc_iterate(ptile, adjc_tile) {
509 if (tile_resource(adjc_tile) == pres) {
510 return TRUE;
512 } adjc_iterate_end;
514 return check_self && tile_resource(ptile) == pres;
517 /****************************************************************************
518 Returns TRUE iff any cardinally adjacent tile contains terrain with the
519 given flag (does not check ptile itself).
520 ****************************************************************************/
521 bool is_terrain_flag_card_near(const struct tile *ptile,
522 enum terrain_flag_id flag)
524 cardinal_adjc_iterate(ptile, adjc_tile) {
525 struct terrain* pterrain = tile_terrain(adjc_tile);
526 if (T_UNKNOWN != pterrain
527 && terrain_has_flag(pterrain, flag)) {
528 return TRUE;
530 } cardinal_adjc_iterate_end;
532 return FALSE;
535 /****************************************************************************
536 Returns TRUE iff any adjacent tile contains terrain with the given flag
537 (does not check ptile itself).
538 ****************************************************************************/
539 bool is_terrain_flag_near_tile(const struct tile *ptile,
540 enum terrain_flag_id flag)
542 adjc_iterate(ptile, adjc_tile) {
543 struct terrain* pterrain = tile_terrain(adjc_tile);
544 if (T_UNKNOWN != pterrain
545 && terrain_has_flag(pterrain, flag)) {
546 return TRUE;
548 } adjc_iterate_end;
550 return FALSE;
553 /****************************************************************************
554 Return the number of adjacent tiles that have terrain with the given flag
555 (not including ptile itself).
556 ****************************************************************************/
557 int count_terrain_flag_near_tile(const struct tile *ptile,
558 bool cardinal_only, bool percentage,
559 enum terrain_flag_id flag)
561 int count = 0, total = 0;
563 variable_adjc_iterate(ptile, adjc_tile, cardinal_only) {
564 struct terrain *pterrain = tile_terrain(adjc_tile);
565 if (T_UNKNOWN != pterrain
566 && terrain_has_flag(pterrain, flag)) {
567 count++;
569 total++;
570 } variable_adjc_iterate_end;
572 if (percentage) {
573 count = count * 100 / total;
575 return count;
578 /****************************************************************************
579 Return a (static) string with extra(s) name(s):
580 eg: "Mine"
581 eg: "Road/Farmland"
582 This only includes "infrastructure", i.e., man-made extras.
583 ****************************************************************************/
584 const char *get_infrastructure_text(bv_extras extras)
586 static char s[256];
587 char *p;
588 int len;
590 s[0] = '\0';
592 extra_type_iterate(pextra) {
593 if (pextra->category == ECAT_INFRA
594 && BV_ISSET(extras, extra_index(pextra))) {
595 bool hidden = FALSE;
597 extra_type_iterate(top) {
598 int topi = extra_index(top);
600 if (BV_ISSET(pextra->hidden_by, topi)
601 && BV_ISSET(extras, topi)) {
602 hidden = TRUE;
603 break;
605 } extra_type_iterate_end;
607 if (!hidden) {
608 cat_snprintf(s, sizeof(s), "%s/", extra_name_translation(pextra));
611 } extra_type_iterate_end;
613 len = strlen(s);
614 p = s + len - 1;
615 if (len > 0 && *p == '/') {
616 *p = '\0';
619 return s;
622 /****************************************************************************
623 Returns the highest-priority (best) infrastructure (man-made extra) to
624 be pillaged from the terrain set. May return NULL if nothing
625 better is available.
626 ****************************************************************************/
627 struct extra_type *get_preferred_pillage(bv_extras extras)
629 extra_type_by_cause_iterate_rev(EC_IRRIGATION, pextra) {
630 if (is_extra_removed_by(pextra, ERM_PILLAGE) && BV_ISSET(extras, extra_index(pextra))) {
631 return pextra;
633 } extra_type_by_cause_iterate_rev_end;
635 extra_type_by_cause_iterate_rev(EC_MINE, pextra) {
636 if (is_extra_removed_by(pextra, ERM_PILLAGE) && BV_ISSET(extras, extra_index(pextra))) {
637 return pextra;
639 } extra_type_by_cause_iterate_rev_end;
641 extra_type_by_cause_iterate_rev(EC_BASE, pextra) {
642 if (is_extra_removed_by(pextra, ERM_PILLAGE) && BV_ISSET(extras, extra_index(pextra))) {
643 return pextra;
645 } extra_type_by_cause_iterate_rev_end;
647 extra_type_by_cause_iterate_rev(EC_ROAD, pextra) {
648 if (is_extra_removed_by(pextra, ERM_PILLAGE) && BV_ISSET(extras, extra_index(pextra))) {
649 return pextra;
651 } extra_type_by_cause_iterate_rev_end;
653 extra_type_by_cause_iterate_rev(EC_NONE, pextra) {
654 if (is_extra_removed_by(pextra, ERM_PILLAGE) && BV_ISSET(extras, extra_index(pextra))) {
655 return pextra;
657 } extra_type_by_cause_iterate_rev_end;
659 return NULL;
662 /****************************************************************************
663 What terrain class terrain type belongs to.
664 ****************************************************************************/
665 enum terrain_class terrain_type_terrain_class(const struct terrain *pterrain)
667 return pterrain->tclass;
670 /****************************************************************************
671 Is there terrain of the given class cardinally near tile?
672 (Does not check ptile itself.)
673 ****************************************************************************/
674 bool is_terrain_class_card_near(const struct tile *ptile,
675 enum terrain_class tclass)
677 cardinal_adjc_iterate(ptile, adjc_tile) {
678 struct terrain* pterrain = tile_terrain(adjc_tile);
680 if (pterrain != T_UNKNOWN) {
681 if (terrain_type_terrain_class(pterrain) == tclass) {
682 return TRUE;
685 } cardinal_adjc_iterate_end;
687 return FALSE;
690 /****************************************************************************
691 Is there terrain of the given class near tile?
692 (Does not check ptile itself.)
693 ****************************************************************************/
694 bool is_terrain_class_near_tile(const struct tile *ptile,
695 enum terrain_class tclass)
697 adjc_iterate(ptile, adjc_tile) {
698 struct terrain* pterrain = tile_terrain(adjc_tile);
700 if (pterrain != T_UNKNOWN) {
701 if (terrain_type_terrain_class(pterrain) == tclass) {
702 return TRUE;
705 } adjc_iterate_end;
707 return FALSE;
710 /****************************************************************************
711 Return the number of adjacent tiles that have given terrain class
712 (not including ptile itself).
713 ****************************************************************************/
714 int count_terrain_class_near_tile(const struct tile *ptile,
715 bool cardinal_only, bool percentage,
716 enum terrain_class tclass)
718 int count = 0, total = 0;
720 variable_adjc_iterate(ptile, adjc_tile, cardinal_only) {
721 struct terrain *pterrain = tile_terrain(adjc_tile);
722 if (T_UNKNOWN != pterrain
723 && terrain_type_terrain_class(pterrain) == tclass) {
724 count++;
726 total++;
727 } variable_adjc_iterate_end;
729 if (percentage) {
730 count = count * 100 / total;
733 return count;
736 /****************************************************************************
737 Return the (translated) name of the given terrain class.
738 You don't have to free the return pointer.
739 ****************************************************************************/
740 const char *terrain_class_name_translation(enum terrain_class tclass)
742 if (!terrain_class_is_valid(tclass)) {
743 return NULL;
746 return _(terrain_class_name(tclass));
749 /****************************************************************************
750 Can terrain support given infrastructure?
751 ****************************************************************************/
752 bool terrain_can_support_alteration(const struct terrain *pterrain,
753 enum terrain_alteration alter)
755 switch (alter) {
756 case TA_CAN_IRRIGATE:
757 return (pterrain == pterrain->irrigation_result);
758 case TA_CAN_MINE:
759 return (pterrain == pterrain->mining_result);
760 case TA_CAN_ROAD:
761 return (pterrain->road_time > 0);
762 default:
763 break;
766 fc_assert(FALSE);
767 return FALSE;
770 /****************************************************************************
771 Time to complete the extra building activity on the given terrain.
772 ****************************************************************************/
773 int terrain_extra_build_time(const struct terrain *pterrain,
774 enum unit_activity activity,
775 const struct extra_type *tgt)
777 int factor;
779 if (tgt != NULL && tgt->build_time != 0) {
780 /* Extra specific build time */
781 return tgt->build_time;
784 if (tgt == NULL) {
785 factor = 1;
786 } else {
787 factor = tgt->build_time_factor;
790 /* Terrain and activity specific build time */
791 switch (activity) {
792 case ACTIVITY_BASE:
793 return pterrain->base_time * factor;
794 case ACTIVITY_GEN_ROAD:
795 return pterrain->road_time * factor;
796 case ACTIVITY_IRRIGATE:
797 return pterrain->irrigation_time * factor;
798 case ACTIVITY_MINE:
799 return pterrain->mining_time * factor;
800 default:
801 fc_assert(FALSE);
802 return 0;
806 /****************************************************************************
807 Time to complete the extra removal activity on the given terrain.
808 ****************************************************************************/
809 int terrain_extra_removal_time(const struct terrain *pterrain,
810 enum unit_activity activity,
811 const struct extra_type *tgt)
813 int factor;
815 if (tgt != NULL && tgt->removal_time != 0) {
816 /* Extra specific removal time */
817 return tgt->removal_time;
820 if (tgt == NULL) {
821 factor = 1;
822 } else {
823 factor = tgt->removal_time_factor;
826 /* Terrain and activity specific removal time */
827 switch (activity) {
828 case ACTIVITY_POLLUTION:
829 return pterrain->clean_pollution_time * factor;
830 case ACTIVITY_FALLOUT:
831 return pterrain->clean_fallout_time * factor;
832 case ACTIVITY_PILLAGE:
833 return pterrain->pillage_time * factor;
834 default:
835 fc_assert(FALSE);
836 return 0;
840 /**************************************************************************
841 Initialize user terrain type flags.
842 **************************************************************************/
843 void user_terrain_flags_init(void)
845 int i;
847 for (i = 0; i < MAX_NUM_USER_TER_FLAGS; i++) {
848 user_flag_init(&user_terrain_flags[i]);
852 /***************************************************************
853 Frees the memory associated with all user terrain flags
854 ***************************************************************/
855 void user_terrain_flags_free(void)
857 int i;
859 for (i = 0; i < MAX_NUM_USER_TER_FLAGS; i++) {
860 user_flag_free(&user_terrain_flags[i]);
864 /**************************************************************************
865 Sets user defined name for terrain flag.
866 **************************************************************************/
867 void set_user_terrain_flag_name(enum terrain_flag_id id, const char *name,
868 const char *helptxt)
870 int tfid = id - TER_USER_1;
872 fc_assert_ret(id >= TER_USER_1 && id <= TER_USER_LAST);
874 if (user_terrain_flags[tfid].name != NULL) {
875 FC_FREE(user_terrain_flags[tfid].name);
876 user_terrain_flags[tfid].name = NULL;
879 if (name && name[0] != '\0') {
880 user_terrain_flags[tfid].name = fc_strdup(name);
883 if (user_terrain_flags[tfid].helptxt != NULL) {
884 FC_FREE(user_terrain_flags[tfid].helptxt);
885 user_terrain_flags[tfid].helptxt = NULL;
888 if (helptxt && helptxt[0] != '\0') {
889 user_terrain_flags[tfid].helptxt = fc_strdup(helptxt);
893 /**************************************************************************
894 Terrain flag name callback, called from specenum code.
895 **************************************************************************/
896 const char *terrain_flag_id_name_cb(enum terrain_flag_id flag)
898 if (flag < TER_USER_1 || flag > TER_USER_LAST) {
899 return NULL;
902 return user_terrain_flags[flag-TER_USER_1].name;
905 /**************************************************************************
906 Return the (untranslated) helptxt of the user terrain flag.
907 **************************************************************************/
908 const char *terrain_flag_helptxt(enum terrain_flag_id id)
910 fc_assert(id >= TER_USER_1 && id <= TER_USER_LAST);
912 return user_terrain_flags[id - TER_USER_1].helptxt;