Removed silencing of gtk warning logs from gtk3.22-client.
[freeciv.git] / common / combat.c
blob3ce6377855a58bd46ed8146df12bbbf0a475d588
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 <math.h>
20 /* utility */
21 #include "bitvector.h"
22 #include "rand.h"
23 #include "log.h"
25 /* common */
26 #include "base.h"
27 #include "game.h"
28 #include "map.h"
29 #include "movement.h"
30 #include "packets.h"
31 #include "unit.h"
32 #include "unitlist.h"
33 #include "unittype.h"
35 #include "combat.h"
37 /***********************************************************************
38 Checks if player is restricted diplomatically from attacking the tile.
39 Returns FLASE if
40 1) the tile is empty or
41 2) the tile contains a non-enemy city or
42 3) the tile contains a non-enemy unit
43 ***********************************************************************/
44 bool can_player_attack_tile(const struct player *pplayer,
45 const struct tile *ptile)
47 struct city *pcity = tile_city(ptile);
49 /* 1. Is there anyone there at all? */
50 if (!pcity && unit_list_size((ptile->units)) == 0) {
51 return FALSE;
54 /* 2. If there is a city there, can we attack it? */
55 if (pcity && !pplayers_at_war(city_owner(pcity), pplayer)) {
56 return FALSE;
59 /* 3. Are we allowed to attack _all_ units there? */
60 unit_list_iterate(ptile->units, aunit) {
61 if (!pplayers_at_war(unit_owner(aunit), pplayer)) {
62 /* Enemy hiding behind a human/diplomatic shield */
63 return FALSE;
65 } unit_list_iterate_end;
67 return TRUE;
70 /***********************************************************************
71 Can unit attack other
72 ***********************************************************************/
73 static bool is_unit_reachable_by_unit(const struct unit *defender,
74 const struct unit *attacker)
76 struct unit_class *dclass = unit_class_get(defender);
77 struct unit_type *atype = unit_type_get(attacker);
79 return BV_ISSET(atype->targets, uclass_index(dclass));
82 /***********************************************************************
83 Can unit attack other at given location
84 ***********************************************************************/
85 bool is_unit_reachable_at(const struct unit *defender,
86 const struct unit *attacker,
87 const struct tile *location)
89 if (NULL != tile_city(location)) {
90 return TRUE;
93 if (is_unit_reachable_by_unit(defender, attacker)) {
94 return TRUE;
97 if (tile_has_native_base(location, unit_type_get(defender))) {
98 return TRUE;
101 return FALSE;
104 /***********************************************************************
105 Checks if a unit can physically attack pdefender at the tile
106 (assuming it is adjacent and at war).
108 Unit can NOT attack if:
109 1) it does not have any attack power.
110 2) it is not a fighter and defender is a flying unit (except city/airbase).
111 3) it is a ground unit without marine ability and it attacks from ocean.
112 4) it is a ground unit and it attacks a target on an ocean square.
113 5) it is a sailing unit without shore bombardment capability and it
114 attempts to attack land.
116 Does NOT check:
117 1) Moves left
118 2) Adjacency
119 3) Diplomatic status
120 ***********************************************************************/
121 enum unit_attack_result unit_attack_unit_at_tile_result(const struct unit *punit,
122 const struct unit *pdefender,
123 const struct tile *dest_tile)
125 /* 1. Can we attack _anything_ ? */
126 if (!is_military_unit(punit) || !is_attack_unit(punit)) {
127 return ATT_NON_ATTACK;
130 /* 2. Only fighters can attack planes, except in city or airbase attacks */
131 if (!is_unit_reachable_at(pdefender, punit, dest_tile)) {
132 return ATT_UNREACHABLE;
135 /* 3. Can't attack with ground unit from ocean, except for marines */
136 if (!is_native_tile(unit_type_get(punit), unit_tile(punit))
137 && !can_attack_from_non_native(unit_type_get(punit))) {
138 return ATT_NONNATIVE_SRC;
141 /* 4. Most units can not attack non-native terrain.
142 * Most ships can attack land tiles (shore bombardment) */
143 if (!is_native_tile(unit_type_get(punit), dest_tile)
144 && !can_attack_non_native(unit_type_get(punit))) {
145 return ATT_NONNATIVE_DST;
148 return ATT_OK;
151 /***********************************************************************
152 When unreachable_protects setting is TRUE:
153 To attack a stack, unit must be able to attack every unit there (not
154 including transported units).
155 ************************************************************************/
156 static enum unit_attack_result unit_attack_all_at_tile_result(const struct unit *punit,
157 const struct tile *ptile)
159 unit_list_iterate(ptile->units, aunit) {
160 /* HACK: we don't count transported units here. This prevents some
161 * bugs like a submarine carrying a cruise missile being invulnerable
162 * to other sea units. However from a gameplay perspective it's a hack,
163 * since players can load and unload their units manually to protect
164 * their transporters. */
165 if (!unit_transported(aunit)) {
166 enum unit_attack_result result;
168 result = unit_attack_unit_at_tile_result(punit, aunit, ptile);
169 if (result != ATT_OK) {
170 return result;
173 } unit_list_iterate_end;
175 return ATT_OK;
178 /***********************************************************************
179 When unreachable_protects setting is FALSE:
180 To attack a stack, unit must be able to attack some unit there (not
181 including transported units).
182 ************************************************************************/
183 static enum unit_attack_result unit_attack_any_at_tile_result(const struct unit *punit,
184 const struct tile *ptile)
186 enum unit_attack_result result = ATT_OK;
188 unit_list_iterate(ptile->units, aunit) {
189 /* HACK: we don't count transported units here. This prevents some
190 * bugs like a cargoplane carrying a land unit being vulnerable. */
191 if (!unit_transported(aunit)) {
192 result = unit_attack_unit_at_tile_result(punit, aunit, ptile);
193 if (result == ATT_OK) {
194 return result;
197 } unit_list_iterate_end;
199 /* That's result from check against last unit on tile, not first.
200 * Shouldn't matter. */
201 return result;
204 /***********************************************************************
205 Check if unit can attack unit stack at tile.
206 ***********************************************************************/
207 enum unit_attack_result unit_attack_units_at_tile_result(const struct unit *punit,
208 const struct tile *ptile)
210 if (game.info.unreachable_protects) {
211 return unit_attack_all_at_tile_result(punit, ptile);
212 } else {
213 return unit_attack_any_at_tile_result(punit, ptile);
217 /***********************************************************************
218 Is unit (1) diplomatically allowed to attack and (2) physically able
219 to do so?
220 ***********************************************************************/
221 bool can_unit_attack_tile(const struct unit *punit,
222 const struct tile *dest_tile)
224 return (can_player_attack_tile(unit_owner(punit), dest_tile)
225 && unit_attack_units_at_tile_result(punit, dest_tile) == ATT_OK);
228 /***********************************************************************
229 Returns the chance of the attacker winning, a number between 0 and 1.
230 If you want the chance that the defender wins just use 1-chance(...)
232 NOTE: this number can be _very_ small, fx in a battle between an
233 ironclad and a battleship the ironclad has less than 1/100000 chance of
234 winning.
236 The algoritm calculates the probability of each possible number of HP's
237 the attacker has left. Maybe that info should be preserved for use in
238 the AI.
239 ***********************************************************************/
240 double win_chance(int as, int ahp, int afp, int ds, int dhp, int dfp)
242 /* number of rounds a unit can fight without dying */
243 int att_N_lose = (ahp + dfp - 1) / dfp;
244 int def_N_lose = (dhp + afp - 1) / afp;
245 /* Probability of losing one round */
246 double att_P_lose1 = (as + ds == 0) ? 0.5 : (double) ds / (as + ds);
247 double def_P_lose1 = 1 - att_P_lose1;
250 This calculates
252 binomial_coeff(def_N_lose-1 + lr, lr)
253 * def_P_lose1^(def_N_lose-1)
254 * att_P_lose1^(lr)
255 * def_P_lose1
257 for each possible number of rounds lost (rl) by the winning unit.
258 rl is of course less than the number of rounds the winning unit
259 should lose to lose all it's hit points.
260 The probabilities are then summed.
262 To see this is correct consider the set of series for all valid fights.
263 These series are the type (win, lose, lose...). The possible lenghts are
264 def_N_lose to def_N_lose+att_N_lose-1. A series is not valid unless it
265 contains def_N_lose wins, and one of the wins must be the last one, or
266 the series would be equivalent the a shorter series (the attacker would
267 have won one or more fights previously).
268 So since the last fight is a win we disregard it while calculating. Now
269 a series contains def_N_lose-1 wins. So for each possible lenght of a
270 series we find the probability of every valid series and then sum.
271 For a specific lenght (a "lr") every series have the probability
272 def_P_lose1^(def_N_lose-1) * att_P_lose1^(lr)
273 and then getting from that to the real series requires a win, ie factor
274 def_N_lose. The number of series with lenght (def_N_lose-1 + lr) and
275 "lr" lost fights is
276 binomial_coeff(def_N_lose-1 + lr, lr)
277 And by multiplying we get the formula on the top of this code block.
278 Adding the cumulative probability for each valid lenght then gives the
279 total probability.
281 We clearly have all valid series this way. To see that we have counted
282 none twice note that would require a series with a smaller series inbedded.
283 But since the smaller series already included def_N_lose wins, and the
284 larger series ends with a win, it would have too many wins and therefore
285 cannot exist.
287 In practice each binomial coefficient for a series lenght can be calculated
288 from the previous. In the coefficient (n, k) n is increased and k is
289 unchanged.
290 The "* def_P_lose1" is multiplied on the sum afterwards.
292 (lots of talk for so little code)
295 double binom_save = pow(def_P_lose1, (double)(def_N_lose - 1));
296 double accum_prob = binom_save; /* lr = 0 */
298 int lr; /* the number of Lost Rounds by the attacker */
299 for (lr = 1; lr < att_N_lose; lr++) {
300 /* update the coefficient */
301 int n = lr + def_N_lose - 1;
302 binom_save *= n;
303 binom_save /= lr;
304 binom_save *= att_P_lose1;
305 /* use it for this lr */
306 accum_prob += binom_save;
308 /* Every element of the sum needs a factor for the very last fight round */
309 accum_prob *= def_P_lose1;
311 return accum_prob;
314 /**************************************************************************
315 A unit's effective firepower depend on the situation.
316 **************************************************************************/
317 void get_modified_firepower(const struct unit *attacker,
318 const struct unit *defender,
319 int *att_fp, int *def_fp)
321 struct city *pcity = tile_city(unit_tile(defender));
323 *att_fp = unit_type_get(attacker)->firepower;
324 *def_fp = unit_type_get(defender)->firepower;
326 /* Check CityBuster flag */
327 if (unit_has_type_flag(attacker, UTYF_CITYBUSTER) && pcity) {
328 *att_fp *= 2;
332 * UTYF_BADWALLATTACKER sets the firepower of the attacking unit to 1 if
333 * an EFT_DEFEND_BONUS applies (such as a land unit attacking a city with
334 * city walls).
336 if (unit_has_type_flag(attacker, UTYF_BADWALLATTACKER)
337 && get_unittype_bonus(unit_owner(defender), unit_tile(defender),
338 unit_type_get(attacker), EFT_DEFEND_BONUS) > 0) {
339 *att_fp = 1;
342 /* pearl harbour - defender's firepower is reduced to one,
343 * attacker's is multiplied by two */
344 if (unit_has_type_flag(defender, UTYF_BADCITYDEFENDER)
345 && tile_city(unit_tile(defender))) {
346 *att_fp *= 2;
347 *def_fp = 1;
351 * When attacked by fighters, helicopters have their firepower
352 * reduced to 1.
354 if (combat_bonus_against(unit_type_get(attacker)->bonuses,
355 unit_type_get(defender),
356 CBONUS_FIREPOWER1)) {
357 *def_fp = 1;
360 /* In land bombardment both units have their firepower reduced to 1 */
361 if (!is_native_tile(unit_type_get(attacker), unit_tile(defender))
362 && !can_exist_at_tile(unit_type_get(defender), unit_tile(attacker))) {
363 *att_fp = 1;
364 *def_fp = 1;
368 /**************************************************************************
369 Returns a double in the range [0;1] indicating the attackers chance of
370 winning. The calculation takes all factors into account.
371 **************************************************************************/
372 double unit_win_chance(const struct unit *attacker,
373 const struct unit *defender)
375 int def_power = get_total_defense_power(attacker, defender);
376 int att_power = get_total_attack_power(attacker, defender);
378 double chance;
380 int def_fp, att_fp;
381 get_modified_firepower(attacker, defender, &att_fp, &def_fp);
383 chance = win_chance(att_power, attacker->hp, att_fp,
384 def_power, defender->hp, def_fp);
386 return chance;
389 /**************************************************************************
390 Try defending against nuclear attack; if successful, return a city which
391 had enough luck and EFT_NUKE_PROOF.
392 If the attack was successful return NULL.
393 **************************************************************************/
394 struct city *sdi_try_defend(const struct player *owner,
395 const struct tile *ptile)
397 square_iterate(ptile, 2, ptile1) {
398 struct city *pcity = tile_city(ptile1);
400 if (pcity
401 && fc_rand(100) < get_target_bonus_effects(NULL,
402 city_owner(pcity), owner,
403 pcity, NULL, ptile,
404 NULL, NULL,
405 NULL, NULL,
406 EFT_NUKE_PROOF)) {
407 return pcity;
409 } square_iterate_end;
411 return NULL;
414 /**************************************************************************
415 Convenience wrapper for base_get_attack_power.
416 **************************************************************************/
417 int get_attack_power(const struct unit *punit)
419 return base_get_attack_power(unit_type_get(punit), punit->veteran,
420 punit->moves_left);
423 /**************************************************************************
424 Returns the attack power, modified by moves left, and veteran
425 status.
426 **************************************************************************/
427 int base_get_attack_power(const struct unit_type *punittype,
428 int veteran, int moves_left)
430 int power;
431 const struct veteran_level *vlevel;
433 fc_assert_ret_val(punittype != NULL, 0);
435 vlevel = utype_veteran_level(punittype, veteran);
436 fc_assert_ret_val(vlevel != NULL, 0);
438 power = punittype->attack_strength * POWER_FACTOR
439 * vlevel->power_fact / 100;
441 if (game.info.tired_attack && moves_left < SINGLE_MOVE) {
442 power = (power * moves_left) / SINGLE_MOVE;
445 return power;
448 /**************************************************************************
449 Returns the defense power, modified by veteran status.
450 **************************************************************************/
451 int base_get_defense_power(const struct unit *punit)
453 const struct veteran_level *vlevel;
455 fc_assert_ret_val(punit != NULL, 0);
457 vlevel = utype_veteran_level(unit_type_get(punit), punit->veteran);
458 fc_assert_ret_val(vlevel != NULL, 0);
460 return unit_type_get(punit)->defense_strength * POWER_FACTOR
461 * vlevel->power_fact / 100;
464 /**************************************************************************
465 Returns the defense power, modified by terrain and veteran status.
466 Note that rivers as special road types are not handled here as
467 terrain property.
468 **************************************************************************/
469 static int get_defense_power(const struct unit *punit)
471 int db, power = base_get_defense_power(punit);
472 struct tile *ptile = unit_tile(punit);
473 struct unit_class *pclass = unit_class_get(punit);
475 if (uclass_has_flag(pclass, UCF_TERRAIN_DEFENSE)) {
476 db = 10 + tile_terrain(ptile)->defense_bonus / 10;
477 power = (power * db) / 10;
480 if (!is_native_tile_to_class(pclass, ptile)) {
481 power = power * pclass->non_native_def_pct / 100;
484 return power;
487 /***************************************************************************
488 return the modified attack power of a unit. Currently they aren't any
489 modifications...
490 ***************************************************************************/
491 int get_total_attack_power(const struct unit *attacker,
492 const struct unit *defender)
494 int attackpower = get_attack_power(attacker);
496 return attackpower;
499 /**************************************************************************
500 Return an increased defensepower. Effects which increase the
501 defensepower are:
502 - unit type effects (horse vs pikemen for example)
503 - defender in a fortress
504 - fortified defender
506 May be called with a non-existing att_type to avoid any unit type
507 effects.
508 **************************************************************************/
509 static int defense_multiplication(const struct unit_type *att_type,
510 const struct unit_type *def_type,
511 const struct player *def_player,
512 const struct tile *ptile,
513 int defensepower, bool fortified)
515 struct city *pcity = tile_city(ptile);
516 int mod;
518 fc_assert_ret_val(NULL != def_type, 0);
520 if (NULL != att_type) {
521 int defense_divider;
522 int defense_multiplier = 1 + def_type->cache.defense_mp_bonuses[utype_index(att_type)];
524 defensepower *= defense_multiplier;
526 /* This applies even if pcity is NULL. */
527 mod = 100 + get_unittype_bonus(def_player, ptile,
528 att_type, EFT_DEFEND_BONUS);
529 defensepower = MAX(0, defensepower * mod / 100);
531 defense_divider = 1 + combat_bonus_against(att_type->bonuses, def_type,
532 CBONUS_DEFENSE_DIVIDER);
533 defensepower /= defense_divider;
536 defensepower +=
537 defensepower * tile_extras_defense_bonus(ptile, def_type) / 100;
539 if ((pcity || fortified)
540 && uclass_has_flag(utype_class(def_type), UCF_CAN_FORTIFY)
541 && !utype_has_flag(def_type, UTYF_CANT_FORTIFY)) {
542 defensepower = (defensepower * 3) / 2;
545 return defensepower;
548 /**************************************************************************
549 May be called with a non-existing att_type to avoid any effects which
550 depend on the attacker.
551 **************************************************************************/
552 int get_virtual_defense_power(const struct unit_type *att_type,
553 const struct unit_type *def_type,
554 const struct player *def_player,
555 const struct tile *ptile,
556 bool fortified, int veteran)
558 int defensepower = def_type->defense_strength;
559 int db;
560 const struct veteran_level *vlevel;
561 struct unit_class *defclass;
563 fc_assert_ret_val(def_type != NULL, 0);
565 if (!can_exist_at_tile(def_type, ptile)) {
566 /* Ground units on ship doesn't defend. */
567 return 0;
570 vlevel = utype_veteran_level(def_type, veteran);
571 fc_assert_ret_val(vlevel != NULL, 0);
573 defclass = utype_class(def_type);
575 db = POWER_FACTOR;
576 if (uclass_has_flag(defclass, UCF_TERRAIN_DEFENSE)) {
577 db += tile_terrain(ptile)->defense_bonus / (100 / POWER_FACTOR);
579 defensepower *= db;
580 defensepower *= vlevel->power_fact / 100;
581 if (!is_native_tile_to_class(defclass, ptile)) {
582 defensepower = defensepower * defclass->non_native_def_pct / 100;
585 return defense_multiplication(att_type, def_type, def_player,
586 ptile, defensepower,
587 fortified);
590 /***************************************************************************
591 return the modified defense power of a unit.
592 An veteran aegis cruiser in a mountain city with SAM and SDI defense
593 being attacked by a missile gets defense 288.
594 ***************************************************************************/
595 int get_total_defense_power(const struct unit *attacker,
596 const struct unit *defender)
598 return defense_multiplication(unit_type_get(attacker),
599 unit_type_get(defender),
600 unit_owner(defender), unit_tile(defender),
601 get_defense_power(defender),
602 defender->activity == ACTIVITY_FORTIFIED);
605 /***************************************************************************
606 Return total defense power of the unit if it fortifies, if possible,
607 where it is. attacker might be NULL to skip calculating attacker specific
608 bonuses.
609 ***************************************************************************/
610 int get_fortified_defense_power(const struct unit *attacker,
611 const struct unit *defender)
613 struct unit_type *att_type = NULL;
615 if (attacker != NULL) {
616 att_type = unit_type_get(attacker);
619 return defense_multiplication(att_type, unit_type_get(defender),
620 unit_owner(defender), unit_tile(defender),
621 get_defense_power(defender),
622 TRUE);
625 /**************************************************************************
626 A number indicating the defense strength.
627 Unlike the one got from win chance this doesn't potentially get insanely
628 small if the units are unevenly matched, unlike win_chance.
629 **************************************************************************/
630 static int get_defense_rating(const struct unit *attacker,
631 const struct unit *defender)
633 int afp, dfp;
635 int rating = get_total_defense_power(attacker, defender);
636 get_modified_firepower(attacker, defender, &afp, &dfp);
638 /* How many rounds the defender will last */
639 rating *= (defender->hp + afp-1)/afp;
641 rating *= dfp;
643 return rating;
646 /**************************************************************************
647 Finds the best defender on the tile, given an attacker. The diplomatic
648 relationship of attacker and defender is ignored; the caller should check
649 this.
650 **************************************************************************/
651 struct unit *get_defender(const struct unit *attacker,
652 const struct tile *ptile)
654 struct unit *bestdef = NULL;
655 int bestvalue = -99, best_cost = 0, rating_of_best = 0;
657 /* Simply call win_chance with all the possible defenders in turn, and
658 * take the best one. It currently uses build cost as a tiebreaker in
659 * case 2 units are identical, but this is crude as build cost does not
660 * neccesarily have anything to do with the value of a unit. This function
661 * could be improved to take the value of the unit into account. It would
662 * also be nice if the function was a bit more fuzzy about prioritizing,
663 * making it able to fx choose a 1a/9d unit over a 10a/10d unit. It should
664 * also be able to spare units without full hp's to some extent, as these
665 * could be more valuable later. */
666 unit_list_iterate(ptile->units, defender) {
667 /* We used to skip over allied units, but the logic for that is
668 * complicated and is now handled elsewhere. */
669 if (unit_can_defend_here(defender)
670 && unit_attack_unit_at_tile_result(attacker, defender, ptile) == ATT_OK) {
671 bool change = FALSE;
672 int build_cost = unit_build_shield_cost(defender);
673 int defense_rating = get_defense_rating(attacker, defender);
674 /* This will make units roughly evenly good defenders look alike. */
675 int unit_def
676 = (int) (100000 * (1 - unit_win_chance(attacker, defender)));
678 fc_assert_action(0 <= unit_def, continue);
680 if (unit_has_type_flag(defender, UTYF_GAMELOSS)
681 && !is_stack_vulnerable(unit_tile(defender))) {
682 unit_def = -1; /* then always use leader as last defender. */
683 /* FIXME: multiple gameloss units with varying defense value
684 * not handled. */
687 if (unit_def > bestvalue) {
688 change = TRUE;
689 } else if (unit_def == bestvalue) {
690 if (build_cost < best_cost) {
691 change = TRUE;
692 } else if (build_cost == best_cost) {
693 if (rating_of_best < defense_rating) {
694 change = TRUE;
699 if (change) {
700 bestvalue = unit_def;
701 bestdef = defender;
702 best_cost = build_cost;
703 rating_of_best = defense_rating;
706 } unit_list_iterate_end;
708 return bestdef;
711 /**************************************************************************
712 get unit at (x, y) that wants to kill defender.
714 Works like get_defender; see comment there.
715 This function is mostly used by the AI.
716 **************************************************************************/
717 struct unit *get_attacker(const struct unit *defender,
718 const struct tile *ptile)
720 struct unit *bestatt = 0;
721 int bestvalue = -1, unit_a, best_cost = 0;
723 unit_list_iterate(ptile->units, attacker) {
724 int build_cost = unit_build_shield_cost(attacker);
726 if (pplayers_allied(unit_owner(defender), unit_owner(attacker))) {
727 return NULL;
729 unit_a = (int) (100000 * (unit_win_chance(attacker, defender)));
730 if (unit_a > bestvalue ||
731 (unit_a == bestvalue && build_cost < best_cost)) {
732 bestvalue = unit_a;
733 bestatt = attacker;
734 best_cost = build_cost;
736 } unit_list_iterate_end;
738 return bestatt;
741 /**************************************************************************
742 Is it a city/fortress/air base or will the whole stack die in an attack
743 **************************************************************************/
744 bool is_stack_vulnerable(const struct tile *ptile)
746 return (game.info.killstack
747 && !tile_has_base_flag(ptile, BF_NO_STACK_DEATH)
748 && NULL == tile_city(ptile));
751 /**************************************************************************
752 Get bonus value against given unit type from bonus list.
754 Consider using cached values instead of calling this recalculation
755 directly.
756 **************************************************************************/
757 int combat_bonus_against(const struct combat_bonus_list *list,
758 const struct unit_type *enemy,
759 enum combat_bonus_type type)
761 int value = 0;
763 combat_bonus_list_iterate(list, pbonus) {
764 if (pbonus->type == type && utype_has_flag(enemy, pbonus->flag)) {
765 value += pbonus->value;
767 } combat_bonus_list_iterate_end;
769 return value;