From fa9ef4d0a0daba9ccf7d177247781017cdd59213 Mon Sep 17 00:00:00 2001 From: Ihnatus Date: Sun, 19 Jun 2022 22:52:48 +0300 Subject: [PATCH] Lua: allow create units in unboardable transports See OSDN#44834. Signed-off-by: Ihnatus --- common/unit.c | 52 ++++++++++++++++----------- common/unit.h | 2 ++ server/scripting/api_server_edit.c | 56 ++++++++++++++++++------------ 3 files changed, 67 insertions(+), 43 deletions(-) diff --git a/common/unit.c b/common/unit.c index b209416a64..14547ea103 100644 --- a/common/unit.c +++ b/common/unit.c @@ -672,33 +672,19 @@ const char *get_activity_text(enum unit_activity activity) } /**********************************************************************//** - Return TRUE iff the given unit could be loaded into the transporter - if we moved there. + Tells wether pcargo could possibly be in ptrans, disregarding + unit positions and ownership and load actions possibility, + but regarding number and types of their current cargo. + pcargo and ptrans must be valid unit pointers, pcargo not loaded anywhere **************************************************************************/ -bool could_unit_load(const struct unit *pcargo, const struct unit *ptrans) +bool could_unit_be_in_transport(const struct unit *pcargo, + const struct unit *ptrans) { - if (!pcargo || !ptrans || pcargo == ptrans) { - return FALSE; - } - - /* Double-check ownership of the units: you can load into an allied unit - * (of course only allied units can be on the same tile). */ - if (!pplayers_allied(unit_owner(pcargo), unit_owner(ptrans))) { - return FALSE; - } - /* Make sure this transporter can carry this type of unit. */ if (!can_unit_transport(ptrans, pcargo)) { return FALSE; } - /* Un-embarkable transport must be in city or base to load cargo. */ - if (!utype_can_freely_load(unit_type_get(pcargo), unit_type_get(ptrans)) - && !tile_city(unit_tile(ptrans)) - && !tile_has_native_base(unit_tile(ptrans), unit_type_get(ptrans))) { - return FALSE; - } - /* Make sure there's room in the transporter. */ if (get_transporter_occupancy(ptrans) >= get_transporter_capacity(ptrans)) { @@ -719,6 +705,32 @@ bool could_unit_load(const struct unit *pcargo, const struct unit *ptrans) return TRUE; } +/**********************************************************************//** + Return TRUE iff the given unit could be loaded into the transporter + if we moved there. +**************************************************************************/ +bool could_unit_load(const struct unit *pcargo, const struct unit *ptrans) +{ + if (!pcargo || !ptrans || pcargo == ptrans) { + return FALSE; + } + + /* Double-check ownership of the units: you can load into an allied unit + * (of course only allied units can be on the same tile). */ + if (!pplayers_allied(unit_owner(pcargo), unit_owner(ptrans))) { + return FALSE; + } + + /* Un-embarkable transport must be in city or base to load cargo. */ + if (!utype_can_freely_load(unit_type_get(pcargo), unit_type_get(ptrans)) + && !tile_city(unit_tile(ptrans)) + && !tile_has_native_base(unit_tile(ptrans), unit_type_get(ptrans))) { + return FALSE; + } + + return could_unit_be_in_transport(pcargo, ptrans); +} + /**********************************************************************//** Return TRUE iff the given unit can be loaded into the transporter. **************************************************************************/ diff --git a/common/unit.h b/common/unit.h index 172fd3e812..ce0df6747d 100644 --- a/common/unit.h +++ b/common/unit.h @@ -317,6 +317,8 @@ enum unit_airlift_result bool unit_can_airlift_to(const struct unit *punit, const struct city *pcity); bool unit_has_orders(const struct unit *punit); +bool could_unit_be_in_transport(const struct unit *pcargo, + const struct unit *ptrans); bool could_unit_load(const struct unit *pcargo, const struct unit *ptrans); bool can_unit_load(const struct unit *punit, const struct unit *ptrans); bool can_unit_unload(const struct unit *punit, const struct unit *ptrans); diff --git a/server/scripting/api_server_edit.c b/server/scripting/api_server_edit.c index 97d7bbde22..7195660454 100644 --- a/server/scripting/api_server_edit.c +++ b/server/scripting/api_server_edit.c @@ -146,6 +146,10 @@ Unit *api_edit_create_unit_full(lua_State *L, Player *pplayer, { struct fc_lua *fcl; struct city *pcity; + struct unit *punit; +#ifndef FREECIV_NDEBUG + bool placed; +#endif LUASCRIPT_CHECK_STATE(L, NULL); LUASCRIPT_CHECK_ARG_NIL(L, pplayer, 2, Player, NULL); @@ -160,16 +164,30 @@ Unit *api_edit_create_unit_full(lua_State *L, Player *pplayer, return NULL; } + if (is_non_allied_unit_tile(ptile, pplayer)) { + luascript_log(fcl, LOG_ERROR, "create_unit_full: tile is occupied by " + "enemy unit"); + return NULL; + } + + pcity = tile_city(ptile); + if (pcity != NULL && !pplayers_allied(pplayer, city_owner(pcity))) { + luascript_log(fcl, LOG_ERROR, "create_unit_full: tile is occupied by " + "enemy city"); + return NULL; + } + + punit = unit_virtual_prepare(pplayer, ptile, ptype, veteran_level, + homecity ? homecity->id : 0, + moves_left, hp_left); if (ptransport) { - /* Extensive check to see if transport and unit are compatible */ - int ret; - struct unit *pvirt = unit_virtual_create(pplayer, NULL, ptype, - veteran_level); - unit_tile_set(pvirt, ptile); - pvirt->homecity = homecity ? homecity->id : 0; - ret = can_unit_load(pvirt, ptransport); - unit_virtual_destroy(pvirt); + /* The unit maybe can't freely load into the transport + * but must be able to be in it, see can_unit_load() */ + int ret = same_pos(ptile, unit_tile(ptransport)) + && could_unit_be_in_transport(punit, ptransport); + if (!ret) { + unit_virtual_destroy(punit); luascript_log(fcl, LOG_ERROR, "create_unit_full: '%s' cannot transport " "'%s' here", utype_rule_name(unit_type_get(ptransport)), @@ -177,27 +195,19 @@ Unit *api_edit_create_unit_full(lua_State *L, Player *pplayer, return NULL; } } else if (!can_exist_at_tile(&(wld.map), ptype, ptile)) { + unit_virtual_destroy(punit); luascript_log(fcl, LOG_ERROR, "create_unit_full: '%s' cannot exist at " "tile", utype_rule_name(ptype)); return NULL; } - if (is_non_allied_unit_tile(ptile, pplayer)) { - luascript_log(fcl, LOG_ERROR, "create_unit_full: tile is occupied by " - "enemy unit"); - return NULL; - } - - pcity = tile_city(ptile); - if (pcity != NULL && !pplayers_allied(pplayer, city_owner(pcity))) { - luascript_log(fcl, LOG_ERROR, "create_unit_full: tile is occupied by " - "enemy city"); - return NULL; - } +#ifndef FREECIV_NDEBUG + placed = +#endif + place_unit(punit, pplayer, homecity, ptransport, TRUE); + fc_assert_action(placed, unit_virtual_destroy(punit); punit = NULL); - return create_unit_full(pplayer, ptile, ptype, veteran_level, - homecity ? homecity->id : 0, moves_left, - hp_left, ptransport); + return punit; } /**********************************************************************//** -- 2.34.1