Freeciv-3.3: /fast/freeciv/nightly/main/common/combat.c Source File

Freeciv-3.3

Loading...
Searching...
No Matches
combat.c
Go to the documentation of this file.
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.
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#include <math.h>
19
20/* utility */
21#include "bitvector.h"
22#include "rand.h"
23#include "log.h"
24
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"
34
35#include "combat.h"
36
37/*******************************************************************/
44 static bool can_player_attack_tile(const struct player *pplayer,
45 const struct tile *ptile)
46{
47 struct city *pcity = tile_city(ptile);
48
49 /* 1. Is there anyone there at all? */
50 if (pcity == NULL && unit_list_size((ptile->units)) == 0) {
51 return FALSE;
52 }
53
54 /* 2. If there is a city there, can we attack it? */
55 if (pcity != NULL && !pplayers_at_war(city_owner(pcity), pplayer)) {
56 return FALSE;
57 }
58
59 /* 3. Are we allowed to attack _all_ units there? */
60 unit_list_iterate(ptile->units, aunit) {
61 if (!unit_has_type_flag(aunit, UTYF_FLAGLESS)
62 && !pplayers_at_war(unit_owner(aunit), pplayer)) {
63 /* Enemy hiding behind a human/diplomatic shield */
64 return FALSE;
65 }
66 } unit_list_iterate_end;
67
68 return TRUE;
69}
70
71/*******************************************************************/
74 static bool is_unit_reachable_by_unit(const struct unit *defender,
75 const struct unit *attacker)
76{
77 struct unit_class *dclass = unit_class_get(defender);
78 const struct unit_type *atype = unit_type_get(attacker);
79
80 return BV_ISSET(atype->targets, uclass_index(dclass));
81}
82
83/*******************************************************************/
86 bool is_unit_reachable_at(const struct unit *defender,
87 const struct unit *attacker,
88 const struct tile *location)
89{
90 if (NULL != tile_city(location)) {
91 return TRUE;
92 }
93
94 if (is_unit_reachable_by_unit(defender, attacker)) {
95 return TRUE;
96 }
97
98 if (tile_has_native_base(location, unit_type_get(defender))) {
99 return TRUE;
100 }
101
102 return FALSE;
103}
104
105/*******************************************************************/
122enum unit_attack_result
123unit_attack_unit_at_tile_result(const struct unit *punit,
124 const struct action *paction,
125 const struct unit *pdefender,
126 const struct tile *dest_tile)
127{
128 /* 1. Can we attack _anything_ ? */
129 if (paction == NULL) {
130 if (!(utype_can_do_action(unit_type_get(punit), ACTION_ATTACK)
131 || utype_can_do_action(unit_type_get(punit),
132 ACTION_SUICIDE_ATTACK)
133 /* Needed because ACTION_NUKE_UNITS uses this when evaluating its
134 * hard requirements. */
135 || utype_can_do_action(unit_type_get(punit),
136 ACTION_NUKE_UNITS))) {
137 return ATT_NON_ATTACK;
138 }
139 } else {
140 if (!utype_can_do_action(unit_type_get(punit), paction->id)) {
141 return ATT_NON_ATTACK;
142 }
143 }
144
145 /* 2. Can't attack with ground unit from ocean, except for marines */
146 if (paction == NULL) {
147 if (!is_native_tile(unit_type_get(punit), unit_tile(punit))
148 && !utype_can_do_act_when_ustate(unit_type_get(punit),
149 ACTION_ATTACK,
150 USP_NATIVE_TILE, FALSE)
151 && !utype_can_do_act_when_ustate(unit_type_get(punit),
152 ACTION_SUICIDE_ATTACK,
153 USP_NATIVE_TILE, FALSE)) {
154 return ATT_NONNATIVE_SRC;
155 }
156 } else {
157 if (!is_native_tile(unit_type_get(punit), unit_tile(punit))
158 && !utype_can_do_act_when_ustate(unit_type_get(punit),
159 paction->id,
160 USP_NATIVE_TILE, FALSE)) {
161 return ATT_NONNATIVE_SRC;
162 }
163 }
164
165 /* 3. Most units can not attack non-native terrain.
166 * Most ships can attack land tiles (shore bombardment) */
167 if (!is_native_tile(unit_type_get(punit), dest_tile)
168 && !can_attack_non_native_hard_reqs(unit_type_get(punit))) {
169 return ATT_NONNATIVE_DST;
170 }
171
172 /* 4. Only fighters can attack planes, except in city or airbase attacks */
173 if (!is_unit_reachable_at(pdefender, punit, dest_tile)) {
174 return ATT_UNREACHABLE;
175 }
176
177 /* Unreachability check must remain the last check, as callers interpret
178 * ATT_UNREACHABLE as "ATT_OK except that unreachable." */
179
180 return ATT_OK;
181}
182
183/*******************************************************************/
188static enum unit_attack_result
189unit_attack_all_at_tile_result(const struct unit *punit,
190 const struct action *paction,
191 const struct tile *ptile)
192{
193 bool any_reachable_unit = FALSE;
194 bool any_neverprotect_unit = FALSE;
195
196 unit_list_iterate(ptile->units, aunit) {
197 /* HACK: We don't count transported units here. This prevents some
198 * bugs like a submarine carrying a cruise missile being invulnerable
199 * to other sea units. However from a gameplay perspective it's a hack,
200 * since players can load and unload their units manually to protect
201 * their transporters. */
202 if (!unit_transported(aunit)) {
203 enum unit_attack_result result;
204
205 result = unit_attack_unit_at_tile_result(punit, paction,
206 aunit, ptile);
207 if (result == ATT_UNREACHABLE
208 && unit_has_type_flag(aunit, UTYF_NEVER_PROTECTS)) {
209 /* Doesn't prevent us from attacking other units on the tile */
210 any_neverprotect_unit = TRUE;
211 continue;
212 } else if (result != ATT_OK) {
213 return result;
214 }
215 any_reachable_unit = TRUE;
216 }
217 } unit_list_iterate_end;
218
219 /* If there are only unreachable, UTYF_NEVER_PROTECTS units, we still have
220 * to return ATT_UNREACHABLE. */
221 return (any_reachable_unit || !any_neverprotect_unit) ? ATT_OK : ATT_UNREACHABLE;
222}
223
224/*******************************************************************/
229static enum unit_attack_result
230unit_attack_any_at_tile_result(const struct unit *punit,
231 const struct action *paction,
232 const struct tile *ptile)
233{
234 enum unit_attack_result result = ATT_OK;
235
236 unit_list_iterate(ptile->units, aunit) {
237 /* HACK: we don't count transported units here. This prevents some
238 * bugs like a cargoplane carrying a land unit being vulnerable. */
239 if (!unit_transported(aunit)) {
240 result = unit_attack_unit_at_tile_result(punit, paction,
241 aunit, ptile);
242 if (result == ATT_OK) {
243 return result;
244 }
245 }
246 } unit_list_iterate_end;
247
248 /* That's result from check against last unit on tile, not first.
249 * Shouldn't matter. */
250 return result;
251}
252
253/*******************************************************************/
256enum unit_attack_result
257unit_attack_units_at_tile_result(const struct unit *punit,
258 const struct action *paction,
259 const struct tile *ptile)
260{
261 if (game.info.unreachable_protects) {
262 return unit_attack_all_at_tile_result(punit, paction, ptile);
263 } else {
264 return unit_attack_any_at_tile_result(punit, paction, ptile);
265 }
266}
267
268/*******************************************************************/
271enum unit_attack_result
272unit_wipe_units_at_tile_result(const struct unit *punit,
273 const struct tile *ptile)
274{
275 /* Can unit wipe in general? */
276 if (!utype_can_do_action(unit_type_get(punit), ACTION_WIPE_UNITS)) {
277 return ATT_NON_ATTACK;
278 }
279
280 unit_list_iterate(ptile->units, target) {
281 if (get_total_defense_power(punit, target) > 0) {
282 return ATT_NOT_WIPABLE;
283 }
284
285 /* Can't wipe with ground unit from ocean, except for marines */
286 if (!is_native_tile(unit_type_get(punit), unit_tile(punit))
287 && !utype_can_do_act_when_ustate(unit_type_get(punit), ACTION_WIPE_UNITS,
288 USP_NATIVE_TILE, FALSE)) {
289 return ATT_NONNATIVE_SRC;
290 }
291
292 /* Most units can not wipe on non-native terrain.
293 * Most ships can wipe on land tiles (shore bombardment) */
294 if (!is_native_tile(unit_type_get(punit), ptile)
295 && !can_attack_non_native_hard_reqs(unit_type_get(punit))) {
296 return ATT_NONNATIVE_DST;
297 }
298
299 /* Only fighters can wipe planes, except in city or airbase attacks */
300 if (!is_unit_reachable_at(target, punit, ptile)) {
301 return ATT_UNREACHABLE;
302 }
303 } unit_list_iterate_end;
304
305 return ATT_OK;
306}
307
308/*******************************************************************/
312 bool can_unit_attack_tile(const struct unit *punit,
313 const struct action *paction,
314 const struct tile *dest_tile)
315{
316 return ((unit_has_type_flag(punit, UTYF_FLAGLESS)
317 || can_player_attack_tile(unit_owner(punit), dest_tile))
318 && (unit_attack_units_at_tile_result(punit, paction, dest_tile)
319 == ATT_OK));
320}
321
322/*******************************************************************/
334 double win_chance(int as, int ahp, int afp, int ds, int dhp, int dfp)
335{
336 /* number of rounds a unit can fight without dying */
337 int att_N_lose = (ahp + dfp - 1) / dfp;
338 int def_N_lose = (dhp + afp - 1) / afp;
339 /* Probability of losing one round */
340 double att_P_lose1 = (as + ds == 0) ? 0.5 : (double) ds / (as + ds);
341 double def_P_lose1 = 1 - att_P_lose1;
342
343 /*
344 This calculates
345
346 binomial_coeff(def_N_lose-1 + lr, lr)
347 * def_P_lose1^(def_N_lose-1)
348 * att_P_lose1^(lr)
349 * def_P_lose1
350
351 for each possible number of rounds lost (rl) by the winning unit.
352 rl is of course less than the number of rounds the winning unit
353 should lose to lose all it's hit points.
354 The probabilities are then summed.
355
356 To see this is correct consider the set of series for all valid fights.
357 These series are the type (win, lose, lose...). The possible lengths are
358 def_N_lose to def_N_lose+att_N_lose-1. A series is not valid unless it
359 contains def_N_lose wins, and one of the wins must be the last one, or
360 the series would be equivalent the a shorter series (the attacker would
361 have won one or more fights previously).
362 So since the last fight is a win we disregard it while calculating. Now
363 a series contains def_N_lose-1 wins. So for each possible length of a
364 series we find the probability of every valid series and then sum.
365 For a specific length (a "lr") every series have the probability
366 def_P_lose1^(def_N_lose-1) * att_P_lose1^(lr)
367 and then getting from that to the real series requires a win, ie factor
368 def_N_lose. The number of series with length (def_N_lose-1 + lr) and
369 "lr" lost fights is
370 binomial_coeff(def_N_lose-1 + lr, lr)
371 And by multiplying we get the formula on the top of this code block.
372 Adding the cumulative probability for each valid length then gives the
373 total probability.
374
375 We clearly have all valid series this way. To see that we have counted
376 none twice note that would require a series with a smaller series inbedded.
377 But since the smaller series already included def_N_lose wins, and the
378 larger series ends with a win, it would have too many wins and therefore
379 cannot exist.
380
381 In practice each binomial coefficient for a series length can be calculated
382 from the previous. In the coefficient (n, k) n is increased and k is
383 unchanged.
384 The "* def_P_lose1" is multiplied on the sum afterwards.
385
386 (lots of talk for so little code)
387 */
388
389 double binom_save = pow(def_P_lose1, (double)(def_N_lose - 1));
390 double accum_prob = binom_save; /* lr = 0 */
391
392 int lr; /* the number of Lost Rounds by the attacker */
393 for (lr = 1; lr < att_N_lose; lr++) {
394 /* update the coefficient */
395 int n = lr + def_N_lose - 1;
396 binom_save *= n;
397 binom_save /= lr;
398 binom_save *= att_P_lose1;
399 /* use it for this lr */
400 accum_prob += binom_save;
401 }
402 /* Every element of the sum needs a factor for the very last fight round */
403 accum_prob *= def_P_lose1;
404
405 return accum_prob;
406}
407
408/*******************************************************************/
411 void get_modified_firepower(const struct civ_map *nmap,
412 const struct unit *attacker,
413 const struct unit *defender,
414 int *att_fp, int *def_fp)
415{
416 struct city *pcity = tile_city(unit_tile(defender));
417 const struct unit_type *att_type;
418 const struct unit_type *def_type;
419 struct tile *att_tile;
420
421 att_type = unit_type_get(attacker);
422 def_type = unit_type_get(defender);
423
424 *att_fp = att_type->firepower;
425 *def_fp = def_type->firepower;
426
427 /* Check CityBuster flag */
428 if (unit_has_type_flag(attacker, UTYF_CITYBUSTER) && pcity) {
429 *att_fp *= 2;
430 }
431
432 /*
433 * UTYF_BADWALLATTACKER reduces the firepower of the attacking unit to
434 * badwallattacker firepower if an EFT_DEFEND_BONUS applies
435 * (such as a land unit attacking a city with city walls).
436 */
437 if (unit_has_type_flag(attacker, UTYF_BADWALLATTACKER)
438 && get_unittype_bonus(unit_owner(defender), unit_tile(defender),
439 att_type, NULL,
440 EFT_DEFEND_BONUS) > 0) {
441 *att_fp = MIN(*att_fp, game.info.low_firepower_badwallattacker);
442 }
443
444 /* pearl harbour - defender's firepower is reduced,
445 * attacker's is multiplied by two */
446 if (unit_has_type_flag(defender, UTYF_BADCITYDEFENDER)
447 && tile_city(unit_tile(defender))) {
448 *att_fp *= 2;
449 *def_fp = MIN(*def_fp, game.info.low_firepower_pearl_harbour);
450 }
451
452 /*
453 * When attacked by fighters, helicopters have their firepower
454 * reduced to low firepower bonus.
455 */
456 if (combat_bonus_against(att_type->bonuses, def_type,
457 CBONUS_LOW_FIREPOWER)) {
458 *def_fp = MIN(*def_fp, game.info.low_firepower_combat_bonus);
459 }
460
461 att_tile = unit_tile(attacker);
462
463 /* In land bombardment both units have their firepower reduced.
464 * Land bombardment is always towards tile not native for attacker.
465 * It's initiated either from a tile not native to defender (Ocean for Land unit)
466 * or from a tile where attacker is despite non-native terrain (city, transport) */
467 if (utype_has_class_flag(def_type, UCF_NONNAT_BOMBARD_TGT)
468 && !is_native_tile(att_type, unit_tile(defender))
469 && (!can_exist_at_tile(nmap, def_type, att_tile)
470 || !is_native_tile(att_type, att_tile))) {
471 *att_fp = MIN(*att_fp, game.info.low_firepower_nonnat_bombard);
472 *def_fp = MIN(*def_fp, game.info.low_firepower_nonnat_bombard);
473 }
474}
475
476/*******************************************************************/
480 double unit_win_chance(const struct civ_map *nmap,
481 const struct unit *attacker,
482 const struct unit *defender,
483 const struct action *paction)
484{
485 int def_power = get_total_defense_power(attacker, defender);
486 int att_power = get_total_attack_power(attacker, defender, paction);
487 double chance;
488 int def_fp, att_fp;
489
490 get_modified_firepower(nmap, attacker, defender, &att_fp, &def_fp);
491
492 chance = win_chance(att_power, attacker->hp, att_fp,
493 def_power, defender->hp, def_fp);
494
495 return chance;
496}
497
498/*******************************************************************/
503 struct city *sdi_try_defend(const struct civ_map *nmap,
504 const struct player *owner,
505 const struct tile *ptile)
506{
507 square_iterate(nmap, ptile, 2, ptile1) {
508 struct city *pcity = tile_city(ptile1);
509
510 if (pcity
511 && fc_rand(100)
512 < get_target_bonus_effects(NULL,
513 &(const struct req_context) {
514 .player = city_owner(pcity),
515 .city = pcity,
516 .tile = ptile,
517 },
518 &(const struct req_context) {
519 .player = owner,
520 },
521 EFT_NUKE_PROOF)) {
522 return pcity;
523 }
524 } square_iterate_end;
525
526 return NULL;
527}
528
529/*******************************************************************/
532 bool is_tired_attack(int moves_left)
533{
534 return game.info.tired_attack && moves_left < SINGLE_MOVE;
535}
536
537/*******************************************************************/
540 int get_attack_power(const struct unit *punit)
541{
542 return base_get_attack_power(unit_type_get(punit), punit->veteran,
543 punit->moves_left);
544}
545
546/*******************************************************************/
550 int base_get_attack_power(const struct unit_type *punittype,
551 int veteran, int moves_left)
552{
553 int power;
554 const struct veteran_level *vlevel;
555
556 fc_assert_ret_val(punittype != NULL, 0);
557
558 vlevel = utype_veteran_level(punittype, veteran);
559 fc_assert_ret_val(vlevel != NULL, 0);
560
561 power = punittype->attack_strength * POWER_FACTOR
562 * vlevel->power_fact / 100;
563
564 if (is_tired_attack(moves_left)) {
565 power = (power * moves_left) / SINGLE_MOVE;
566 }
567
568 return power;
569}
570
571/*******************************************************************/
574 int base_get_defense_power(const struct unit *punit)
575{
576 const struct veteran_level *vlevel;
577
578 fc_assert_ret_val(punit != NULL, 0);
579
580 vlevel = utype_veteran_level(unit_type_get(punit), punit->veteran);
581 fc_assert_ret_val(vlevel != NULL, 0);
582
583 return unit_type_get(punit)->defense_strength * POWER_FACTOR
584 * vlevel->power_fact / 100;
585}
586
587/*******************************************************************/
592 static int get_defense_power(const struct unit *punit)
593{
594 int db, power = base_get_defense_power(punit);
595 struct tile *ptile = unit_tile(punit);
596 struct unit_class *pclass = unit_class_get(punit);
597
598 if (uclass_has_flag(pclass, UCF_TERRAIN_DEFENSE)) {
599 db = 100 + tile_terrain(ptile)->defense_bonus;
600 power = (power * db) / 100;
601 }
602
603 if (!is_native_tile_to_class(pclass, ptile)) {
604 power = power * pclass->non_native_def_pct / 100;
605 }
606
607 return power;
608}
609
610/*******************************************************************/
613 int get_total_attack_power(const struct unit *attacker,
614 const struct unit *defender,
615 const struct action *paction)
616{
617 int mod;
618 int attackpower = get_attack_power(attacker);
619 struct tile *deftile = unit_tile(defender);
620 struct city *pcity = tile_city(deftile);
621
622 /* Note: get_unit_bonus() would use the tile unit is on,
623 * but we want defending tile. */
624 mod = 100 + get_target_bonus_effects(NULL,
625 &(const struct req_context) {
626 .player = unit_owner(attacker),
627 .city = pcity,
628 .tile = deftile,
629 .unit = attacker,
630 .unittype = unit_type_get(attacker),
631 .action = paction,
632 },
633 NULL, EFT_ATTACK_BONUS);
634
635 return attackpower * mod / 100;
636}
637
638/*******************************************************************/
648 static int defense_multiplication(const struct unit_type *att_type,
649 const struct unit *def,
650 const struct player *def_player,
651 const struct tile *ptile,
652 int defensepower)
653{
654 const struct city *pcity = tile_city(ptile);
655 const struct unit_type *def_type = unit_type_get(def);
656
657 fc_assert_ret_val(NULL != def_type, 0);
658
659 if (NULL != att_type) {
660 int scramble_bonus = 0;
661 int defense_divider_pct;
662
663 if (pcity) {
664 scramble_bonus = def_type->cache.scramble_coeff[utype_index(att_type)];
665 }
666
667 if (scramble_bonus) {
668 /* Use type-specific city bonus,
669 * already multiplied on common type-specific bonus */
670 defensepower = defensepower * scramble_bonus / 10000;
671 defensepower = MAX(0, defensepower);
672 } else {
673 /* Use city defense effect */
674 int defense_multiplier_pct = 100
675 + def_type->cache.defense_mp_bonuses_pct[utype_index(att_type)];
676 int mod = 100 + get_unittype_bonus(def_player, ptile,
677 att_type, NULL, EFT_DEFEND_BONUS);
678
679 /* This applies even if pcity is NULL. */
680 defensepower = defensepower * defense_multiplier_pct / 100;
681 defensepower = MAX(0, defensepower * mod / 100);
682 }
683
684 defense_divider_pct = 100 + combat_bonus_against(att_type->bonuses,
685 def_type, CBONUS_DEFENSE_DIVIDER_PCT)
686 + 100 * combat_bonus_against(att_type->bonuses, def_type,
687 CBONUS_DEFENSE_DIVIDER);
688
689 defensepower = defensepower * 100 / defense_divider_pct;
690 }
691
692 defensepower +=
693 defensepower * tile_extras_defense_bonus(ptile, def_type) / 100;
694
695 defensepower = defensepower
696 * (100
697 + get_target_bonus_effects(NULL,
698 &(const struct req_context) {
699 .player = unit_owner(def),
700 .city = pcity,
701 .tile = ptile,
702 .unit = def,
703 .unittype = unit_type_get(def),
704 },
705 NULL,
706 EFT_FORTIFY_DEFENSE_BONUS)) / 100;
707
708 return defensepower;
709}
710
711/*******************************************************************/
715 int get_virtual_defense_power(const struct civ_map *nmap,
716 const struct unit_type *att_type,
717 const struct unit_type *def_type,
718 struct player *def_player,
719 struct tile *ptile,
720 bool fortified, int veteran)
721{
722 int defensepower = def_type->defense_strength;
723 int db;
724 const struct veteran_level *vlevel;
725 struct unit_class *defclass;
726 struct unit *vdef;
727 int def;
728
729 fc_assert_ret_val(def_type != NULL, 0);
730
731 if (!can_exist_at_tile(nmap, def_type, ptile)) {
732 /* Ground units on ship doesn't defend. */
733 return 0;
734 }
735
736 vlevel = utype_veteran_level(def_type, veteran);
737 fc_assert_ret_val(vlevel != NULL, 0);
738
739 defclass = utype_class(def_type);
740
741 vdef = unit_virtual_create(def_player, NULL, def_type, veteran);
742 unit_tile_set(vdef, ptile);
743 if (fortified) {
744 vdef->activity = ACTIVITY_FORTIFIED;
745 }
746
747 db = POWER_FACTOR;
748 if (uclass_has_flag(defclass, UCF_TERRAIN_DEFENSE)) {
749 db += tile_terrain(ptile)->defense_bonus / (100 / POWER_FACTOR);
750 }
751 defensepower *= db;
752 defensepower *= vlevel->power_fact / 100;
753 if (!is_native_tile_to_class(defclass, ptile)) {
754 defensepower = defensepower * defclass->non_native_def_pct / 100;
755 }
756
757 def = defense_multiplication(att_type, vdef, def_player,
758 ptile, defensepower);
759
760 unit_virtual_destroy(vdef);
761
762 return def;
763}
764
765/*******************************************************************/
770 int get_total_defense_power(const struct unit *attacker,
771 const struct unit *defender)
772{
773 return defense_multiplication(unit_type_get(attacker),
774 defender,
775 unit_owner(defender), unit_tile(defender),
776 get_defense_power(defender));
777}
778
779/*******************************************************************/
784 int get_fortified_defense_power(const struct unit *attacker,
785 struct unit *defender)
786{
787 const struct unit_type *att_type = NULL;
788 enum unit_activity real_act;
789 int def;
790 const struct unit_type *utype;
791
792 if (attacker != NULL) {
793 att_type = unit_type_get(attacker);
794 }
795
796 real_act = defender->activity;
797
798 utype = unit_type_get(defender);
799 if (utype_can_do_action_result(utype, ACTRES_FORTIFY)) {
800 defender->activity = ACTIVITY_FORTIFIED;
801 }
802
803 def = defense_multiplication(att_type, defender,
804 unit_owner(defender), unit_tile(defender),
805 get_defense_power(defender));
806
807 defender->activity = real_act;
808
809 return def;
810}
811
812/*******************************************************************/
817 static int get_defense_rating(const struct civ_map *nmap,
818 const struct unit *attacker,
819 const struct unit *defender)
820{
821 int afp, dfp;
822 int rating = get_total_defense_power(attacker, defender);
823
824 get_modified_firepower(nmap, attacker, defender, &afp, &dfp);
825
826 /* How many rounds the defender will last */
827 rating *= (defender->hp + afp-1)/afp;
828
829 rating *= dfp;
830
831 return rating;
832}
833
834/*******************************************************************/
839 struct unit *get_defender(const struct civ_map *nmap,
840 const struct unit *attacker,
841 const struct tile *ptile,
842 const struct action *paction)
843{
844 struct unit *bestdef = NULL;
845 int bestvalue = -99, best_cost = 0, rating_of_best = 0;
846
847 /* Simply call unit_win_chance() with all the possible defenders in turn, and
848 * take the best one. It currently uses build cost as a tiebreaker in
849 * case 2 units are identical, but this is crude as build cost does not
850 * necessarily have anything to do with the value of a unit. This function
851 * could be improved to take the value of the unit into account. It would
852 * also be nice if the function was a bit more fuzzy about prioritizing,
853 * making it able to fx choose a 1a/9d unit over a 10a/10d unit. It should
854 * also be able to spare units without full hp's to some extent, as these
855 * could be more valuable later. */
856 unit_list_iterate(ptile->units, defender) {
857 /* We used to skip over allied units, but the logic for that is
858 * complicated and is now handled elsewhere. */
859 if (unit_can_defend_here(nmap, defender)
860 && (unit_attack_unit_at_tile_result(attacker, NULL, defender, ptile)
861 == ATT_OK)) {
862 bool change = FALSE;
863 int build_cost = unit_build_shield_cost_base(defender);
864 int defense_rating = get_defense_rating(nmap, attacker, defender);
865 /* This will make units roughly evenly good defenders look alike. */
866 int unit_def
867 = (int) (100000 * (1 - unit_win_chance(nmap, attacker,
868 defender, paction)));
869
870 fc_assert_action(0 <= unit_def, continue);
871
872 if (unit_has_type_flag(defender, UTYF_GAMELOSS)
873 && !is_stack_vulnerable(unit_tile(defender))) {
874 unit_def = -1; /* Then always use leader as last defender. */
875 /* FIXME: Multiple gameloss units with varying defense value
876 * not handled. */
877 }
878
879 if (unit_def > bestvalue) {
880 change = TRUE;
881 } else if (unit_def == bestvalue) {
882 if (build_cost < best_cost) {
883 change = TRUE;
884 } else if (build_cost == best_cost) {
885 if (rating_of_best < defense_rating) {
886 change = TRUE;
887 }
888 }
889 }
890
891 if (change) {
892 bestvalue = unit_def;
893 bestdef = defender;
894 best_cost = build_cost;
895 rating_of_best = defense_rating;
896 }
897 }
898 } unit_list_iterate_end;
899
900 return bestdef;
901}
902
903/*******************************************************************/
909 struct unit *get_attacker(const struct civ_map *nmap,
910 const struct unit *defender,
911 const struct tile *ptile)
912{
913 struct unit *bestatt = 0;
914 int bestvalue = -1, unit_a, best_cost = 0;
915
916 unit_list_iterate(ptile->units, attacker) {
917 int build_cost = unit_build_shield_cost_base(attacker);
918
919 if (pplayers_allied(unit_owner(defender), unit_owner(attacker))) {
920 return NULL;
921 }
922 unit_a = (int) (100000 * (unit_win_chance(nmap, attacker,
923 defender, NULL)));
924 if (unit_a > bestvalue
925 || (unit_a == bestvalue && build_cost < best_cost)) {
926 bestvalue = unit_a;
927 bestatt = attacker;
928 best_cost = build_cost;
929 }
930 } unit_list_iterate_end;
931
932 return bestatt;
933}
934
935/**********************************************************************/
945 struct unit *get_diplomatic_defender(const struct unit *act_unit,
946 const struct unit *pvictim,
947 const struct tile *tgt_tile,
948 const struct action *paction)
949{
950 fc_assert_ret_val(act_unit, NULL);
951 fc_assert_ret_val(tgt_tile, NULL);
952
953 unit_list_iterate(tgt_tile->units, punit) {
954 if (unit_owner(punit) == unit_owner(act_unit)) {
955 /* I can't confirm if we won't deny that we weren't involved.
956 * (Won't defend against its owner.) */
957 continue;
958 }
959
960 if (punit == pvictim
961 && !unit_has_type_flag(punit, UTYF_SUPERSPY)) {
962 /* The victim unit is defenseless unless it's a SuperSpy.
963 * Rationalization: A regular diplomat don't mind being bribed. A
964 * SuperSpy is high enough up the chain that accepting a bribe is
965 * against their own interests. */
966 continue;
967 }
968
969 if (!(unit_has_type_flag(punit, UTYF_DIPLOMAT)
970 || unit_has_type_flag(punit, UTYF_SUPERSPY))) {
971 /* A UTYF_SUPERSPY unit may not actually be a spy, but a superboss
972 * which we cannot allow puny diplomats from getting the better
973 * of. UTYF_SUPERSPY vs UTYF_SUPERSPY in a diplomatic contest always
974 * kills the attacker. */
975
976 /* The unit can't defend in a diplomatic battle. */
977 continue;
978 }
979
980 /* The first potential defender found is chosen. No priority is given
981 * to the best defender. */
982 return punit;
983 } unit_list_iterate_end;
984
985 /* No diplomatic defender found. */
986 return NULL;
987}
988
989/*******************************************************************/
992 bool is_stack_vulnerable(const struct tile *ptile)
993{
994 return (game.info.killstack
995 && !tile_has_extra_flag(ptile, EF_NO_STACK_DEATH)
996 && NULL == tile_city(ptile));
997}
998
999/*******************************************************************/
1005 int combat_bonus_against(const struct combat_bonus_list *list,
1006 const struct unit_type *enemy,
1007 enum combat_bonus_type type)
1008{
1009 int value = 0;
1010
1011 combat_bonus_list_iterate(list, pbonus) {
1012 if (pbonus->type == type && utype_has_flag(enemy, pbonus->flag)) {
1013 value += pbonus->value;
1014 }
1015 } combat_bonus_list_iterate_end;
1016
1017 return value;
1018}
1019
1020/*******************************************************************/
1023 int unit_bombard_rate(struct unit *punit)
1024{
1025 const struct unit_type *utype = unit_type_get(punit);
1026 int base_bombard_rate = utype->bombard_rate;
1027
1028 if (game.info.damage_reduces_bombard_rate && base_bombard_rate > 0) {
1029 int rate = (base_bombard_rate * punit->hp) / utype->hp;
1030
1031 return MAX(rate, 1);
1032 }
1033
1034 return base_bombard_rate;
1035}
n
#define n
Definition astring.c:77
base.h
bitvector.h
BV_ISSET
#define BV_ISSET(bv, bit)
Definition bitvector.h:78
city_owner
#define city_owner(_pcity_)
Definition city.h:563
list
static struct fc_sockaddr_list * list
Definition clinet.c:102
unit_win_chance
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
is_unit_reachable_at
bool is_unit_reachable_at(const struct unit *defender, const struct unit *attacker, const struct tile *location)
Definition combat.c:86
is_stack_vulnerable
bool is_stack_vulnerable(const struct tile *ptile)
Definition combat.c:992
get_virtual_defense_power
int get_virtual_defense_power(const struct civ_map *nmap, const struct unit_type *att_type, const struct unit_type *def_type, struct player *def_player, struct tile *ptile, bool fortified, int veteran)
Definition combat.c:715
unit_attack_any_at_tile_result
static enum unit_attack_result unit_attack_any_at_tile_result(const struct unit *punit, const struct action *paction, const struct tile *ptile)
Definition combat.c:230
get_attack_power
int get_attack_power(const struct unit *punit)
Definition combat.c:540
unit_bombard_rate
int unit_bombard_rate(struct unit *punit)
Definition combat.c:1023
combat_bonus_against
int combat_bonus_against(const struct combat_bonus_list *list, const struct unit_type *enemy, enum combat_bonus_type type)
Definition combat.c:1005
get_fortified_defense_power
int get_fortified_defense_power(const struct unit *attacker, struct unit *defender)
Definition combat.c:784
unit_attack_units_at_tile_result
enum unit_attack_result unit_attack_units_at_tile_result(const struct unit *punit, const struct action *paction, const struct tile *ptile)
Definition combat.c:257
get_defense_rating
static int get_defense_rating(const struct civ_map *nmap, const struct unit *attacker, const struct unit *defender)
Definition combat.c:817
get_attacker
struct unit * get_attacker(const struct civ_map *nmap, const struct unit *defender, const struct tile *ptile)
Definition combat.c:909
base_get_attack_power
int base_get_attack_power(const struct unit_type *punittype, int veteran, int moves_left)
Definition combat.c:550
sdi_try_defend
struct city * sdi_try_defend(const struct civ_map *nmap, const struct player *owner, const struct tile *ptile)
Definition combat.c:503
get_total_defense_power
int get_total_defense_power(const struct unit *attacker, const struct unit *defender)
Definition combat.c:770
get_total_attack_power
int get_total_attack_power(const struct unit *attacker, const struct unit *defender, const struct action *paction)
Definition combat.c:613
unit_attack_unit_at_tile_result
enum unit_attack_result unit_attack_unit_at_tile_result(const struct unit *punit, const struct action *paction, const struct unit *pdefender, const struct tile *dest_tile)
Definition combat.c:123
unit_attack_all_at_tile_result
static enum unit_attack_result unit_attack_all_at_tile_result(const struct unit *punit, const struct action *paction, const struct tile *ptile)
Definition combat.c:189
get_defense_power
static int get_defense_power(const struct unit *punit)
Definition combat.c:592
is_tired_attack
bool is_tired_attack(int moves_left)
Definition combat.c:532
defense_multiplication
static int defense_multiplication(const struct unit_type *att_type, const struct unit *def, const struct player *def_player, const struct tile *ptile, int defensepower)
Definition combat.c:648
win_chance
double win_chance(int as, int ahp, int afp, int ds, int dhp, int dfp)
Definition combat.c:334
unit_wipe_units_at_tile_result
enum unit_attack_result unit_wipe_units_at_tile_result(const struct unit *punit, const struct tile *ptile)
Definition combat.c:272
get_defender
struct unit * get_defender(const struct civ_map *nmap, const struct unit *attacker, const struct tile *ptile, const struct action *paction)
Definition combat.c:839
get_diplomatic_defender
struct unit * get_diplomatic_defender(const struct unit *act_unit, const struct unit *pvictim, const struct tile *tgt_tile, const struct action *paction)
Definition combat.c:945
can_unit_attack_tile
bool can_unit_attack_tile(const struct unit *punit, const struct action *paction, const struct tile *dest_tile)
Definition combat.c:312
base_get_defense_power
int base_get_defense_power(const struct unit *punit)
Definition combat.c:574
get_modified_firepower
void get_modified_firepower(const struct civ_map *nmap, const struct unit *attacker, const struct unit *defender, int *att_fp, int *def_fp)
Definition combat.c:411
can_player_attack_tile
static bool can_player_attack_tile(const struct player *pplayer, const struct tile *ptile)
Definition combat.c:44
is_unit_reachable_by_unit
static bool is_unit_reachable_by_unit(const struct unit *defender, const struct unit *attacker)
Definition combat.c:74
combat.h
POWER_FACTOR
#define POWER_FACTOR
Definition combat.h:32
unit_attack_result
unit_attack_result
Definition combat.h:34
ATT_NOT_WIPABLE
@ ATT_NOT_WIPABLE
Definition combat.h:40
ATT_NONNATIVE_DST
@ ATT_NONNATIVE_DST
Definition combat.h:39
ATT_OK
@ ATT_OK
Definition combat.h:35
ATT_NON_ATTACK
@ ATT_NON_ATTACK
Definition combat.h:36
ATT_UNREACHABLE
@ ATT_UNREACHABLE
Definition combat.h:37
ATT_NONNATIVE_SRC
@ ATT_NONNATIVE_SRC
Definition combat.h:38
incite_cost
char * incite_cost
Definition comments.c:74
punit
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
get_target_bonus_effects
int get_target_bonus_effects(struct effect_list *plist, const struct req_context *context, const struct req_context *other_context, enum effect_type effect_type)
Definition effects.c:744
get_unittype_bonus
int get_unittype_bonus(const struct player *pplayer, const struct tile *ptile, const struct unit_type *punittype, const struct action *paction, enum effect_type effect_type)
Definition effects.c:1031
game
struct civ_game game
Definition game.c:61
game.h
owner
struct city * owner
Definition citydlg.c:226
type
GType type
Definition repodlgs.c:1313
log.h
fc_assert_ret_val
#define fc_assert_ret_val(condition, val)
Definition log.h:194
fc_assert_action
#define fc_assert_action(condition, action)
Definition log.h:187
map.h
square_iterate
#define square_iterate(nmap, center_tile, radius, tile_itr)
Definition map.h:377
square_iterate_end
#define square_iterate_end
Definition map.h:380
can_exist_at_tile
bool can_exist_at_tile(const struct civ_map *nmap, const struct unit_type *utype, const struct tile *ptile)
Definition movement.c:289
is_native_tile
bool is_native_tile(const struct unit_type *punittype, const struct tile *ptile)
Definition movement.c:330
can_attack_non_native_hard_reqs
bool can_attack_non_native_hard_reqs(const struct unit_type *utype)
Definition movement.c:203
unit_can_defend_here
bool unit_can_defend_here(const struct civ_map *nmap, const struct unit *punit)
Definition movement.c:173
movement.h
SINGLE_MOVE
#define SINGLE_MOVE
Definition movement.h:26
is_native_tile_to_class
static bool is_native_tile_to_class(const struct unit_class *punitclass, const struct tile *ptile)
Definition movement.h:84
packets.h
pplayers_at_war
bool pplayers_at_war(const struct player *pplayer, const struct player *pplayer2)
Definition player.c:1388
pplayers_allied
bool pplayers_allied(const struct player *pplayer, const struct player *pplayer2)
Definition player.c:1409
rand.h
fc_rand
#define fc_rand(_size)
Definition rand.h:56
MIN
#define MIN(x, y)
Definition shared.h:55
MAX
#define MAX(x, y)
Definition shared.h:54
action
Definition actions.h:106
city
Definition city.h:320
city::tile
struct tile * tile
Definition city.h:322
civ_game::info
struct packet_game_info info
Definition game.h:89
civ_map
Definition map_types.h:71
packet_game_info::killstack
bool killstack
Definition packets_gen.h:192
packet_game_info::damage_reduces_bombard_rate
bool damage_reduces_bombard_rate
Definition packets_gen.h:196
packet_game_info::tired_attack
bool tired_attack
Definition packets_gen.h:239
packet_game_info::low_firepower_pearl_harbour
int low_firepower_pearl_harbour
Definition packets_gen.h:198
packet_game_info::low_firepower_nonnat_bombard
int low_firepower_nonnat_bombard
Definition packets_gen.h:200
packet_game_info::low_firepower_combat_bonus
int low_firepower_combat_bonus
Definition packets_gen.h:199
packet_game_info::unreachable_protects
bool unreachable_protects
Definition packets_gen.h:223
packet_game_info::low_firepower_badwallattacker
int low_firepower_badwallattacker
Definition packets_gen.h:197
player
Definition player.h:249
req_context
Definition requirements.h:100
tile
Definition tile.h:50
tile::units
struct unit_list * units
Definition tile.h:58
unit_class
Definition unittype.h:149
unit_type
Definition unittype.h:507
unit_type::defense_strength
int defense_strength
Definition unittype.h:523
unit_type::veteran
struct veteran_system * veteran
Definition unittype.h:551
unit_type::bombard_rate
int bombard_rate
Definition unittype.h:554
unit_type::hp
int hp
Definition unittype.h:531
unit
Definition unit.h:140
unit::activity
enum unit_activity activity
Definition unit.h:159
unit::moves_left
int moves_left
Definition unit.h:152
unit::hp
int hp
Definition unit.h:153
unit::veteran
int veteran
Definition unit.h:154
veteran_level
Definition unittype.h:493
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
tile_has_extra_flag
bool tile_has_extra_flag(const struct tile *ptile, enum extra_flag_id flag)
Definition tile.c:886
tile_extras_defense_bonus
int tile_extras_defense_bonus(const struct tile *ptile, const struct unit_type *punittype)
Definition tile.c:233
tile_has_native_base
bool tile_has_native_base(const struct tile *ptile, const struct unit_type *punittype)
Definition tile.c:324
tile_city
struct city * tile_city(const struct tile *ptile)
Definition tile.c:83
tile_terrain
#define tile_terrain(_tile)
Definition tile.h:111
unit_virtual_create
struct unit * unit_virtual_create(struct player *pplayer, struct city *pcity, const struct unit_type *punittype, int veteran_level)
Definition unit.c:1662
unit_virtual_destroy
void unit_virtual_destroy(struct unit *punit)
Definition unit.c:1767
unit_tile_set
void unit_tile_set(struct unit *punit, struct tile *ptile)
Definition unit.c:1285
unit_transported
bool unit_transported(const struct unit *pcargo)
Definition unit.c:2483
unit.h
unit_tile
#define unit_tile(_pu)
Definition unit.h:397
unit_owner
#define unit_owner(_pu)
Definition unit.h:396
unitlist.h
unit_list_iterate
#define unit_list_iterate(unitlist, punit)
Definition unitlist.h:31
unit_list_iterate_end
#define unit_list_iterate_end
Definition unitlist.h:33
unit_type_get
const struct unit_type * unit_type_get(const struct unit *punit)
Definition unittype.c:123
utype_has_class_flag
bool utype_has_class_flag(const struct unit_type *ptype, enum unit_class_flag_id flag)
Definition unittype.c:1657
unit_build_shield_cost_base
int unit_build_shield_cost_base(const struct unit *punit)
Definition unittype.c:1484
utype_can_do_act_when_ustate
bool utype_can_do_act_when_ustate(const struct unit_type *punit_type, const action_id act_id, const enum ustate_prop prop, const bool is_there)
Definition unittype.c:955
unit_class_get
struct unit_class * unit_class_get(const struct unit *punit)
Definition unittype.c:2498
utype_can_do_action_result
bool utype_can_do_action_result(const struct unit_type *putype, enum action_result result)
Definition unittype.c:387
utype_veteran_level
const struct veteran_level * utype_veteran_level(const struct unit_type *punittype, int level)
Definition unittype.c:2583
unit_has_type_flag
bool unit_has_type_flag(const struct unit *punit, enum unit_type_flag_id flag)
Definition unittype.c:190
utype_index
Unit_type_id utype_index(const struct unit_type *punittype)
Definition unittype.c:91
utype_can_do_action
bool utype_can_do_action(const struct unit_type *putype, const action_id act_id)
Definition unittype.c:371
unittype.h
uclass_has_flag
static bool uclass_has_flag(const struct unit_class *punitclass, enum unit_class_flag_id flag)
Definition unittype.h:773
utype_class
#define utype_class(_t_)
Definition unittype.h:756
combat_bonus_list_iterate_end
#define combat_bonus_list_iterate_end
Definition unittype.h:489
combat_bonus_list_iterate
#define combat_bonus_list_iterate(bonuslist, pbonus)
Definition unittype.h:487
utype_has_flag
static bool utype_has_flag(const struct unit_type *punittype, int flag)
Definition unittype.h:624
uclass_index
#define uclass_index(_c_)
Definition unittype.h:749