From 78e417b55006532d44272e3bfa2cca6a62000074 Mon Sep 17 00:00:00 2001 From: Sveinung Kvilhaugsvik Date: Mon, 21 Aug 2017 16:45:36 +0200 Subject: [PATCH 2/2] Lua API: allow forcing an action. Add unit_perform_action() to edit. Add perform_action() to Unit. This makes it possible to force a unit to perform an action from Lua. See osdn #41520 --- server/scripting/api_server_edit.c | 227 +++++++++++++++++++++++++++++ server/scripting/api_server_edit.h | 18 +++ server/scripting/tolua_server.pkg | 31 ++++ 3 files changed, 276 insertions(+) diff --git a/server/scripting/api_server_edit.c b/server/scripting/api_server_edit.c index 98544a535d..d7690cf337 100644 --- a/server/scripting/api_server_edit.c +++ b/server/scripting/api_server_edit.c @@ -39,6 +39,7 @@ #include "srv_main.h" /* game_was_started() */ #include "stdinhand.h" #include "techtools.h" +#include "unithand.h" #include "unittools.h" /* server/scripting */ @@ -206,6 +207,232 @@ bool api_edit_unit_teleport(lua_State *L, Unit *punit, Tile *dest) return alive; } +/***********************************************************************//** + Force a unit to perform an action against a city. +***************************************************************************/ +bool api_edit_unit_perform_action_vs_city(lua_State *L, Unit *punit, + Action *paction, City *tgt) +{ + LUASCRIPT_CHECK_STATE(L, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, punit, 2, Unit, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, paction, 3, Action, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, tgt, 4, City, FALSE); + + fc_assert_ret_val(action_get_target_kind(paction) == ATK_CITY, FALSE); + if (is_action_enabled_unit_on_city(paction->id, punit, tgt)) { + return unit_perform_action(unit_owner(punit), punit->id, + tgt->id, IDENTITY_NUMBER_ZERO, "", + paction->id, ACT_REQ_RULES); + } else { + /* Action not enabled */ + return FALSE; + } +} + +/***********************************************************************//** + Force a unit to perform an action against a city and a building. +***************************************************************************/ +bool api_edit_unit_perform_action_vs_city_impr(lua_State *L, Unit *punit, + Action *paction, City *tgt, + Building_Type *sub_tgt) +{ + LUASCRIPT_CHECK_STATE(L, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, punit, 2, Unit, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, paction, 3, Action, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, tgt, 4, City, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, sub_tgt, 5, Building_Type, FALSE); + + fc_assert_ret_val(action_get_target_kind(paction) == ATK_CITY, FALSE); + if (is_action_enabled_unit_on_city(paction->id, punit, tgt)) { + return unit_perform_action(unit_owner(punit), punit->id, + tgt->id, sub_tgt->item_number, "", + paction->id, ACT_REQ_RULES); + } else { + /* Action not enabled */ + return FALSE; + } +} + +/***********************************************************************//** + Force a unit to perform an action against a city and a tech. +***************************************************************************/ +bool api_edit_unit_perform_action_vs_city_tech(lua_State *L, Unit *punit, + Action *paction, City *tgt, + Tech_Type *sub_tgt) +{ + LUASCRIPT_CHECK_STATE(L, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, punit, 2, Unit, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, paction, 3, Action, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, tgt, 4, City, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, sub_tgt, 5, Tech_Type, FALSE); + + fc_assert_ret_val(action_get_target_kind(paction) == ATK_CITY, FALSE); + if (is_action_enabled_unit_on_city(paction->id, punit, tgt)) { + return unit_perform_action(unit_owner(punit), punit->id, + tgt->id, sub_tgt->item_number, "", + paction->id, ACT_REQ_RULES); + } else { + /* Action not enabled */ + return FALSE; + } +} + +/***********************************************************************//** + Force a unit to perform an action against a unit. +***************************************************************************/ +bool api_edit_unit_perform_action_vs_unit(lua_State *L, Unit *punit, + Action *paction, Unit *tgt) +{ + LUASCRIPT_CHECK_STATE(L, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, punit, 2, Unit, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, paction, 3, Action, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, tgt, 4, Unit, FALSE); + + fc_assert_ret_val(action_get_target_kind(paction) == ATK_UNIT, FALSE); + if (is_action_enabled_unit_on_unit(paction->id, punit, tgt)) { + return unit_perform_action(unit_owner(punit), punit->id, + tgt->id, IDENTITY_NUMBER_ZERO, "", + paction->id, ACT_REQ_RULES); + } else { + /* Action not enabled */ + return FALSE; + } +} + +/***********************************************************************//** + Force a unit to perform an action against a tile. +***************************************************************************/ +bool api_edit_unit_perform_action_vs_tile(lua_State *L, Unit *punit, + Action *paction, Tile *tgt) +{ + bool enabled = FALSE; + + LUASCRIPT_CHECK_STATE(L, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, punit, 2, Unit, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, paction, 3, Action, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, tgt, 4, Tile, FALSE); + + switch (action_get_target_kind(paction)) { + case ATK_UNITS: + enabled = is_action_enabled_unit_on_units(paction->id, punit, tgt); + break; + case ATK_TILE: + enabled = is_action_enabled_unit_on_tile(paction->id, punit, + tgt, NULL); + break; + case ATK_EXTRAS: + enabled = is_action_enabled_unit_on_extras(paction->id, punit, + tgt, NULL); + break; + case ATK_CITY: + /* Not handled here. */ + fc_assert(action_get_target_kind(paction) != ATK_CITY); + break; + case ATK_UNIT: + /* Not handled here. */ + fc_assert(action_get_target_kind(paction) != ATK_UNIT); + break; + case ATK_SELF: + /* Not handled here. */ + fc_assert(action_get_target_kind(paction) != ATK_SELF); + break; + case ATK_COUNT: + /* Should not exist */ + fc_assert(action_get_target_kind(paction) != ATK_COUNT); + break; + } + + if (enabled) { + return unit_perform_action(unit_owner(punit), punit->id, + tile_index(tgt), IDENTITY_NUMBER_ZERO, "", + paction->id, ACT_REQ_RULES); + } else { + /* Action not enabled */ + return FALSE; + } +} + +/***********************************************************************//** + Force a unit to perform an action against a tile and an extra. +***************************************************************************/ +bool api_edit_unit_perform_action_vs_tile_extra(lua_State *L, Unit *punit, + Action *paction, Tile *tgt, + const char *sub_tgt) +{ + struct extra_type *sub_target; + bool enabled = FALSE; + + LUASCRIPT_CHECK_STATE(L, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, punit, 2, Unit, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, paction, 3, Action, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, tgt, 4, Tile, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, sub_tgt, 5, string, FALSE); + + sub_target = extra_type_by_rule_name(sub_tgt); + LUASCRIPT_CHECK_ARG(L, sub_target != NULL, 5, "No such extra", FALSE); + + switch (action_get_target_kind(paction)) { + case ATK_UNITS: + enabled = is_action_enabled_unit_on_units(paction->id, punit, tgt); + break; + case ATK_TILE: + enabled = is_action_enabled_unit_on_tile(paction->id, punit, + tgt, sub_target); + break; + case ATK_EXTRAS: + enabled = is_action_enabled_unit_on_extras(paction->id, punit, + tgt, sub_target); + break; + case ATK_CITY: + /* Not handled here. */ + fc_assert(action_get_target_kind(paction) != ATK_CITY); + break; + case ATK_UNIT: + /* Not handled here. */ + fc_assert(action_get_target_kind(paction) != ATK_UNIT); + break; + case ATK_SELF: + /* Not handled here. */ + fc_assert(action_get_target_kind(paction) != ATK_SELF); + break; + case ATK_COUNT: + /* Should not exist */ + fc_assert(action_get_target_kind(paction) != ATK_COUNT); + break; + } + + if (enabled) { + return unit_perform_action(unit_owner(punit), punit->id, + tile_index(tgt), sub_target->id, "", + paction->id, ACT_REQ_RULES); + } else { + /* Action not enabled */ + return FALSE; + } +} + +/***********************************************************************//** + Force a unit to perform an action against it self. +***************************************************************************/ +bool api_edit_unit_perform_action_vs_self(lua_State *L, Unit *punit, + Action *paction) +{ + LUASCRIPT_CHECK_STATE(L, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, punit, 2, Unit, FALSE); + LUASCRIPT_CHECK_ARG_NIL(L, paction, 3, Action, FALSE); + + fc_assert_ret_val(action_get_target_kind(paction) == ATK_SELF, FALSE); + if (is_action_enabled_unit_on_self(paction->id, punit)) { + return unit_perform_action(unit_owner(punit), punit->id, + IDENTITY_NUMBER_ZERO, IDENTITY_NUMBER_ZERO, + "", + paction->id, ACT_REQ_RULES); + } else { + /* Action not enabled */ + return FALSE; + } +} + /*************************************************************************//** Change unit orientation *****************************************************************************/ diff --git a/server/scripting/api_server_edit.h b/server/scripting/api_server_edit.h index f478262d74..85d14a5dfb 100644 --- a/server/scripting/api_server_edit.h +++ b/server/scripting/api_server_edit.h @@ -37,6 +37,24 @@ Unit *api_edit_create_unit_full(lua_State *L, Player *pplayer, Tile *ptile, Unit *ptransport); bool api_edit_unit_teleport(lua_State *L, Unit *punit, Tile *dest); +bool api_edit_unit_perform_action_vs_city(lua_State *L, Unit *punit, + Action *paction, City *tgt); +bool api_edit_unit_perform_action_vs_city_impr(lua_State *L, Unit *punit, + Action *paction, City *tgt, + Building_Type *sub_tgt); +bool api_edit_unit_perform_action_vs_city_tech(lua_State *L, Unit *punit, + Action *paction, City *tgt, + Tech_Type *sub_tgt); +bool api_edit_unit_perform_action_vs_unit(lua_State *L, Unit *punit, + Action *paction, Unit *tgt); +bool api_edit_unit_perform_action_vs_tile(lua_State *L, Unit *punit, + Action *paction, Tile *tgt); +bool api_edit_unit_perform_action_vs_tile_extra(lua_State *L, Unit *punit, + Action *paction, Tile *tgt, + const char *sub_tgt); +bool api_edit_unit_perform_action_vs_self(lua_State *L, Unit *punit, + Action *paction); + void api_edit_unit_turn(lua_State *L, Unit *punit, Direction dir); void api_edit_unit_kill(lua_State *L, Unit *punit, const char *reason, diff --git a/server/scripting/tolua_server.pkg b/server/scripting/tolua_server.pkg index b24980e7f9..ae2ed52ca6 100644 --- a/server/scripting/tolua_server.pkg +++ b/server/scripting/tolua_server.pkg @@ -183,6 +183,27 @@ module edit { void api_edit_unit_moving_allow @ movement_allow(lua_State *L, Unit *self); + bool api_edit_unit_perform_action_vs_city + @ unit_perform_action(lua_State *L, Unit *punit, Action *paction, + City *tgt); + bool api_edit_unit_perform_action_vs_city_impr + @ unit_perform_action(lua_State *L, Unit *punit, Action *paction, + City *tgt, Building_Type *sub_tgt); + bool api_edit_unit_perform_action_vs_city_tech + @ unit_perform_action(lua_State *L, Unit *punit, Action *paction, + City *tgt, Tech_Type *sub_tgt); + bool api_edit_unit_perform_action_vs_unit + @ unit_perform_action(lua_State *L, Unit *punit, Action *paction, + Unit *tgt); + bool api_edit_unit_perform_action_vs_tile + @ unit_perform_action(lua_State *L, Unit *punit, Action *paction, + Tile *tgt); + bool api_edit_unit_perform_action_vs_tile_extra + @ unit_perform_action(lua_State *L, Unit *punit, Action *paction, + Tile *tgt, const char *sub_tgt); + bool api_edit_unit_perform_action_vs_self + @ unit_perform_action(lua_State *L, Unit *punit, Action *paction); + void api_edit_city_add_history @ add_city_history(lua_State *L, City *self, int amount); void api_edit_player_add_history @@ -334,6 +355,16 @@ function Unit:teleport(dest) return edit.unit_teleport(self, dest) end +function Unit:perform_action(action, target, sub_target) + if target == nil then + return edit.unit_perform_action(self, action) + elseif sub_target == nil then + return edit.unit_perform_action(self, action, target) + else + return edit.unit_perform_action(self, action, target, sub_target) + end +end + function Unit:turn(direction) edit.unit_turn(self, direction) end -- 2.20.1