Stop sharing requirement_unit_state_ereq().
[freeciv.git] / common / tech.c
blob7cc916e6346a614713de35a7792e56e801bac544
1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
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 #include <stdlib.h> /* exit */
19 #include <string.h>
20 #include <math.h>
22 /* utility */
23 #include "fcintl.h"
24 #include "iterator.h"
25 #include "log.h"
26 #include "mem.h" /* free */
27 #include "shared.h" /* ARRAY_SIZE */
28 #include "string_vector.h"
29 #include "support.h"
31 /* common */
32 #include "game.h"
33 #include "research.h"
35 #include "tech.h"
38 struct advance_req_iter {
39 struct iterator base;
40 bv_techs done;
41 const struct advance *array[A_LAST];
42 const struct advance **current, **end;
44 #define ADVANCE_REQ_ITER(it) ((struct advance_req_iter *) it)
46 /* the advances array is now setup in:
47 * server/ruleset.c (for the server)
48 * client/packhand.c (for the client)
50 struct advance advances[A_ARRAY_SIZE];
52 struct tech_class tech_classes[MAX_NUM_TECH_CLASSES];
54 static struct user_flag user_tech_flags[MAX_NUM_USER_TECH_FLAGS];
56 /**************************************************************************
57 Return the last item of advances/technologies.
58 **************************************************************************/
59 const struct advance *advance_array_last(void)
61 if (game.control.num_tech_types > 0) {
62 return &advances[game.control.num_tech_types - 1];
64 return NULL;
67 /**************************************************************************
68 Return the number of advances/technologies.
69 **************************************************************************/
70 Tech_type_id advance_count(void)
72 return game.control.num_tech_types;
75 /**************************************************************************
76 Return the advance index.
78 Currently same as advance_number(), paired with advance_count()
79 indicates use as an array index.
80 **************************************************************************/
81 Tech_type_id advance_index(const struct advance *padvance)
83 fc_assert_ret_val(NULL != padvance, -1);
84 return padvance - advances;
87 /**************************************************************************
88 Return the advance index.
89 **************************************************************************/
90 Tech_type_id advance_number(const struct advance *padvance)
92 fc_assert_ret_val(NULL != padvance, -1);
93 return padvance->item_number;
96 /**************************************************************************
97 Return the advance for the given advance index.
98 **************************************************************************/
99 struct advance *advance_by_number(const Tech_type_id atype)
101 if (atype != A_FUTURE
102 && (atype < 0 || atype >= game.control.num_tech_types)) {
103 /* This isn't an error; some callers depend on it. */
104 return NULL;
107 return &advances[atype];
110 /**************************************************************************
111 Accessor for requirements.
112 **************************************************************************/
113 Tech_type_id advance_required(const Tech_type_id tech,
114 enum tech_req require)
116 fc_assert_ret_val(require >= 0 && require < AR_SIZE, -1);
117 fc_assert_ret_val(tech >= A_NONE && tech < A_LAST, -1);
118 if (A_NEVER == advances[tech].require[require]) {
119 /* out of range */
120 return A_LAST;
122 return advance_number(advances[tech].require[require]);
125 /**************************************************************************
126 Accessor for requirements.
127 **************************************************************************/
128 struct advance *advance_requires(const struct advance *padvance,
129 enum tech_req require)
131 fc_assert_ret_val(require >= 0 && require < AR_SIZE, NULL);
132 fc_assert_ret_val(NULL != padvance, NULL);
133 return padvance->require[require];
136 /**************************************************************************
137 Returns pointer when the advance "exists" in this game, returns NULL
138 otherwise.
140 A tech doesn't exist if it has been flagged as removed by setting its
141 require values to A_NEVER. Note that this function returns NULL if either
142 of req values is A_NEVER, rather than both, to be on the safe side.
143 **************************************************************************/
144 struct advance *valid_advance(struct advance *padvance)
146 if (NULL == padvance
147 || A_NEVER == padvance->require[AR_ONE]
148 || A_NEVER == padvance->require[AR_TWO]) {
149 return NULL;
152 return padvance;
155 /**************************************************************************
156 Returns pointer when the advance "exists" in this game,
157 returns NULL otherwise.
159 In addition to valid_advance(), tests for id is out of range.
160 **************************************************************************/
161 struct advance *valid_advance_by_number(const Tech_type_id id)
163 return valid_advance(advance_by_number(id));
166 /**************************************************************************
167 Does a linear search of advances[].name.translated
168 Returns NULL when none match.
169 **************************************************************************/
170 struct advance *advance_by_translated_name(const char *name)
172 advance_iterate(A_NONE, padvance) {
173 if (0 == strcmp(advance_name_translation(padvance), name)) {
174 return padvance;
176 } advance_iterate_end;
178 return NULL;
181 /**************************************************************************
182 Does a linear search of advances[].name.vernacular
183 Returns NULL when none match.
184 **************************************************************************/
185 struct advance *advance_by_rule_name(const char *name)
187 const char *qname = Qn_(name);
189 advance_iterate(A_NONE, padvance) {
190 if (0 == fc_strcasecmp(advance_rule_name(padvance), qname)) {
191 return padvance;
193 } advance_iterate_end;
195 return NULL;
198 /**************************************************************************
199 Return TRUE if the tech has this flag otherwise FALSE
200 **************************************************************************/
201 bool advance_has_flag(Tech_type_id tech, enum tech_flag_id flag)
203 fc_assert_ret_val(tech_flag_id_is_valid(flag), FALSE);
204 return BV_ISSET(advance_by_number(tech)->flags, flag);
207 /****************************************************************************
208 Function to precalculate needed data for technologies.
209 ****************************************************************************/
210 void techs_precalc_data(void)
212 fc_assert_msg(tech_cost_style_is_valid(game.info.tech_cost_style),
213 "Invalid tech_cost_style %d", game.info.tech_cost_style);
215 advance_iterate(A_FIRST, padvance) {
216 int num_reqs = 0;
217 bool min_req = TRUE;
219 advance_req_iterate(padvance, preq) {
220 (void) preq; /* Compiler wants us to do something with 'preq'. */
221 num_reqs++;
222 } advance_req_iterate_end;
223 padvance->num_reqs = num_reqs;
225 switch (game.info.tech_cost_style) {
226 case TECH_COST_CIV1CIV2:
227 padvance->cost = game.info.base_tech_cost * num_reqs;
228 break;
229 case TECH_COST_CLASSIC_PRESET:
230 if (-1 != padvance->cost) {
231 min_req = FALSE;
232 break;
234 /* No break. */
235 case TECH_COST_CLASSIC:
236 padvance->cost = game.info.base_tech_cost * (1.0 + num_reqs)
237 * sqrt(1.0 + num_reqs) / 2;
238 break;
239 case TECH_COST_EXPERIMENTAL_PRESET:
240 if (-1 != padvance->cost) {
241 min_req = FALSE;
242 break;
244 /* No break. */
245 case TECH_COST_EXPERIMENTAL:
246 padvance->cost = game.info.base_tech_cost * ((num_reqs) * (num_reqs)
247 / (1 + sqrt(sqrt(num_reqs + 1))) - 0.5);
248 break;
251 if (min_req && padvance->cost < game.info.base_tech_cost) {
252 padvance->cost = game.info.base_tech_cost;
255 /* Class cost */
256 if (padvance->tclass != NULL) {
257 padvance->cost = padvance->cost * padvance->tclass->cost_pct / 100;
259 } advance_iterate_end;
262 /**************************************************************************
263 Is the given tech a future tech.
264 **************************************************************************/
265 bool is_future_tech(Tech_type_id tech)
267 return tech == A_FUTURE;
270 /**************************************************************************
271 Return the (translated) name of the given advance/technology.
272 You don't have to free the return pointer.
273 **************************************************************************/
274 const char *advance_name_translation(const struct advance *padvance)
276 return name_translation_get(&padvance->name);
279 /****************************************************************************
280 Return the (untranslated) rule name of the advance/technology.
281 You don't have to free the return pointer.
282 ****************************************************************************/
283 const char *advance_rule_name(const struct advance *padvance)
285 return rule_name_get(&padvance->name);
288 /**************************************************************************
289 Initialize tech classes
290 **************************************************************************/
291 void tech_classes_init(void)
293 int i;
295 for (i = 0; i < MAX_NUM_TECH_CLASSES; i++) {
296 tech_classes[i].idx = i;
297 tech_classes[i].disabled = FALSE;
301 /**************************************************************************
302 Return the tech_class for the given index.
303 **************************************************************************/
304 struct tech_class *tech_class_by_number(const int idx)
306 if (idx < 0 || idx >= game.control.num_tech_classes) {
307 return NULL;
310 return &tech_classes[idx];
313 /**************************************************************************
314 Return the (translated) name of the given tech_class
315 You must not free the return pointer.
316 **************************************************************************/
317 const char *tech_class_name_translation(const struct tech_class *ptclass)
319 return name_translation_get(&ptclass->name);
322 /****************************************************************************
323 Return the (untranslated) rule name of tech_class
324 You must not free the return pointer.
325 ****************************************************************************/
326 const char *tech_class_rule_name(const struct tech_class *ptclass)
328 return rule_name_get(&ptclass->name);
331 /**************************************************************************
332 Does a linear search of tech_classes[].name.vernacular
333 Returns NULL when none match.
334 **************************************************************************/
335 struct tech_class *tech_class_by_rule_name(const char *name)
337 const char *qname = Qn_(name);
338 int i;
340 for (i = 0; i < game.control.num_tech_classes; i++) {
341 struct tech_class *ptclass = tech_class_by_number(i);
343 if (!fc_strcasecmp(tech_class_rule_name(ptclass), qname)) {
344 return ptclass;
348 return NULL;
351 /**************************************************************************
352 Initialize user tech flags.
353 **************************************************************************/
354 void user_tech_flags_init(void)
356 int i;
358 for (i = 0; i < MAX_NUM_USER_TECH_FLAGS; i++) {
359 user_flag_init(&user_tech_flags[i]);
363 /***************************************************************
364 Frees the memory associated with all user tech flags
365 ***************************************************************/
366 void user_tech_flags_free(void)
368 int i;
370 for (i = 0; i < MAX_NUM_USER_TECH_FLAGS; i++) {
371 user_flag_free(&user_tech_flags[i]);
375 /**************************************************************************
376 Sets user defined name for tech flag.
377 **************************************************************************/
378 void set_user_tech_flag_name(enum tech_flag_id id, const char *name,
379 const char *helptxt)
381 int tfid = id - TECH_USER_1;
383 fc_assert_ret(id >= TECH_USER_1 && id <= TECH_USER_LAST);
385 if (user_tech_flags[tfid].name != NULL) {
386 FC_FREE(user_tech_flags[tfid].name);
387 user_tech_flags[tfid].name = NULL;
390 if (name && name[0] != '\0') {
391 user_tech_flags[tfid].name = fc_strdup(name);
394 if (user_tech_flags[tfid].helptxt != NULL) {
395 FC_FREE(user_tech_flags[tfid].helptxt);
396 user_tech_flags[tfid].helptxt = NULL;
399 if (helptxt && helptxt[0] != '\0') {
400 user_tech_flags[tfid].helptxt = fc_strdup(helptxt);
404 /**************************************************************************
405 Tech flag name callback, called from specenum code.
406 **************************************************************************/
407 const char *tech_flag_id_name_cb(enum tech_flag_id flag)
409 if (flag < TECH_USER_1 || flag > TECH_USER_LAST) {
410 return NULL;
413 return user_tech_flags[flag-TECH_USER_1].name;
416 /**************************************************************************
417 Return the (untranslated) helptxt of the user tech flag.
418 **************************************************************************/
419 const char *tech_flag_helptxt(enum tech_flag_id id)
421 fc_assert(id >= TECH_USER_1 && id <= TECH_USER_LAST);
423 return user_tech_flags[id - TECH_USER_1].helptxt;
426 /**************************************************************************
427 Returns true if the costs for the given technology will stay constant
428 during the game. False otherwise.
430 Checking every tech_cost_style with fixed costs seems a waste of system
431 resources, when we can check that it is not the one style without fixed
432 costs.
433 **************************************************************************/
434 bool techs_have_fixed_costs()
436 return (game.info.tech_leakage == TECH_LEAKAGE_NONE
437 && game.info.tech_cost_style != TECH_COST_CIV1CIV2);
440 /****************************************************************************
441 Initialize tech structures.
442 ****************************************************************************/
443 void techs_init(void)
445 struct advance *a_none = &advances[A_NONE];
446 struct advance *a_future = &advances[A_FUTURE];
447 int i;
449 memset(advances, 0, sizeof(advances));
450 for (i = 0; i < ARRAY_SIZE(advances); i++) {
451 advances[i].item_number = i;
452 advances[i].cost = -1;
453 advances[i].tclass = 0;
455 requirement_vector_init(&(advances[i].research_reqs));
458 /* Initialize dummy tech A_NONE */
459 /* TRANS: "None" tech */
460 name_set(&a_none->name, NULL, N_("?tech:None"));
461 a_none->require[AR_ONE] = a_none;
462 a_none->require[AR_TWO] = a_none;
463 a_none->require[AR_ROOT] = A_NEVER;
465 name_set(&a_future->name, NULL, "Future");
466 a_future->require[AR_ONE] = A_NEVER;
467 a_future->require[AR_TWO] = A_NEVER;
468 a_future->require[AR_ROOT] = A_NEVER;
471 /***************************************************************
472 De-allocate resources associated with the given tech.
473 ***************************************************************/
474 static void tech_free(Tech_type_id tech)
476 struct advance *p = &advances[tech];
478 if (NULL != p->helptext) {
479 strvec_destroy(p->helptext);
480 p->helptext = NULL;
483 if (p->bonus_message) {
484 free(p->bonus_message);
485 p->bonus_message = NULL;
489 /***************************************************************
490 De-allocate resources of all techs.
491 ***************************************************************/
492 void techs_free(void)
494 int i;
496 advance_index_iterate(A_FIRST, adv_idx) {
497 tech_free(adv_idx);
498 } advance_index_iterate_end;
500 for (i = 0; i < ARRAY_SIZE(advances); i++) {
501 requirement_vector_free(&(advances[i].research_reqs));
505 /****************************************************************************
506 Return the size of the advance requirements iterator.
507 ****************************************************************************/
508 size_t advance_req_iter_sizeof(void)
510 return sizeof(struct advance_req_iter);
513 /****************************************************************************
514 Return the current advance.
515 ****************************************************************************/
516 static void *advance_req_iter_get(const struct iterator *it)
518 return (void *) *ADVANCE_REQ_ITER(it)->current;
521 /****************************************************************************
522 Jump to next advance requirement.
523 ****************************************************************************/
524 static void advance_req_iter_next(struct iterator *it)
526 struct advance_req_iter *iter = ADVANCE_REQ_ITER(it);
527 const struct advance *padvance = *iter->current, *preq;
528 enum tech_req req;
529 bool new = FALSE;
531 for (req = AR_ONE; req < AR_SIZE; req++) {
532 preq = valid_advance(advance_requires(padvance, req));
533 if (NULL != preq
534 && A_NONE != advance_number(preq)
535 && !BV_ISSET(iter->done, advance_number(preq))) {
536 BV_SET(iter->done, advance_number(preq));
537 if (new) {
538 *iter->end++ = preq;
539 } else {
540 *iter->current = preq;
541 new = TRUE;
546 if (!new) {
547 iter->current++;
551 /****************************************************************************
552 Return whether we finished to iterate or not.
553 ****************************************************************************/
554 static bool advance_req_iter_valid(const struct iterator *it)
556 const struct advance_req_iter *iter = ADVANCE_REQ_ITER(it);
558 return iter->current < iter->end;
561 /****************************************************************************
562 Initialize an advance requirements iterator.
563 ****************************************************************************/
564 struct iterator *advance_req_iter_init(struct advance_req_iter *it,
565 const struct advance *goal)
567 struct iterator *base = ITERATOR(it);
569 base->get = advance_req_iter_get;
570 base->next = advance_req_iter_next;
571 base->valid = advance_req_iter_valid;
573 BV_CLR_ALL(it->done);
574 it->current = it->array;
575 *it->current = goal;
576 it->end = it->current + 1;
578 return base;