From 6f58703d3ada22099131b1672ef9f9dae57c5838 Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Wed, 4 Oct 2023 23:11:22 +0300 Subject: [PATCH 48/48] Disallow flagless units to stack with unknowingly allied units See osdn #48804 Signed-off-by: Marko Lindqvist --- ai/default/daimilitary.c | 4 +- ai/default/daiunit.c | 16 ++++--- ai/default/daiunit.h | 1 + client/control.c | 2 +- client/goto.c | 64 +++++++++++++++++----------- client/gui-gtk-3.22/editprop.c | 7 +-- client/gui-gtk-4.0/editprop.c | 3 +- common/actres.c | 23 ++++++---- common/aicore/pf_tools.c | 12 ++++-- common/movement.c | 8 ++-- common/scriptcore/api_game_methods.c | 2 +- common/unit.c | 12 +++++- common/unit.h | 8 ++-- server/advisors/advgoto.c | 28 ++++++------ server/advisors/autoexplorer.c | 10 +++-- server/animals.c | 3 +- server/barbarian.c | 2 +- server/edithand.c | 9 ++-- server/gamehand.c | 11 +++-- server/maphand.c | 8 ++-- server/scripting/api_server_edit.c | 9 ++-- server/unithand.c | 30 +++++++------ server/unittools.c | 23 +++++++--- 23 files changed, 186 insertions(+), 109 deletions(-) diff --git a/ai/default/daimilitary.c b/ai/default/daimilitary.c index a55daad827..6d7014b2eb 100644 --- a/ai/default/daimilitary.c +++ b/ai/default/daimilitary.c @@ -1257,7 +1257,7 @@ static void process_attacker_want(struct ai_type *ait, } if (utype_class(orig_utype)->adv.sea_move == MOVE_NONE - && !boat && boattype) { + && !boat && boattype != NULL) { /* Cost of ferry */ needferry = utype_build_shield_cost(pcity, NULL, boattype); } @@ -1336,7 +1336,7 @@ static void process_attacker_want(struct ai_type *ait, struct tile *dest_tile; if (find_beachhead(pplayer, ferry_map, ptile, punittype, - &dest_tile, NULL) + boattype, &dest_tile, NULL) && pf_map_position(ferry_map, dest_tile, &pos)) { move_time = pos.turn; dest_tile = pf_map_parameter(ferry_map)->start_tile; diff --git a/ai/default/daiunit.c b/ai/default/daiunit.c index 2727a7ecf9..eb0163fb83 100644 --- a/ai/default/daiunit.c +++ b/ai/default/daiunit.c @@ -1060,6 +1060,7 @@ static void invasion_funct(struct ai_type *ait, struct unit *punit, bool find_beachhead(const struct player *pplayer, struct pf_map *ferry_map, struct tile *dest_tile, const struct unit_type *cargo_type, + const struct unit_type *ferry_type, struct tile **ferry_dest, struct tile **beachhead_tile) { if (NULL == tile_city(dest_tile) @@ -1091,6 +1092,7 @@ bool find_beachhead(const struct player *pplayer, struct pf_map *ferry_map, struct tile *best_tile = NULL, *best_beach = NULL; struct tile_list *checked_tiles = tile_list_new(); int best_cost = PF_IMPOSSIBLE_MC, cost; + bool flagless_ferry = utype_has_flag(ferry_type, UTYF_FLAGLESS); tile_list_append(checked_tiles, dest_tile); adjc_iterate(&(wld.map), dest_tile, beach) { @@ -1098,7 +1100,8 @@ bool find_beachhead(const struct player *pplayer, struct pf_map *ferry_map, /* Can land there. */ adjc_iterate(&(wld.map), beach, ptile) { if (!tile_list_search(checked_tiles, ptile) - && !is_non_allied_unit_tile(ptile, pplayer)) { + && !is_non_allied_unit_tile(ptile, pplayer, + flagless_ferry)) { tile_list_append(checked_tiles, ptile); cost = pf_map_move_cost(ferry_map, ptile); if (cost != PF_IMPOSSIBLE_MC @@ -1363,7 +1366,7 @@ adv_want find_something_to_kill(struct ai_type *ait, struct player *pplayer, struct tile *dest, *beach; if (!find_beachhead(pplayer, ferry_map, atile, punit_type, - &dest, &beach)) { + boattype, &dest, &beach)) { continue; /* Impossible to go by boat. */ } if (!pf_map_position(ferry_map, dest, &pos)) { @@ -3111,8 +3114,9 @@ void dai_consider_tile_dangerous(struct ai_type *ait, struct tile *ptile, return; } - if (pcity && pplayers_allied(city_owner(pcity), unit_owner(punit)) - && !is_non_allied_unit_tile(ptile, pplayer)) { + if (pcity != NULL && pplayers_allied(city_owner(pcity), pplayer) + && !is_non_allied_unit_tile(ptile, pplayer, + unit_has_type_flag(punit, UTYF_FLAGLESS))) { /* We will be safe in a friendly city */ *result = OVERRIDE_FALSE; return; @@ -3127,12 +3131,12 @@ void dai_consider_tile_dangerous(struct ai_type *ait, struct tile *ptile, adjc_iterate(&(wld.map), ptile, ptile1) { if (has_handicap(pplayer, H_FOG) - && !map_is_known_and_seen(ptile1, unit_owner(punit), V_MAIN)) { + && !map_is_known_and_seen(ptile1, pplayer, V_MAIN)) { /* We cannot see danger at (ptile1) => assume there is none */ continue; } unit_list_iterate(ptile1->units, enemy) { - if (pplayers_at_war(unit_owner(enemy), unit_owner(punit)) + if (pplayers_at_war(unit_owner(enemy), pplayer) && (unit_attack_unit_at_tile_result(enemy, NULL, punit, ptile) == ATT_OK) && (unit_attack_units_at_tile_result(enemy, NULL, ptile) diff --git a/ai/default/daiunit.h b/ai/default/daiunit.h index 6fe7db7248..817e832aa3 100644 --- a/ai/default/daiunit.h +++ b/ai/default/daiunit.h @@ -106,6 +106,7 @@ bool dai_can_unit_type_follow_unit_type(const struct unit_type *follower, bool find_beachhead(const struct player *pplayer, struct pf_map *ferry_map, struct tile *dest_tile, const struct unit_type *cargo_type, + const struct unit_type *ferry_type, struct tile **ferry_dest, struct tile **beachhead_tile); adv_want find_something_to_kill(struct ai_type *ait, struct player *pplayer, struct unit *punit, diff --git a/client/control.c b/client/control.c index caa4684bb1..89138603f7 100644 --- a/client/control.c +++ b/client/control.c @@ -3190,7 +3190,7 @@ void do_unit_paradrop_to(struct unit *punit, struct tile *ptile) void do_unit_patrol_to(struct tile *ptile) { if (is_valid_goto_draw_line(ptile) - && !is_non_allied_unit_tile(ptile, client.conn.playing)) { + && !is_non_allied_unit_tile(ptile, client_player(), FALSE)) { send_patrol_route(); } else { create_event(ptile, E_BAD_COMMAND, ftc_client, diff --git a/client/goto.c b/client/goto.c index 8ac0743aa1..e2e36e6aa0 100644 --- a/client/goto.c +++ b/client/goto.c @@ -143,6 +143,7 @@ static struct unit *goto_map_unit(const struct goto_map *goto_map) fc_assert(punit != NULL); fc_assert(unit_is_in_focus(punit)); fc_assert(punit == player_unit_by_number(client_player(), punit->id)); + return punit; } @@ -559,7 +560,7 @@ static unsigned get_EC(const struct tile *ptile, enum known_type known, } /************************************************************************//** - PF callback to prohibit going into the unknown. Also makes sure we + PF callback to prohibit going into the unknown. Also makes sure we don't plan our route through enemy city/tile. ****************************************************************************/ static enum tile_behavior get_TB_aggr(const struct tile *ptile, @@ -570,11 +571,13 @@ static enum tile_behavior get_TB_aggr(const struct tile *ptile, if (!gui_options.goto_into_unknown) { return TB_IGNORE; } - } else if (is_non_allied_unit_tile(ptile, param->owner) + } else if (is_non_allied_unit_tile(ptile, param->owner, + utype_has_flag(param->utype, UTYF_FLAGLESS)) || is_non_allied_city_tile(ptile, param->owner)) { /* Can attack but can't count on going through */ return TB_DONT_LEAVE; } + return TB_NORMAL; } @@ -595,7 +598,8 @@ static enum tile_behavior get_TB_caravan(const struct tile *ptile, * establish an embassy can travel to, but not through, enemy cities. * FIXME: ACTION_HELP_WONDER units cannot. */ return TB_DONT_LEAVE; - } else if (is_non_allied_unit_tile(ptile, param->owner)) { + } else if (is_non_allied_unit_tile(ptile, param->owner, + utype_has_flag(param->utype, UTYF_FLAGLESS))) { /* Note this must be below the city check. */ return TB_IGNORE; } @@ -1431,25 +1435,29 @@ static void make_path_orders(struct unit *punit, struct pf_path *path, } if (i > 0 - && order_list[i - 1].order == ORDER_MOVE - && (is_non_allied_city_tile(old_tile, client_player()) - || is_non_allied_unit_tile(old_tile, client_player()))) { - /* Won't be able to perform a regular move to the target tile... */ - if (!final_order) { - /* ...and no final order exists. Choose what to do when the unit gets - * there. */ - order_list[i - 1].order = ORDER_ACTION_MOVE; - } else { - /* ...and a final order exist. Can't assume an action move. Did the - * caller hope that the situation would change before the unit got - * there? */ - - /* It's currently illegal to walk into tiles with non-allied units or - * cities. Some actions causes the actor to enter the target tile but - * that is a part of the action it self, not a regular pre action - * move. */ - log_verbose("unit or city blocks the path of your %s", - unit_rule_name(punit)); + && order_list[i - 1].order == ORDER_MOVE) { + struct player *cplayer = client_player(); + + if (is_non_allied_city_tile(old_tile, cplayer) + || is_non_allied_unit_tile(old_tile, cplayer, + unit_has_type_flag(punit, UTYF_FLAGLESS))) { + /* Won't be able to perform a regular move to the target tile... */ + if (!final_order) { + /* ...and no final order exists. Choose what to do when the unit gets + * there. */ + order_list[i - 1].order = ORDER_ACTION_MOVE; + } else { + /* ...and a final order exist. Can't assume an action move. Did the + * caller hope that the situation would change before the unit got + * there? */ + + /* It's currently illegal to walk into tiles with non-allied units or + * cities. Some actions causes the actor to enter the target tile but + * that is a part of the action it self, not a regular pre action + * move. */ + log_verbose("unit or city blocks the path of your %s", + unit_rule_name(punit)); + } } } @@ -1799,8 +1807,10 @@ void send_connect_route(enum unit_activity activity, Use order_demands_direction() for that. ****************************************************************************/ static bool order_wants_direction(enum unit_orders order, action_id act_id, - struct tile *tgt_tile) + struct tile *tgt_tile, struct unit *punit) { + struct player *cplayer; + switch (order) { case ORDER_MOVE: case ORDER_ACTION_MOVE: @@ -1818,8 +1828,10 @@ static bool order_wants_direction(enum unit_orders order, action_id act_id, return FALSE; } - if (is_non_allied_city_tile(tgt_tile, client_player()) - || is_non_allied_unit_tile(tgt_tile, client_player())) { + cplayer = client_player(); + if (is_non_allied_city_tile(tgt_tile, cplayer) + || is_non_allied_unit_tile(tgt_tile, cplayer, + unit_has_type_flag(punit, UTYF_FLAGLESS))) { /* Won't be able to move to the target tile to perform the action on * top of it. */ /* TODO: Detect situations where it also would be illegal to perform @@ -1936,7 +1948,7 @@ void send_goto_route(void) if (path->length > 1 && goto_last_tgt == NO_TARGET && ((on_tile = path->positions[path->length - 2].tile)) && order_wants_direction(goto_last_order, goto_last_action, - tgt_tile) + tgt_tile, punit) && !same_pos(on_tile, tgt_tile)) { /* The last order prefers to handle the last direction it self. * There exists a tile before the target tile to do it from. */ diff --git a/client/gui-gtk-3.22/editprop.c b/client/gui-gtk-3.22/editprop.c index 9ed445aa14..f9ac56b708 100644 --- a/client/gui-gtk-3.22/editprop.c +++ b/client/gui-gtk-3.22/editprop.c @@ -992,7 +992,7 @@ static gchar *built_status_to_string(struct built_status *bs) /************************************************************************//** Returns TRUE if a unit can be created at the given tile based on the - state of the editor (see editor_unit_virtual_create). + state of the editor (see editor_unit_virtual_create() ). ****************************************************************************/ static bool can_create_unit_at_tile(struct tile *ptile) { @@ -1006,7 +1006,7 @@ static bool can_create_unit_at_tile(struct tile *ptile) } vunit = editor_unit_virtual_create(); - if (!vunit) { + if (vunit == NULL) { return FALSE; } @@ -1014,7 +1014,8 @@ static bool can_create_unit_at_tile(struct tile *ptile) pplayer = unit_owner(vunit); ret = (can_unit_exist_at_tile(&(wld.map), vunit, ptile) - && !is_non_allied_unit_tile(ptile, pplayer) + && !is_non_allied_unit_tile(ptile, pplayer, + unit_has_type_flag(vunit, UTYF_FLAGLESS)) && (pcity == NULL || pplayers_allied(city_owner(pcity), unit_owner(vunit)))); diff --git a/client/gui-gtk-4.0/editprop.c b/client/gui-gtk-4.0/editprop.c index 27da1974b8..9f94e44067 100644 --- a/client/gui-gtk-4.0/editprop.c +++ b/client/gui-gtk-4.0/editprop.c @@ -1014,7 +1014,8 @@ static bool can_create_unit_at_tile(struct tile *ptile) pplayer = unit_owner(vunit); ret = (can_unit_exist_at_tile(&(wld.map), vunit, ptile) - && !is_non_allied_unit_tile(ptile, pplayer) + && !is_non_allied_unit_tile(ptile, pplayer, + unit_has_type_flag(vunit, UTYF_FLAGLESS)) && (pcity == NULL || pplayers_allied(city_owner(pcity), unit_owner(vunit)))); diff --git a/common/actres.c b/common/actres.c index 8ed851584c..4c11bd8da4 100644 --- a/common/actres.c +++ b/common/actres.c @@ -955,10 +955,12 @@ enum fc_tristate actres_possible(enum action_result result, * units or cities not allied with all of our cargo. */ if (get_transporter_capacity(actor->unit) > 0) { unit_list_iterate(unit_tile(actor->unit)->units, pcargo) { + struct player *cowner = unit_owner(pcargo); + if (unit_contained_in(pcargo, actor->unit) - && (is_non_allied_unit_tile(target->tile, unit_owner(pcargo)) - || is_non_allied_city_tile(target->tile, - unit_owner(pcargo)))) { + && (is_non_allied_unit_tile(target->tile, cowner, + unit_has_type_flag(pcargo, UTYF_FLAGLESS)) + || is_non_allied_city_tile(target->tile, cowner))) { return TRI_NO; } } unit_list_iterate_end; @@ -985,10 +987,13 @@ enum fc_tristate actres_possible(enum action_result result, * units or cities not allied with all of our cargo. */ if (get_transporter_capacity(actor->unit) > 0) { unit_list_iterate(unit_tile(actor->unit)->units, pcargo) { + struct player *cowner = unit_owner(pcargo); + if (unit_contained_in(pcargo, actor->unit) - && (is_non_allied_unit_tile(target->tile, unit_owner(pcargo)) + && (is_non_allied_unit_tile(target->tile, cowner, + unit_has_type_flag(pcargo, UTYF_FLAGLESS)) || is_non_allied_city_tile(target->tile, - unit_owner(pcargo)))) { + cowner))) { return TRI_NO; } } unit_list_iterate_end; @@ -1076,10 +1081,12 @@ enum fc_tristate actres_possible(enum action_result result, * units or cities not allied with ani of our cargo. */ if (get_transporter_capacity(actor->unit) > 0) { unit_list_iterate(unit_tile(actor->unit)->units, pcargo) { + struct player *cowner = unit_owner(pcargo); + if (unit_contained_in(pcargo, actor->unit) - && (is_non_allied_unit_tile(target->tile, unit_owner(pcargo)) - || is_non_allied_city_tile(target->tile, - unit_owner(pcargo)))) { + && (is_non_allied_unit_tile(target->tile, cowner, + unit_has_type_flag(pcargo, UTYF_FLAGLESS)) + || is_non_allied_city_tile(target->tile, cowner))) { return TRI_NO; } } unit_list_iterate_end; diff --git a/common/aicore/pf_tools.c b/common/aicore/pf_tools.c index fb0304f90e..6ca898bf3c 100644 --- a/common/aicore/pf_tools.c +++ b/common/aicore/pf_tools.c @@ -109,7 +109,8 @@ static enum pf_action pf_get_action(const struct tile *ptile, } } - if (is_non_allied_unit_tile(ptile, param->owner)) { + if (is_non_allied_unit_tile(ptile, param->owner, + utype_has_flag(param->utype, UTYF_FLAGLESS))) { if (PF_AA_DIPLOMAT & param->actions) { return PF_ACTION_DIPLOMAT; } @@ -495,7 +496,8 @@ enum tile_behavior no_fights_or_unknown(const struct tile *ptile, const struct pf_parameter *param) { if (known == TILE_UNKNOWN - || is_non_allied_unit_tile(ptile, param->owner) + || is_non_allied_unit_tile(ptile, param->owner, + utype_has_flag(param->utype, UTYF_FLAGLESS)) || is_non_allied_city_tile(ptile, param->owner)) { /* Can't attack */ return TB_IGNORE; @@ -510,7 +512,8 @@ enum tile_behavior no_fights(const struct tile *ptile, enum known_type known, const struct pf_parameter *param) { - if (is_non_allied_unit_tile(ptile, param->owner) + if (is_non_allied_unit_tile(ptile, param->owner, + utype_has_flag(param->utype, UTYF_FLAGLESS)) || is_non_allied_city_tile(ptile, param->owner)) { /* Can't attack */ return TB_IGNORE; @@ -525,7 +528,8 @@ enum tile_behavior no_intermediate_fights(const struct tile *ptile, enum known_type known, const struct pf_parameter *param) { - if (is_non_allied_unit_tile(ptile, param->owner) + if (is_non_allied_unit_tile(ptile, param->owner, + utype_has_flag(param->utype, UTYF_FLAGLESS)) || is_non_allied_city_tile(ptile, param->owner)) { return TB_DONT_LEAVE; } diff --git a/common/movement.c b/common/movement.c index 529578cfb3..04bfa7e8e3 100644 --- a/common/movement.c +++ b/common/movement.c @@ -664,7 +664,8 @@ unit_move_to_tile_test(const struct civ_map *nmap, } /* 5) */ - if (is_non_allied_unit_tile(dst_tile, puowner)) { + if (is_non_allied_unit_tile(dst_tile, puowner, + utype_has_flag(punittype, UTYF_FLAGLESS))) { /* You can't move onto a tile with non-allied units on it (try * attacking instead). */ return MR_DESTINATION_OCCUPIED_BY_NON_ALLIED_UNIT; @@ -692,7 +693,7 @@ unit_move_to_tile_test(const struct civ_map *nmap, /* You can't move into a non-allied tile. * * FIXME: this should never happen since it should be caught by check - * #4. */ + * #5. */ return MR_NO_WAR; } @@ -783,7 +784,8 @@ unit_teleport_to_tile_test(const struct civ_map *nmap, const struct player *puowner = unit_owner(punit); /* 1) */ - if (is_non_allied_unit_tile(dst_tile, puowner)) { + if (is_non_allied_unit_tile(dst_tile, puowner, + utype_has_flag(punittype, UTYF_FLAGLESS))) { /* You can't move onto a tile with non-allied units on it (try * attacking instead). */ return MR_DESTINATION_OCCUPIED_BY_NON_ALLIED_UNIT; diff --git a/common/scriptcore/api_game_methods.c b/common/scriptcore/api_game_methods.c index 183b43d3d9..2227a981b2 100644 --- a/common/scriptcore/api_game_methods.c +++ b/common/scriptcore/api_game_methods.c @@ -1198,7 +1198,7 @@ bool api_methods_enemy_tile(lua_State *L, Tile *ptile, Player *against) LUASCRIPT_CHECK_STATE(L, FALSE); LUASCRIPT_CHECK_SELF(L, ptile, FALSE); - if (is_non_allied_unit_tile(ptile, against)) { + if (is_non_allied_unit_tile(ptile, against, FALSE)) { return TRUE; } diff --git a/common/unit.c b/common/unit.c index 879d9624f4..9c4eb22afb 100644 --- a/common/unit.c +++ b/common/unit.c @@ -1320,10 +1320,18 @@ struct unit *tile_enemy_unit(const struct tile *ptile, Return one of the non-allied units on the tile, if there is any **************************************************************************/ struct unit *tile_non_allied_unit(const struct tile *ptile, - const struct player *pplayer) + const struct player *pplayer, + bool everyone_non_allied) { unit_list_iterate(ptile->units, punit) { - if (!pplayers_allied(unit_owner(punit), pplayer)) { + struct player *owner = unit_owner(punit); + + if (everyone_non_allied && owner != pplayer) { + return punit; + } + + if (!pplayers_allied(owner, pplayer) + || is_flagless_to_player(punit, pplayer)) { return punit; } } diff --git a/common/unit.h b/common/unit.h index b9fa1f2294..16f0c29db0 100644 --- a/common/unit.h +++ b/common/unit.h @@ -416,15 +416,17 @@ static inline bool is_enemy_unit_tile(const struct tile *ptile, } struct unit *tile_non_allied_unit(const struct tile *ptile, - const struct player *pplayer); + const struct player *pplayer, + bool everyone_non_allied); /**********************************************************************//** Are there any non-allied unit(s) on tile? **************************************************************************/ static inline bool is_non_allied_unit_tile(const struct tile *ptile, - const struct player *pplayer) + const struct player *pplayer, + bool everyone_non_allied) { - return NULL != tile_non_allied_unit(ptile, pplayer); + return NULL != tile_non_allied_unit(ptile, pplayer, everyone_non_allied); } struct unit *tile_other_players_unit(const struct tile *ptile, diff --git a/server/advisors/advgoto.c b/server/advisors/advgoto.c index db215452f8..38b5e47a7f 100644 --- a/server/advisors/advgoto.c +++ b/server/advisors/advgoto.c @@ -316,25 +316,26 @@ static bool adv_unit_move(struct unit *punit, struct tile *ptile) Fix to bizarre did-not-find bug. Thanks, Katvrr -- Syela **************************************************************************/ -static bool adv_could_be_my_zoc(struct unit *myunit, struct tile *ptile) +static bool adv_could_be_my_zoc(struct unit *punit, struct tile *ptile) { - struct tile *utile = unit_tile(myunit); + struct tile *utile = unit_tile(punit); struct player *owner; struct civ_map *cmap = &(wld.map); + bool flagless = unit_has_type_flag(punit, UTYF_FLAGLESS); if (same_pos(ptile, utile)) { return FALSE; /* Can't be my zoc */ } - owner = unit_owner(myunit); + owner = unit_owner(punit); if (is_tiles_adjacent(ptile, utile) - && !is_non_allied_unit_tile(ptile, owner)) { + && !is_non_allied_unit_tile(ptile, owner, flagless)) { return FALSE; } adjc_iterate(cmap, ptile, atile) { if (!terrain_has_flag(tile_terrain(atile), TER_NO_ZOC) - && is_non_allied_unit_tile(atile, owner)) { + && is_non_allied_unit_tile(atile, owner, flagless)) { return FALSE; } } adjc_iterate_end; @@ -423,17 +424,19 @@ bool adv_danger_at(struct unit *punit, struct tile *ptile) struct city *pcity = tile_city(ptile); enum override_bool dc = NO_OVERRIDE; int extras_bonus = 0; + struct player *owner = unit_owner(punit); /* Give AI code possibility to decide itself */ - CALL_PLR_AI_FUNC(consider_tile_dangerous, unit_owner(punit), ptile, punit, &dc); + CALL_PLR_AI_FUNC(consider_tile_dangerous, owner, ptile, punit, &dc); if (dc == OVERRIDE_TRUE) { return TRUE; } else if (dc == OVERRIDE_FALSE) { return FALSE; } - if (pcity && pplayers_allied(city_owner(pcity), unit_owner(punit)) - && !is_non_allied_unit_tile(ptile, pplayer)) { + if (pcity != NULL && pplayers_allied(city_owner(pcity), owner) + && !is_non_allied_unit_tile(ptile, pplayer, + unit_has_type_flag(punit, UTYF_FLAGLESS))) { /* We will be safe in a friendly city */ return FALSE; } @@ -445,12 +448,12 @@ bool adv_danger_at(struct unit *punit, struct tile *ptile) d = adv_unit_def_rating_basic_squared(punit) * db; adjc_iterate(&(wld.map), ptile, ptile1) { - if (!map_is_known_and_seen(ptile1, unit_owner(punit), V_MAIN)) { + if (!map_is_known_and_seen(ptile1, owner, V_MAIN)) { /* We cannot see danger at (ptile1) => assume there is none */ continue; } unit_list_iterate(ptile1->units, enemy) { - if (pplayers_at_war(unit_owner(enemy), unit_owner(punit)) + if (pplayers_at_war(unit_owner(enemy), owner) && (unit_attack_unit_at_tile_result(enemy, NULL, punit, ptile) == ATT_OK) && (unit_attack_units_at_tile_result(enemy, NULL, ptile) @@ -464,7 +467,7 @@ bool adv_danger_at(struct unit *punit, struct tile *ptile) } unit_list_iterate_end; } adjc_iterate_end; - return FALSE; /* as good a quick'n'dirty should be -- Syela */ + return FALSE; /* As good a quick'n'dirty should be -- Syela */ } /**********************************************************************//** @@ -557,7 +560,8 @@ static unsigned stack_risk(const struct tile *ptile, if (risk_cost->enemy_zoc_cost != 0 && (is_non_allied_city_tile(ptile, param->owner) || !is_plr_zoc_srv(param->owner, ptile, param->map) - || is_non_allied_unit_tile(ptile, param->owner))) { + || is_non_allied_unit_tile(ptile, param->owner, + utype_has_flag(param->utype, UTYF_FLAGLESS)))) { /* We could become stuck. */ risk += risk_cost->enemy_zoc_cost; } diff --git a/server/advisors/autoexplorer.c b/server/advisors/autoexplorer.c index 51bdf2a289..a40a0eddae 100644 --- a/server/advisors/autoexplorer.c +++ b/server/advisors/autoexplorer.c @@ -87,6 +87,8 @@ static bool player_may_explore(const struct tile *ptile, const struct player *pplayer, const struct unit_type *punittype) { + struct city *pcity; + /* Don't allow military units to cross borders. */ if (!utype_has_flag(punittype, UTYF_CIVILIAN) && !player_can_invade_tile(pplayer, ptile)) { @@ -94,13 +96,15 @@ static bool player_may_explore(const struct tile *ptile, } /* Can't visit tiles with non-allied units. */ - if (is_non_allied_unit_tile(ptile, pplayer)) { + if (is_non_allied_unit_tile(ptile, pplayer, + utype_has_flag(punittype, UTYF_FLAGLESS))) { return FALSE; } /* Non-allied cities are taboo even if no units are inside. */ - if (tile_city(ptile) - && !pplayers_allied(city_owner(tile_city(ptile)), pplayer)) { + pcity = tile_city(ptile); + if (pcity != NULL + && !pplayers_allied(city_owner(pcity), pplayer)) { return FALSE; } diff --git a/server/animals.c b/server/animals.c index 6a8a587066..616f514ad7 100644 --- a/server/animals.c +++ b/server/animals.c @@ -71,7 +71,8 @@ static void place_animal(struct player *plr, int sqrdist) } circle_iterate(&(wld.map), ptile, sqrdist, check) { - if (tile_city(check) || is_non_allied_unit_tile(check, plr)) { + if (tile_city(check) != NULL + || is_non_allied_unit_tile(check, plr, TRUE)) { return; } } circle_iterate_end; diff --git a/server/barbarian.c b/server/barbarian.c index 6ffabfb323..5284759551 100644 --- a/server/barbarian.c +++ b/server/barbarian.c @@ -329,7 +329,7 @@ bool unleash_barbarians(struct tile *ptile) dir_tiles[dir] = mapstep(&(wld.map), ptile, dir); if (dir_tiles[dir] == NULL) { terrainc[dir] = terrain_class_invalid(); - } else if (!is_non_allied_unit_tile(dir_tiles[dir], barbarians)) { + } else if (!is_non_allied_unit_tile(dir_tiles[dir], barbarians, TRUE)) { if (is_ocean_tile(dir_tiles[dir])) { terrainc[dir] = TC_OCEAN; ocean_tiles++; diff --git a/server/edithand.c b/server/edithand.c index 65518eb032..0ec1648c7f 100644 --- a/server/edithand.c +++ b/server/edithand.c @@ -438,6 +438,7 @@ void handle_edit_unit_create(struct connection *pc, int owner, int tile, struct player *pplayer; struct city *homecity; struct unit *punit; + struct city *pcity; int id, i; ptile = index_to_tile(&(wld.map), tile); @@ -485,9 +486,11 @@ void handle_edit_unit_create(struct connection *pc, int owner, int tile, } } - if (is_non_allied_unit_tile(ptile, pplayer) - || (tile_city(ptile) - && !pplayers_allied(pplayer, city_owner(tile_city(ptile))))) { + pcity = tile_city(ptile); + if (is_non_allied_unit_tile(ptile, pplayer, + utype_has_flag(punittype, UTYF_FLAGLESS)) + || (pcity != NULL + && !pplayers_allied(pplayer, city_owner(pcity)))) { notify_conn(pc->self, ptile, E_BAD_COMMAND, ftc_editor, /* TRANS: ..." type on enemy tile * "... */ diff --git a/server/gamehand.c b/server/gamehand.c index be34307c6a..ad41b135de 100644 --- a/server/gamehand.c +++ b/server/gamehand.c @@ -172,7 +172,8 @@ static struct tile *place_starting_unit(struct tile *starttile, if (utype != NULL) { iterate_outward(&(wld.map), starttile, wld.map.xsize + wld.map.ysize, itertile) { - if (!is_non_allied_unit_tile(itertile, pplayer) + if (!is_non_allied_unit_tile(itertile, pplayer, + utype_has_flag(utype, UTYF_FLAGLESS)) && is_native_tile(utype, itertile)) { ptile = itertile; break; @@ -185,13 +186,15 @@ static struct tile *place_starting_unit(struct tile *starttile, return NULL; } - fc_assert_ret_val(!is_non_allied_unit_tile(ptile, pplayer), NULL); + fc_assert_ret_val(!is_non_allied_unit_tile(ptile, pplayer, + utype_has_flag(utype, UTYF_FLAGLESS)), + NULL); /* For scenarios or dispersion, huts may coincide with player starts (in * other cases, huts are avoided as start positions). Remove any such hut, * and make sure to tell the client, since we may have already sent this * tile (with the hut) earlier: */ - /* FIXME: don't remove under a unit that can't enter or frighten hut */ + /* FIXME: Don't remove under a unit that can't enter or frighten hut */ extra_type_by_rmcause_iterate(ERM_ENTER, pextra) { if (tile_has_extra(ptile, pextra)) { tile_extra_rm_apply(ptile, pextra); @@ -246,7 +249,7 @@ static struct tile *find_dispersed_position(struct player *pplayer, && !is_ocean_tile(ptile) && real_map_distance(pcenter, ptile) < game.server.dispersion + 1 - && !is_non_allied_unit_tile(ptile, pplayer))); + && !is_non_allied_unit_tile(ptile, pplayer, TRUE))); return ptile; } diff --git a/server/maphand.c b/server/maphand.c index 25ff995c3a..7ac0103dfa 100644 --- a/server/maphand.c +++ b/server/maphand.c @@ -1809,16 +1809,18 @@ static void terrain_change_bounce_single_unit(struct unit *punit, struct tile *from) { bool unit_alive = TRUE; + struct player *owner = unit_owner(punit); /* Look for a nearby safe tile */ adjc_iterate(&(wld.map), from, ptile2) { if (can_unit_exist_at_tile(&(wld.map), punit, ptile2) - && !is_non_allied_unit_tile(ptile2, unit_owner(punit)) - && !is_non_allied_city_tile(ptile2, unit_owner(punit))) { + && !is_non_allied_unit_tile(ptile2, owner, + unit_has_type_flag(punit, UTYF_FLAGLESS)) + && !is_non_allied_city_tile(ptile2, owner)) { log_verbose("Moved %s %s due to changing terrain at (%d,%d).", nation_rule_name(nation_of_unit(punit)), unit_rule_name(punit), TILE_XY(unit_tile(punit))); - notify_player(unit_owner(punit), unit_tile(punit), + notify_player(owner, unit_tile(punit), E_UNIT_RELOCATED, ftc_server, _("Moved your %s due to changing terrain."), unit_link(punit)); diff --git a/server/scripting/api_server_edit.c b/server/scripting/api_server_edit.c index e59d4647c7..6f2023c896 100644 --- a/server/scripting/api_server_edit.c +++ b/server/scripting/api_server_edit.c @@ -148,7 +148,8 @@ Unit *api_edit_create_unit_full(lua_State *L, Player *pplayer, return NULL; } - if (is_non_allied_unit_tile(ptile, pplayer)) { + if (is_non_allied_unit_tile(ptile, pplayer, + utype_has_flag(ptype, UTYF_FLAGLESS))) { luascript_log(fcl, LOG_ERROR, "create_unit_full: tile is occupied by " "enemy unit"); return NULL; @@ -244,8 +245,10 @@ bool api_edit_unit_teleport(lua_State *L, Unit *punit, Tile *dest, wipe_unit(punit, ULR_NONNATIVE_TERR, NULL); return FALSE; } - if (is_non_allied_unit_tile(dest, owner) - || (pcity && !pplayers_allied(city_owner(pcity), owner))) { + if (is_non_allied_unit_tile(dest, owner, + unit_has_type_flag(punit, UTYF_FLAGLESS)) + || (pcity != NULL + && !pplayers_allied(city_owner(pcity), owner))) { wipe_unit(punit, ULR_STACK_CONFLICT, NULL); return FALSE; } diff --git a/server/unithand.c b/server/unithand.c index d1b0317443..6562d8fab6 100644 --- a/server/unithand.c +++ b/server/unithand.c @@ -453,17 +453,22 @@ static bool do_capture_units(struct player *pplayer, continue; } - if (to_capture - && (NULL != pcity /* Keep old behavior */ - || is_non_allied_city_tile(ptile, unit_owner(to_capture)) - || (unit_owner(to_capture) == pplayer - ? non_allied_not_listed_at(pplayer, capt + (i + 1), - n - (i + 1), ptile) - : (bool) - is_non_allied_unit_tile(ptile, unit_owner(to_capture))))) { - /* The captured unit is in a city or with a foreign unit - * that its owner is not capturing. Bounce it. */ - bounce_unit(to_capture, TRUE); + if (to_capture != NULL) { + struct player *new_owner = unit_owner(to_capture); + + if (NULL != pcity /* Keep old behavior */ + || is_non_allied_city_tile(ptile, new_owner) + || (new_owner == pplayer + ? non_allied_not_listed_at(pplayer, capt + (i + 1), + n - (i + 1), ptile) + : (bool) + is_non_allied_unit_tile(ptile, new_owner, + unit_has_type_flag(to_capture, + UTYF_FLAGLESS)))) { + /* The captured unit is in a city or with a foreign unit + * that its owner is not capturing. Bounce it. */ + bounce_unit(to_capture, TRUE); + } } /* Check if the city we are going to home units in stays. */ @@ -497,7 +502,8 @@ static bool do_capture_units(struct player *pplayer, static bool occupy_move(struct tile *def_tile, struct unit *punit, const struct action *paction) { - if (!is_non_allied_unit_tile(def_tile, unit_owner(punit))) { + if (!is_non_allied_unit_tile(def_tile, unit_owner(punit), + unit_has_type_flag(punit, UTYF_FLAGLESS))) { /* Hack: make sure the unit has enough moves_left for the move to succeed, * and adjust moves_left to afterward (if successful). */ int old_moves = punit->moves_left; diff --git a/server/unittools.c b/server/unittools.c index f43826d8ad..ac1f3d49c3 100644 --- a/server/unittools.c +++ b/server/unittools.c @@ -1275,7 +1275,8 @@ void bounce_unit(struct unit *punit, bool verbose) if (can_unit_survive_at_tile(&(wld.map), punit, ptile) && !is_non_allied_city_tile(ptile, pplayer) - && !is_non_allied_unit_tile(ptile, pplayer)) { + && !is_non_allied_unit_tile(ptile, pplayer, + unit_has_type_flag(punit, UTYF_FLAGLESS))) { tiles[count++] = ptile; } } square_iterate_end; @@ -1396,7 +1397,9 @@ static void resolve_stack_conflicts(struct player *pplayer, unit_list_iterate_safe(pplayer->units, punit) { struct tile *ptile = unit_tile(punit); - if (is_non_allied_unit_tile(ptile, pplayer)) { + /* Can pass FALSE 'everyone_non_allied' since no flagless + * unit could be stacked there to begin with. */ + if (is_non_allied_unit_tile(ptile, pplayer, FALSE)) { unit_list_iterate_safe(ptile->units, aunit) { if (unit_owner(aunit) == pplayer || unit_owner(aunit) == aplayer @@ -1552,7 +1555,8 @@ bool is_refuel_point(const struct tile *ptile, const struct player *pplayer, const struct unit *punit) { - if (is_non_allied_unit_tile(ptile, pplayer)) { + if (is_non_allied_unit_tile(ptile, pplayer, + unit_has_type_flag(punit, UTYF_FLAGLESS))) { return FALSE; } @@ -3032,7 +3036,8 @@ bool do_paradrop(struct unit *punit, struct tile *ptile, if ((pcity != NULL && !pplayers_allied(pplayer, city_owner(pcity)) && !action_has_result(paction, ACTRES_PARADROP_CONQUER)) - || is_non_allied_unit_tile(ptile, pplayer)) { + || is_non_allied_unit_tile(ptile, pplayer, + unit_has_type_flag(punit, UTYF_FLAGLESS))) { struct player *main_victim = NULL; struct player *secondary_victim = NULL; char victim_link[MAX_LEN_LINK]; @@ -4254,8 +4259,11 @@ bool unit_move(struct unit *punit, struct tile *pdesttile, int move_cost, static bool maybe_cancel_goto_due_to_enemy(struct unit *punit, struct tile *ptile) { - return (is_non_allied_unit_tile(ptile, unit_owner(punit)) - || is_non_allied_city_tile(ptile, unit_owner(punit))); + struct player *owner = unit_owner(punit); + + return (is_non_allied_unit_tile(ptile, owner, + unit_has_type_flag(punit, UTYF_FLAGLESS)) + || is_non_allied_city_tile(ptile, owner)); } /**********************************************************************//** @@ -4271,7 +4279,8 @@ static bool maybe_cancel_patrol_due_to_enemy(struct unit *punit) struct player *pplayer = unit_owner(punit); circle_iterate(&(wld.map), unit_tile(punit), radius_sq, ptile) { - struct unit *penemy = tile_non_allied_unit(ptile, pplayer); + struct unit *penemy = tile_non_allied_unit(ptile, pplayer, + unit_has_type_flag(punit, UTYF_FLAGLESS)); struct vision_site *pdcity = map_get_player_site(ptile, pplayer); if ((penemy && can_player_see_unit(pplayer, penemy)) -- 2.40.1