From a964f5bc0d53d4824ed8e8b7def951b0b195184c Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Sat, 26 Nov 2022 22:02:09 +0200 Subject: [PATCH 13/32] Add Clean action See osdn #45975 Signed-off-by: Marko Lindqvist --- ai/default/daicity.c | 1 + ai/default/daidiplomacy.c | 1 + client/helpdata.c | 14 +++--- client/packhand.c | 1 + client/tilespec.c | 1 + common/actions.c | 78 +++++++++++++++++++++++++++++++++- common/actions.h | 18 ++++---- common/aicore/aiactions.c | 11 +++-- common/aicore/aiactions.h | 9 ++-- common/clientutils.c | 18 ++++++++ common/fc_types.h | 5 +++ common/terrain.c | 35 +++++++++++++++ common/tile.c | 2 + common/unit.c | 15 ++++++- common/unittype.c | 1 + doc/README.actions | 16 +++++++ server/advisors/advdata.c | 1 + server/advisors/autosettlers.c | 20 +++++---- server/savegame/savecompat.c | 4 +- server/savegame/savegame2.c | 6 ++- server/savegame/savegame3.c | 6 ++- server/unithand.c | 16 ++++--- server/unittools.c | 58 +++++++++++++++++++++++-- 23 files changed, 286 insertions(+), 51 deletions(-) diff --git a/ai/default/daicity.c b/ai/default/daicity.c index 6bd3236372..57b0875b60 100644 --- a/ai/default/daicity.c +++ b/ai/default/daicity.c @@ -1290,6 +1290,7 @@ static int action_target_neg_util(action_id act_id, case ACTRES_CULTIVATE: case ACTRES_PLANT: case ACTRES_PILLAGE: + case ACTRES_CLEAN: case ACTRES_CLEAN_POLLUTION: case ACTRES_CLEAN_FALLOUT: case ACTRES_FORTIFY: diff --git a/ai/default/daidiplomacy.c b/ai/default/daidiplomacy.c index 125998c362..6ea015887e 100644 --- a/ai/default/daidiplomacy.c +++ b/ai/default/daidiplomacy.c @@ -2039,6 +2039,7 @@ void dai_incident(struct ai_type *ait, enum incident_type type, case ACTRES_TRANSFORM_TERRAIN: case ACTRES_CULTIVATE: case ACTRES_PLANT: + case ACTRES_CLEAN: case ACTRES_CLEAN_POLLUTION: case ACTRES_CLEAN_FALLOUT: case ACTRES_FORTIFY: diff --git a/client/helpdata.c b/client/helpdata.c index b23909cbe3..990d6b6e3c 100644 --- a/client/helpdata.c +++ b/client/helpdata.c @@ -311,13 +311,13 @@ static bool insert_generated_text(char *outbuf, size_t outlen, const char *name) if (factor < 0) { factor = pextra->removal_time_factor; } else if (factor != pextra->removal_time_factor) { - factor = 0; /* give up */ + factor = 0; /* Give up */ } } else { if (time < 0) { time = pextra->removal_time; } else if (time != pextra->removal_time) { - time = 0; /* give up */ + time = 0; /* Give up */ } } } extra_type_by_rmcause_iterate_end; @@ -351,13 +351,13 @@ static bool insert_generated_text(char *outbuf, size_t outlen, const char *name) if (factor < 0) { factor = pextra->removal_time_factor; } else if (factor != pextra->removal_time_factor) { - factor = 0; /* give up */ + factor = 0; /* Give up */ } } else { if (time < 0) { time = pextra->removal_time; } else if (time != pextra->removal_time) { - time = 0; /* give up */ + time = 0; /* Give up */ } } } extra_type_by_rmcause_iterate_end; @@ -391,13 +391,13 @@ static bool insert_generated_text(char *outbuf, size_t outlen, const char *name) if (factor < 0) { factor = pextra->removal_time_factor; } else if (factor != pextra->removal_time_factor) { - factor = 0; /* give up */ + factor = 0; /* Give up */ } } else { if (time < 0) { time = pextra->removal_time; } else if (time != pextra->removal_time) { - time = 0; /* give up */ + time = 0; /* Give up */ } } } extra_type_by_rmcause_iterate_end; @@ -2871,6 +2871,7 @@ char *helptext_unit(char *buf, size_t bufsz, struct player *pplayer, strvec_destroy(extras_vec); } break; + case ACTRES_CLEAN: case ACTRES_CLEAN_POLLUTION: case ACTRES_CLEAN_FALLOUT: { @@ -3857,6 +3858,7 @@ void helptext_extra(char *buf, size_t bufsz, struct player *pplayer, && pterrain->clean_fallout_time != 0) { int terr_clean_fall_time = pterrain->clean_fallout_time * pextra->removal_time_factor; + if (terr_clean_time > 0 && terr_clean_time != terr_clean_fall_time) { /* Pollution/fallout cleaning activities taking different time diff --git a/client/packhand.c b/client/packhand.c index 399331e120..8758ccd0c2 100644 --- a/client/packhand.c +++ b/client/packhand.c @@ -198,6 +198,7 @@ const action_id auto_attack_blockers[] = { ACTION_CULTIVATE, ACTION_PLANT, ACTION_PILLAGE, + ACTION_CLEAN, ACTION_CLEAN_POLLUTION, ACTION_CLEAN_FALLOUT, ACTION_ROAD, diff --git a/client/tilespec.c b/client/tilespec.c index a063e8e57e..ee9e2441a3 100644 --- a/client/tilespec.c +++ b/client/tilespec.c @@ -4414,6 +4414,7 @@ static int fill_unit_sprite_array(const struct tileset *t, case ACTIVITY_CULTIVATE: s = t->sprites.unit.cultivate; break; + case ACTIVITY_CLEAN: case ACTIVITY_POLLUTION: case ACTIVITY_FALLOUT: s = t->sprites.extras[extra_index(punit->activity_target)].rmact; diff --git a/common/actions.c b/common/actions.c index ab8d226aa4..ab20caa37c 100644 --- a/common/actions.c +++ b/common/actions.c @@ -531,6 +531,7 @@ static void hard_code_oblig_hard_reqs(void) ACTRES_BASE, ACTRES_MINE, ACTRES_IRRIGATE, + ACTRES_CLEAN, ACTRES_CLEAN_POLLUTION, ACTRES_CLEAN_FALLOUT, ACTRES_NONE); @@ -1324,6 +1325,10 @@ static void hard_code_actions(void) unit_action_new(ACTION_PILLAGE, ACTRES_PILLAGE, TRUE, FALSE, MAK_STAYS, 0, 0, FALSE); + actions[ACTION_CLEAN] = + unit_action_new(ACTION_CLEAN, ACTRES_CLEAN, + TRUE, FALSE, + MAK_STAYS, 0, 0, FALSE); actions[ACTION_CLEAN_POLLUTION] = unit_action_new(ACTION_CLEAN_POLLUTION, ACTRES_CLEAN_POLLUTION, TRUE, FALSE, @@ -2162,6 +2167,8 @@ enum unit_activity action_get_activity(const struct action *paction) return ACTIVITY_GEN_ROAD; } else if (action_has_result(paction, ACTRES_PILLAGE)) { return ACTIVITY_PILLAGE; + } else if (action_has_result(paction, ACTRES_CLEAN)) { + return ACTIVITY_CLEAN; } else if (action_has_result(paction, ACTRES_CLEAN_POLLUTION)) { return ACTIVITY_POLLUTION; } else if (action_has_result(paction, ACTRES_CLEAN_FALLOUT)) { @@ -2203,6 +2210,7 @@ int action_get_act_time(const struct action *paction, switch (pactivity) { case ACTIVITY_PILLAGE: + case ACTIVITY_CLEAN: case ACTIVITY_POLLUTION: case ACTIVITY_FALLOUT: case ACTIVITY_BASE: @@ -2306,6 +2314,7 @@ bool action_creates_extra(const struct action *paction, case ACTRES_CULTIVATE: case ACTRES_PLANT: case ACTRES_PILLAGE: + case ACTRES_CLEAN: case ACTRES_CLEAN_POLLUTION: case ACTRES_CLEAN_FALLOUT: case ACTRES_FORTIFY: @@ -2342,6 +2351,9 @@ bool action_removes_extra(const struct action *paction, switch (paction->result) { case ACTRES_PILLAGE: return is_extra_removed_by(pextra, ERM_PILLAGE); + case ACTRES_CLEAN: + return is_extra_removed_by(pextra, ERM_CLEANPOLLUTION) + || is_extra_removed_by(pextra, ERM_CLEANFALLOUT); case ACTRES_CLEAN_POLLUTION: return is_extra_removed_by(pextra, ERM_CLEANPOLLUTION); case ACTRES_CLEAN_FALLOUT: @@ -3499,6 +3511,7 @@ action_actor_utype_hard_reqs_ok_full(const struct action *paction, case ACTRES_CONQUER_CITY: case ACTRES_HEAL_UNIT: case ACTRES_PILLAGE: + case ACTRES_CLEAN: case ACTRES_CLEAN_POLLUTION: case ACTRES_CLEAN_FALLOUT: case ACTRES_FORTIFY: @@ -3691,6 +3704,7 @@ action_hard_reqs_actor(const struct action *paction, case ACTRES_CULTIVATE: case ACTRES_PLANT: case ACTRES_PILLAGE: + case ACTRES_CLEAN: case ACTRES_CLEAN_POLLUTION: case ACTRES_CLEAN_FALLOUT: case ACTRES_FORTIFY: @@ -4349,6 +4363,49 @@ is_action_possible(const action_id wanted_action, } break; + case ACTRES_CLEAN: + { + const struct extra_type *pextra = NULL; + const struct extra_type *fextra = NULL; + + pterrain = tile_terrain(target->tile); + + if (target_extra != NULL) { + if (is_extra_removed_by(target_extra, ERM_CLEANPOLLUTION) + && tile_has_extra(target->tile, target_extra)) { + pextra = target_extra; + } + if (is_extra_removed_by(target_extra, ERM_CLEANFALLOUT) + && tile_has_extra(target->tile, target_extra)) { + fextra = target_extra; + } + } else { + /* TODO: Make sure that all callers set target so that + * we don't need this fallback. */ + + pextra = prev_extra_in_tile(target->tile, + ERM_CLEANPOLLUTION, + actor->player, + actor->unit); + fextra = prev_extra_in_tile(target->tile, + ERM_CLEANFALLOUT, + actor->player, + actor->unit); + } + + if (pextra != NULL && pterrain->clean_pollution_time > 0 + && can_remove_extra(pextra, actor->unit, target->tile)) { + return TRI_YES; + } + + if (fextra != NULL && pterrain->clean_fallout_time > 0 + && can_remove_extra(fextra, actor->unit, target->tile)) { + return TRI_YES; + } + + return TRI_NO; + } + case ACTRES_CLEAN_POLLUTION: { const struct extra_type *pextra; @@ -5777,6 +5834,7 @@ action_prob(const action_id wanted_action, case ACTRES_CULTIVATE: case ACTRES_PLANT: case ACTRES_PILLAGE: + case ACTRES_CLEAN: case ACTRES_CLEAN_POLLUTION: case ACTRES_CLEAN_FALLOUT: case ACTRES_FORTIFY: @@ -7088,6 +7146,7 @@ int action_dice_roll_initial_odds(const struct action *paction) case ACTRES_CULTIVATE: case ACTRES_PLANT: case ACTRES_PILLAGE: + case ACTRES_CLEAN: case ACTRES_CLEAN_POLLUTION: case ACTRES_CLEAN_FALLOUT: case ACTRES_FORTIFY: @@ -7655,6 +7714,8 @@ const char *action_ui_name_ruleset_var_name(int act) return "ui_name_plant"; case ACTION_PILLAGE: return "ui_name_pillage"; + case ACTION_CLEAN: + return "ui_name_clean"; case ACTION_CLEAN_POLLUTION: return "ui_name_clean_pollution"; case ACTION_CLEAN_FALLOUT: @@ -7964,6 +8025,9 @@ const char *action_ui_name_default(int act) case ACTION_PILLAGE: /* TRANS: Pilla_ge (100% chance of success). */ return N_("Pilla%sge%s"); + case ACTION_CLEAN: + /* TRANS: Clean (100% chance of success). */ + return N_("%sClean%s"); case ACTION_CLEAN_POLLUTION: /* TRANS: Clean _Pollution (100% chance of success). */ return N_("Clean %sPollution%s"); @@ -8130,6 +8194,7 @@ const char *action_min_range_ruleset_var_name(int act) case ACTION_CULTIVATE: case ACTION_PLANT: case ACTION_PILLAGE: + case ACTION_CLEAN: case ACTION_CLEAN_POLLUTION: case ACTION_CLEAN_FALLOUT: case ACTION_FORTIFY: @@ -8246,6 +8311,7 @@ int action_min_range_default(enum action_result result) case ACTRES_CULTIVATE: case ACTRES_PLANT: case ACTRES_PILLAGE: + case ACTRES_CLEAN: case ACTRES_CLEAN_POLLUTION: case ACTRES_CLEAN_FALLOUT: case ACTRES_FORTIFY: @@ -8350,6 +8416,7 @@ const char *action_max_range_ruleset_var_name(int act) case ACTION_CULTIVATE: case ACTION_PLANT: case ACTION_PILLAGE: + case ACTION_CLEAN: case ACTION_CLEAN_POLLUTION: case ACTION_CLEAN_FALLOUT: case ACTION_FORTIFY: @@ -8472,6 +8539,7 @@ int action_max_range_default(enum action_result result) case ACTRES_CULTIVATE: case ACTRES_PLANT: case ACTRES_PILLAGE: + case ACTRES_CLEAN: case ACTRES_CLEAN_POLLUTION: case ACTRES_CLEAN_FALLOUT: case ACTRES_FORTIFY: @@ -8587,6 +8655,7 @@ const char *action_target_kind_ruleset_var_name(int act) case ACTION_TRANSFORM_TERRAIN: case ACTION_CULTIVATE: case ACTION_PLANT: + case ACTION_CLEAN: case ACTION_CLEAN_POLLUTION: case ACTION_CLEAN_FALLOUT: case ACTION_FORTIFY: @@ -8718,6 +8787,7 @@ action_target_kind_default(enum action_result result) case ACTRES_CULTIVATE: case ACTRES_PLANT: case ACTRES_PILLAGE: + case ACTRES_CLEAN: case ACTRES_CLEAN_POLLUTION: case ACTRES_CLEAN_FALLOUT: case ACTRES_ROAD: @@ -8807,6 +8877,7 @@ bool action_result_legal_target_kind(enum action_result result, case ACTRES_TRANSFORM_TERRAIN: case ACTRES_CULTIVATE: case ACTRES_PLANT: + case ACTRES_CLEAN: case ACTRES_CLEAN_POLLUTION: case ACTRES_CLEAN_FALLOUT: case ACTRES_ROAD: @@ -8920,6 +8991,7 @@ action_sub_target_kind_default(enum action_result result) case ACTRES_SPY_ESCAPE: return ASTK_NONE; case ACTRES_PILLAGE: + case ACTRES_CLEAN: case ACTRES_CLEAN_POLLUTION: case ACTRES_CLEAN_FALLOUT: return ASTK_EXTRA; @@ -9014,6 +9086,7 @@ action_target_compl_calc(enum action_result result, case ACTRES_SPY_ESCAPE: return ACT_TGT_COMPL_SIMPLE; case ACTRES_PILLAGE: + case ACTRES_CLEAN: case ACTRES_CLEAN_POLLUTION: case ACTRES_CLEAN_FALLOUT: return ACT_TGT_COMPL_FLEXIBLE; @@ -9107,6 +9180,7 @@ const char *action_actor_consuming_always_ruleset_var_name(action_id act) case ACTION_CULTIVATE: case ACTION_PLANT: case ACTION_PILLAGE: + case ACTION_CLEAN: case ACTION_CLEAN_POLLUTION: case ACTION_CLEAN_FALLOUT: case ACTION_FORTIFY: @@ -9152,7 +9226,7 @@ const char *action_actor_consuming_always_ruleset_var_name(action_id act) case ACTION_UNIT_MOVE2: case ACTION_UNIT_MOVE3: case ACTION_SPY_ESCAPE: - /* actor consuming always is not ruleset changeable */ + /* Actor consuming always is not ruleset changeable */ return NULL; case ACTION_FOUND_CITY: return "found_city_consuming_always"; @@ -9283,6 +9357,7 @@ const char *action_blocked_by_ruleset_var_name(const struct action *act) case ACTION_CULTIVATE: case ACTION_PLANT: case ACTION_PILLAGE: + case ACTION_CLEAN: case ACTION_CLEAN_POLLUTION: case ACTION_CLEAN_FALLOUT: case ACTION_FORTIFY: @@ -9424,6 +9499,7 @@ action_post_success_forced_ruleset_var_name(const struct action *act) case ACTION_CULTIVATE: case ACTION_PLANT: case ACTION_PILLAGE: + case ACTION_CLEAN: case ACTION_CLEAN_POLLUTION: case ACTION_CLEAN_FALLOUT: case ACTION_FORTIFY: diff --git a/common/actions.h b/common/actions.h index eb801f1706..8d781f69d0 100644 --- a/common/actions.h +++ b/common/actions.h @@ -287,14 +287,16 @@ extern "C" { #define SPECENUM_VALUE109NAME "Unit Move 2" #define SPECENUM_VALUE110 ACTION_UNIT_MOVE3 #define SPECENUM_VALUE110NAME "Unit Move 3" -#define SPECENUM_VALUE111 ACTION_USER_ACTION1 -#define SPECENUM_VALUE111NAME "User Action 1" -#define SPECENUM_VALUE112 ACTION_USER_ACTION2 -#define SPECENUM_VALUE112NAME "User Action 2" -#define SPECENUM_VALUE113 ACTION_USER_ACTION3 -#define SPECENUM_VALUE113NAME "User Action 3" -#define SPECENUM_VALUE114 ACTION_USER_ACTION4 -#define SPECENUM_VALUE114NAME "User Action 4" +#define SPECENUM_VALUE111 ACTION_CLEAN +#define SPECENUM_VALUE111NAME "Clean" +#define SPECENUM_VALUE112 ACTION_USER_ACTION1 +#define SPECENUM_VALUE112NAME "User Action 1" +#define SPECENUM_VALUE113 ACTION_USER_ACTION2 +#define SPECENUM_VALUE113NAME "User Action 2" +#define SPECENUM_VALUE114 ACTION_USER_ACTION3 +#define SPECENUM_VALUE114NAME "User Action 3" +#define SPECENUM_VALUE115 ACTION_USER_ACTION4 +#define SPECENUM_VALUE115NAME "User Action 4" #define SPECENUM_BITVECTOR bv_actions #define SPECENUM_COUNT ACTION_COUNT #include "specenum_gen.h" diff --git a/common/aicore/aiactions.c b/common/aicore/aiactions.c index a590e0ba38..8d18f89fd3 100644 --- a/common/aicore/aiactions.c +++ b/common/aicore/aiactions.c @@ -1,4 +1,4 @@ -/********************************************************************** +/*********************************************************************** Freeciv - Copyright (C) 2020 - The Freeciv Project contributors. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,10 +18,8 @@ /* common */ #include "unittype.h" - #include "aiactions.h" - /**********************************************************************//** Returns TRUE if the specified unit type is able to perform diplomatic actions against cities. @@ -68,9 +66,9 @@ bool aia_utype_is_considered_spy(const struct unit_type *putype) bool aia_utype_is_considered_caravan_trade(const struct unit_type *putype) { return (utype_can_do_action_result(putype, - ACTRES_TRADE_ROUTE) + ACTRES_TRADE_ROUTE) || utype_can_do_action_result(putype, - ACTRES_MARKETPLACE)); + ACTRES_MARKETPLACE)); } /**********************************************************************//** @@ -81,7 +79,7 @@ bool aia_utype_is_considered_caravan(const struct unit_type *putype) { return (aia_utype_is_considered_caravan_trade(putype) || utype_can_do_action_result(putype, - ACTRES_HELP_WONDER)); + ACTRES_HELP_WONDER)); } /**********************************************************************//** @@ -97,6 +95,7 @@ bool aia_utype_is_considered_worker(const struct unit_type *putype) || utype_can_do_action_result(putype, ACTRES_BASE) || utype_can_do_action_result(putype, ACTRES_MINE) || utype_can_do_action_result(putype, ACTRES_IRRIGATE) + || utype_can_do_action_result(putype, ACTRES_CLEAN) || utype_can_do_action_result(putype, ACTRES_CLEAN_POLLUTION) || utype_can_do_action_result(putype, ACTRES_CLEAN_FALLOUT)); } diff --git a/common/aicore/aiactions.h b/common/aicore/aiactions.h index 17597a2665..8592b13d99 100644 --- a/common/aicore/aiactions.h +++ b/common/aicore/aiactions.h @@ -1,4 +1,4 @@ -/********************************************************************** +/*********************************************************************** Freeciv - Copyright (C) 2020 - The Freeciv Project contributors. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -10,17 +10,16 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ***********************************************************************/ - #ifndef FC_AI_ACTIONS_H #define FC_AI_ACTIONS_H -/* common */ -#include "fc_types.h" - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ +/* common */ +#include "fc_types.h" + bool aia_utype_is_considered_spy_vs_city(const struct unit_type *putype); bool aia_utype_is_considered_spy(const struct unit_type *putype); bool aia_utype_is_considered_worker(const struct unit_type *putype); diff --git a/common/clientutils.c b/common/clientutils.c index 3c42ef5cc0..cceadf5cf4 100644 --- a/common/clientutils.c +++ b/common/clientutils.c @@ -248,6 +248,7 @@ const char *concat_tile_activity_text(struct tile *ptile) case ACTIVITY_PILLAGE: rmcause = ERM_PILLAGE; break; + case ACTIVITY_CLEAN: /* ERM_CLEANPOLLUTION first, ERM_CLEANFALLOUT later */ case ACTIVITY_POLLUTION: rmcause = ERM_CLEANPOLLUTION; break; @@ -275,6 +276,23 @@ const char *concat_tile_activity_text(struct tile *ptile) } } extra_type_by_rmcause_iterate_end; } + + if (i == ACTIVITY_CLEAN) { + extra_type_by_rmcause_iterate(ERM_CLEANFALLOUT, ep) { + if (!is_extra_caused_by(ep, ERM_CLEANPOLLUTION)) { + int ei = extra_index(ep); + + if (calc->rmextra_turns[ei][i] > 0) { + if (num_activities > 0) { + astr_add(&str, "/"); + } + astr_add(&str, _("Clean %s(%d)"), + extra_name_translation(ep), calc->rmextra_turns[ei][i]); + num_activities++; + } + } + } extra_type_by_rmcause_iterate_end; + } } else if (is_tile_activity(i)) { if (calc->activity_turns[i] > 0) { if (num_activities > 0) { diff --git a/common/fc_types.h b/common/fc_types.h index 34003134d0..38de637c6c 100644 --- a/common/fc_types.h +++ b/common/fc_types.h @@ -191,6 +191,9 @@ enum counter_target { CTGT_CITY }; /* Action with the result ACTRES_PLANT */ #define SPECENUM_VALUE22 ACTIVITY_PLANT #define SPECENUM_VALUE22NAME N_("Plant") +/* Action with the result ACTRES_CLEAN */ +#define SPECENUM_VALUE23 ACTIVITY_CLEAN +#define SPECENUM_VALUE23NAME N_("Clean") /* Number of activities */ #define SPECENUM_COUNT ACTIVITY_LAST #include "specenum_gen.h" @@ -325,6 +328,8 @@ enum counter_target { CTGT_CITY }; #define SPECENUM_VALUE62NAME "Unit Spy Escape" #define SPECENUM_VALUE63 ACTRES_TRANSPORT_LOAD #define SPECENUM_VALUE63NAME "Unit Transport Load" +#define SPECENUM_VALUE64 ACTRES_CLEAN +#define SPECENUM_VALUE64NAME "Clean" /* All consequences are handled as (ruleset) action data. */ #define SPECENUM_COUNT ACTRES_NONE #include "specenum_gen.h" diff --git a/common/terrain.c b/common/terrain.c index 8c34e6988e..2321f159fd 100644 --- a/common/terrain.c +++ b/common/terrain.c @@ -756,6 +756,41 @@ int terrain_extra_removal_time(const struct terrain *pterrain, /* Terrain and activity specific removal time */ switch (activity) { + case ACTIVITY_CLEAN: + { + if (tgt == NULL) { + if (pterrain->clean_pollution_time > 0 + && pterrain->clean_fallout_time > 0) { + return MIN(pterrain->clean_pollution_time, pterrain->clean_fallout_time) + * factor; + } + + if (pterrain->clean_pollution_time > 0) { + return pterrain->clean_pollution_time * factor; + } + + return pterrain->clean_fallout_time * factor; + } + + if (is_extra_removed_by(tgt, ERM_CLEANPOLLUTION)) { + if (!is_extra_removed_by(tgt, ERM_CLEANFALLOUT)) { + return pterrain->clean_pollution_time * factor; + } + + /* Has both removal causes */ + if (pterrain->clean_pollution_time > 0 + && pterrain->clean_fallout_time > 0) { + return MIN(pterrain->clean_pollution_time, pterrain->clean_fallout_time) + * factor; + } + + if (pterrain->clean_pollution_time > 0) { + return pterrain->clean_pollution_time * factor; + } + } + + return pterrain->clean_fallout_time * factor; + } case ACTIVITY_POLLUTION: return pterrain->clean_pollution_time * factor; case ACTIVITY_FALLOUT: diff --git a/common/tile.c b/common/tile.c index 9ba12eba29..c55edc3306 100644 --- a/common/tile.c +++ b/common/tile.c @@ -424,6 +424,7 @@ int tile_activity_time(enum unit_activity activity, const struct tile *ptile, && activity != ACTIVITY_AIRBASE, FC_INFINITY); switch (activity) { + case ACTIVITY_CLEAN: case ACTIVITY_POLLUTION: case ACTIVITY_FALLOUT: case ACTIVITY_PILLAGE: @@ -696,6 +697,7 @@ bool tile_apply_activity(struct tile *ptile, Activity_type_id act, case ACTIVITY_PILLAGE: case ACTIVITY_BASE: case ACTIVITY_GEN_ROAD: + case ACTIVITY_CLEAN: case ACTIVITY_POLLUTION: case ACTIVITY_FALLOUT: /* do nothing - not implemented */ diff --git a/common/unit.c b/common/unit.c index e7fc60e076..62e0515be7 100644 --- a/common/unit.c +++ b/common/unit.c @@ -529,6 +529,7 @@ bool activity_requires_target(enum unit_activity activity) case ACTIVITY_GEN_ROAD: case ACTIVITY_IRRIGATE: case ACTIVITY_MINE: + case ACTIVITY_CLEAN: case ACTIVITY_POLLUTION: case ACTIVITY_FALLOUT: return TRUE; @@ -618,6 +619,8 @@ const char *get_activity_text(enum unit_activity activity) switch (activity) { case ACTIVITY_IDLE: return _("Idle"); + case ACTIVITY_CLEAN: + return _("Clean"); case ACTIVITY_POLLUTION: return _("Pollution"); case ACTIVITY_MINE: @@ -954,6 +957,13 @@ bool can_unit_do_activity_targeted_at(const struct unit *punit, case ACTIVITY_GOTO: return TRUE; + case ACTIVITY_CLEAN: + /* The call below doesn't support actor tile speculation. */ + fc_assert_msg(unit_tile(punit) == ptile, + "Please use action_speculate_unit_on_tile()"); + return is_action_enabled_unit_on_tile(ACTION_CLEAN, + punit, ptile, target); + case ACTIVITY_POLLUTION: /* The call below doesn't support actor tile speculation. */ fc_assert_msg(unit_tile(punit) == ptile, @@ -1194,6 +1204,7 @@ void unit_activity_astr(const struct unit *punit, struct astring *astr) move_points_text(punit->moves_left, FALSE)); } return; + case ACTIVITY_CLEAN: case ACTIVITY_POLLUTION: case ACTIVITY_FALLOUT: case ACTIVITY_OLD_ROAD: @@ -1523,6 +1534,7 @@ bool is_clean_activity(enum unit_activity activity) { switch (activity) { case ACTIVITY_PILLAGE: + case ACTIVITY_CLEAN: case ACTIVITY_POLLUTION: case ACTIVITY_FALLOUT: return TRUE; @@ -2567,8 +2579,9 @@ bool unit_order_list_is_sane(int length, const struct unit_order *orders) /* Replaced by action orders */ case ACTIVITY_BASE: case ACTIVITY_GEN_ROAD: - case ACTIVITY_FALLOUT: + case ACTIVITY_CLEAN: case ACTIVITY_POLLUTION: + case ACTIVITY_FALLOUT: case ACTIVITY_PILLAGE: case ACTIVITY_MINE: case ACTIVITY_IRRIGATE: diff --git a/common/unittype.c b/common/unittype.c index f7132a80b9..7282d462e0 100644 --- a/common/unittype.c +++ b/common/unittype.c @@ -359,6 +359,7 @@ static bool action_is_hostile(action_id act_id) case ACTRES_TRANSFORM_TERRAIN: case ACTRES_CULTIVATE: case ACTRES_PLANT: + case ACTRES_CLEAN: case ACTRES_CLEAN_POLLUTION: case ACTRES_CLEAN_FALLOUT: case ACTRES_FORTIFY: diff --git a/doc/README.actions b/doc/README.actions index b77da44470..5ce597ebc9 100644 --- a/doc/README.actions +++ b/doc/README.actions @@ -1143,6 +1143,22 @@ Actions done by a unit against a tile * the target extra must be the rule chosen extra if the civstyle section's pillage_select is FALSE +"Clean" - clean extra from the target tile. + * UI name can be set using ui_name_clean + * actor must be on the same tile as the target. + * the actor unit has the "Settlers" unit type flag (!) + * the target extra must be present at the target tile + * the terrain of the target tile must have a non 0 clean_pollution_time + or non 0 clean_fallout_time, depending on the removal cause + of the extra + * the target extra must have the CleanPollution or + CleanFallout removal cause + * the target extra's rmreqs must be fulfilled + * the target extra can't have the AlwaysOnCityCenter extra flag if the + target tile has a city + * the target extra can't have the AutoOnCityCenter extra flag if the + target tile has a city and the city's owner can rebuild it + "Clean Pollution" - clean extra from the target tile. * UI name can be set using ui_name_clean_pollution * actor must be on the same tile as the target. diff --git a/server/advisors/advdata.c b/server/advisors/advdata.c index 3e3df92897..18f75f69a1 100644 --- a/server/advisors/advdata.c +++ b/server/advisors/advdata.c @@ -918,6 +918,7 @@ adv_want adv_gov_action_immunity_want(struct government *gov) case ACTRES_BASE: case ACTRES_MINE: case ACTRES_IRRIGATE: + case ACTRES_CLEAN: case ACTRES_CLEAN_POLLUTION: case ACTRES_CLEAN_FALLOUT: case ACTRES_TRANSPORT_ALIGHT: diff --git a/server/advisors/autosettlers.c b/server/advisors/autosettlers.c index 9878663394..e67879b1b4 100644 --- a/server/advisors/autosettlers.c +++ b/server/advisors/autosettlers.c @@ -98,29 +98,31 @@ void auto_settlers_ruleset_init(void) i = 0; action_array_add_all_by_result(as_actions_transform, &i, - ACTRES_CULTIVATE); + ACTRES_CULTIVATE); action_array_add_all_by_result(as_actions_transform, &i, - ACTRES_PLANT); + ACTRES_PLANT); action_array_add_all_by_result(as_actions_transform, &i, - ACTRES_TRANSFORM_TERRAIN); + ACTRES_TRANSFORM_TERRAIN); action_array_end(as_actions_transform, i); i = 0; action_array_add_all_by_result(as_actions_extra, &i, - ACTRES_IRRIGATE); + ACTRES_IRRIGATE); action_array_add_all_by_result(as_actions_extra, &i, - ACTRES_MINE); + ACTRES_MINE); action_array_add_all_by_result(as_actions_extra, &i, - ACTRES_ROAD); + ACTRES_ROAD); action_array_add_all_by_result(as_actions_extra, &i, - ACTRES_BASE); + ACTRES_BASE); action_array_end(as_actions_extra, i); i = 0; action_array_add_all_by_result(as_actions_rmextra, &i, - ACTRES_CLEAN_POLLUTION); + ACTRES_CLEAN); action_array_add_all_by_result(as_actions_rmextra, &i, - ACTRES_CLEAN_FALLOUT); + ACTRES_CLEAN_POLLUTION); + action_array_add_all_by_result(as_actions_rmextra, &i, + ACTRES_CLEAN_FALLOUT); /* We could have ACTRES_PILLAGE here, but currently we don't */ action_array_end(as_actions_rmextra, i); } diff --git a/server/savegame/savecompat.c b/server/savegame/savecompat.c index 048386a50a..7699626805 100644 --- a/server/savegame/savecompat.c +++ b/server/savegame/savecompat.c @@ -1655,8 +1655,9 @@ static void unit_order_activity_to_action(struct unit *act_unit) } switch (order->activity) { - case ACTIVITY_FALLOUT: + case ACTIVITY_CLEAN: case ACTIVITY_POLLUTION: + case ACTIVITY_FALLOUT: case ACTIVITY_MINE: case ACTIVITY_IRRIGATE: case ACTIVITY_PLANT: @@ -1669,6 +1670,7 @@ static void unit_order_activity_to_action(struct unit *act_unit) case ACTIVITY_PILLAGE: action_iterate(act_id) { struct action *paction = action_by_number(act_id); + if (action_get_activity(paction) == order->activity) { order->order = ORDER_PERFORM_ACTION; order->action = action_number(paction); diff --git a/server/savegame/savegame2.c b/server/savegame/savegame2.c index 2073e1aad3..ba68473d4f 100644 --- a/server/savegame/savegame2.c +++ b/server/savegame/savegame2.c @@ -625,13 +625,15 @@ static enum direction8 char2dir(char dir) } /************************************************************************//** - Returns a character identifier for an activity. See also char2activity. + Returns a character identifier for an activity. See also char2activity. ****************************************************************************/ static char activity2char(enum unit_activity activity) { switch (activity) { case ACTIVITY_IDLE: return 'w'; + case ACTIVITY_CLEAN: + return 'C'; case ACTIVITY_POLLUTION: return 'p'; case ACTIVITY_OLD_ROAD: @@ -682,7 +684,7 @@ static char activity2char(enum unit_activity activity) } /************************************************************************//** - Returns an activity for a character identifier. See also activity2char. + Returns an activity for a character identifier. See also activity2char. ****************************************************************************/ static enum unit_activity char2activity(char activity) { diff --git a/server/savegame/savegame3.c b/server/savegame/savegame3.c index 4811769a5d..29eef41c40 100644 --- a/server/savegame/savegame3.c +++ b/server/savegame/savegame3.c @@ -804,13 +804,15 @@ static char dir2char(enum direction8 dir) } /************************************************************************//** - Returns a character identifier for an activity. See also char2activity. + Returns a character identifier for an activity. See also char2activity. ****************************************************************************/ static char activity2char(enum unit_activity activity) { switch (activity) { case ACTIVITY_IDLE: return 'w'; + case ACTIVITY_CLEAN: + return 'C'; case ACTIVITY_POLLUTION: return 'p'; case ACTIVITY_MINE: @@ -859,7 +861,7 @@ static char activity2char(enum unit_activity activity) } /************************************************************************//** - Returns an activity for a character identifier. See also activity2char. + Returns an activity for a character identifier. See also activity2char. ****************************************************************************/ static enum unit_activity char2activity(char activity) { diff --git a/server/unithand.c b/server/unithand.c index 5255b35334..e782df7db9 100644 --- a/server/unithand.c +++ b/server/unithand.c @@ -1158,6 +1158,7 @@ static struct player *need_war_player_hlp(const struct unit *actor, case ACTRES_CULTIVATE: case ACTRES_PLANT: case ACTRES_PILLAGE: + case ACTRES_CLEAN: case ACTRES_CLEAN_POLLUTION: case ACTRES_CLEAN_FALLOUT: case ACTRES_FORTIFY: @@ -3912,12 +3913,8 @@ bool unit_perform_action(struct player *pplayer, paction, &target_extra)); break; + case ACTRES_CLEAN: case ACTRES_CLEAN_POLLUTION: - ACTION_PERFORM_UNIT_TILE(action_type, actor_unit, target_tile, - do_action_activity_targeted(actor_unit, - paction, - &target_extra)); - break; case ACTRES_CLEAN_FALLOUT: ACTION_PERFORM_UNIT_TILE(action_type, actor_unit, target_tile, do_action_activity_targeted(actor_unit, @@ -4300,6 +4297,13 @@ void handle_unit_change_activity(struct player *pplayer, int unit_id, activity_target = base_extra_get(pbase); } + } else if (activity == ACTIVITY_CLEAN) { + activity_target = prev_extra_in_tile(unit_tile(punit), ERM_CLEANPOLLUTION, + pplayer, punit); + if (activity_target == NULL) { + activity_target = prev_extra_in_tile(unit_tile(punit), ERM_CLEANFALLOUT, + pplayer, punit); + } } else if (activity == ACTIVITY_POLLUTION) { activity_target = prev_extra_in_tile(unit_tile(punit), ERM_CLEANPOLLUTION, pplayer, punit); @@ -6485,7 +6489,7 @@ static bool unit_activity_targeted_internal(struct unit *punit, unit_activity_handling(punit, new_activity); } else { set_unit_activity_targeted(punit, new_activity, *new_target); - send_unit_info(NULL, punit); + send_unit_info(NULL, punit); unit_activity_dependencies(punit, old_activity, old_target); if (new_activity == ACTIVITY_PILLAGE) { diff --git a/server/unittools.c b/server/unittools.c index eae07942fb..851d2f95aa 100644 --- a/server/unittools.c +++ b/server/unittools.c @@ -888,6 +888,7 @@ static void update_unit_activity(struct unit *punit) punit->activity_count += get_activity_rate_this_turn(punit); break; + case ACTIVITY_CLEAN: case ACTIVITY_POLLUTION: case ACTIVITY_MINE: case ACTIVITY_IRRIGATE: @@ -900,7 +901,7 @@ static void update_unit_activity(struct unit *punit) case ACTIVITY_GEN_ROAD: punit->activity_count += get_activity_rate_this_turn(punit); - /* settler may become veteran when doing something useful */ + /* Settler may become veteran when doing something useful */ if (maybe_become_veteran_real(punit, 100, TRUE)) { notify_unit_experience(punit); } @@ -925,7 +926,7 @@ static void update_unit_activity(struct unit *punit) case ACTIVITY_CONVERT: case ACTIVITY_PATROL_UNUSED: case ACTIVITY_LAST: - /* no default, ensure all handled */ + /* No default, ensure all handled */ break; case ACTIVITY_EXPLORE: @@ -945,6 +946,54 @@ static void update_unit_activity(struct unit *punit) } break; + case ACTIVITY_CLEAN: + /* TODO: Remove this fallback target setting when target always correctly + * set */ + { + struct extra_type *pextra; + struct extra_type *fextra; + + if (punit->activity_target == NULL) { + pextra = prev_extra_in_tile(ptile, ERM_CLEANPOLLUTION, + NULL, punit); + + if (pextra != NULL) { + punit->activity_target = pextra; + fextra = NULL; /* fextra not needed, keep compiler happy */ + } else { + fextra = prev_extra_in_tile(ptile, ERM_CLEANFALLOUT, + NULL, punit); + punit->activity_target = fextra; + } + } else { + if (is_extra_removed_by(punit->activity_target, ERM_CLEANPOLLUTION)) { + pextra = punit->activity_target; + fextra = NULL; /* fextra not needed, keep compiler happy */ + } else { + pextra = NULL; + + if (is_extra_removed_by(punit->activity_target, ERM_CLEANFALLOUT)) { + fextra = punit->activity_target; + } else { + fextra = NULL; + } + } + } + + if (pextra != NULL) { + if (total_activity_done(ptile, ACTIVITY_CLEAN, pextra)) { + destroy_extra(ptile, pextra); + unit_activity_done = TRUE; + } + } else if (fextra != NULL) { + if (total_activity_done(ptile, ACTIVITY_CLEAN, fextra)) { + destroy_extra(ptile, fextra); + unit_activity_done = TRUE; + } + } + } + break; + case ACTIVITY_POLLUTION: /* TODO: Remove this fallback target setting when target always correctly * set */ @@ -3595,7 +3644,7 @@ static bool unit_move_consequences(struct unit *punit, } /**********************************************************************//** - Check if the units activity is legal for a move , and reset it if + Check if the units activity is legal for a move, and reset it if it isn't. **************************************************************************/ static void check_unit_activity(struct unit *punit) @@ -3606,7 +3655,9 @@ static void check_unit_activity(struct unit *punit) case ACTIVITY_EXPLORE: case ACTIVITY_GOTO: break; + case ACTIVITY_CLEAN: case ACTIVITY_POLLUTION: + case ACTIVITY_FALLOUT: case ACTIVITY_MINE: case ACTIVITY_IRRIGATE: case ACTIVITY_CULTIVATE: @@ -3618,7 +3669,6 @@ static void check_unit_activity(struct unit *punit) case ACTIVITY_UNKNOWN: case ACTIVITY_AIRBASE: case ACTIVITY_FORTIFYING: - case ACTIVITY_FALLOUT: case ACTIVITY_PATROL_UNUSED: case ACTIVITY_BASE: case ACTIVITY_GEN_ROAD: -- 2.35.1