Project

Profile

Help

HostedRedmine.com has moved to the Planio platform. All logins and passwords remained the same. All users will be able to login and use Redmine just as before. Read more...

Feature #864356 » 0035-Add-Action-Wipe-Units.patch

Marko Lindqvist, 2021-03-15 04:22 PM

View differences:

ai/default/daicity.c
1282 1282
  case ACTRES_NUKE_UNITS:
1283 1283
  case ACTRES_PARADROP:
1284 1284
  case ACTRES_ATTACK:
1285
  case ACTRES_WIPE_UNITS:
1285 1286
  case ACTRES_HEAL_UNIT:
1286 1287
  case ACTRES_TRANSFORM_TERRAIN:
1287 1288
  case ACTRES_CULTIVATE:
ai/default/daidiplomacy.c
1945 1945
    case ACTRES_CAPTURE_UNITS:
1946 1946
    case ACTRES_BOMBARD:
1947 1947
    case ACTRES_ATTACK:
1948
    case ACTRES_WIPE_UNITS:
1948 1949
    case ACTRES_SPY_ATTACK:
1949 1950
      /* Unit loss */
1950 1951
      dai_incident_simple(receiver, violator, victim, scope, 5);
client/gui-qt/dialogs.cpp
111 111
static void unit_recycle(QVariant data1, QVariant data2);
112 112
static void capture_units(QVariant data1, QVariant data2);
113 113
static void nuke_units(QVariant data1, QVariant data2);
114
static void wipe_units(QVariant data1, QVariant data2);
114 115
static void expel_unit(QVariant data1, QVariant data2);
115 116
static void bombard(QVariant data1, QVariant data2);
116 117
static void bombard2(QVariant data1, QVariant data2);
......
263 264
      = paradrop_frighten_conquer;
264 265
  action_function[ACTION_ATTACK] = attack;
265 266
  action_function[ACTION_SUICIDE_ATTACK] = suicide_attack;
267
  action_function[ACTION_WIPE_UNITS] = wipe_units;
266 268
  action_function[ACTION_TRANSFORM_TERRAIN] = transform_terrain;
267 269
  action_function[ACTION_CULTIVATE] = cultivate;
268 270
  action_function[ACTION_PLANT] = plant;
......
2592 2594
                    target_id, 0, "");
2593 2595
}
2594 2596

  
2597
/**********************************************************************//**
2598
  Action "Wipe Units" for choice dialog
2599
***************************************************************************/
2600
static void wipe_units(QVariant data1, QVariant data2)
2601
{
2602
  int actor_id = data1.toInt();
2603
  int target_id = data2.toInt();
2604

  
2605
  request_do_action(ACTION_WIPE_UNITS, actor_id,
2606
                    target_id, 0, "");
2607
}
2608

  
2595 2609
/**********************************************************************//**
2596 2610
  Action capture units for choice dialog
2597 2611
***************************************************************************/
client/helpdata.c
2669 2669
                         "is reduced accordingly.\n"));
2670 2670
        }
2671 2671
        break;
2672
      case ACTRES_WIPE_UNITS:
2673
        cat_snprintf(buf, bufsz,
2674
                     _("  * can wipe stack of units with zero defense.\n"));
2675
        break;
2672 2676
      case ACTRES_CONVERT:
2673 2677
        cat_snprintf(buf, bufsz,
2674 2678
                     /* TRANS: %s is a unit type. "MP" = movement points. */
client/packhand.c
4785 4785
      case ACTION_NUKE_UNITS:
4786 4786
      case ACTION_ATTACK:
4787 4787
      case ACTION_SUICIDE_ATTACK:
4788
      case ACTION_WIPE_UNITS:
4788 4789
      case ACTION_CONQUER_CITY:
4789 4790
      case ACTION_CONQUER_CITY2:
4790 4791
      case ACTION_CONQUER_CITY3:
common/actions.c
388 388
                             " a target the actor is at war with."),
389 389
                          ACTRES_BOMBARD,
390 390
                          ACTRES_ATTACK,
391
                          ACTRES_WIPE_UNITS,
391 392
                          ACTRES_NONE);
392 393

  
393 394
  /* Why this is a hard requirement: Keep the old rules. Need to work
......
523 524
                             " the NonMil utype flag."),
524 525
                          ACTRES_ATTACK,
525 526
                          ACTRES_CONQUER_CITY,
527
                          ACTRES_WIPE_UNITS,
526 528
                          ACTRES_NONE);
527 529
  oblig_hard_req_reg(req_contradiction_or(
528 530
                       2,
......
1113 1115
      unit_action_new(ACTION_SUICIDE_ATTACK, ACTRES_ATTACK,
1114 1116
                      FALSE, TRUE,
1115 1117
                      MAK_FORCED, 1, 1, TRUE);
1118
  actions[ACTION_WIPE_UNITS] =
1119
      unit_action_new(ACTION_WIPE_UNITS, ACTRES_WIPE_UNITS,
1120
                      FALSE, TRUE,
1121
                      /* Tries a forced move if the target unit's tile has
1122
                       * no non allied units and the occupychance dice roll
1123
                       * tells it to move. */
1124
                      MAK_FORCED,
1125
                      1, 1, FALSE);
1116 1126
  actions[ACTION_STRIKE_BUILDING] =
1117 1127
      unit_action_new(ACTION_STRIKE_BUILDING, ACTRES_STRIKE_BUILDING,
1118 1128
                      FALSE, FALSE,
......
1609 1619
{
1610 1620
  switch (pact->result) {
1611 1621
  case ACTRES_ATTACK:
1622
  case ACTRES_WIPE_UNITS:
1612 1623
    return ABK_STANDARD;
1613 1624
  case ACTRES_SPY_ATTACK:
1614 1625
  case ACTRES_SPY_POISON:
......
2137 2148
  case ACTRES_STRIKE_BUILDING:
2138 2149
  case ACTRES_STRIKE_PRODUCTION:
2139 2150
  case ACTRES_ATTACK:
2151
  case ACTRES_WIPE_UNITS:
2140 2152
  case ACTRES_CONQUER_CITY:
2141 2153
  case ACTRES_CONQUER_EXTRAS:
2142 2154
  case ACTRES_HEAL_UNIT:
......
2222 2234
  case ACTRES_STRIKE_BUILDING:
2223 2235
  case ACTRES_STRIKE_PRODUCTION:
2224 2236
  case ACTRES_ATTACK:
2237
  case ACTRES_WIPE_UNITS:
2225 2238
  case ACTRES_CONQUER_CITY:
2226 2239
  case ACTRES_CONQUER_EXTRAS:
2227 2240
  case ACTRES_HEAL_UNIT:
......
3157 3170
    break;
3158 3171

  
3159 3172
  case ACTRES_ATTACK:
3173
  case ACTRES_WIPE_UNITS:
3160 3174
    if (actor_unittype->attack_strength <= 0) {
3161 3175
      /* Reason: Can't attack without strength. */
3162 3176
      return FALSE;
......
3447 3461
  case ACTRES_HOME_CITY:
3448 3462
  case ACTRES_UPGRADE_UNIT:
3449 3463
  case ACTRES_ATTACK:
3464
  case ACTRES_WIPE_UNITS:
3450 3465
  case ACTRES_STRIKE_BUILDING:
3451 3466
  case ACTRES_STRIKE_PRODUCTION:
3452 3467
  case ACTRES_CONQUER_CITY:
......
3923 3938
    }
3924 3939
    break;
3925 3940

  
3941
  case ACTRES_WIPE_UNITS:
3942
    if (!can_unit_attack_tile(actor_unit, target_tile)) {
3943
      return TRI_NO;
3944
    }
3945

  
3946
    unit_list_iterate(target_tile->units, punit) {
3947
      if (unit_type_get(punit)->defense_strength > 0) {
3948
        return TRI_NO;
3949
      }
3950
    } unit_list_iterate_end;
3951
    break;
3952

  
3926 3953
  case ACTRES_CONQUER_CITY:
3927 3954
    /* Reason: "Conquer City" involves moving into the city. */
3928 3955
    if (!unit_can_move_to_tile(&(wld.map), actor_unit, target_tile,
......
5433 5460
      }
5434 5461
    }
5435 5462
    break;
5463
  case ACTRES_WIPE_UNITS:
5464
    chance = ACTPROB_CERTAIN;
5465
    break;
5436 5466
  case ACTRES_STRIKE_BUILDING:
5437 5467
    /* TODO: not implemented yet because:
5438 5468
     * - dice roll 100% * Action_Odds_Pct could be handled with
......
5788 5818
  }
5789 5819

  
5790 5820
  if ((action_id_has_result_safe(act_id, ACTRES_ATTACK)
5791
       || action_id_has_result_safe(act_id, ACTRES_BOMBARD))
5821
       || action_id_has_result_safe(act_id, ACTRES_BOMBARD)
5822
       || action_id_has_result_safe(act_id, ACTRES_WIPE_UNITS))
5792 5823
      && tile_city(target_tile) != NULL
5793 5824
      && !pplayers_at_war(city_owner(tile_city(target_tile)),
5794 5825
                          unit_owner(actor_unit))) {
......
6638 6669
  case ACTRES_PARADROP_CONQUER:
6639 6670
  case ACTRES_AIRLIFT:
6640 6671
  case ACTRES_ATTACK:
6672
  case ACTRES_WIPE_UNITS:
6641 6673
  case ACTRES_CONQUER_CITY:
6642 6674
  case ACTRES_CONQUER_EXTRAS:
6643 6675
  case ACTRES_HEAL_UNIT:
......
7163 7195
    return "ui_name_attack";
7164 7196
  case ACTION_SUICIDE_ATTACK:
7165 7197
    return "ui_name_suicide_attack";
7198
  case ACTION_WIPE_UNITS:
7199
    return "ui_name_wipe_units";
7166 7200
  case ACTION_STRIKE_BUILDING:
7167 7201
    return "ui_name_surgical_strike_building";
7168 7202
  case ACTION_STRIKE_PRODUCTION:
......
7444 7478
  case ACTION_SUICIDE_ATTACK:
7445 7479
    /* TRANS: _Suicide Attack (100% chance of success). */
7446 7480
    return N_("%sSuicide Attack%s");
7481
  case ACTION_WIPE_UNITS:
7482
    /* TRANS: _Wipe Units (100% chance of success). */
7483
    return N_("%sWipe Units%s");
7447 7484
  case ACTION_STRIKE_BUILDING:
7448 7485
    /* TRANS: Surgical Str_ike Building (100% chance of success). */
7449 7486
    return N_("Surgical Str%sike Building%s");
......
7621 7658
  case ACTION_AIRLIFT:
7622 7659
  case ACTION_ATTACK:
7623 7660
  case ACTION_SUICIDE_ATTACK:
7661
  case ACTION_WIPE_UNITS:
7624 7662
  case ACTION_STRIKE_BUILDING:
7625 7663
  case ACTION_STRIKE_PRODUCTION:
7626 7664
  case ACTION_CONQUER_CITY:
......
7732 7770
  case ACTRES_STRIKE_BUILDING:
7733 7771
  case ACTRES_STRIKE_PRODUCTION:
7734 7772
  case ACTRES_ATTACK:
7773
  case ACTRES_WIPE_UNITS:
7735 7774
  case ACTRES_CONQUER_CITY:
7736 7775
  case ACTRES_HEAL_UNIT:
7737 7776
  case ACTRES_TRANSFORM_TERRAIN:
......
7827 7866
  case ACTION_PARADROP_ENTER_CONQUER:
7828 7867
  case ACTION_ATTACK:
7829 7868
  case ACTION_SUICIDE_ATTACK:
7869
  case ACTION_WIPE_UNITS:
7830 7870
  case ACTION_STRIKE_BUILDING:
7831 7871
  case ACTION_STRIKE_PRODUCTION:
7832 7872
  case ACTION_CONQUER_CITY:
......
7943 7983
  case ACTRES_STRIKE_BUILDING:
7944 7984
  case ACTRES_STRIKE_PRODUCTION:
7945 7985
  case ACTRES_ATTACK:
7986
  case ACTRES_WIPE_UNITS:
7946 7987
  case ACTRES_CONQUER_CITY:
7947 7988
  case ACTRES_HEAL_UNIT:
7948 7989
  case ACTRES_TRANSFORM_TERRAIN:
......
8050 8091
  case ACTION_AIRLIFT:
8051 8092
  case ACTION_ATTACK:
8052 8093
  case ACTION_SUICIDE_ATTACK:
8094
  case ACTION_WIPE_UNITS:
8053 8095
  case ACTION_STRIKE_BUILDING:
8054 8096
  case ACTION_STRIKE_PRODUCTION:
8055 8097
  case ACTION_CONQUER_CITY:
......
8172 8214
     * target tile (Units) and, depending on the
8173 8215
     * unreachable_protects setting, each or any
8174 8216
     * *non transported* unit at the target tile. */
8217
  case ACTRES_WIPE_UNITS:
8175 8218
  case ACTRES_CAPTURE_UNITS:
8176 8219
  case ACTRES_NUKE_UNITS:
8177 8220
  case ACTRES_SPY_ATTACK:
......
8262 8305
  case ACTRES_BOMBARD:
8263 8306
  case ACTRES_NUKE_UNITS:
8264 8307
  case ACTRES_ATTACK:
8308
  case ACTRES_WIPE_UNITS:
8265 8309
  case ACTRES_SPY_ATTACK:
8266 8310
    return tgt_kind == ATK_UNITS;
8267 8311
  case ACTRES_FOUND_CITY:
......
8365 8409
  case ACTRES_BOMBARD:
8366 8410
  case ACTRES_NUKE_UNITS:
8367 8411
  case ACTRES_ATTACK:
8412
  case ACTRES_WIPE_UNITS:
8368 8413
  case ACTRES_SPY_ATTACK:
8369 8414
    return ASTK_NONE;
8370 8415
  case ACTRES_FOUND_CITY:
......
8456 8501
  case ACTRES_BOMBARD:
8457 8502
  case ACTRES_NUKE_UNITS:
8458 8503
  case ACTRES_ATTACK:
8504
  case ACTRES_WIPE_UNITS:
8459 8505
  case ACTRES_SPY_ATTACK:
8460 8506
    return ACT_TGT_COMPL_SIMPLE;
8461 8507
  case ACTRES_FOUND_CITY:
......
8552 8598
  case ACTION_AIRLIFT:
8553 8599
  case ACTION_ATTACK:
8554 8600
  case ACTION_SUICIDE_ATTACK:
8601
  case ACTION_WIPE_UNITS:
8555 8602
  case ACTION_STRIKE_BUILDING:
8556 8603
  case ACTION_STRIKE_PRODUCTION:
8557 8604
  case ACTION_CONQUER_CITY:
......
8655 8702
    return "attack_blocked_by";
8656 8703
  case ACTION_SUICIDE_ATTACK:
8657 8704
    return "suicide_attack_blocked_by";
8705
  case ACTION_WIPE_UNITS:
8706
    return "wipe_units_blocked_by";
8658 8707
  case ACTION_CONQUER_CITY:
8659 8708
    return "conquer_city_blocked_by";
8660 8709
  case ACTION_CONQUER_CITY2:
......
8778 8827
  fc_assert_ret_val(act != NULL, NULL);
8779 8828

  
8780 8829
  if (!(action_has_result(act, ACTRES_SPY_BRIBE_UNIT)
8781
        ||action_has_result(act, ACTRES_ATTACK))) {
8830
        || action_has_result(act, ACTRES_ATTACK)
8831
        || action_has_result(act, ACTRES_WIPE_UNITS))) {
8782 8832
    /* No support in the action performer function */
8783 8833
    return NULL;
8784 8834
  }
......
8788 8838
    return "bribe_unit_post_success_forced_actions";
8789 8839
  case ACTION_ATTACK:
8790 8840
    return "attack_post_success_forced_actions";
8841
  case ACTION_WIPE_UNITS:
8842
    return "wipe_units_post_success_forced_actions";
8791 8843
  case ACTION_MARKETPLACE:
8792 8844
  case ACTION_BOMBARD:
8793 8845
  case ACTION_BOMBARD2:
common/actions.h
274 274
#define SPECENUM_VALUE103NAME "Paradrop Unit Enter Conquer"
275 275
#define SPECENUM_VALUE104 ACTION_HOMELESS
276 276
#define SPECENUM_VALUE104NAME "Unit Make Homeless"
277
#define SPECENUM_VALUE105 ACTION_WIPE_UNITS
278
#define SPECENUM_VALUE105NAME "Wipe Units"
277 279
#define SPECENUM_BITVECTOR bv_actions
278 280
#define SPECENUM_COUNT ACTION_COUNT
279 281
#include "specenum_gen.h"
......
602 604

  
603 605
/* Hard coded location of action auto performers. Used for conversion while
604 606
 * action auto performers aren't directly exposed to the ruleset. */
605
#define ACTION_AUTO_UPKEEP_FOOD   0
606
#define ACTION_AUTO_UPKEEP_GOLD   1
607
#define ACTION_AUTO_UPKEEP_SHIELD 2
608
#define ACTION_AUTO_MOVED_ADJ     3
609
#define ACTION_AUTO_POST_BRIBE    4
610
#define ACTION_AUTO_POST_ATTACK   5
611
#define ACTION_AUTO_ESCAPE_CITY   6
612
#define ACTION_AUTO_ESCAPE_STACK  7
607
#define ACTION_AUTO_UPKEEP_FOOD     0
608
#define ACTION_AUTO_UPKEEP_GOLD     1
609
#define ACTION_AUTO_UPKEEP_SHIELD   2
610
#define ACTION_AUTO_MOVED_ADJ       3
611
#define ACTION_AUTO_POST_BRIBE      4
612
#define ACTION_AUTO_POST_ATTACK     5
613
#define ACTION_AUTO_ESCAPE_CITY     6
614
#define ACTION_AUTO_ESCAPE_STACK    7
615
#define ACTION_AUTO_POST_WIPE_UNITS 8
613 616

  
614 617
/* Initialization */
615 618
void actions_init(void);
common/combat.c
236 236
  }
237 237
}
238 238

  
239
/*******************************************************************//**
240
  Check if unit can wipe unit stack from tile.
241
***********************************************************************/
242
enum unit_attack_result unit_wipe_units_at_tile_result(const struct unit *punit,
243
                                                       const struct tile *ptile)
244
{
245
  /* Can unit wipe in general? */
246
  if (!utype_can_do_action(unit_type_get(punit), ACTION_WIPE_UNITS)) {
247
    return ATT_NON_ATTACK;
248
  }
249

  
250
  unit_list_iterate(ptile->units, target) {
251
    if (unit_type_get(target)->defense_strength > 0) {
252
      return ATT_NOT_WIPABLE;
253
    }
254

  
255
    /* Can't wipe with ground unit from ocean, except for marines */
256
    if (!is_native_tile(unit_type_get(punit), unit_tile(punit))
257
        && !utype_can_do_act_when_ustate(unit_type_get(punit), ACTION_WIPE_UNITS,
258
                                         USP_NATIVE_TILE, FALSE)) {
259
      return ATT_NONNATIVE_SRC;
260
    }
261

  
262
    /* Most units can not wipe on non-native terrain.
263
     * Most ships can wipe on land tiles (shore bombardment) */
264
    if (!is_native_tile(unit_type_get(punit), ptile)
265
        && !can_attack_non_native(unit_type_get(punit))) {
266
      return ATT_NONNATIVE_DST;
267
    }
268

  
269
    /* Only fighters can wipe planes, except in city or airbase attacks */
270
    if (!is_unit_reachable_at(target, punit, ptile)) {
271
      return ATT_UNREACHABLE;
272
    }
273
  } unit_list_iterate_end;
274

  
275
  return ATT_OK;
276
}
277

  
239 278
/*******************************************************************//**
240 279
  Is unit (1) diplomatically allowed to attack and (2) physically able
241 280
  to do so?
common/combat.h
34 34
  ATT_NON_ATTACK,
35 35
  ATT_UNREACHABLE,
36 36
  ATT_NONNATIVE_SRC,
37
  ATT_NONNATIVE_DST
37
  ATT_NONNATIVE_DST,
38
  ATT_NOT_WIPABLE
38 39
};
39 40

  
40 41
bool is_unit_reachable_at(const struct unit *defender,
......
45 46
                                                        const struct tile *dest_tile);
46 47
enum unit_attack_result unit_attack_units_at_tile_result(const struct unit *punit,
47 48
                                                         const struct tile *ptile);
49
enum unit_attack_result unit_wipe_units_at_tile_result(const struct unit *punit,
50
                                                       const struct tile *ptile);
48 51
bool can_unit_attack_tile(const struct unit *punit,
49 52
                          const struct tile *ptile);
50 53

  
common/explanation.h
1
/**********************************************************************
1
/***********************************************************************
2 2
 Freeciv - Copyright (C) 2014-2020 - The Freeciv Project contributors.
3 3
   This program is free software; you can redistribute it and/or modify
4 4
   it under the terms of the GNU General Public License as published by
......
94 94
  ANEK_ACT_NOT_ENOUGH_MONEY,
95 95
  /* Explanation: the action is blocked by another action. */
96 96
  ANEK_ACTION_BLOCKS,
97
  /* Explanation: the target unit is not wipable. */
98
  ANEK_NOT_WIPABLE,
97 99
  /* Explanation not detected. */
98 100
  ANEK_UNKNOWN,
99 101
};
common/fc_types.h
53 53
#define MAX_GOODS_TYPES 25
54 54
#define MAX_DISASTER_TYPES 10
55 55
#define MAX_ACHIEVEMENT_TYPES 40
56
#define MAX_NUM_ACTION_AUTO_PERFORMERS 8
56
#define MAX_NUM_ACTION_AUTO_PERFORMERS 9
57 57
#define MAX_NUM_MULTIPLIERS 15
58 58
#define MAX_NUM_LEADERS MAX_NUM_ITEMS /* Used in the network protocol. */
59 59
#define MAX_NUM_NATION_SETS 32 /* Used in the network protocol.
......
295 295
#define SPECENUM_VALUE59NAME "Unit Paradrop Conquer"
296 296
#define SPECENUM_VALUE60 ACTRES_HOMELESS
297 297
#define SPECENUM_VALUE60NAME "Unit Make Homeless"
298
#define SPECENUM_VALUE61 ACTRES_WIPE_UNITS
299
#define SPECENUM_VALUE61NAME "Wipe Units"
298 300
/* All consequences are handled as (ruleset) action data. */
299 301
#define SPECENUM_COUNT ACTRES_NONE
300 302
#include "specenum_gen.h"
common/movement.c
163 163
}
164 164

  
165 165
/************************************************************************//**
166
 This unit can attack non-native tiles (eg. Ships ability to
167
 shore bombardment)
166
  This unit can attack non-native tiles (eg. Ships ability to
167
  shore bombardment)
168 168
****************************************************************************/
169 169
bool can_attack_non_native(const struct unit_type *utype)
170 170
{
171 171
  return uclass_has_flag(utype_class(utype), UCF_ATTACK_NON_NATIVE)
172 172
         && (utype_can_do_action_result(utype, ACTRES_ATTACK)
173
             || utype_can_do_action_result(utype, ACTRES_BOMBARD))
173
             || utype_can_do_action_result(utype, ACTRES_BOMBARD)
174
             || utype_can_do_action_result(utype, ACTRES_WIPE_UNITS))
174 175
         && utype->attack_strength > 0
175 176
         && !utype_has_flag(utype, UTYF_ONLY_NATIVE_ATTACK);
176 177
}
177 178

  
178 179
/************************************************************************//**
179
 This unit can attack from non-native tiles (Marines can attack from
180
 transport, ships from harbour cities)
180
  This unit can attack from non-native tiles (Marines can attack from
181
  transport, ships from harbour cities)
181 182
****************************************************************************/
182 183
bool can_attack_from_non_native(const struct unit_type *utype)
183 184
{
......
185 186
                                       USP_NATIVE_TILE, FALSE)
186 187
          || utype_can_do_act_when_ustate(utype, ACTION_SUICIDE_ATTACK,
187 188
                                          USP_NATIVE_TILE, FALSE)
189
          || utype_can_do_act_when_ustate(utype, ACTION_WIPE_UNITS,
190
                                          USP_LIVABLE_TILE, FALSE)
188 191
          || utype_can_do_act_when_ustate(utype, ACTION_CONQUER_CITY4,
189 192
                                          USP_LIVABLE_TILE, FALSE)
190 193
          || utype_can_do_act_when_ustate(utype, ACTION_CONQUER_CITY3,
common/unit.c
303 303
bool is_attack_unit(const struct unit *punit)
304 304
{
305 305
  return ((unit_can_do_action_result(punit, ACTRES_ATTACK)
306
           || unit_can_do_action_result(punit, ACTRES_BOMBARD))
306
           || unit_can_do_action_result(punit, ACTRES_BOMBARD)
307
           || unit_can_do_action_result(punit, ACTRES_WIPE_UNITS))
307 308
          && unit_type_get(punit)->attack_strength > 0);
308 309
}
309 310

  
common/unittype.c
328 328
  case ACTRES_STRIKE_BUILDING:
329 329
  case ACTRES_STRIKE_PRODUCTION:
330 330
  case ACTRES_ATTACK:
331
  case ACTRES_WIPE_UNITS:
331 332
  case ACTRES_CONQUER_CITY:
332 333
  case ACTRES_PILLAGE:
333 334
  case ACTRES_SPY_ATTACK:
doc/README.actions
769 769
   - it is in a city
770 770
   - it is on a tile with a native Extra
771 771

  
772
"Wipe Units"
773
 * UI name can be set using ui_name_wipe_units
774
 * any action listed in wipe_units_blocked_by must be impossible
775
 * forced actions after success can be set with
776
   wipe_units_post_success_forced_actions
777
 * the actor must be on the tile next to the target.
778
 * the actor's attack must be above 0
779
 * the actor can't have the "NonMil" unit type flag (!)
780
 * the actor must be native to the target tile unless it has the
781
   "AttackNonNative" unit class flag and not the "Only_Native_Attack" unit
782
   type flag.
783
 * the target tile has no non enemy units. (!)
784
 * the target tile has no non enemy city.
785
 * the target tile has no units with positive defense strength
786
 * all units at the target tile must be reachable.
787
   A unit is reachable if any of the following is true:
788
   - it doesn't have the "Unreachable" unit class flag
789
   - it is listed in the actor unit's targets
790
   - it is in a city
791
   - it is on a tile with a native Extra
792

  
772 793
"Nuke Units" - Detonate at the target unit stack. Cause a nuclear explosion.
773 794
 * UI name can be set using ui_name_nuke_units
774 795
 * set if the actor unit is spent with nuke_units_consuming_always
fc_version
56 56
#   - No new mandatory capabilities can be added to the release branch; doing
57 57
#     so would break network capability of supposedly "compatible" releases.
58 58
#
59
NETWORK_CAPSTRING="+Freeciv.Devel-3.2-2021.Mar.15"
59
NETWORK_CAPSTRING="+Freeciv.Devel-3.2-2021.Mar.15b"
60 60

  
61 61
FREECIV_DISTRIBUTOR=""
62 62

  
server/actiontools.c
51 51
    } else if (action_has_result(paction, ACTRES_NUKE)
52 52
               || action_has_result(paction, ACTRES_NUKE_UNITS)) {
53 53
      wipe_unit(actor, ULR_DETONATED, NULL);
54
    } else if (action_has_result(paction, ACTRES_ATTACK)) {
54
    } else if (action_has_result(paction, ACTRES_ATTACK)
55
               || action_has_result(paction, ACTRES_WIPE_UNITS)) {
55 56
      wipe_unit(actor, ULR_MISSILE, NULL);
56 57
    } else {
57 58
      wipe_unit(actor, ULR_USED, NULL);
server/advisors/advdata.c
899 899
            break;
900 900
          case ACTRES_CONQUER_EXTRAS:
901 901
          case ACTRES_PILLAGE:
902
          case ACTRES_WIPE_UNITS:
902 903
            bonus += 0.2;
903 904
            break;
904 905
          case ACTRES_HUT_ENTER:
server/ruleset.c
6942 6942
        ok = FALSE;
6943 6943
      }
6944 6944

  
6945
      /* "Wipe Units" */
6946
      if (!load_action_post_success_force(file, filename,
6947
                                          ACTION_AUTO_POST_WIPE_UNITS,
6948
                                          action_by_number(
6949
                                            ACTION_WIPE_UNITS))) {
6950
        ok = FALSE;
6951
      }
6952

  
6945 6953
      /* No "Suicide Attack". Can't act when dead. */
6946 6954
    }
6947 6955

  
server/unithand.c
382 382
  return TRUE;
383 383
}
384 384

  
385
/**********************************************************************//**
386
  Wipe all units at target tile.
387

  
388
  Returns TRUE iff action could be done, FALSE if it couldn't. Even if
389
  this returns TRUE, unit may have died during the action.
390
**************************************************************************/
391
static bool do_wipe_units(struct unit *punit,
392
                          struct tile *pdesttile,
393
                          const struct action *paction)
394
{
395
  struct player *wiper = unit_owner(punit);
396
  char wiper_link[MAX_LEN_LINK];
397
  const char *wiper_nation = nation_plural_for_player(wiper);
398
  const struct unit_type *act_utype = unit_type_get(punit);
399

  
400
  /* N.B: unit_link() always returns the same pointer. */
401
  sz_strlcpy(wiper_link, unit_link(punit));
402

  
403
  unit_list_iterate_safe(pdesttile->units, to_wipe) {
404
    struct player *owner = unit_owner(to_wipe);
405
    const char *victim_link = unit_link(to_wipe);
406

  
407
    wipe_unit(to_wipe, ULR_KILLED, wiper);
408

  
409
    /* Notify players */
410
    notify_player(wiper, pdesttile, E_UNIT_WIN_ATT, ftc_server,
411
                  /* TRANS: <unit> ... <unit> */
412
                  _("Your %s wiped the %s %s."),
413
                  wiper_link, nation_adjective_for_player(owner),
414
                  victim_link);
415
    notify_player(owner, pdesttile,
416
                  E_UNIT_LOST_DEF, ftc_server,
417
                  /* TRANS: <unit> ... <Poles> */
418
                  _("Your %s was wiped by the %s."),
419
                  victim_link, wiper_nation);
420

  
421
    /* May cause an incident */
422
    action_consequence_success(paction, wiper, act_utype, owner,
423
                               pdesttile, victim_link);
424

  
425
  } unit_list_iterate_safe_end;
426

  
427
  unit_did_action(punit);
428
  unit_forget_last_activity(punit);
429

  
430
  send_unit_info(NULL, punit);
431

  
432
  return TRUE;
433
}
434

  
385 435
/**********************************************************************//**
386 436
  Expel the target unit to his owner's capital.
387 437

  
......
820 870
  switch (paction->result) {
821 871
  case ACTRES_BOMBARD:
822 872
  case ACTRES_ATTACK:
873
  case ACTRES_WIPE_UNITS:
823 874
    /* Target is a unit stack but a city can block it. */
824 875
    fc_assert_action(action_get_target_kind(paction) == ATK_UNITS, break);
876

  
825 877
    if (target_tile) {
826 878
      struct city *tcity;
827 879

  
......
1245 1297
    case ACTRES_ATTACK:
1246 1298
      action_custom = unit_attack_units_at_tile_result(punit, target_tile);
1247 1299
      break;
1300
    case ACTRES_WIPE_UNITS:
1301
      action_custom = unit_wipe_units_at_tile_result(punit, target_tile);
1302
      break;
1248 1303
    case ACTRES_CONQUER_CITY:
1249 1304
      if (target_city) {
1250 1305
        action_custom = unit_move_to_tile_test(&(wld.map), punit,
......
1488 1543
                                       + unit_pop_value(punit))))) {
1489 1544
    explnat->kind = ANEK_CITY_POP_LIMIT;
1490 1545
  } else if ((action_has_result_safe(paction, ACTRES_NUKE_UNITS)
1491
              || action_has_result_safe(paction, ACTRES_ATTACK))
1546
              || action_has_result_safe(paction, ACTRES_ATTACK)
1547
              || action_has_result_safe(paction, ACTRES_WIPE_UNITS))
1492 1548
             && action_custom != ATT_OK) {
1493 1549
    switch (action_custom) {
1494 1550
    case ATT_NON_ATTACK:
......
1505 1561
      explnat->kind = ANEK_BAD_TERRAIN_TGT;
1506 1562
      explnat->no_act_terrain = tile_terrain(target_tile);
1507 1563
      break;
1564
    case ATT_NOT_WIPABLE:
1565
      explnat->kind = ANEK_NOT_WIPABLE;
1566
      break;
1508 1567
    default:
1509 1568
      fc_assert(action_custom != ATT_OK);
1510 1569
      explnat->kind = ANEK_UNKNOWN;
......
1861 1920
                    "unit."),
1862 1921
                  unit_name_translation(punit));
1863 1922
    break;
1923
  case ANEK_NOT_WIPABLE:
1924
    notify_player(pplayer, target_tile, E_BAD_COMMAND, ftc_server,
1925
                  _("%s can't do anything since there is unit with a positive "
1926
                    "defense value."),
1927
                  unit_name_translation(punit));
1928
    break;
1864 1929
  case ANEK_TGT_IS_UNIQUE_ACT_HAS:
1865 1930
    notify_player(pplayer, target_tile, E_BAD_COMMAND, ftc_server,
1866 1931
                  _("%s can't do anything since you already have a %s."),
......
2563 2628
                  unit_name_translation(actor),
2564 2629
                  action_id_name_translation(stopped_action));
2565 2630
    break;
2631
  case ANEK_NOT_WIPABLE:
2632
    notify_player(pplayer, target_tile,
2633
                  event, ftc_server,
2634
                  /* TRANS: "Your Legion can't do Wipe Units there ..." */
2635
                  _("Your %s can't do %s there since there's an "
2636
                    "unit with positive defense value."),
2637
                  unit_name_translation(actor),
2638
                  action_id_name_translation(stopped_action));
2639
    break;
2566 2640
  case ANEK_TGT_IS_UNIQUE_ACT_HAS:
2567 2641
    notify_player(pplayer, target_tile, event, ftc_server,
2568 2642
                  /* TRANS: "You already have a Leader." */
......
3468 3542
    ACTION_STARTED_UNIT_UNITS(action_type, actor_unit, target_tile,
3469 3543
                              do_attack(actor_unit, target_tile, paction));
3470 3544
    break;
3545
  case ACTRES_WIPE_UNITS:
3546
    ACTION_STARTED_UNIT_UNITS(action_type, actor_unit, target_tile,
3547
                              do_wipe_units(actor_unit, target_tile, paction));
3548
    break;
3471 3549
  case ACTRES_NUKE_UNITS:
3472 3550
    ACTION_STARTED_UNIT_UNITS(action_type, actor_unit, target_tile,
3473 3551
                              unit_nuke(pplayer, actor_unit, target_tile,
tools/ruleutil/rulesave.c
1286 1286
    return FALSE;
1287 1287
  }
1288 1288

  
1289
  if (!save_action_post_success_force(sfile, ACTION_AUTO_POST_WIPE_UNITS,
1290
                                      action_by_number(ACTION_WIPE_UNITS))) {
1291
    log_error("Didn't save all post success forced actions.");
1292
    return FALSE;
1293
  }
1294

  
1289 1295
  if (!save_action_auto_actions(sfile, ACTION_AUTO_ESCAPE_CITY,
1290 1296
                                "actions.escape_city")) {
1291 1297
    log_error("Didn't save all escape city forced actions.");
1292
- 
(2-2/3)