Freeciv-3.2: /fast/freeciv/nightly/S3_2/common/combat.c Source File

Freeciv-3.2

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