From 44d3de9ce81f636213e0c99504f346db0c4bc067 Mon Sep 17 00:00:00 2001 From: sveinung Date: Fri, 5 May 2017 10:30:07 +0000 Subject: [PATCH] Add action property actor_consuming_always. Introduce the new action property actor_consuming_always. It is true if successfully performing the action always consumes the actor. Have it replace the spends_unit parameter of diplomat_embassy() and diplomat_investigate(). See hrm Feature #657303 git-svn-id: svn://svn.gna.org/svn/freeciv/trunk@35404 a0f10bec-cc02-0410-94fc-a9cfff90b4cd --- common/actions.c | 83 +++++++++++++++++++++++++++++++----------------------- common/actions.h | 6 ++++ common/unittype.c | 11 ++++++++ common/unittype.h | 3 ++ server/diplomats.c | 34 +++++++++++----------- server/diplomats.h | 6 ++-- server/unithand.c | 17 +++-------- 7 files changed, 89 insertions(+), 71 deletions(-) diff --git a/common/actions.c b/common/actions.c index 5999139176..e8b363d05e 100644 --- a/common/actions.c +++ b/common/actions.c @@ -86,7 +86,8 @@ static struct action *action_new(enum gen_action id, bool rare_pop_up, bool unitwaittime_controlled, const int min_distance, - const int max_distance); + const int max_distance, + bool actor_consuming_always); static bool is_enabler_active(const struct action_enabler *enabler, const struct player *actor_player, @@ -324,74 +325,75 @@ static void hard_code_actions(void) { actions[ACTION_SPY_POISON] = action_new(ACTION_SPY_POISON, ATK_CITY, TRUE, FALSE, FALSE, TRUE, - 0, 1); + 0, 1, FALSE); actions[ACTION_SPY_SABOTAGE_UNIT] = action_new(ACTION_SPY_SABOTAGE_UNIT, ATK_UNIT, TRUE, FALSE, FALSE, TRUE, - 0, 1); + 0, 1, FALSE); actions[ACTION_SPY_BRIBE_UNIT] = action_new(ACTION_SPY_BRIBE_UNIT, ATK_UNIT, TRUE, FALSE, FALSE, TRUE, - 0, 1); + 0, 1, FALSE); actions[ACTION_SPY_SABOTAGE_CITY] = action_new(ACTION_SPY_SABOTAGE_CITY, ATK_CITY, TRUE, FALSE, FALSE, TRUE, - 0, 1); + 0, 1, FALSE); actions[ACTION_SPY_TARGETED_SABOTAGE_CITY] = action_new(ACTION_SPY_TARGETED_SABOTAGE_CITY, ATK_CITY, TRUE, TRUE, FALSE, TRUE, - 0, 1); + 0, 1, FALSE); actions[ACTION_SPY_INCITE_CITY] = action_new(ACTION_SPY_INCITE_CITY, ATK_CITY, TRUE, FALSE, FALSE, TRUE, - 0, 1); + 0, 1, FALSE); actions[ACTION_ESTABLISH_EMBASSY] = action_new(ACTION_ESTABLISH_EMBASSY, ATK_CITY, FALSE, FALSE, FALSE, TRUE, - 0, 1); + 0, 1, FALSE); actions[ACTION_ESTABLISH_EMBASSY_STAY] = action_new(ACTION_ESTABLISH_EMBASSY_STAY, ATK_CITY, FALSE, FALSE, FALSE, TRUE, - 0, 1); + 0, 1, TRUE); actions[ACTION_SPY_STEAL_TECH] = action_new(ACTION_SPY_STEAL_TECH, ATK_CITY, TRUE, FALSE, FALSE, TRUE, - 0, 1); + 0, 1, FALSE); actions[ACTION_SPY_TARGETED_STEAL_TECH] = action_new(ACTION_SPY_TARGETED_STEAL_TECH, ATK_CITY, TRUE, TRUE, FALSE, TRUE, - 0, 1); + 0, 1, FALSE); actions[ACTION_SPY_INVESTIGATE_CITY] = action_new(ACTION_SPY_INVESTIGATE_CITY, ATK_CITY, TRUE, FALSE, FALSE, TRUE, - 0, 1); + 0, 1, FALSE); actions[ACTION_INV_CITY_SPEND] = action_new(ACTION_INV_CITY_SPEND, ATK_CITY, TRUE, FALSE, FALSE, TRUE, - 0, 1); + 0, 1, TRUE); actions[ACTION_SPY_STEAL_GOLD] = action_new(ACTION_SPY_STEAL_GOLD, ATK_CITY, TRUE, FALSE, FALSE, TRUE, - 0, 1); + 0, 1, FALSE); actions[ACTION_TRADE_ROUTE] = action_new(ACTION_TRADE_ROUTE, ATK_CITY, FALSE, FALSE, FALSE, TRUE, - 0, 1); + 0, 1, TRUE); actions[ACTION_MARKETPLACE] = action_new(ACTION_MARKETPLACE, ATK_CITY, FALSE, FALSE, FALSE, TRUE, - 0, 1); + 0, 1, TRUE); actions[ACTION_HELP_WONDER] = action_new(ACTION_HELP_WONDER, ATK_CITY, FALSE, FALSE, FALSE, TRUE, - 0, 1); + 0, 1, TRUE); actions[ACTION_CAPTURE_UNITS] = action_new(ACTION_CAPTURE_UNITS, ATK_UNITS, TRUE, FALSE, FALSE, TRUE, /* A single domestic unit at the target tile will make the * action illegal. It must therefore be performed from * another tile. */ - 1, 1); + 1, 1, + FALSE); actions[ACTION_FOUND_CITY] = action_new(ACTION_FOUND_CITY, ATK_TILE, FALSE, FALSE, TRUE, TRUE, @@ -399,15 +401,16 @@ static void hard_code_actions(void) * Reason: The Freeciv code assumes that the city founding * unit is located at the tile were the new city is * founded. */ - 0, 0); + 0, 0, + TRUE); actions[ACTION_JOIN_CITY] = action_new(ACTION_JOIN_CITY, ATK_CITY, FALSE, FALSE, TRUE, TRUE, - 0, 1); + 0, 1, TRUE); actions[ACTION_STEAL_MAPS] = action_new(ACTION_STEAL_MAPS, ATK_CITY, TRUE, FALSE, FALSE, TRUE, - 0, 1); + 0, 1, FALSE); actions[ACTION_BOMBARD] = action_new(ACTION_BOMBARD, /* FIXME: Target is actually Units + City */ @@ -418,58 +421,63 @@ static void hard_code_actions(void) * another tile. */ 1, /* Overwritten by the ruleset's bombard_max_range */ - 1); + 1, + FALSE); actions[ACTION_SPY_NUKE] = action_new(ACTION_SPY_NUKE, ATK_CITY, TRUE, FALSE, FALSE, TRUE, - 0, 1); + 0, 1, FALSE); actions[ACTION_NUKE] = action_new(ACTION_NUKE, /* FIXME: Target is actually Tile + Units + City */ ATK_TILE, TRUE, FALSE, TRUE, TRUE, - 0, 1); + 0, 1, TRUE); actions[ACTION_DESTROY_CITY] = action_new(ACTION_DESTROY_CITY, ATK_CITY, TRUE, FALSE, TRUE, TRUE, - 0, 1); + 0, 1, FALSE); actions[ACTION_EXPEL_UNIT] = action_new(ACTION_EXPEL_UNIT, ATK_UNIT, TRUE, FALSE, FALSE, TRUE, - 0, 1); + 0, 1, FALSE); actions[ACTION_RECYCLE_UNIT] = action_new(ACTION_RECYCLE_UNIT, ATK_CITY, FALSE, FALSE, TRUE, TRUE, /* Illegal to perform to a target on another tile to * keep the rules exactly as they were for now. */ - 0, 1); + 0, 1, + TRUE); actions[ACTION_DISBAND_UNIT] = action_new(ACTION_DISBAND_UNIT, ATK_SELF, FALSE, FALSE, TRUE, TRUE, - 0, 0); + 0, 0, TRUE); actions[ACTION_HOME_CITY] = action_new(ACTION_HOME_CITY, ATK_CITY, FALSE, FALSE, TRUE, FALSE, /* Illegal to perform to a target on another tile to * keep the rules exactly as they were for now. */ - 0, 0); + 0, 0, FALSE); actions[ACTION_UPGRADE_UNIT] = action_new(ACTION_UPGRADE_UNIT, ATK_CITY, FALSE, FALSE, TRUE, TRUE, /* Illegal to perform to a target on another tile to * keep the rules exactly as they were for now. */ - 0, 0); + 0, 0, + FALSE); actions[ACTION_PARADROP] = action_new(ACTION_PARADROP, ATK_TILE, FALSE, FALSE, TRUE, TRUE, 1, /* Still limited by each unit type's paratroopers_range * field. */ - ACTION_DISTANCE_MAX); + ACTION_DISTANCE_MAX, + FALSE); actions[ACTION_AIRLIFT] = action_new(ACTION_AIRLIFT, ATK_CITY, FALSE, FALSE, TRUE, TRUE, - 1, ACTION_DISTANCE_UNLIMITED); + 1, ACTION_DISTANCE_UNLIMITED, + FALSE); actions[ACTION_ATTACK] = action_new(ACTION_ATTACK, /* FIXME: Target is actually City and, depending on the @@ -477,15 +485,15 @@ static void hard_code_actions(void) * tile (Units) or any unit at the target tile. */ ATK_TILE, TRUE, FALSE, FALSE, TRUE, - 1, 1); + 1, 1, FALSE); actions[ACTION_CONQUER_CITY] = action_new(ACTION_CONQUER_CITY, ATK_CITY, TRUE, FALSE, FALSE, TRUE, - 1, 1); + 1, 1, FALSE); actions[ACTION_HEAL_UNIT] = action_new(ACTION_HEAL_UNIT, ATK_UNIT, FALSE, FALSE, FALSE, TRUE, - 0, 1); + 0, 1, FALSE); } /************************************************************************** @@ -614,7 +622,8 @@ static struct action *action_new(enum gen_action id, bool rare_pop_up, bool unitwaittime_controlled, const int min_distance, - const int max_distance) + const int max_distance, + bool actor_consuming_always) { struct action *action; @@ -637,6 +646,8 @@ static struct action *action_new(enum gen_action id, action->unitwaittime_controlled = unitwaittime_controlled; + action->actor_consuming_always = actor_consuming_always; + /* Loaded from the ruleset. Until generalized actions are ready it has to * be defined seperatly from other action data. */ action->ui_name[0] = '\0'; diff --git a/common/actions.h b/common/actions.h index 9aa39a04ab..673fac768a 100644 --- a/common/actions.h +++ b/common/actions.h @@ -201,6 +201,12 @@ struct action /* Actions that blocks this action. The action will be illegal if any * bloking action is legal. */ bv_actions blocked_by; + + /* Successfully performing this action will always consume the actor. + * Don't set this for actions that consumes the unit in some cases + * (depending on luck, the presence of a flag, etc) but not in other + * cases. */ + bool actor_consuming_always; }; struct action_enabler diff --git a/common/unittype.c b/common/unittype.c index 835ecc1216..3ea2004dc7 100644 --- a/common/unittype.c +++ b/common/unittype.c @@ -843,6 +843,17 @@ bool utype_may_act_tgt_city_tile(struct unit_type *punit_type, return FALSE; } +/************************************************************************** + Returns TRUE iff performing the specified action will consume an actor + unit of the specified type. +**************************************************************************/ +bool utype_is_consumed_by_action(const struct action *paction, + const struct unit_type *utype) +{ + /* Only care about the action it self for now. */ + return paction->actor_consuming_always; +} + /**************************************************************************** Returns the number of shields it takes to build this unit type. ****************************************************************************/ diff --git a/common/unittype.h b/common/unittype.h index 8985b76fd5..9f34eda169 100644 --- a/common/unittype.h +++ b/common/unittype.h @@ -634,6 +634,9 @@ bool utype_may_act_tgt_city_tile(struct unit_type *punit_type, const enum citytile_type prop, const bool is_there); +bool utype_is_consumed_by_action(const struct action *paction, + const struct unit_type *utype); + /* Functions to operate on various flag and roles. */ typedef bool (*role_unit_callback)(struct unit_type *ptype, void *data); diff --git a/server/diplomats.c b/server/diplomats.c index 4bf04f6256..d1fb5cef8e 100644 --- a/server/diplomats.c +++ b/server/diplomats.c @@ -165,16 +165,15 @@ bool spy_poison(struct player *pplayer, struct unit *pdiplomat, - It costs some minimal movement to investigate a city. - - If spends_unit is TRUE the actor unit dies after investigation. - - If it isn't the actor unit always survive. There is no risk. + - The actor unit always survives the investigation unless the action + being performed is configured to always consume the actor unit. Returns TRUE iff action could be done, FALSE if it couldn't. Even if this returns TRUE, unit may have died during the action. ****************************************************************************/ bool diplomat_investigate(struct player *pplayer, struct unit *pdiplomat, struct city *pcity, - const enum gen_action action_id, - bool spends_unit) + const struct action *paction) { struct player *cplayer; struct packet_unit_short_info unit_packet; @@ -241,12 +240,12 @@ bool diplomat_investigate(struct player *pplayer, struct unit *pdiplomat, } /* this may cause a diplomatic incident */ - action_id_consequence_success(action_id, pplayer, cplayer, - city_tile(pcity), city_link(pcity)); + action_consequence_success(paction, pplayer, cplayer, + city_tile(pcity), city_link(pcity)); - /* The actor unit always survive when spends_unit is FALSE, it never does - * when it is TRUE. */ - if (spends_unit) { + /* The actor unit always survive unless the action it self has determined + * to always consume it. */ + if (utype_is_consumed_by_action(paction, unit_type_get(pdiplomat))) { wipe_unit(pdiplomat, ULR_USED, NULL); } else { send_unit_info(NULL, pdiplomat); @@ -289,15 +288,14 @@ void spy_send_sabotage_list(struct connection *pc, struct unit *pdiplomat, - Otherwise, the embassy is created. - It costs some minimal movement to establish an embassy. - - If spends_unit is TRUE the actor unit is consumed in creation of - embassy. If it isn't the actor unit always survive. + - The actor unit always survives the investigation unless the action + being performed is configured to always consume the actor unit. Returns TRUE iff action could be done, FALSE if it couldn't. Even if this returns TRUE, unit may have died during the action. ****************************************************************************/ bool diplomat_embassy(struct player *pplayer, struct unit *pdiplomat, - struct city *pcity, const enum gen_action action_id, - bool spends_unit) + struct city *pcity, const struct action *paction) { struct player *cplayer; @@ -340,12 +338,12 @@ bool diplomat_embassy(struct player *pplayer, struct unit *pdiplomat, } /* this may cause a diplomatic incident */ - action_id_consequence_success(action_id, pplayer, cplayer, - city_tile(pcity), city_link(pcity)); + action_consequence_success(paction, pplayer, cplayer, + city_tile(pcity), city_link(pcity)); - /* The actor unit always survive when spends_unit is FALSE, it never does - * when it is TRUE. */ - if (spends_unit) { + /* The actor unit always survive unless the action it self has determined + * to always consume it. */ + if (utype_is_consumed_by_action(paction, unit_type_get(pdiplomat))) { wipe_unit(pdiplomat, ULR_USED, NULL); } else { send_unit_info(NULL, pdiplomat); diff --git a/server/diplomats.h b/server/diplomats.h index 6f39c86bbd..b3eb6b7a85 100644 --- a/server/diplomats.h +++ b/server/diplomats.h @@ -16,12 +16,10 @@ #include "fc_types.h" bool diplomat_embassy(struct player *pplayer, struct unit *pdiplomat, - struct city *pcity, const enum gen_action action_id, - bool spends_unit); + struct city *pcity, const struct action *paction); bool diplomat_investigate(struct player *pplayer, struct unit *pdiplomat, struct city *pcity, - const enum gen_action action_id, - bool spends_unit); + const struct action *paction); void spy_send_sabotage_list(struct connection *pc, struct unit *pdiplomat, struct city *pcity, const enum gen_action action_id); diff --git a/server/unithand.c b/server/unithand.c index d156b01d68..9bbdfb9a18 100644 --- a/server/unithand.c +++ b/server/unithand.c @@ -2363,28 +2363,19 @@ bool unit_perform_action(struct player *pplayer, action_type)); break; case ACTION_SPY_INVESTIGATE_CITY: - ACTION_STARTED_UNIT_CITY(action_type, actor_unit, pcity, - diplomat_investigate(pplayer, - actor_unit, pcity, - action_type, - FALSE)); - break; case ACTION_INV_CITY_SPEND: + /* Difference is caused by data in the action structure. */ ACTION_STARTED_UNIT_CITY(action_type, actor_unit, pcity, diplomat_investigate(pplayer, actor_unit, pcity, - action_type, - TRUE)); + paction)); break; case ACTION_ESTABLISH_EMBASSY: - ACTION_STARTED_UNIT_CITY(action_type, actor_unit, pcity, - diplomat_embassy(pplayer, actor_unit, pcity, - action_type, FALSE)); - break; case ACTION_ESTABLISH_EMBASSY_STAY: + /* Difference is caused by data in the action structure. */ ACTION_STARTED_UNIT_CITY(action_type, actor_unit, pcity, diplomat_embassy(pplayer, actor_unit, pcity, - action_type, TRUE)); + paction)); break; case ACTION_SPY_INCITE_CITY: ACTION_STARTED_UNIT_CITY(action_type, actor_unit, pcity, -- 2.11.4.GIT