Freeciv-3.3
Loading...
Searching...
No Matches
daiair.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 2002 - The Freeciv Team
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
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***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18/* utility */
19#include "log.h"
20
21/* common */
22#include "combat.h"
23#include "game.h"
24#include "map.h"
25#include "movement.h"
26#include "player.h"
27#include "pf_tools.h"
28#include "unit.h"
29
30/* server */
31#include "citytools.h"
32#include "maphand.h"
33#include "srv_log.h"
34#include "unithand.h"
35#include "unittools.h"
36
37/* server/advisors */
38#include "advbuilding.h"
39#include "advgoto.h"
40
41/* ai */
42#include "handicaps.h"
43
44/* ai/default */
45#include "daicity.h"
46#include "daiplayer.h"
47#include "daitools.h"
48#include "daiunit.h"
49
50#include "daiair.h"
51
52/******************************************************************/
56static inline int regen_turns(struct unit *punit, struct tile *ptile,
57 int lost_hp)
58{
59 struct tile *real_tile = unit_tile(punit);
60 int res, regen, recov;
61
62 punit->tile = ptile;
63 /* unit_list_prepend(ptile, punit); ... (handle "MaxUnitsOnTile" etc.) */
66 if (lost_hp - recov <= 0) {
67 res = 0;
68 } else {
69 res = 1 + (lost_hp - recov) / (recov + regen);
70 }
72
73 return res;
74}
75
76/******************************************************************/
87static struct tile *find_nearest_airbase(struct unit *punit,
88 struct pf_path **path)
89{
90 struct player *pplayer = unit_owner(punit);
91 struct pf_parameter parameter;
92 struct pf_map *pfm;
93 struct tile *best = NULL;
96 const struct civ_map *nmap = &(wld.map);
97
99 parameter.omniscience = !has_handicap(pplayer, H_MAP);
100 pfm = pf_map_new(&parameter);
101
102 pf_map_move_costs_iterate(pfm, ptile, move_cost, TRUE) {
103 if (move_cost > punit->moves_left) {
104 /* Too far! */
105 break;
106 }
107
108 if (is_refuel_point(ptile, pplayer, punit)) {
109 if (lost_hp > 0) {
110 int regt = regen_turns(punit, ptile, lost_hp);
111
112 if (regt <= 0) {
113 /* Nothing better to search */
114 best = ptile;
115 break;
116 } else if (!best || regt < best_regt) {
117 /* Regenerates faster */
118 best_regt = regt;
119 best = ptile;
120 }
121 } else {
122 best = ptile;
123 break;
124 }
125 }
127
128 if (path && best) {
129 *path = pf_map_path(pfm, best);
130 }
132 return best;
133}
134
135/******************************************************************/
140 struct unit *punit, struct tile *ptile)
141{
142 struct city *acity = tile_city(ptile);
143
144 /* For a virtual unit (punit->id == 0), all targets are good */
145 /* TODO: There is a danger of producing too many units that will not
146 * attack anything. Production should not happen if there is an idle
147 * unit of the same type nearby */
148 if (acity && punit->id != 0
149 && def_ai_city_data(acity, ait)->invasion.occupy == 0
151 /* No units capable of occupying are invading */
152 log_debug("Don't want to attack %s, although we could",
154 return FALSE;
155 }
156
157 return TRUE;
158}
159
160/******************************************************************/
165 struct unit *punit,
166 struct tile *dst_tile)
167{
168 struct unit *pdefender;
169 /* Unit costs in shields */
171 /* Unit stats */
173 /* Final answer */
175 /* Time spent in the air */
176 int sortie_time;
177
178#define PROB_MULTIPLIER 100 /* Should unify with those in combat.c */
179
182 return 0;
183 }
184
185 /* Ok, we can attack, but is it worth it? */
186
187 /* Cost of our unit */
189 /* This is to say "wait, ill unit will get better!" */
191
192 /* Determine cost of enemy units */
194 if (0 == victim_cost) {
195 return 0;
196 }
197
198 /* Missile would die 100% so we adjust the victim_cost -- GB */
200 /* Assume that the attack will be a suicide attack even if a regular
201 * attack may be legal. */
203 }
204
207
209
211
216 /* Assume that dst_tile is closer to the tile the actor
217 * unit will attack from than its current tile. */
218 dst_tile,
219 dst_tile) >= MAX_MOVE_FRAGS ? 1 : 0);
220
223 if (profit > 0) {
227 log_debug("%s at (%d, %d) is a worthy target with profit " ADV_WANT_PRINTF,
229 } else {
230 log_debug("%s(%d, %d): %s at (%d, %d) is unworthy with profit " ADV_WANT_PRINTF,
233 profit = 0;
234 }
235
236 return profit;
237}
238
239/******************************************************************/
249 const struct civ_map *nmap,
250 struct unit *punit, struct pf_path **path,
251 struct tile **pptile)
252{
253 struct player *pplayer = unit_owner(punit);
254 struct pf_parameter parameter;
255 struct pf_map *pfm;
256 struct tile *best_tile = NULL;
257 adv_want best = 0;
258
259 pft_fill_unit_parameter(&parameter, nmap, punit);
260 parameter.omniscience = !has_handicap(pplayer, H_MAP);
261 pfm = pf_map_new(&parameter);
262
263 /* Let's find something to bomb */
264 pf_map_move_costs_iterate(pfm, ptile, move_cost, FALSE) {
265 if (move_cost >= punit->moves_left) {
266 /* Too far! */
267 break;
268 }
269
270 if (has_handicap(pplayer, H_MAP) && !map_is_known(ptile, pplayer)) {
271 /* The target tile is unknown */
272 continue;
273 }
274
275 if (has_handicap(pplayer, H_FOG)
276 && !map_is_known_and_seen(ptile, pplayer, V_MAIN)) {
277 /* The tile is fogged */
278 continue;
279 }
280
281 if (is_enemy_unit_tile(ptile, pplayer)
283 && can_unit_attack_tile(punit, NULL, ptile)) {
285 ptile);
286
287 if (new_best > best) {
288 best_tile = ptile;
289 best = new_best;
290 log_debug("%s wants to attack tile (%d, %d)",
291 unit_rule_name(punit), TILE_XY(ptile));
292 }
293 }
295
296 /* Return the best values. */
297 if (pptile) {
298 *pptile = best_tile;
299 }
300 if (path) {
301 *path = best_tile ? pf_map_path(pfm, best_tile) : NULL;
302 }
303
305
306 return best;
307}
308
309/******************************************************************/
320static struct tile *dai_find_strategic_airbase(struct ai_type *ait,
321 struct unit *punit,
322 struct pf_path **path)
323{
324 struct player *pplayer = unit_owner(punit);
325 struct pf_parameter parameter;
326 struct pf_map *pfm;
327 struct tile *best_tile = NULL;
328 struct city *pcity;
329 struct unit *pvirtual = NULL;
333 bool defend = FALSE; /* Used only for lost_hp > 0 */
334 bool refuel_start = FALSE; /* Used for not a "grave danger" start */
335 const struct civ_map *nmap = &(wld.map);
336
337 /* Consider staying at the current position
338 * before we generate the map, maybe we should not */
340 /* We suppose here for speed that the recovery effect is global.
341 * It's so in the standard rulesets but might be not elsewhere */
344 const struct tile *ptile = unit_tile(punit);
345
346 if (lost_hp > 0 && regen + recov > 0) {
349 if (regen_turns_min <= 0) {
350 if (lost_hp - recov > 0) {
351 /* Probably, nothing can repair us faster */
352 log_debug("Repairment of %s is almost finished, stays here",
355 return NULL;
356 } else {
357 regen_turns_min = 0;
358 }
359 } else {
361 regen_turns_min += 1;
362 }
363 }
364 pcity = tile_city(ptile);
365 if (pcity
366 && def_ai_city_data(pcity, ait)->grave_danger
367 > (unit_list_size(ptile->units) - 1) << 1) {
368 if (lost_hp <= 0 || regen_turns_min <= 1) {
369 log_debug("%s stays defending %s",
371 return NULL;
372 } else {
373 /* We may find a city in grave danger that restores faster */
374 defend = TRUE;
375 }
376 } else {
378 }
379 }
380
381 pft_fill_unit_parameter(&parameter, nmap, punit);
382 parameter.omniscience = !has_handicap(pplayer, H_MAP);
383 pfm = pf_map_new(&parameter);
384 pf_map_move_costs_iterate(pfm, ptile, move_cost, FALSE) {
385 bool chg_for_regen = FALSE;
386
387 if (move_cost >= punit->moves_left) {
388 break; /* Too far! */
389 }
390
391 if (!is_refuel_point(ptile, pplayer, punit)) {
392 continue; /* Cannot refuel here. */
393 }
394
395 if (lost_hp > 0) {
396 /* Don't fly to a point where we'll regenerate longer */
397 int regen_tn = regen_turns(punit, ptile, lost_hp);
398
400 log_debug("%s knows a better repair base than %d,%d",
401 unit_rule_name(punit), TILE_XY(ptile));
402 continue;
403 } else if (regen_turns_min > regen_tn) {
405 best_tile = ptile;
406 best_worth = 0; /* to be calculated if necessary */
408 }
409 }
410
411 if ((pcity = tile_city(ptile))
412 /* Two defenders per attacker is enough,
413 * at least considering that planes are usually
414 * expensive and weak city defenders */
415 && def_ai_city_data(pcity, ait)->grave_danger
416 > unit_list_size(ptile->units) << 1) {
417 if (lost_hp <= 0) {
418 best_tile = ptile;
419 break; /* Fly there immediately!! */
420 } else {
421 if (!defend) {
422 /* We maybe have equally regenerating base but not in danger */
423 best_tile = ptile;
424 defend = TRUE;
425 }
426 continue;
427 }
428 } else if (defend) {
429 if (chg_for_regen) {
430 /* We better regenerate faster and take a revenge a bit later */
431 defend = FALSE;
432 } else {
433 /* We already have a base in grave danger that restores not worse */
434 continue;
435 }
436 }
437
438 if (!pvirtual) {
439 pvirtual =
440 unit_virtual_create(pplayer,
443 if (refuel_start) {
444 /* What worth really worth moving out? */
446
449 NULL, NULL);
451 }
452 }
453
454 unit_tile_set(pvirtual, ptile);
456 if (target_worth > best_worth) {
457 /* It's either a first find or it's better than the previous. */
459 best_tile = ptile;
460 /* We can still look for something better. */
461 }
463
464 if (pvirtual) {
466 }
467
468 if (path) {
469 /* Stores the path. */
470 *path = best_tile ? pf_map_path(pfm, best_tile) : NULL;
471 }
473
474 return best_tile;
475}
476
477/******************************************************************/
490void dai_manage_airunit(struct ai_type *ait, struct player *pplayer,
491 struct unit *punit)
492{
493 struct tile *dst_tile = unit_tile(punit);
494 /* Loop prevention */
495 int moves = punit->moves_left;
496 int id = punit->id;
497 struct pf_parameter parameter;
498 struct pf_map *pfm;
499 struct pf_path *path;
500 const struct civ_map *nmap = &(wld.map);
501
503
505 /* We are out in the open, what shall we do? */
507 /* We are on a GOTO. Check if it will get us anywhere */
508 && NULL != punit->goto_tile
510 && is_refuel_point(punit->goto_tile, pplayer, punit)) {
511 pfm = pf_map_new(&parameter);
512 path = pf_map_path(pfm, punit->goto_tile);
513 if (path) {
514 bool alive = adv_follow_path(punit, path, punit->goto_tile);
515
516 pf_path_destroy(path);
518 if (alive && punit->moves_left > 0) {
519 /* Maybe do something else. */
520 dai_manage_airunit(ait, pplayer, punit);
521 }
522 return;
523 }
525 } else if ((dst_tile = find_nearest_airbase(punit, &path))) {
526 /* Go refuelling */
527 if (!adv_follow_path(punit, path, dst_tile)) {
528 pf_path_destroy(path);
529 return; /* The unit died. */
530 }
531 pf_path_destroy(path);
532 } else {
533 if (punit->fuel == 1) {
534 UNIT_LOG(LOG_DEBUG, punit, "Oops, fallin outta the sky");
535 }
536 def_ai_unit_data(punit, ait)->done = TRUE; /* Won't help trying again */
537 return;
538 }
539
540 } else if (punit->fuel == unit_type_get(punit)->fuel) {
541 /* We only leave a refuel point when we are on full fuel */
542
543 if (find_something_to_bomb(ait, nmap, punit, &path, &dst_tile) > 0) {
544 /* Found target, coordinates are in punit's goto_dest.
545 * TODO: separate attacking into a function, check for the best
546 * tile to attack from */
547 fc_assert_ret(path != NULL && dst_tile != NULL);
548 if (!adv_follow_path(punit, path, dst_tile)) {
549 pf_path_destroy(path);
550 return; /* The unit died. */
551 }
552 pf_path_destroy(path);
554 } else if ((dst_tile = dai_find_strategic_airbase(ait, punit, &path))) {
555 log_debug("%s will fly to (%i, %i) (%s) to fight there",
558 def_ai_unit_data(punit, ait)->done = TRUE; /* Wait for next turn */
559 if (!adv_follow_path(punit, path, dst_tile)) {
560 pf_path_destroy(path);
561 return; /* The unit died. */
562 }
563 pf_path_destroy(path);
564 } else {
565 log_debug("%s cannot find anything to kill and is staying put",
569 }
570 }
571
572 if ((punit = game_unit_by_number(id)) != NULL && punit->moves_left > 0
573 && punit->moves_left != moves) {
574 /* We have moved this turn, might have ended up stuck out in the fields
575 * so, as a safety measure, let's manage again */
576 dai_manage_airunit(ait, pplayer, punit);
577 }
578
579}
580
581/******************************************************************/
587bool dai_choose_attacker_air(struct ai_type *ait, const struct civ_map *nmap,
588 struct player *pplayer,
589 struct city *pcity, struct adv_choice *choice,
591{
592 bool want_something = FALSE;
593
594 /* This AI doesn't know how to build planes */
595 if (has_handicap(pplayer, H_NOPLANES)) {
596 return FALSE;
597 }
598
599 /* military_advisor_choose_build() does something idiotic,
600 * this function should not be called if there is danger... */
601 if (choice->want >= DAI_WANT_MILITARY_EMERGENCY
602 && choice->type != CT_ATTACKER) {
603 return FALSE;
604 }
605
607 return FALSE;
608 }
609
612
613 if (pclass->adv.land_move == MOVE_NONE
614 || pclass->adv.sea_move == MOVE_NONE
616 || unit_type_is_losing_hp(pplayer, punittype)) {
617 /* We don't consider this a plane */
618 continue;
619 }
620
621 if (!allow_gold_upkeep && utype_upkeep_cost(punittype, pplayer, O_GOLD) > 0) {
622 continue;
623 }
624
626 struct unit *virtual_unit =
628 pplayer, pcity, punittype,
631 NULL, NULL);
632
633 if (profit > choice->want) {
634 /* Update choice */
635 choice->want = profit;
636 choice->value.utype = punittype;
637 choice->type = CT_ATTACKER;
638 choice->need_boat = FALSE;
639 adv_choice_set_use(choice, "offensive air");
641 log_debug("%s wants to build %s (want = " ADV_WANT_PRINTF ")",
643 } else {
644 log_debug("%s doesn't want to build %s (want = " ADV_WANT_PRINTF ")",
646 }
648 }
650
651 return want_something;
652}
static struct action * action_by_number(action_id act_id)
Definition actions.h:400
#define ACTION_NONE
Definition actions.h:59
#define TRADE_WEIGHTING
Definition advbuilding.h:21
#define SHIELD_WEIGHTING
Definition advbuilding.h:20
#define adv_choice_set_use(_choice, _use)
Definition advchoice.h:85
@ CT_ATTACKER
Definition advchoice.h:40
bool adv_follow_path(struct unit *punit, struct pf_path *path, struct tile *ptile)
Definition advgoto.c:47
const char * city_name_get(const struct city *pcity)
Definition city.c:1137
int city_production_unit_veteran_level(struct city *pcity, const struct unit_type *punittype)
Definition city.c:804
bool can_city_build_unit_now(const struct civ_map *nmap, const struct city *pcity, const struct unit_type *punittype)
Definition city.c:947
double unit_win_chance(const struct civ_map *nmap, const struct unit *attacker, const struct unit *defender, const struct action *paction)
Definition combat.c:480
struct unit * get_defender(const struct civ_map *nmap, const struct unit *attacker, const struct tile *ptile, const struct action *paction)
Definition combat.c:841
bool can_unit_attack_tile(const struct unit *punit, const struct action *paction, const struct tile *dest_tile)
Definition combat.c:312
char * incite_cost
Definition comments.c:76
static struct tile * find_nearest_airbase(struct unit *punit, struct pf_path **path)
Definition daiair.c:87
void dai_manage_airunit(struct ai_type *ait, struct player *pplayer, struct unit *punit)
Definition daiair.c:490
static adv_want find_something_to_bomb(struct ai_type *ait, const struct civ_map *nmap, struct unit *punit, struct pf_path **path, struct tile **pptile)
Definition daiair.c:248
static adv_want dai_evaluate_tile_for_air_attack(const struct civ_map *nmap, struct unit *punit, struct tile *dst_tile)
Definition daiair.c:164
#define PROB_MULTIPLIER
static int regen_turns(struct unit *punit, struct tile *ptile, int lost_hp)
Definition daiair.c:56
bool dai_choose_attacker_air(struct ai_type *ait, const struct civ_map *nmap, struct player *pplayer, struct city *pcity, struct adv_choice *choice, bool allow_gold_upkeep)
Definition daiair.c:587
static bool dai_should_we_air_attack_tile(struct ai_type *ait, struct unit *punit, struct tile *ptile)
Definition daiair.c:139
static struct tile * dai_find_strategic_airbase(struct ai_type *ait, struct unit *punit, struct pf_path **path)
Definition daiair.c:320
static struct ai_city * def_ai_city_data(const struct city *pcity, struct ai_type *deftype)
Definition daiplayer.h:42
static struct unit_ai * def_ai_unit_data(const struct unit *punit, struct ai_type *deftype)
Definition daiplayer.h:48
int stack_cost(struct unit *pattacker, struct unit *pdefender)
Definition daitools.c:1281
adv_want military_amortize(struct player *pplayer, struct city *pcity, adv_want value, int delay, int build_cost)
Definition daitools.c:117
#define DAI_WANT_MILITARY_EMERGENCY
Definition daitools.h:32
adv_want kill_desire(adv_want benefit, int attack, int loss, int vuln, int victim_count)
Definition daiunit.c:342
int build_cost_balanced(const struct unit_type *punittype)
Definition daiunit.c:250
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit * punit
Definition dialogs_g.h:74
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit int const struct action *paction struct unit struct city * pcity
Definition dialogs_g.h:78
int get_unit_bonus(const struct unit *punit, enum effect_type effect_type)
Definition effects.c:1066
float adv_want
Definition fc_types.h:1063
#define ADV_WANT_PRINTF
Definition fc_types.h:1064
@ O_GOLD
Definition fc_types.h:101
struct world wld
Definition game.c:62
struct unit * game_unit_by_number(int id)
Definition game.c:115
struct city * game_city_by_number(int id)
Definition game.c:106
bool has_handicap(const struct player *pplayer, enum handicap_type htype)
Definition handicaps.c:66
@ H_MAP
Definition handicaps.h:28
@ H_NOPLANES
Definition handicaps.h:27
@ H_FOG
Definition handicaps.h:26
#define fc_assert_ret(condition)
Definition log.h:192
#define log_debug(message,...)
Definition log.h:116
@ LOG_DEBUG
Definition log.h:35
bool same_pos(const struct tile *tile1, const struct tile *tile2)
Definition map.c:1076
bool map_is_known(const struct tile *ptile, const struct player *pplayer)
Definition maphand.c:899
bool map_is_known_and_seen(const struct tile *ptile, const struct player *pplayer, enum vision_layer vlayer)
Definition maphand.c:925
#define MAX_MOVE_FRAGS
Definition movement.h:29
void pf_path_destroy(struct pf_path *path)
struct pf_map * pf_map_new(const struct pf_parameter *parameter)
struct pf_path * pf_map_path(struct pf_map *pfm, struct tile *ptile)
void pf_map_destroy(struct pf_map *pfm)
#define pf_map_move_costs_iterate_end
#define pf_map_move_costs_iterate(ARG_pfm, NAME_tile, NAME_cost, COND_from_start)
void pft_fill_unit_parameter(struct pf_parameter *parameter, const struct civ_map *nmap, const struct unit *punit)
Definition pf_tools.c:843
bool player_knows_techs_with_flag(const struct player *pplayer, enum tech_flag_id flag)
Definition player.c:1328
struct city * player_city_by_number(const struct player *pplayer, int city_id)
Definition player.c:1203
#define FC_INFINITY
Definition shared.h:36
#define MAX(x, y)
Definition shared.h:54
#define UNIT_LOG(loglevel, punit, msg,...)
Definition srv_log.h:98
enum choice_type type
Definition advchoice.h:46
adv_want want
Definition advchoice.h:48
universals_u value
Definition advchoice.h:47
bool need_boat
Definition advchoice.h:49
Definition ai.h:50
Definition city.h:317
Definition tile.h:50
struct unit_list * units
Definition tile.h:58
bool done
Definition daiunit.h:44
Definition unit.h:140
enum unit_activity activity
Definition unit.h:159
int moves_left
Definition unit.h:152
int id
Definition unit.h:147
bool moved
Definition unit.h:176
int hp
Definition unit.h:153
int fuel
Definition unit.h:155
struct tile * tile
Definition unit.h:142
int homecity
Definition unit.h:148
struct tile * goto_tile
Definition unit.h:157
int veteran
Definition unit.h:154
struct civ_map map
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
struct city * tile_city(const struct tile *ptile)
Definition tile.c:83
#define TILE_XY(ptile)
Definition tile.h:43
const struct unit_type * utype
Definition fc_types.h:553
bool unit_type_is_losing_hp(const struct player *pplayer, const struct unit_type *punittype)
Definition unit.c:2303
int hp_gain_coord(const struct unit *punit)
Definition unit.c:2225
struct unit * unit_virtual_create(struct player *pplayer, struct city *pcity, const struct unit_type *punittype, int veteran_level)
Definition unit.c:1687
void unit_virtual_destroy(struct unit *punit)
Definition unit.c:1792
void unit_tile_set(struct unit *punit, struct tile *ptile)
Definition unit.c:1310
#define unit_tile(_pu)
Definition unit.h:407
static bool is_enemy_unit_tile(const struct tile *ptile, const struct player *pplayer)
Definition unit.h:430
#define CHECK_UNIT(punit)
Definition unit.h:273
#define unit_owner(_pu)
Definition unit.h:406
bool unit_activity_handling(struct unit *punit, enum unit_activity new_activity, enum gen_action trigger_action)
Definition unithand.c:6665
bool is_refuel_point(const struct tile *ptile, const struct player *pplayer, const struct unit *punit)
Definition unittools.c:1535
bool is_unit_being_refueled(const struct unit *punit)
Definition unittools.c:1526
const struct unit_type * unit_type_get(const struct unit *punit)
Definition unittype.c:123
int utype_upkeep_cost(const struct unit_type *ut, struct player *pplayer, Output_type_id otype)
Definition unittype.c:132
const char * unit_rule_name(const struct unit *punit)
Definition unittype.c:1591
int unit_build_shield_cost_base(const struct unit *punit)
Definition unittype.c:1488
int utype_pays_mp_for_action_estimate(const struct civ_map *nmap, const struct action *paction, const struct unit_type *putype, const struct player *act_player, const struct tile *act_tile, const struct tile *tgt_tile)
Definition unittype.c:1397
const char * utype_rule_name(const struct unit_type *punittype)
Definition unittype.c:1582
bool unit_can_take_over(const struct unit *punit)
Definition unittype.c:268
bool utype_can_do_action(const struct unit_type *putype, const action_id act_id)
Definition unittype.c:375
static bool uclass_has_flag(const struct unit_class *punitclass, enum unit_class_flag_id flag)
Definition unittype.h:771
#define utype_class(_t_)
Definition unittype.h:754
@ MOVE_NONE
Definition unittype.h:144
#define unit_type_iterate(_p)
Definition unittype.h:860
#define unit_type_iterate_end
Definition unittype.h:867