Author: sveinung Date: Thu Mar 10 14:14:45 2016 New Revision: 32221 URL: http://svn.gna.org/viewcvs/freeciv?rev=32221&view=rev Log: Action not enabled explain ruleset terrain.
Identify cases where the action enablers make it impossible to perform an action because of the actor tile's or target tile's terrain. See patch #7047 Modified: branches/S2_6/server/unithand.c Modified: branches/S2_6/server/unithand.c URL: http://svn.gna.org/viewcvs/freeciv/branches/S2_6/server/unithand.c?rev=32221&r1=32220&r2=32221&view=diff ============================================================================== --- branches/S2_6/server/unithand.c (original) +++ branches/S2_6/server/unithand.c Thu Mar 10 14:14:45 2016 @@ -74,8 +74,10 @@ /* A category of reasons why an action isn't enabled. */ enum ane_kind { - /* Explanation: bad terrain. */ - ANEK_BAD_TERRAIN, + /* Explanation: bad actor terrain. */ + ANEK_BAD_TERRAIN_ACT, + /* Explanation: bad target terrain. */ + ANEK_BAD_TERRAIN_TGT, /* Explanation: being transported. */ ANEK_IS_TRANSPORTED, /* Explanation: not being transported. */ @@ -95,7 +97,7 @@ union { /* The bad terrain in question. */ - struct terrain *cant_act_from; + struct terrain *no_act_terrain; /* The player to advice declaring war on. */ struct player *no_war_with; @@ -597,6 +599,48 @@ } /************************************************************************** + Returns TRUE iff the specified terrain type blocks the specified action. + + If the "action" is ACTION_ANY all actions are checked. +**************************************************************************/ +static bool does_terrain_block_action(const int action_id, + bool is_target, + struct terrain *pterrain) +{ + struct universal univ_terr + = {.kind = VUT_TERRAIN, .value = {.terrain = pterrain}}; + + if (action_id == ACTION_ANY) { + /* Any action is OK. */ + action_iterate(alt_act) { + if (!does_terrain_block_action(alt_act, is_target, pterrain)) { + /* Only one action has to be possible. */ + return FALSE; + } + } action_iterate_end; + + /* No action enabled. */ + return TRUE; + } + + /* ACTION_ANY is handled above. */ + fc_assert_ret_val(action_id_is_valid(action_id), FALSE); + + action_enabler_list_iterate(action_enablers_for_action(action_id), + enabler) { + if (universal_fulfills_requirement(FALSE, + (is_target ? &enabler->target_reqs + : &enabler->actor_reqs), + &univ_terr)) { + /* This terrain kind doesn't block this action enabler. */ + return FALSE; + } + } action_enabler_list_iterate_end; + + return TRUE; +} + +/************************************************************************** Returns an explaination why punit can't perform the specified action based on the current game state. **************************************************************************/ @@ -616,8 +660,20 @@ || (can_exist && !utype_can_do_act_when_ustate(unit_type_get(punit), action_id, USP_LIVABLE_TILE, TRUE))) { - expl->kind = ANEK_BAD_TERRAIN; - expl->cant_act_from = tile_terrain(unit_tile(punit)); + expl->kind = ANEK_BAD_TERRAIN_ACT; + expl->no_act_terrain = tile_terrain(unit_tile(punit)); + } else if (punit + && does_terrain_block_action(action_id, FALSE, + tile_terrain(unit_tile(punit)))) { + /* No action enabler allows acting against this terrain kind. */ + expl->kind = ANEK_BAD_TERRAIN_ACT; + expl->no_act_terrain = tile_terrain(unit_tile(punit)); + } else if (target_tile + && does_terrain_block_action(action_id, TRUE, + tile_terrain(target_tile))) { + /* No action enabler allows acting against this terrain kind. */ + expl->kind = ANEK_BAD_TERRAIN_TGT; + expl->no_act_terrain = tile_terrain(target_tile); } else if (unit_transported(punit) && !utype_can_do_act_when_ustate(unit_type_get(punit), action_id, USP_TRANSPORTED, TRUE)) { @@ -657,10 +713,15 @@ target_city, target_unit); switch (expl->kind) { - case ANEK_BAD_TERRAIN: + case ANEK_BAD_TERRAIN_ACT: notify_player(pplayer, unit_tile(punit), E_BAD_COMMAND, ftc_server, _("Unit cannot act from %s."), - terrain_name_translation(expl->cant_act_from)); + terrain_name_translation(expl->no_act_terrain)); + break; + case ANEK_BAD_TERRAIN_TGT: + notify_player(pplayer, unit_tile(punit), E_BAD_COMMAND, ftc_server, + _("Unit cannot act against %s."), + terrain_name_translation(expl->no_act_terrain)); break; case ANEK_IS_TRANSPORTED: notify_player(pplayer, unit_tile(punit), E_BAD_COMMAND, ftc_server, @@ -864,13 +925,21 @@ expl = expl_act_not_enabl(actor, stopped_action, target_tile, target_city, target_unit); switch (expl->kind) { - case ANEK_BAD_TERRAIN: + case ANEK_BAD_TERRAIN_ACT: notify_player(pplayer, unit_tile(actor), E_UNIT_ILLEGAL_ACTION, ftc_server, _("Your %s can't do %s from %s."), unit_name_translation(actor), action_get_ui_name(stopped_action), - terrain_name_translation(expl->cant_act_from)); + terrain_name_translation(expl->no_act_terrain)); + break; + case ANEK_BAD_TERRAIN_TGT: + notify_player(pplayer, unit_tile(actor), + E_UNIT_ILLEGAL_ACTION, ftc_server, + _("Your %s can't do %s to %s."), + unit_name_translation(actor), + action_get_ui_name(stopped_action), + terrain_name_translation(expl->no_act_terrain)); break; case ANEK_IS_TRANSPORTED: notify_player(pplayer, unit_tile(actor), _______________________________________________ Freeciv-commits mailing list Freeciv-commits@gna.org https://mail.gna.org/listinfo/freeciv-commits