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 » 0008-Add-Action-Wipe-Units.patch

Marko Lindqvist, 2021-03-23 09:57 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
2680 2680
                         "is reduced accordingly.\n"));
2681 2681
        }
2682 2682
        break;
2683
      case ACTRES_WIPE_UNITS:
2684
        cat_snprintf(buf, bufsz,
2685
                     _("  * can wipe stack of units with zero defense.\n"));
2686
        break;
2683 2687
      case ACTRES_CONVERT:
2684 2688
        cat_snprintf(buf, bufsz,
2685 2689
                     /* TRANS: %s is a unit type. "MP" = movement points. */
client/packhand.c
4784 4784
      case ACTION_NUKE_UNITS:
4785 4785
      case ACTION_ATTACK:
4786 4786
      case ACTION_SUICIDE_ATTACK:
4787
      case ACTION_WIPE_UNITS:
4787 4788
      case ACTION_CONQUER_CITY:
4788 4789
      case ACTION_CONQUER_CITY2:
4789 4790
      case ACTION_CONQUER_CITY3:
common/actions.c
453 453
                             " that the actor is at war with the target."),
454 454
                          ACTRES_BOMBARD,
455 455
                          ACTRES_ATTACK,
456
                          ACTRES_WIPE_UNITS,
456 457
                          ACTRES_NONE);
457 458

  
458 459
  /* Why this is a hard requirement: Keep the old rules. Need to work
......
588 589
                             " the NonMil utype flag."),
589 590
                          ACTRES_ATTACK,
590 591
                          ACTRES_CONQUER_CITY,
592
                          ACTRES_WIPE_UNITS,
591 593
                          ACTRES_NONE);
592 594
  oblig_hard_req_reg(req_contradiction_or(
593 595
                       2,
......
1206 1208
      unit_action_new(ACTION_SUICIDE_ATTACK, ACTRES_ATTACK,
1207 1209
                      FALSE, TRUE,
1208 1210
                      MAK_FORCED, 1, 1, TRUE);
1211
  actions[ACTION_WIPE_UNITS] =
1212
      unit_action_new(ACTION_WIPE_UNITS, ACTRES_WIPE_UNITS,
1213
                      FALSE, TRUE,
1214
                      /* Tries a forced move if the target unit's tile has
1215
                       * no non allied units and the occupychance dice roll
1216
                       * tells it to move. */
1217
                      MAK_FORCED,
1218
                      1, 1, FALSE);
1209 1219
  actions[ACTION_STRIKE_BUILDING] =
1210 1220
      unit_action_new(ACTION_STRIKE_BUILDING, ACTRES_STRIKE_BUILDING,
1211 1221
                      FALSE, FALSE,
......
1713 1723
{
1714 1724
  switch (pact->result) {
1715 1725
  case ACTRES_ATTACK:
1726
  case ACTRES_WIPE_UNITS:
1716 1727
    return ABK_STANDARD;
1717 1728
  case ACTRES_SPY_ATTACK:
1718 1729
  case ACTRES_SPY_POISON:
......
2241 2252
  case ACTRES_STRIKE_BUILDING:
2242 2253
  case ACTRES_STRIKE_PRODUCTION:
2243 2254
  case ACTRES_ATTACK:
2255
  case ACTRES_WIPE_UNITS:
2244 2256
  case ACTRES_CONQUER_CITY:
2245 2257
  case ACTRES_CONQUER_EXTRAS:
2246 2258
  case ACTRES_HEAL_UNIT:
......
2326 2338
  case ACTRES_STRIKE_BUILDING:
2327 2339
  case ACTRES_STRIKE_PRODUCTION:
2328 2340
  case ACTRES_ATTACK:
2341
  case ACTRES_WIPE_UNITS:
2329 2342
  case ACTRES_CONQUER_CITY:
2330 2343
  case ACTRES_CONQUER_EXTRAS:
2331 2344
  case ACTRES_HEAL_UNIT:
......
3302 3315
    break;
3303 3316

  
3304 3317
  case ACTRES_ATTACK:
3318
  case ACTRES_WIPE_UNITS:
3305 3319
    if (actor_unittype->attack_strength <= 0) {
3306 3320
      /* Reason: Can't attack without strength. */
3307 3321
      return FALSE;
......
3592 3606
  case ACTRES_HOME_CITY:
3593 3607
  case ACTRES_UPGRADE_UNIT:
3594 3608
  case ACTRES_ATTACK:
3609
  case ACTRES_WIPE_UNITS:
3595 3610
  case ACTRES_STRIKE_BUILDING:
3596 3611
  case ACTRES_STRIKE_PRODUCTION:
3597 3612
  case ACTRES_CONQUER_CITY:
......
4068 4083
    }
4069 4084
    break;
4070 4085

  
4086
  case ACTRES_WIPE_UNITS:
4087
    if (!can_unit_attack_tile(actor_unit, target_tile)) {
4088
      return TRI_NO;
4089
    }
4090

  
4091
    unit_list_iterate(target_tile->units, punit) {
4092
      if (get_total_defense_power(actor_unit, punit) > 0) {
4093
        return TRI_NO;
4094
      }
4095
    } unit_list_iterate_end;
4096
    break;
4097

  
4071 4098
  case ACTRES_CONQUER_CITY:
4072 4099
    /* Reason: "Conquer City" involves moving into the city. */
4073 4100
    if (!unit_can_move_to_tile(&(wld.map), actor_unit, target_tile,
......
5578 5605
      }
5579 5606
    }
5580 5607
    break;
5608
  case ACTRES_WIPE_UNITS:
5609
    chance = ACTPROB_CERTAIN;
5610
    break;
5581 5611
  case ACTRES_STRIKE_BUILDING:
5582 5612
    /* TODO: not implemented yet because:
5583 5613
     * - dice roll 100% * Action_Odds_Pct could be handled with
......
5933 5963
  }
5934 5964

  
5935 5965
  if ((action_id_has_result_safe(act_id, ACTRES_ATTACK)
5936
       || action_id_has_result_safe(act_id, ACTRES_BOMBARD))
5966
       || action_id_has_result_safe(act_id, ACTRES_BOMBARD)
5967
       || action_id_has_result_safe(act_id, ACTRES_WIPE_UNITS))
5937 5968
      && tile_city(target_tile) != NULL
5938 5969
      && !pplayers_at_war(city_owner(tile_city(target_tile)),
5939 5970
                          unit_owner(actor_unit))) {
......
6783 6814
  case ACTRES_PARADROP_CONQUER:
6784 6815
  case ACTRES_AIRLIFT:
6785 6816
  case ACTRES_ATTACK:
6817
  case ACTRES_WIPE_UNITS:
6786 6818
  case ACTRES_CONQUER_CITY:
6787 6819
  case ACTRES_CONQUER_EXTRAS:
6788 6820
  case ACTRES_HEAL_UNIT:
......
7308 7340
    return "ui_name_attack";
7309 7341
  case ACTION_SUICIDE_ATTACK:
7310 7342
    return "ui_name_suicide_attack";
7343
  case ACTION_WIPE_UNITS:
7344
    return "ui_name_wipe_units";
7311 7345
  case ACTION_STRIKE_BUILDING:
7312 7346
    return "ui_name_surgical_strike_building";
7313 7347
  case ACTION_STRIKE_PRODUCTION:
......
7589 7623
  case ACTION_SUICIDE_ATTACK:
7590 7624
    /* TRANS: _Suicide Attack (100% chance of success). */
7591 7625
    return N_("%sSuicide Attack%s");
7626
  case ACTION_WIPE_UNITS:
7627
    /* TRANS: _Wipe Units (100% chance of success). */
7628
    return N_("%sWipe Units%s");
7592 7629
  case ACTION_STRIKE_BUILDING:
7593 7630
    /* TRANS: Surgical Str_ike Building (100% chance of success). */
7594 7631
    return N_("Surgical Str%sike Building%s");
......
7766 7803
  case ACTION_AIRLIFT:
7767 7804
  case ACTION_ATTACK:
7768 7805
  case ACTION_SUICIDE_ATTACK:
7806
  case ACTION_WIPE_UNITS:
7769 7807
  case ACTION_STRIKE_BUILDING:
7770 7808
  case ACTION_STRIKE_PRODUCTION:
7771 7809
  case ACTION_CONQUER_CITY:
......
7877 7915
  case ACTRES_STRIKE_BUILDING:
7878 7916
  case ACTRES_STRIKE_PRODUCTION:
7879 7917
  case ACTRES_ATTACK:
7918
  case ACTRES_WIPE_UNITS:
7880 7919
  case ACTRES_CONQUER_CITY:
7881 7920
  case ACTRES_HEAL_UNIT:
7882 7921
  case ACTRES_TRANSFORM_TERRAIN:
......
7972 8011
  case ACTION_PARADROP_ENTER_CONQUER:
7973 8012
  case ACTION_ATTACK:
7974 8013
  case ACTION_SUICIDE_ATTACK:
8014
  case ACTION_WIPE_UNITS:
7975 8015
  case ACTION_STRIKE_BUILDING:
7976 8016
  case ACTION_STRIKE_PRODUCTION:
7977 8017
  case ACTION_CONQUER_CITY:
......
8088 8128
  case ACTRES_STRIKE_BUILDING:
8089 8129
  case ACTRES_STRIKE_PRODUCTION:
8090 8130
  case ACTRES_ATTACK:
8131
  case ACTRES_WIPE_UNITS:
8091 8132
  case ACTRES_CONQUER_CITY:
8092 8133
  case ACTRES_HEAL_UNIT:
8093 8134
  case ACTRES_TRANSFORM_TERRAIN:
......
8195 8236
  case ACTION_AIRLIFT:
8196 8237
  case ACTION_ATTACK:
8197 8238
  case ACTION_SUICIDE_ATTACK:
8239
  case ACTION_WIPE_UNITS:
8198 8240
  case ACTION_STRIKE_BUILDING:
8199 8241
  case ACTION_STRIKE_PRODUCTION:
8200 8242
  case ACTION_CONQUER_CITY:
......
8317 8359
     * target tile (Units) and, depending on the
8318 8360
     * unreachable_protects setting, each or any
8319 8361
     * *non transported* unit at the target tile. */
8362
  case ACTRES_WIPE_UNITS:
8320 8363
  case ACTRES_CAPTURE_UNITS:
8321 8364
  case ACTRES_NUKE_UNITS:
8322 8365
  case ACTRES_SPY_ATTACK:
......
8407 8450
  case ACTRES_BOMBARD:
8408 8451
  case ACTRES_NUKE_UNITS:
8409 8452
  case ACTRES_ATTACK:
8453
  case ACTRES_WIPE_UNITS:
8410 8454
  case ACTRES_SPY_ATTACK:
8411 8455
    return tgt_kind == ATK_UNITS;
8412 8456
  case ACTRES_FOUND_CITY:
......
8510 8554
  case ACTRES_BOMBARD:
8511 8555
  case ACTRES_NUKE_UNITS:
8512 8556
  case ACTRES_ATTACK:
8557
  case ACTRES_WIPE_UNITS:
8513 8558
  case ACTRES_SPY_ATTACK:
8514 8559
    return ASTK_NONE;
8515 8560
  case ACTRES_FOUND_CITY:
......
8601 8646
  case ACTRES_BOMBARD:
8602 8647
  case ACTRES_NUKE_UNITS:
8603 8648
  case ACTRES_ATTACK:
8649
  case ACTRES_WIPE_UNITS:
8604 8650
  case ACTRES_SPY_ATTACK:
8605 8651
    return ACT_TGT_COMPL_SIMPLE;
8606 8652
  case ACTRES_FOUND_CITY:
......
8697 8743
  case ACTION_AIRLIFT:
8698 8744
  case ACTION_ATTACK:
8699 8745
  case ACTION_SUICIDE_ATTACK:
8746
  case ACTION_WIPE_UNITS:
8700 8747
  case ACTION_STRIKE_BUILDING:
8701 8748
  case ACTION_STRIKE_PRODUCTION:
8702 8749
  case ACTION_CONQUER_CITY:
......
8800 8847
    return "attack_blocked_by";
8801 8848
  case ACTION_SUICIDE_ATTACK:
8802 8849
    return "suicide_attack_blocked_by";
8850
  case ACTION_WIPE_UNITS:
8851
    return "wipe_units_blocked_by";
8803 8852
  case ACTION_CONQUER_CITY:
8804 8853
    return "conquer_city_blocked_by";
8805 8854
  case ACTION_CONQUER_CITY2:
......
8923 8972
  fc_assert_ret_val(act != NULL, NULL);
8924 8973

  
8925 8974
  if (!(action_has_result(act, ACTRES_SPY_BRIBE_UNIT)
8926
        ||action_has_result(act, ACTRES_ATTACK))) {
8975
        || action_has_result(act, ACTRES_ATTACK)
8976
        || action_has_result(act, ACTRES_WIPE_UNITS))) {
8927 8977
    /* No support in the action performer function */
8928 8978
    return NULL;
8929 8979
  }
......
8933 8983
    return "bribe_unit_post_success_forced_actions";
8934 8984
  case ACTION_ATTACK:
8935 8985
    return "attack_post_success_forced_actions";
8986
  case ACTION_WIPE_UNITS:
8987
    return "wipe_units_post_success_forced_actions";
8936 8988
  case ACTION_MARKETPLACE:
8937 8989
  case ACTION_BOMBARD:
8938 8990
  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"
......
586 588

  
587 589
/* Hard coded location of action auto performers. Used for conversion while
588 590
 * action auto performers aren't directly exposed to the ruleset. */
589
#define ACTION_AUTO_UPKEEP_FOOD   0
590
#define ACTION_AUTO_UPKEEP_GOLD   1
591
#define ACTION_AUTO_UPKEEP_SHIELD 2
592
#define ACTION_AUTO_MOVED_ADJ     3
593
#define ACTION_AUTO_POST_BRIBE    4
594
#define ACTION_AUTO_POST_ATTACK   5
595
#define ACTION_AUTO_ESCAPE_CITY   6
596
#define ACTION_AUTO_ESCAPE_STACK  7
591
#define ACTION_AUTO_UPKEEP_FOOD     0
592
#define ACTION_AUTO_UPKEEP_GOLD     1
593
#define ACTION_AUTO_UPKEEP_SHIELD   2
594
#define ACTION_AUTO_MOVED_ADJ       3
595
#define ACTION_AUTO_POST_BRIBE      4
596
#define ACTION_AUTO_POST_ATTACK     5
597
#define ACTION_AUTO_ESCAPE_CITY     6
598
#define ACTION_AUTO_ESCAPE_STACK    7
599
#define ACTION_AUTO_POST_WIPE_UNITS 8
597 600

  
598 601
/* Initialization */
599 602
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 (get_total_defense_power(punit, target) > 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
187 187
}
188 188

  
189 189
/************************************************************************//**
190
 This unit can attack non-native tiles (eg. Ships ability to
191
 shore bombardment)
190
  This unit can attack non-native tiles (eg. Ships ability to
191
  shore bombardment)
192 192
****************************************************************************/
193 193
bool can_attack_non_native(const struct unit_type *utype)
194 194
{
195 195
  return uclass_has_flag(utype_class(utype), UCF_ATTACK_NON_NATIVE)
196 196
         && (utype_can_do_action_result(utype, ACTRES_ATTACK)
197
             || utype_can_do_action_result(utype, ACTRES_BOMBARD))
197
             || utype_can_do_action_result(utype, ACTRES_BOMBARD)
198
             || utype_can_do_action_result(utype, ACTRES_WIPE_UNITS))
198 199
         && utype->attack_strength > 0
199 200
         && !utype_has_flag(utype, UTYF_ONLY_NATIVE_ATTACK);
200 201
}
201 202

  
202 203
/************************************************************************//**
203
 This unit can attack from non-native tiles (Marines can attack from
204
 transport, ships from harbour cities)
204
  This unit can attack from non-native tiles (Marines can attack from
205
  transport, ships from harbour cities)
205 206
****************************************************************************/
206 207
bool can_attack_from_non_native(const struct unit_type *utype)
207 208
{
......
209 210
                                       USP_NATIVE_TILE, FALSE)
210 211
          || utype_can_do_act_when_ustate(utype, ACTION_SUICIDE_ATTACK,
211 212
                                          USP_NATIVE_TILE, FALSE)
213
          || utype_can_do_act_when_ustate(utype, ACTION_WIPE_UNITS,
214
                                          USP_LIVABLE_TILE, FALSE)
212 215
          || utype_can_do_act_when_ustate(utype, ACTION_CONQUER_CITY4,
213 216
                                          USP_LIVABLE_TILE, FALSE)
214 217
          || 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
771 771
   - it is in a city
772 772
   - it is on a tile with a native Extra
773 773

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

  
774 795
"Nuke Units" - Detonate at the target unit stack. Cause a nuclear explosion.
775 796
 * UI name can be set using ui_name_nuke_units
776 797
 * 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.22"
59
NETWORK_CAPSTRING="+Freeciv.Devel-3.2-2021.Mar.23"
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
6946 6946
        ok = FALSE;
6947 6947
      }
6948 6948

  
6949
      /* "Wipe Units" */
6950
      if (!load_action_post_success_force(file, filename,
6951
                                          ACTION_AUTO_POST_WIPE_UNITS,
6952
                                          action_by_number(
6953
                                            ACTION_WIPE_UNITS))) {
6954
        ok = FALSE;
6955
      }
6956

  
6949 6957
      /* No "Suicide Attack". Can't act when dead. */
6950 6958
    }
6951 6959

  
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

  
......
830 880
  switch (paction->result) {
831 881
  case ACTRES_BOMBARD:
832 882
  case ACTRES_ATTACK:
883
  case ACTRES_WIPE_UNITS:
833 884
    /* Target is a unit stack but a city can block it. */
834 885
    fc_assert_action(action_get_target_kind(paction) == ATK_UNITS, break);
886

  
835 887
    if (target_tile) {
836 888
      struct city *tcity;
837 889

  
......
1255 1307
    case ACTRES_ATTACK:
1256 1308
      action_custom = unit_attack_units_at_tile_result(punit, target_tile);
1257 1309
      break;
1310
    case ACTRES_WIPE_UNITS:
1311
      action_custom = unit_wipe_units_at_tile_result(punit, target_tile);
1312
      break;
1258 1313
    case ACTRES_CONQUER_CITY:
1259 1314
      if (target_city) {
1260 1315
        action_custom = unit_move_to_tile_test(&(wld.map), punit,
......
1498 1553
                                       + unit_pop_value(punit))))) {
1499 1554
    explnat->kind = ANEK_CITY_POP_LIMIT;
1500 1555
  } else if ((action_has_result_safe(paction, ACTRES_NUKE_UNITS)
1501
              || action_has_result_safe(paction, ACTRES_ATTACK))
1556
              || action_has_result_safe(paction, ACTRES_ATTACK)
1557
              || action_has_result_safe(paction, ACTRES_WIPE_UNITS))
1502 1558
             && action_custom != ATT_OK) {
1503 1559
    switch (action_custom) {
1504 1560
    case ATT_NON_ATTACK:
......
1515 1571
      explnat->kind = ANEK_BAD_TERRAIN_TGT;
1516 1572
      explnat->no_act_terrain = tile_terrain(target_tile);
1517 1573
      break;
1574
    case ATT_NOT_WIPABLE:
1575
      explnat->kind = ANEK_NOT_WIPABLE;
1576
      break;
1518 1577
    default:
1519 1578
      fc_assert(action_custom != ATT_OK);
1520 1579
      explnat->kind = ANEK_UNKNOWN;
......
1871 1930
                    "unit."),
1872 1931
                  unit_name_translation(punit));
1873 1932
    break;
1933
  case ANEK_NOT_WIPABLE:
1934
    notify_player(pplayer, target_tile, E_BAD_COMMAND, ftc_server,
1935
                  _("%s can't do anything since there is unit with a positive "
1936
                    "defense value."),
1937
                  unit_name_translation(punit));
1938
    break;
1874 1939
  case ANEK_TGT_IS_UNIQUE_ACT_HAS:
1875 1940
    notify_player(pplayer, target_tile, E_BAD_COMMAND, ftc_server,
1876 1941
                  _("%s can't do anything since you already have a %s."),
......
2573 2638
                  unit_name_translation(actor),
2574 2639
                  action_id_name_translation(stopped_action));
2575 2640
    break;
2641
  case ANEK_NOT_WIPABLE:
2642
    notify_player(pplayer, target_tile,
2643
                  event, ftc_server,
2644
                  /* TRANS: "Your Legion can't do Wipe Units there ..." */
2645
                  _("Your %s can't do %s there since there's an "
2646
                    "unit with positive defense value."),
2647
                  unit_name_translation(actor),
2648
                  action_id_name_translation(stopped_action));
2649
    break;
2576 2650
  case ANEK_TGT_IS_UNIQUE_ACT_HAS:
2577 2651
    notify_player(pplayer, target_tile, event, ftc_server,
2578 2652
                  /* TRANS: "You already have a Leader." */
......
3478 3552
    ACTION_STARTED_UNIT_UNITS(action_type, actor_unit, target_tile,
3479 3553
                              do_attack(actor_unit, target_tile, paction));
3480 3554
    break;
3555
  case ACTRES_WIPE_UNITS:
3556
    ACTION_STARTED_UNIT_UNITS(action_type, actor_unit, target_tile,
3557
                              do_wipe_units(actor_unit, target_tile, paction));
3558
    break;
3481 3559
  case ACTRES_NUKE_UNITS:
3482 3560
    ACTION_STARTED_UNIT_UNITS(action_type, actor_unit, target_tile,
3483 3561
                              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
- 
(3-3/3)