Freeciv21
Develop your civilization from humble roots to a global empire
caravan.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 
16 // common
17 #include "game.h"
18 #include "traderoutes.h"
19 
20 // aicore
21 #include "path_finding.h"
22 #include "pf_tools.h"
23 
24 #include "caravan.h"
25 
30 {
31  parameter->horizon = FC_INFINITY;
32  parameter->discount = 0.95;
33  parameter->consider_windfall = true;
34  parameter->consider_trade = true;
35  parameter->consider_wonders = true; // see also init_from_unit
36  parameter->account_for_broken_routes = true;
38  parameter->ignore_transit_time = false;
39  parameter->convert_trade = false;
40  parameter->callback = nullptr;
41 }
42 
47  const struct unit *caravan)
48 {
50  if (!unit_can_do_action(caravan, ACTION_TRADE_ROUTE)) {
51  parameter->consider_trade = false;
52  }
53  if (!unit_can_do_action(caravan, ACTION_MARKETPLACE)
54  && !unit_can_do_action(caravan, ACTION_TRADE_ROUTE)) {
55  parameter->consider_windfall = false;
56  }
57  if (!unit_can_do_action(caravan, ACTION_HELP_WONDER)) {
58  parameter->consider_wonders = false;
59  }
60 }
61 
66 {
67  result->src = result->dest = nullptr;
68  result->arrival_time = 0;
69  result->value = 0;
70  result->help_wonder = false;
71 }
72 
77 static void caravan_result_init(struct caravan_result *result,
78  const struct city *src,
79  const struct city *dest, int arrival_time)
80 {
81  result->src = src;
82  result->dest = dest;
83  result->arrival_time = arrival_time;
84 
85  result->value = 0;
86  result->help_wonder = false;
87 }
88 
93  const struct caravan_result *b)
94 {
95  if (a->value > b->value) {
96  return 1;
97  } else if (a->value < b->value) {
98  return -1;
99  } else {
100  // faster time is better, so reverse-sort on time.
101  return b->arrival_time - a->arrival_time;
102  }
103 }
104 
113 typedef bool (*search_callback)(void *data, const struct city *pcity,
114  int arrival_turn, int arrival_moves_left);
115 
116 static void caravan_search_from(const struct unit *caravan,
117  const struct caravan_parameter *param,
118  struct tile *start_tile,
119  int moves_left_before, bool omniscient,
120  search_callback callback,
121  void *callback_data)
122 {
123  struct pf_map *pfm;
124  struct pf_parameter pfparam;
125  int end_time;
126 
127  end_time = param->horizon;
128 
129  // Initialize the pf run.
130  pft_fill_unit_parameter(&pfparam, const_cast<struct unit *>(caravan));
131  pfparam.start_tile = start_tile;
132  pfparam.moves_left_initially = moves_left_before;
133  pfparam.omniscience = omniscient;
134  pfm = pf_map_new(&pfparam);
135 
136  /* For every tile in distance order:
137  quit if we've exceeded the maximum number of turns
138  otherwise, run the callback if we're on a city.
139  Do-while loop rather than while loop to make sure to process the
140  start tile.
141  */
142  pf_map_positions_iterate(pfm, pos, true)
143  {
144  struct city *pcity;
145 
146  if (pos.turn > end_time) {
147  break;
148  }
149 
150  pcity = tile_city(pos.tile);
151  if (pcity && callback(callback_data, pcity, pos.turn, pos.moves_left)) {
152  break;
153  }
154  }
156 
157  pf_map_destroy(pfm);
158 }
159 
164 static double windfall_benefit(const struct unit *caravan,
165  const struct city *src,
166  const struct city *dest,
167  const struct caravan_parameter *param)
168 {
169  if (!param->consider_windfall || !can_cities_trade(src, dest)) {
170  return 0;
171  } else {
172  bool can_establish = (unit_can_do_action(caravan, ACTION_TRADE_ROUTE)
173  && can_establish_trade_route(src, dest));
175  src, dest, unit_owner(caravan), nullptr, can_establish);
176 
177  // bonus goes to both sci and gold.
178  bonus *= 2;
179 
180  return bonus;
181  }
182 }
183 
184 /*
185  * Compute the change in the per-turn trade.
186  */
187 
192 static int one_city_trade_benefit(const struct city *pcity,
193  const struct player *pplayer,
194  bool countloser, int newtrade)
195 {
196  int losttrade = 0;
197 
198  /* if the city is owned by someone else, we don't benefit from the
199  new trade (but we might still lose from a broken trade route) */
200  if (city_owner(pcity) != pplayer) {
201  newtrade = 0;
202  }
203 
204  if (city_num_trade_routes(pcity) < max_trade_routes(pcity)) {
205  // if the city can handle this route, we don't break any old routes
206  losttrade = 0;
207  } else {
208  struct trade_route_list *would_remove =
209  (countloser ? trade_route_list_new() : nullptr);
210  int oldtrade = city_trade_removable(pcity, would_remove);
211 
212  /* if we own the city, the trade benefit is only by how much
213  better we are than the old trade route */
214  if (city_owner(pcity) == pplayer) {
215  newtrade -= oldtrade;
216  }
217 
218  /* if the cities that lost a trade route is one of ours, and if we
219  care about accounting for the lost trade, count it. */
220  if (countloser) {
221  trade_route_list_iterate(would_remove, plost)
222  {
223  struct city *losercity = game_city_by_number(plost->partner);
224 
225  if (city_owner(losercity) == pplayer) {
226  trade_routes_iterate(losercity, pback)
227  {
228  if (pback->partner == pcity->id) {
229  losttrade += pback->value;
230  }
231  }
233  }
234  }
236  trade_route_list_destroy(would_remove);
237  }
238  }
239 
240  // find the increase or decrease in trade we benefit from
241  return newtrade - losttrade;
242 }
243 
249 static double trade_benefit(const struct player *caravan_owner,
250  const struct city *src, const struct city *dest,
251  const struct caravan_parameter *param)
252 {
253  // do we care about trade at all?
254  if (!param->consider_trade) {
255  return 0;
256  }
257 
258  // first, see if a new route is made.
259  if (!can_cities_trade(src, dest)
260  || !can_establish_trade_route(src, dest)) {
261  return 0;
262  }
263  if (max_trade_routes(src) <= 0 || max_trade_routes(dest) <= 0) {
264  /* Can't create new traderoutes even by replacing old ones if
265  * there's no slots at all. */
266  return 0;
267  }
268 
269  if (!param->convert_trade) {
270  bool countloser = param->account_for_broken_routes;
271  int newtrade = trade_base_between_cities(src, dest);
272 
273  return one_city_trade_benefit(src, caravan_owner, countloser, newtrade)
274  + one_city_trade_benefit(dest, caravan_owner, countloser,
275  newtrade);
276  } else {
277  // Always fails.
278  fc_assert_msg(false == param->convert_trade,
279  "Unimplemented functionality: "
280  "using CM to calculate trade.");
281  return 0;
282  }
283 }
284 
292 static double wonder_benefit(const struct unit *caravan, int arrival_time,
293  const struct city *dest,
294  const struct caravan_parameter *param)
295 {
296  int costwithout, costwith;
297  int shields_at_arrival;
298 
299  if (!param->consider_wonders
300  // TODO: Should helping an ally to build be considered when legal?
301  || unit_owner(caravan) != city_owner(dest)
303  // TODO: Should helping to build a unit be considered when legal?
304  || VUT_UTYPE == dest->production.kind
305  /* TODO: Should helping to build an improvement be considered when
306  * legal? */
307  || !is_wonder(dest->production.value.building)) {
308  return 0;
309  }
310 
311  shields_at_arrival =
312  dest->shield_stock + arrival_time * dest->surplus[O_SHIELD];
313 
314  costwithout = impr_buy_gold_cost(dest, dest->production.value.building,
315  shields_at_arrival);
316  costwith = impr_buy_gold_cost(dest, dest->production.value.building,
317  shields_at_arrival
318  + unit_build_shield_cost_base(caravan));
319 
320  fc_assert_ret_val(costwithout >= costwith, -1.0);
321  return costwithout - costwith;
322 }
323 
328 static double presentvalue(double payment, int term, double rate)
329 {
330  return payment * pow(rate, term);
331 }
332 
337 static double perpetuity(double payment, double rate)
338 {
339  return payment / (1.0 - rate);
340 }
341 
346 static double annuity(double payment, int term, double rate)
347 {
348  return perpetuity(payment, rate) * (1.0 - 1.0 / pow(rate, term));
349 }
350 
354 static bool
356  struct player *src, struct player *dest)
357 {
358  switch (param->allow_foreign_trade) {
359  case FTL_NATIONAL_ONLY:
360  return (src == dest);
361  break;
362  case FTL_ALLIED:
363  return pplayers_allied(src, dest);
364  break;
365  case FTL_PEACEFUL:
366  return pplayers_in_peace(src, dest);
367  break;
368  case FTL_NONWAR:
369  return !pplayers_at_war(src, dest);
370  }
371 
372  fc_assert(false);
373  return false;
374 }
375 
382 static bool get_discounted_reward(const struct unit *caravan,
383  const struct caravan_parameter *parameter,
384  struct caravan_result *result)
385 {
386  double trade;
387  double windfall;
388  double wonder;
389  const struct city *src = result->src;
390  const struct city *dest = result->dest;
391  int arrival_time = result->arrival_time;
392  double discount = parameter->discount;
393  struct player *pplayer_src = city_owner(src);
394  struct player *pplayer_dest = city_owner(dest);
395  bool consider_wonder;
396  bool consider_trade;
397  bool consider_windfall;
398 
399  // if no foreign trade is allowed, just quit.
400  if (!does_foreign_trade_param_allow(parameter, pplayer_src,
401  pplayer_dest)) {
402  caravan_result_init_zero(result);
403  return false;
404  }
405 
406  consider_wonder =
407  parameter->consider_wonders
409  ACTION_HELP_WONDER, caravan, src, city_tile(dest), true, dest));
410  consider_trade =
411  parameter->consider_trade
413  ACTION_TRADE_ROUTE, caravan, src, city_tile(dest), true, dest));
414  consider_windfall =
415  parameter->consider_windfall
417  ACTION_MARKETPLACE, caravan, src, city_tile(dest), true, dest));
418 
419  if (!consider_wonder && !consider_trade && !consider_windfall) {
420  // No caravan action is possible against this target.
421  caravan_result_init_zero(result);
422 
423  return false;
424  }
425 
426  trade = trade_benefit(pplayer_src, src, dest, parameter);
427  windfall = windfall_benefit(caravan, src, dest, parameter);
428  if (consider_wonder) {
429  wonder = wonder_benefit(caravan, arrival_time, dest, parameter);
430  // we want to aid for wonder building
431  wonder *= 2;
432 
433  wonder = presentvalue(wonder, arrival_time, discount);
434  } else {
435  wonder = -1.0;
436  }
437 
438  if (consider_trade) {
439  if (parameter->horizon == FC_INFINITY) {
440  trade = perpetuity(trade, discount);
441  } else {
442  trade = annuity(trade, parameter->horizon - arrival_time, discount);
443  }
444  trade = presentvalue(trade, arrival_time, discount);
445  } else {
446  trade = 0.0;
447  }
448 
449  if (consider_windfall) {
450  windfall = presentvalue(windfall, arrival_time, discount);
451  } else {
452  windfall = 0.0;
453  }
454 
455  if (consider_trade && trade + windfall >= wonder) {
456  result->value = trade + windfall;
457  result->help_wonder = false;
458  } else if (consider_wonder) {
459  result->value = wonder;
460  result->help_wonder = true;
461  } else {
462  caravan_result_init_zero(result);
463  return false;
464  }
465 
466  if (parameter->callback) {
467  parameter->callback(result, parameter->callback_data);
468  }
469 
470  return true;
471 }
472 
481  const struct unit *caravan, const struct caravan_parameter *param,
482  struct caravan_result *best)
483 {
484  struct caravan_result current;
485  struct city *pcity = game_city_by_number(caravan->homecity);
486  struct player *src_owner = city_owner(pcity);
487 
488  caravan_result_init(best, pcity, nullptr, 0);
489  current = *best;
490 
491  players_iterate(dest_owner)
492  {
493  if (does_foreign_trade_param_allow(param, src_owner, dest_owner)) {
494  city_list_iterate(dest_owner->cities, dest)
495  {
496  caravan_result_init(&current, pcity, dest, 0);
497  get_discounted_reward(caravan, param, &current);
498 
499  if (caravan_result_compare(&current, best) > 0) {
500  *best = current;
501  }
502  }
504  }
505  }
507 }
508 
513 struct cfbdw_data {
514  const struct caravan_parameter *param;
515  const struct unit *caravan;
517 };
518 
519 static bool cfbdw_callback(void *vdata, const struct city *dest,
520  int arrival_time, int moves_left)
521 {
522  Q_UNUSED(moves_left)
523  cfbdw_data *data = static_cast<cfbdw_data *>(vdata);
524  struct caravan_result current;
525 
526  caravan_result_init(&current, data->best->src, dest, arrival_time);
527 
528  get_discounted_reward(data->caravan, data->param, &current);
529  if (caravan_result_compare(&current, data->best) > 0) {
530  *data->best = current;
531  }
532 
533  return false; // don't stop.
534 }
535 
540  const struct unit *caravan, const struct caravan_parameter *param,
541  const struct city *src, int moves_left, bool omniscient,
542  struct caravan_result *result)
543 {
544  Q_UNUSED(moves_left)
545  struct tile *start_tile;
546  struct cfbdw_data data;
547 
548  data.param = param;
549  data.caravan = caravan;
550  data.best = result;
551  caravan_result_init(data.best, src, nullptr, 0);
552 
553  if (src->id != caravan->homecity) {
554  start_tile = src->tile;
555  } else {
556  start_tile = unit_tile(caravan);
557  }
558 
560  omniscient, cfbdw_callback, &data);
561 }
562 
569  const struct caravan_parameter *parameter,
570  struct caravan_result *result,
571  bool omniscient)
572 {
573  if (parameter->ignore_transit_time) {
575  } else {
576  const struct city *src = game_city_by_number(caravan->homecity);
577 
578  fc_assert(src != nullptr);
579 
581  caravan, parameter, src, caravan->moves_left, omniscient, result);
582  }
583 }
bool action_prob_possible(const struct act_prob probability)
Returns TRUE iff the given action probability belongs to an action that may be possible.
Definition: actions.cpp:5380
struct act_prob action_speculate_unit_on_city(const action_id act_id, const struct unit *actor, const struct city *actor_home, const struct tile *actor_tile, const bool omniscient_cheat, const struct city *target)
Returns a speculation about the actor unit's probability of successfully performing the chosen action...
Definition: actions.cpp:5213
static double wonder_benefit(const struct unit *caravan, int arrival_time, const struct city *dest, const struct caravan_parameter *param)
Check the benefit of helping build the wonder in dest.
Definition: caravan.cpp:292
static double perpetuity(double payment, double rate)
Compute the net present value of an perpetuity given the discount rate.
Definition: caravan.cpp:337
static bool does_foreign_trade_param_allow(const struct caravan_parameter *param, struct player *src, struct player *dest)
Are the two players allowed to trade by the parameter settings?
Definition: caravan.cpp:355
bool(* search_callback)(void *data, const struct city *pcity, int arrival_turn, int arrival_moves_left)
We use the path finding in several places.
Definition: caravan.cpp:113
static void caravan_find_best_destination_notransit(const struct unit *caravan, const struct caravan_parameter *param, struct caravan_result *best)
Functions to compute the benefit of moving the caravan to dest.
Definition: caravan.cpp:480
static int one_city_trade_benefit(const struct city *pcity, const struct player *pplayer, bool countloser, int newtrade)
How much does the city benefit from the new trade route? How much does the former partner lose?
Definition: caravan.cpp:192
void caravan_find_best_destination(const struct unit *caravan, const struct caravan_parameter *parameter, struct caravan_result *result, bool omniscient)
Find the best destination city for the caravan.
Definition: caravan.cpp:568
static void caravan_search_from(const struct unit *caravan, const struct caravan_parameter *param, struct tile *start_tile, int moves_left_before, bool omniscient, search_callback callback, void *callback_data)
Definition: caravan.cpp:116
void caravan_result_init_zero(struct caravan_result *result)
Initialize the result to be worth zero and go from nowhere to nowhere.
Definition: caravan.cpp:65
static double annuity(double payment, int term, double rate)
Compute the net present value of an annuity given the discount rate.
Definition: caravan.cpp:346
static bool cfbdw_callback(void *vdata, const struct city *dest, int arrival_time, int moves_left)
Definition: caravan.cpp:519
int caravan_result_compare(const struct caravan_result *a, const struct caravan_result *b)
Compare the two results for sorting.
Definition: caravan.cpp:92
static bool get_discounted_reward(const struct unit *caravan, const struct caravan_parameter *parameter, struct caravan_result *result)
Compute the discounted reward from the trade route that is indicated by the src, dest,...
Definition: caravan.cpp:382
static double trade_benefit(const struct player *caravan_owner, const struct city *src, const struct city *dest, const struct caravan_parameter *param)
Compute one_trade_benefit for both cities and do some other logic.
Definition: caravan.cpp:249
static void caravan_find_best_destination_withtransit(const struct unit *caravan, const struct caravan_parameter *param, const struct city *src, int moves_left, bool omniscient, struct caravan_result *result)
Using caravan_search, find the best destination.
Definition: caravan.cpp:539
void caravan_parameter_init_default(struct caravan_parameter *parameter)
Create a valid parameter with default values.
Definition: caravan.cpp:29
static double windfall_benefit(const struct unit *caravan, const struct city *src, const struct city *dest, const struct caravan_parameter *param)
When the caravan arrives, compute the benefit from the immediate windfall, taking into account the pa...
Definition: caravan.cpp:164
static double presentvalue(double payment, int term, double rate)
Discount a value by the given discount rate.
Definition: caravan.cpp:328
void caravan_parameter_init_from_unit(struct caravan_parameter *parameter, const struct unit *caravan)
Create a valid parameter with default values based on the caravan.
Definition: caravan.cpp:46
static void caravan_result_init(struct caravan_result *result, const struct city *src, const struct city *dest, int arrival_time)
Initialize the result to go from src to dest with the given amount of time.
Definition: caravan.cpp:77
@ FTL_ALLIED
Definition: caravan.h:17
@ FTL_NATIONAL_ONLY
Definition: caravan.h:16
@ FTL_NONWAR
Definition: caravan.h:19
@ FTL_PEACEFUL
Definition: caravan.h:18
bool city_production_gets_caravan_shields(const struct universal *tgt)
Returns TRUE iff the specified production should get shields from units that has done ACTION_HELP_WON...
Definition: city.cpp:1752
struct player * city_owner(const struct city *pcity)
Return the owner of the city.
Definition: city.cpp:1083
struct tile * city_tile(const struct city *pcity)
Return the tile location of the city.
Definition: city.cpp:1095
#define city_list_iterate(citylist, pcity)
Definition: city.h:482
#define city_list_iterate_end
Definition: city.h:484
@ O_SHIELD
Definition: fc_types.h:86
struct city * game_city_by_number(int id)
Often used function to get a city pointer from a city ID.
Definition: game.cpp:103
int impr_buy_gold_cost(const struct city *pcity, const struct impr_type *pimprove, int shields_in_stock)
Returns the amount of gold it takes to rush this improvement.
bool is_wonder(const struct impr_type *pimprove)
Returns whether improvement is some kind of wonder.
#define fc_assert_msg(condition, message,...)
Definition: log.h:96
#define fc_assert(condition)
Definition: log.h:89
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
struct pf_map * pf_map_new(const struct pf_parameter *parameter)
Factory function to create a new map according to the parameter.
void pf_map_destroy(struct pf_map *pfm)
After usage the map must be destroyed.
#define pf_map_positions_iterate_end
Definition: path_finding.h:564
#define pf_map_positions_iterate(ARG_pfm, NAME_pos, COND_from_start)
Definition: path_finding.h:557
void pft_fill_unit_parameter(struct pf_parameter *parameter, const struct unit *punit)
Fill classic parameters for an unit.
Definition: pf_tools.cpp:822
bool pplayers_at_war(const struct player *pplayer, const struct player *pplayer2)
Returns true iff players can attack each other.
Definition: player.cpp:1317
bool pplayers_allied(const struct player *pplayer, const struct player *pplayer2)
Returns true iff players are allied.
Definition: player.cpp:1334
bool pplayers_in_peace(const struct player *pplayer, const struct player *pplayer2)
Returns true iff players are allied or at peace.
Definition: player.cpp:1355
#define players_iterate_end
Definition: player.h:520
#define players_iterate(_pplayer)
Definition: player.h:514
#define FC_INFINITY
Definition: shared.h:32
bool consider_trade
Definition: caravan.h:70
bool convert_trade
Definition: caravan.h:100
bool consider_windfall
Definition: caravan.h:69
void(* callback)(const struct caravan_result *result, void *data)
Definition: caravan.h:108
enum foreign_trade_limit allow_foreign_trade
Definition: caravan.h:83
bool consider_wonders
Definition: caravan.h:71
bool ignore_transit_time
Definition: caravan.h:92
double discount
Definition: caravan.h:61
bool account_for_broken_routes
Definition: caravan.h:77
void * callback_data
Definition: caravan.h:109
An advisor for using caravans optimally.
Definition: caravan.h:36
const struct city * src
Definition: caravan.h:37
const struct city * dest
Definition: caravan.h:38
int arrival_time
Definition: caravan.h:39
bool help_wonder
Definition: caravan.h:42
double value
Definition: caravan.h:41
Callback and struct for caravan_search invocation in caravan_find_best_destination_withtransit.
Definition: caravan.cpp:513
struct caravan_result * best
Definition: caravan.cpp:516
const struct unit * caravan
Definition: caravan.cpp:515
const struct caravan_parameter * param
Definition: caravan.cpp:514
Definition: city.h:291
int surplus[O_LAST]
Definition: city.h:324
int id
Definition: city.h:296
struct universal production
Definition: city.h:368
int bonus[O_LAST]
Definition: city.h:335
struct tile * tile
Definition: city.h:293
int shield_stock
Definition: city.h:339
int moves_left_initially
Definition: path_finding.h:343
struct tile * start_tile
Definition: path_finding.h:341
Definition: player.h:231
Definition: tile.h:42
Definition: unit.h:134
int moves_left
Definition: unit.h:147
int homecity
Definition: unit.h:142
enum universals_n kind
Definition: fc_types.h:740
universals_u value
Definition: fc_types.h:739
struct city * tile_city(const struct tile *ptile)
Return the city on this tile (or nullptr), checking for city center.
Definition: tile.cpp:72
bool can_cities_trade(const struct city *pc1, const struct city *pc2)
Return TRUE iff the two cities are capable of trade; i.e., if a caravan from one city can enter the o...
int max_trade_routes(const struct city *pcity)
Return current maximum number of trade routes city can have.
Definition: traderoutes.cpp:41
int trade_base_between_cities(const struct city *pc1, const struct city *pc2)
Return the trade that exists between these cities, assuming they have a trade route.
int city_num_trade_routes(const struct city *pcity)
Return number of trade route city has.
int city_trade_removable(const struct city *pcity, struct trade_route_list *would_remove)
Return the minimum value of the sum of trade routes which could be replaced by a new one.
int get_caravan_enter_city_trade_bonus(const struct city *pc1, const struct city *pc2, const player *seen_as, struct goods_type *pgood, const bool establish_trade)
Returns the revenue trade bonus - you get this when establishing a trade route and also when you simp...
bool can_establish_trade_route(const struct city *pc1, const struct city *pc2)
Returns TRUE iff the two cities can establish a trade route.
#define trade_route_list_iterate(trade_route_list, proute)
Definition: traderoutes.h:84
#define trade_routes_iterate_end
Definition: traderoutes.h:127
#define trade_route_list_iterate_end
Definition: traderoutes.h:86
#define trade_routes_iterate(c, proute)
Definition: traderoutes.h:122
const struct impr_type * building
Definition: fc_types.h:579
bool unit_can_do_action(const struct unit *punit, const action_id act_id)
Return TRUE iff this unit can do the specified generalized (ruleset defined) action enabler controlle...
Definition: unit.cpp:309
#define unit_tile(_pu)
Definition: unit.h:371
#define unit_owner(_pu)
Definition: unit.h:370
int unit_build_shield_cost_base(const struct unit *punit)
Returns the number of shields this unit represents.
Definition: unittype.cpp:1185