Freeciv21
Develop your civilization from humble roots to a global empire
tech.cpp
Go to the documentation of this file.
1 /*__ ___ ***************************************
2 / \ / \ Copyright (c) 1996-2020 Freeciv21 and Freeciv
3 \_ \ / __/ contributors. This file is part of Freeciv21.
4  _\ \ / /__ Freeciv21 is free software: you can redistribute it
5  \___ \____/ __/ and/or modify it under the terms of the GNU General
6  \_ _/ Public License as published by the Free Software
7  | @ @ \_ Foundation, either version 3 of the License,
8  | or (at your option) any later version.
9  _/ /\ You should have received a copy of the GNU
10  /o) (o/\ \_ General Public License along with Freeciv21.
11  \_____/ / If not, see https://www.gnu.org/licenses/.
12  \____/ ********************************************************/
13 
14 #include <cmath>
15 #include <cstring>
16 
17 // utility
18 #include "fcintl.h"
19 #include "iterator.h"
20 #include "log.h"
21 #include "shared.h" // ARRAY_SIZE
22 #include "support.h"
23 
24 // common
25 #include "game.h"
26 #include "tech.h"
27 
29  struct iterator base;
30  bv_techs done;
31  const struct advance *array[A_LAST];
32  const struct advance **current, **end;
33 };
34 #define ADVANCE_REQ_ITER(it) ((struct advance_req_iter *) it)
35 
37  struct iterator base;
38  bv_techs done, rootdone;
39  const struct advance *array[A_LAST];
40  const struct advance **current, **end;
41 };
42 #define ADVANCE_ROOT_REQ_ITER(it) ((struct advance_root_req_iter *) it)
43 
44 /* the advances array is now setup in:
45  * server/ruleset.c (for the server)
46  * client/packhand.c (for the client)
47  */
49 
51 
53 
57 const struct advance *advance_array_last()
58 {
59  if (game.control.num_tech_types > 0) {
60  return &advances[game.control.num_tech_types - 1];
61  }
62  return nullptr;
63 }
64 
68 Tech_type_id advance_count() { return game.control.num_tech_types; }
69 
76 Tech_type_id advance_index(const struct advance *padvance)
77 {
78  fc_assert_ret_val(nullptr != padvance, 0);
79  return padvance - advances;
80 }
81 
85 Tech_type_id advance_number(const struct advance *padvance)
86 {
87  fc_assert_ret_val(nullptr != padvance, 0);
88  return padvance->item_number;
89 }
90 
95 {
96  if (atype != A_FUTURE
97  && (atype < 0 || atype >= game.control.num_tech_types)) {
98  // This isn't an error; some callers depend on it.
99  return nullptr;
100  }
101 
102  return &advances[atype];
103 }
104 
109 {
111  fc_assert_ret_val(tech >= A_NONE && tech < A_LAST, 0);
112  if (A_NEVER == advances[tech].require[require]) {
113  // out of range
114  return A_LAST;
115  }
116  return advance_number(advances[tech].require[require]);
117 }
118 
122 struct advance *advance_requires(const struct advance *padvance,
123  enum tech_req require)
124 {
125  fc_assert_ret_val(require >= 0 && require < AR_SIZE, nullptr);
126  fc_assert_ret_val(nullptr != padvance, nullptr);
127  return padvance->require[require];
128 }
129 
138 struct advance *valid_advance(struct advance *padvance)
139 {
140  if (nullptr == padvance || A_NEVER == padvance->require[AR_ONE]
141  || A_NEVER == padvance->require[AR_TWO]) {
142  return nullptr;
143  }
144 
145  return padvance;
146 }
147 
155 {
156  return valid_advance(advance_by_number(id));
157 }
158 
164 {
165  advance_iterate(A_NONE, padvance)
166  {
167  if (0 == strcmp(advance_name_translation(padvance), name)) {
168  return padvance;
169  }
170  }
172 
173  return nullptr;
174 }
175 
180 struct advance *advance_by_rule_name(const char *name)
181 {
182  const char *qname = Qn_(name);
183 
184  advance_iterate(A_NONE, padvance)
185  {
186  if (0 == fc_strcasecmp(advance_rule_name(padvance), qname)) {
187  return padvance;
188  }
189  }
191 
192  return nullptr;
193 }
194 
198 bool advance_has_flag(Tech_type_id tech, enum tech_flag_id flag)
199 {
200  fc_assert_ret_val(tech_flag_id_is_valid(flag), false);
201  return BV_ISSET(advance_by_number(tech)->flags, flag);
202 }
203 
208 {
209  fc_assert_msg(tech_cost_style_is_valid(game.info.tech_cost_style),
210  "Invalid tech_cost_style %d", game.info.tech_cost_style);
211 
212  advance_iterate(A_FIRST, padvance)
213  {
214  int num_reqs = 0;
215  bool min_req = true;
216 
217  advance_req_iterate(padvance, preq)
218  {
219  (void) preq; // Compiler wants us to do something with 'preq'.
220  num_reqs++;
221  }
223  padvance->num_reqs = num_reqs;
224 
225  switch (game.info.tech_cost_style) {
226  case TECH_COST_CIV1CIV2:
227  case TECH_COST_LINEAR:
228  padvance->cost = game.info.base_tech_cost * num_reqs;
229  break;
230  case TECH_COST_CLASSIC_PRESET:
231  if (-1 != padvance->cost) {
232  min_req = false;
233  break;
234  }
235  fc__fallthrough; // No break.
236  case TECH_COST_CLASSIC:
237  padvance->cost = game.info.base_tech_cost * (1.0 + num_reqs)
238  * sqrt(1.0 + num_reqs) / 2;
239  break;
240  case TECH_COST_EXPERIMENTAL_PRESET:
241  if (-1 != padvance->cost) {
242  min_req = false;
243  break;
244  }
245  fc__fallthrough; // No break.
246  case TECH_COST_EXPERIMENTAL:
247  padvance->cost =
248  game.info.base_tech_cost
249  * ((num_reqs) * (num_reqs) / (1 + sqrt(sqrt(num_reqs + 1))) - 0.5);
250  break;
251  }
252 
253  if (min_req && padvance->cost < game.info.base_tech_cost) {
254  padvance->cost = game.info.base_tech_cost;
255  }
256 
257  // Class cost
258  if (padvance->tclass != nullptr) {
259  padvance->cost = padvance->cost * padvance->tclass->cost_pct / 100;
260  }
261  }
263 }
264 
268 bool is_future_tech(Tech_type_id tech) { return tech == A_FUTURE; }
269 
274 const char *advance_name_translation(const struct advance *padvance)
275 {
276  return name_translation_get(&padvance->name);
277 }
278 
283 const char *advance_rule_name(const struct advance *padvance)
284 {
285  return rule_name_get(&padvance->name);
286 }
287 
292 {
293  int i;
294 
295  for (i = 0; i < MAX_NUM_TECH_CLASSES; i++) {
296  tech_classes[i].idx = i;
297  tech_classes[i].ruledit_disabled = false;
298  }
299 }
300 
305 {
306  if (idx < 0 || idx >= game.control.num_tech_classes) {
307  return nullptr;
308  }
309 
310  return &tech_classes[idx];
311 }
312 
317 const char *tech_class_name_translation(const struct tech_class *ptclass)
318 {
319  return name_translation_get(&ptclass->name);
320 }
321 
326 const char *tech_class_rule_name(const struct tech_class *ptclass)
327 {
328  return rule_name_get(&ptclass->name);
329 }
330 
336 {
337  const char *qname = Qn_(name);
338  int i;
339 
340  for (i = 0; i < game.control.num_tech_classes; i++) {
341  struct tech_class *ptclass = tech_class_by_number(i);
342 
343  if (!fc_strcasecmp(tech_class_rule_name(ptclass), qname)) {
344  return ptclass;
345  }
346  }
347 
348  return nullptr;
349 }
350 
355 {
356  int i;
357 
358  for (i = 0; i < MAX_NUM_USER_TECH_FLAGS; i++) {
360  }
361 }
362 
367 {
368  int i;
369 
370  for (i = 0; i < MAX_NUM_USER_TECH_FLAGS; i++) {
372  }
373 }
374 
378 void set_user_tech_flag_name(enum tech_flag_id id, const char *name,
379  const char *helptxt)
380 {
381  int tfid = id - TECH_USER_1;
382 
383  fc_assert_ret(id >= TECH_USER_1 && id <= TECH_USER_LAST);
384 
385  delete[] user_tech_flags[tfid].name;
386  user_tech_flags[tfid].name = nullptr;
387  if (name && name[0] != '\0') {
389  }
390 
391  delete[] user_tech_flags[tfid].helptxt;
392  user_tech_flags[tfid].helptxt = nullptr;
393  if (helptxt && helptxt[0] != '\0') {
394  user_tech_flags[tfid].helptxt = fc_strdup(helptxt);
395  }
396 }
397 
401 const char *tech_flag_id_name_cb(enum tech_flag_id flag)
402 {
403  if (flag < TECH_USER_1 || flag > TECH_USER_LAST) {
404  return nullptr;
405  }
406 
407  return user_tech_flags[flag - TECH_USER_1].name;
408 }
409 
413 const char *tech_flag_helptxt(enum tech_flag_id id)
414 {
415  fc_assert(id >= TECH_USER_1 && id <= TECH_USER_LAST);
416 
417  return user_tech_flags[id - TECH_USER_1].helptxt;
418 }
419 
429 {
430  return (game.info.tech_leakage == TECH_LEAKAGE_NONE
431  && game.info.tech_cost_style != TECH_COST_CIV1CIV2);
432 }
433 
438 {
439  struct advance *a_none = &advances[A_NONE];
440  struct advance *a_future = &advances[A_FUTURE];
441  int i;
442 
443  memset(advances, 0, sizeof(advances));
444  for (i = 0; i < ARRAY_SIZE(advances); i++) {
445  advances[i].item_number = i;
446  advances[i].cost = -1;
447  advances[i].inherited_root_req = false;
448  advances[i].tclass = 0;
449 
450  requirement_vector_init(&(advances[i].research_reqs));
451  }
452 
453  // Initialize dummy tech A_NONE
454  // TRANS: "None" tech
455  name_set(&a_none->name, nullptr, N_("?tech:None"));
456  a_none->require[AR_ONE] = a_none;
457  a_none->require[AR_TWO] = a_none;
458  a_none->require[AR_ROOT] = A_NEVER;
459 
460  name_set(&a_future->name, nullptr, "Future");
461  a_future->require[AR_ONE] = A_NEVER;
462  a_future->require[AR_TWO] = A_NEVER;
463  a_future->require[AR_ROOT] = A_NEVER;
464 }
465 
469 static void tech_free(Tech_type_id tech)
470 {
471  struct advance *p = &advances[tech];
472  delete p->helptext;
473  p->helptext = nullptr;
474  delete[] p->bonus_message;
475  p->bonus_message = nullptr;
476 }
477 
482 {
483  int i;
484 
485  advance_index_iterate(A_FIRST, adv_idx) { tech_free(adv_idx); }
487 
488  for (i = 0; i < ARRAY_SIZE(advances); i++) {
489  requirement_vector_free(&(advances[i].research_reqs));
490  }
491 }
492 
496 size_t advance_req_iter_sizeof() { return sizeof(struct advance_req_iter); }
497 
501 static void *advance_req_iter_get(const struct iterator *it)
502 {
503  return (void *) *ADVANCE_REQ_ITER(it)->current;
504 }
505 
509 static void advance_req_iter_next(struct iterator *it)
510 {
511  struct advance_req_iter *iter = ADVANCE_REQ_ITER(it);
512  const struct advance *padvance = *iter->current, *preq;
513  bool is_new = false;
514 
515  for (int req = AR_ONE; req < AR_SIZE; req++) {
516  preq = valid_advance(advance_requires(padvance, tech_req(req)));
517  if (nullptr != preq && A_NONE != advance_number(preq)
518  && !BV_ISSET(iter->done, advance_number(preq))) {
519  BV_SET(iter->done, advance_number(preq));
520  if (is_new) {
521  *iter->end++ = preq;
522  } else {
523  *iter->current = preq;
524  is_new = true;
525  }
526  }
527  }
528 
529  if (!is_new) {
530  iter->current++;
531  }
532 }
533 
537 static bool advance_req_iter_valid(const struct iterator *it)
538 {
539  const struct advance_req_iter *iter = ADVANCE_REQ_ITER(it);
540 
541  return iter->current < iter->end;
542 }
543 
548  const struct advance *goal)
549 {
550  struct iterator *base = ITERATOR(it);
551 
552  base->get = advance_req_iter_get;
553  base->next = advance_req_iter_next;
554  base->valid = advance_req_iter_valid;
555 
556  BV_CLR_ALL(it->done);
557  it->current = it->array;
558  *it->current = goal;
559  it->end = it->current + 1;
560 
561  return base;
562 }
563 
568 {
569  return sizeof(struct advance_root_req_iter);
570 }
571 
575 static void *advance_root_req_iter_get(const struct iterator *it)
576 {
577  return (void *) advance_requires(*ADVANCE_ROOT_REQ_ITER(it)->current,
578  AR_ROOT);
579 }
580 
584 static bool advance_root_req_iter_valid(const struct iterator *it)
585 {
586  const struct advance_root_req_iter *iter = ADVANCE_ROOT_REQ_ITER(it);
587 
588  return iter->current < iter->end;
589 }
590 
594 static void advance_root_req_iter_next(struct iterator *it)
595 {
596  struct advance_root_req_iter *iter = ADVANCE_ROOT_REQ_ITER(it);
597 
598  /* Precondition: either iteration has already finished, or iter->current
599  * points at a tech with an interesting root_req (which means its
600  * requirements may have more). */
601  while (advance_root_req_iter_valid(it)) {
602  const struct advance *padvance = *iter->current;
603  bool is_new = false;
604 
605  for (int req = AR_ONE; req < AR_SIZE; req++) {
606  const struct advance *preq =
607  valid_advance(advance_requires(padvance, tech_req(req)));
608 
609  if (nullptr != preq && A_NONE != advance_number(preq)
610  && !BV_ISSET(iter->done, advance_number(preq))) {
611  BV_SET(iter->done, advance_number(preq));
612  /* Do we need to look at this subtree at all? If it has A_NONE as
613  * root_req, further root_reqs can't propagate through it, so no. */
615  /* Yes, this subtree needs iterating over at some point, starting
616  * with preq (whose own root_req we'll consider in a bit) */
617  if (!is_new) {
618  *iter->current = preq;
619  is_new = true;
620  } else {
621  *iter->end++ = preq; // make a note for later
622  }
623  }
624  }
625  }
626  if (!is_new) {
627  // Didn't find an interesting new subtree.
628  iter->current++;
629  }
630  /* Precondition: *current has been moved on from where we started, and
631  * it has an interesting root_req or it wouldn't be on the list; but
632  * it may be one that we've already yielded. */
633  if (advance_root_req_iter_valid(it)) {
634  Tech_type_id root =
636  if (!BV_ISSET(iter->rootdone, root)) {
637  // A previously unseen root_req. Stop and yield it.
638  break;
639  } // else keep looking
640  }
641  }
642 }
643 
648  const struct advance *goal)
649 {
650  struct iterator *base = ITERATOR(it);
651 
655 
656  BV_CLR_ALL(it->done);
657  BV_CLR_ALL(it->rootdone);
658  it->current = it->array;
660  /* First root_req to return is goal's own, and there may be more
661  * for next() to find. */
662  *it->current = goal;
663  it->end = it->current + 1;
664  } else {
665  // No root_reqs -- go straight to invalid state
666  it->end = it->current;
667  }
668 
669  return base;
670 }
#define BV_CLR_ALL(bv)
Definition: bitvector.h:62
#define BV_SET(bv, bit)
Definition: bitvector.h:44
bool BV_ISSET(const BV &bv, int bit)
Definition: bitvector.h:37
static void base(QVariant data1, QVariant data2)
Action "Build Base" for choice dialog.
Definition: dialogs.cpp:2393
int Tech_type_id
Definition: fc_types.h:294
#define MAX_NUM_TECH_CLASSES
Definition: fc_types.h:58
#define Qn_(String)
Definition: fcintl.h:66
#define N_(String)
Definition: fcintl.h:52
void user_flag_init(struct user_flag *flag)
Initialize user flag.
Definition: game.cpp:788
void user_flag_free(struct user_flag *flag)
Free user flag.
Definition: game.cpp:797
struct civ_game game
Definition: game.cpp:47
const char * name
Definition: inputfile.cpp:118
#define ITERATOR(p)
Definition: iterator.h:26
#define fc_assert_msg(condition, message,...)
Definition: log.h:96
#define fc_assert_ret(condition)
Definition: log.h:112
#define fc_assert(condition)
Definition: log.h:89
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
static void name_set(struct name_translation *ptrans, const char *domain, const char *vernacular_name)
static const char * rule_name_get(const struct name_translation *ptrans)
static const char * name_translation_get(const struct name_translation *ptrans)
#define ARRAY_SIZE(x)
Definition: shared.h:79
bv_techs done
Definition: tech.cpp:30
const struct advance ** end
Definition: tech.cpp:32
const struct advance ** current
Definition: tech.cpp:32
struct iterator base
Definition: tech.cpp:29
const struct advance * array[A_LAST]
Definition: tech.cpp:31
const struct advance * array[A_LAST]
Definition: tech.cpp:39
const struct advance ** current
Definition: tech.cpp:40
bv_techs rootdone
Definition: tech.cpp:38
const struct advance ** end
Definition: tech.cpp:40
struct iterator base
Definition: tech.cpp:37
Definition: tech.h:113
struct requirement_vector research_reqs
Definition: tech.h:125
struct tech_class * tclass
Definition: tech.h:118
double cost
Definition: tech.h:138
struct advance * require[AR_SIZE]
Definition: tech.h:120
struct name_translation name
Definition: tech.h:115
char * bonus_message
Definition: tech.h:133
bool inherited_root_req
Definition: tech.h:121
bv_tech_flags flags
Definition: tech.h:127
int num_reqs
Definition: tech.h:144
Tech_type_id item_number
Definition: tech.h:114
QVector< QString > * helptext
Definition: tech.h:128
struct packet_ruleset_control control
Definition: game.h:74
struct packet_game_info info
Definition: game.h:80
struct name_translation name
Definition: tech.h:108
bool ruledit_disabled
Definition: tech.h:109
int idx
Definition: tech.h:107
Definition: game.h:64
char * name
Definition: game.h:65
char * helptxt
Definition: game.h:66
int fc_strcasecmp(const char *str0, const char *str1)
Compare strings like strcmp(), but ignoring case.
Definition: support.cpp:89
#define fc_strdup(str)
Definition: support.h:111
#define fc__fallthrough
Definition: support.h:49
struct tech_class * tech_class_by_rule_name(const char *name)
Does a linear search of tech_classes[].name.vernacular Returns nullptr when none match.
Definition: tech.cpp:335
struct advance * advance_by_translated_name(const char *name)
Does a linear search of advances[].name.translated Returns nullptr when none match.
Definition: tech.cpp:163
void set_user_tech_flag_name(enum tech_flag_id id, const char *name, const char *helptxt)
Sets user defined name for tech flag.
Definition: tech.cpp:378
bool is_future_tech(Tech_type_id tech)
Is the given tech a future tech.
Definition: tech.cpp:268
static void advance_req_iter_next(struct iterator *it)
Jump to next advance requirement.
Definition: tech.cpp:509
const char * tech_class_name_translation(const struct tech_class *ptclass)
Return the (translated) name of the given tech_class You must not free the return pointer.
Definition: tech.cpp:317
struct tech_class * tech_class_by_number(const int idx)
Return the tech_class for the given index.
Definition: tech.cpp:304
struct iterator * advance_req_iter_init(struct advance_req_iter *it, const struct advance *goal)
Initialize an advance requirements iterator.
Definition: tech.cpp:547
struct iterator * advance_root_req_iter_init(struct advance_root_req_iter *it, const struct advance *goal)
Initialize a root requirements iterator.
Definition: tech.cpp:647
void tech_classes_init()
Initialize tech classes.
Definition: tech.cpp:291
bool advance_has_flag(Tech_type_id tech, enum tech_flag_id flag)
Return TRUE if the tech has this flag otherwise FALSE.
Definition: tech.cpp:198
struct advance * valid_advance(struct advance *padvance)
Returns pointer when the advance "exists" in this game, returns nullptr otherwise.
Definition: tech.cpp:138
#define ADVANCE_ROOT_REQ_ITER(it)
Definition: tech.cpp:42
static struct user_flag user_tech_flags[MAX_NUM_USER_TECH_FLAGS]
Definition: tech.cpp:52
struct advance advances[A_ARRAY_SIZE]
Definition: tech.cpp:48
struct advance * advance_requires(const struct advance *padvance, enum tech_req require)
Accessor for requirements.
Definition: tech.cpp:122
static void tech_free(Tech_type_id tech)
De-allocate resources associated with the given tech.
Definition: tech.cpp:469
struct advance * advance_by_rule_name(const char *name)
Does a linear search of advances[].name.vernacular Returns nullptr when none match.
Definition: tech.cpp:180
const char * advance_rule_name(const struct advance *padvance)
Return the (untranslated) rule name of the advance/technology.
Definition: tech.cpp:283
struct advance * advance_by_number(const Tech_type_id atype)
Return the advance for the given advance index.
Definition: tech.cpp:94
static bool advance_root_req_iter_valid(const struct iterator *it)
Return whether we finished to iterate or not.
Definition: tech.cpp:584
const char * tech_class_rule_name(const struct tech_class *ptclass)
Return the (untranslated) rule name of tech_class You must not free the return pointer.
Definition: tech.cpp:326
void techs_precalc_data()
Function to precalculate needed data for technologies.
Definition: tech.cpp:207
const char * tech_flag_helptxt(enum tech_flag_id id)
Return the (untranslated) helptxt of the user tech flag.
Definition: tech.cpp:413
Tech_type_id advance_required(const Tech_type_id tech, enum tech_req require)
Accessor for requirements.
Definition: tech.cpp:108
struct tech_class tech_classes[MAX_NUM_TECH_CLASSES]
Definition: tech.cpp:50
static void * advance_req_iter_get(const struct iterator *it)
Return the current advance.
Definition: tech.cpp:501
size_t advance_root_req_iter_sizeof()
Return the size of the advance root requirements iterator.
Definition: tech.cpp:567
size_t advance_req_iter_sizeof()
Return the size of the advance requirements iterator.
Definition: tech.cpp:496
struct advance * valid_advance_by_number(const Tech_type_id id)
Returns pointer when the advance "exists" in this game, returns nullptr otherwise.
Definition: tech.cpp:154
Tech_type_id advance_index(const struct advance *padvance)
Return the advance index.
Definition: tech.cpp:76
static void * advance_root_req_iter_get(const struct iterator *it)
Return the current root_req.
Definition: tech.cpp:575
bool techs_have_fixed_costs()
Returns true if the costs for the given technology will stay constant during the game.
Definition: tech.cpp:428
void user_tech_flags_init()
Initialize user tech flags.
Definition: tech.cpp:354
static bool advance_req_iter_valid(const struct iterator *it)
Return whether we finished to iterate or not.
Definition: tech.cpp:537
const char * tech_flag_id_name_cb(enum tech_flag_id flag)
Tech flag name callback, called from specenum code.
Definition: tech.cpp:401
static void advance_root_req_iter_next(struct iterator *it)
Jump to next advance which has a previously unseen root_req.
Definition: tech.cpp:594
Tech_type_id advance_count()
Return the number of advances/technologies.
Definition: tech.cpp:68
const struct advance * advance_array_last()
Return the last item of advances/technologies.
Definition: tech.cpp:57
void techs_free()
De-allocate resources of all techs.
Definition: tech.cpp:481
#define ADVANCE_REQ_ITER(it)
Definition: tech.cpp:34
void techs_init()
Initialize tech structures.
Definition: tech.cpp:437
Tech_type_id advance_number(const struct advance *padvance)
Return the advance index.
Definition: tech.cpp:85
const char * advance_name_translation(const struct advance *padvance)
Return the (translated) name of the given advance/technology.
Definition: tech.cpp:274
void user_tech_flags_free()
Frees the memory associated with all user tech flags.
Definition: tech.cpp:366
#define A_ARRAY_SIZE
Definition: tech.h:40
#define A_FUTURE
Definition: tech.h:39
#define A_NEVER
Definition: tech.h:44
#define advance_index_iterate_end
Definition: tech.h:226
#define advance_req_iterate(_goal, _padvance)
Definition: tech.h:262
#define MAX_NUM_USER_TECH_FLAGS
Definition: tech.h:102
tech_req
Definition: tech.h:104
@ AR_TWO
Definition: tech.h:104
@ AR_ROOT
Definition: tech.h:104
@ AR_ONE
Definition: tech.h:104
@ AR_SIZE
Definition: tech.h:104
#define advance_iterate(_start, _p)
Definition: tech.h:232
#define advance_req_iterate_end
Definition: tech.h:266
#define A_FIRST
Definition: tech.h:37
#define A_NONE
Definition: tech.h:36
#define advance_iterate_end
Definition: tech.h:238
#define A_LAST
Definition: tech.h:38
#define advance_index_iterate(_start, _index)
Definition: tech.h:221