remove ai.synced_command
fixes #1649 . ai.synced_command could easily be used to implement all types of undeteced cheats so it was removed. As a replacement this commit adds a [custom_command] synced command that just calls wesnoth.game_events.on_synced_command which calls a lua handler that must first be set.
This commit is contained in:
parent
e752a172d1
commit
fef953a48e
15 changed files with 101 additions and 35 deletions
|
@ -60,6 +60,7 @@
|
||||||
{scenario-story.cfg}
|
{scenario-story.cfg}
|
||||||
{ai/scenarios/}
|
{ai/scenarios/}
|
||||||
{ai/micro_ais/scenarios/}
|
{ai/micro_ais/scenarios/}
|
||||||
|
{ai/utils/custom_command.cfg}
|
||||||
#define DONT_RELOAD_CORE
|
#define DONT_RELOAD_CORE
|
||||||
#enddef
|
#enddef
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ local W = H.set_wml_action_metatable {}
|
||||||
local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
||||||
local LS = wesnoth.require "location_set"
|
local LS = wesnoth.require "location_set"
|
||||||
local M = wesnoth.map
|
local M = wesnoth.map
|
||||||
|
local T = H.set_wml_tag_metatable {}
|
||||||
|
|
||||||
local function get_forest_animals(cfg)
|
local function get_forest_animals(cfg)
|
||||||
-- We want the deer/rabbits to move first, tuskers afterward
|
-- We want the deer/rabbits to move first, tuskers afterward
|
||||||
|
@ -157,8 +158,7 @@ function ca_forest_animals_move:execution(cfg)
|
||||||
|
|
||||||
-- If this is a rabbit ending on a hole -> disappears
|
-- If this is a rabbit ending on a hole -> disappears
|
||||||
if (unit.type == rabbit_type) and hole_map:get(farthest_hex[1], farthest_hex[2]) then
|
if (unit.type == rabbit_type) and hole_map:get(farthest_hex[1], farthest_hex[2]) then
|
||||||
local command = "wesnoth.erase_unit(x1, y1)"
|
wesnoth.invoke_synced_command("rabbit_despawn", { x = farthest_hex[1], y = farthest_hex[2]})
|
||||||
ai.synced_command(command, farthest_hex[1], farthest_hex[2])
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
local H = wesnoth.require "helper"
|
local H = wesnoth.require "helper"
|
||||||
local W = H.set_wml_action_metatable {}
|
local W = H.set_wml_action_metatable {}
|
||||||
local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
||||||
|
local T = H.set_wml_tag_metatable {}
|
||||||
|
|
||||||
local ca_forest_animals_new_rabbit = {}
|
local ca_forest_animals_new_rabbit = {}
|
||||||
|
|
||||||
|
@ -58,12 +59,7 @@ function ca_forest_animals_new_rabbit:execution(cfg)
|
||||||
x, y = wesnoth.find_vacant_tile(holes[i].x, holes[i].y)
|
x, y = wesnoth.find_vacant_tile(holes[i].x, holes[i].y)
|
||||||
end
|
end
|
||||||
|
|
||||||
local command = "wesnoth.put_unit({ side = "
|
wesnoth.invoke_synced_command("rabbit_spawn", { rabbit_type = cfg.rabbit_type, x = x, y = y})
|
||||||
.. wesnoth.current.side
|
|
||||||
.. ", type = '"
|
|
||||||
.. cfg.rabbit_type
|
|
||||||
.. "' }, x1, y1)"
|
|
||||||
ai.synced_command(command, x, y)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if wesnoth.sides[wesnoth.current.side].shroud then
|
if wesnoth.sides[wesnoth.current.side].shroud then
|
||||||
|
|
18
data/ai/utils/custom_command.cfg
Normal file
18
data/ai/utils/custom_command.cfg
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
#define ENABLE_AI_COMMAND_RABBIT_SPAWN
|
||||||
|
[lua]
|
||||||
|
code = <<
|
||||||
|
|
||||||
|
function wesnoth.custom_synced_commands.rabbit_despawn(cfg)
|
||||||
|
--TODO: maybe we only want to allow erasing of unit of certain types/sides/locations ?
|
||||||
|
wesnoth.erase_unit(cfg.x, cfg.y)
|
||||||
|
end
|
||||||
|
|
||||||
|
function wesnoth.custom_synced_commands.rabbit_spawn(cfg)
|
||||||
|
--TODO: maybe we only want to allow creation of unit of certain types/sides/locations ?
|
||||||
|
wesnoth.put_unit({ side = wesnoth.current.side, type = cfg.rabbit_type}, cfg.x, cfg.y)
|
||||||
|
end
|
||||||
|
|
||||||
|
>>
|
||||||
|
[/lua]
|
||||||
|
#enddef
|
|
@ -1,6 +1,7 @@
|
||||||
local H = wesnoth.require "helper"
|
local H = wesnoth.require "helper"
|
||||||
local LS = wesnoth.require "location_set"
|
local LS = wesnoth.require "location_set"
|
||||||
local M = wesnoth.map
|
local M = wesnoth.map
|
||||||
|
local T = H.set_wml_tag_metatable {}
|
||||||
|
|
||||||
local ca_transport = {}
|
local ca_transport = {}
|
||||||
|
|
||||||
|
@ -110,29 +111,12 @@ function ca_transport:execution()
|
||||||
-- Also unload units
|
-- Also unload units
|
||||||
table.sort(best_adj_tiles, function(a, b) return a[3] > b[3] end)
|
table.sort(best_adj_tiles, function(a, b) return a[3] > b[3] end)
|
||||||
|
|
||||||
local command = "local unit = wesnoth.get_unit(x1, y1) "
|
local command_data = { x = best_unit.x, y = best_unit.y }
|
||||||
.. "unit.variables.landed = 'yes' "
|
for i = 1, math.min(#best_adj_tiles, 3) do
|
||||||
.. "unit.variables.destination_x = 1 "
|
table.insert(command_data, T.dst { x = best_adj_tiles[i][1], y = best_adj_tiles[i][2]} )
|
||||||
.. "unit.variables.destination_y = 30"
|
end
|
||||||
ai.synced_command(command, best_unit.x, best_unit.y)
|
|
||||||
|
|
||||||
-- Unload 1 level 2 unit
|
wesnoth.invoke_synced_command("ship_unload", command_data)
|
||||||
local l2_type = H.rand('Swordsman,Javelineer,Pikeman')
|
|
||||||
local command = "wesnoth.put_unit({ side = " .. wesnoth.current.side
|
|
||||||
.. ", type = '" .. l2_type
|
|
||||||
.. "', moves = 2 }, "
|
|
||||||
.. best_adj_tiles[1][1] .. "," .. best_adj_tiles[1][2] .. ")"
|
|
||||||
ai.synced_command(command, best_unit.x, best_unit.y)
|
|
||||||
|
|
||||||
-- Unload up to 2 level 1 units
|
|
||||||
for i = 2, math.min(#best_adj_tiles, 3) do
|
|
||||||
local l1_type = H.rand('Fencer,Mage,Cavalryman,Bowman,Spearman')
|
|
||||||
local command = "wesnoth.put_unit({ side = " .. wesnoth.current.side
|
|
||||||
.. ", type = '" .. l1_type
|
|
||||||
.. "', moves = 2 }, "
|
|
||||||
.. best_adj_tiles[i][1] .. "," .. best_adj_tiles[i][2] .. ")"
|
|
||||||
ai.synced_command(command, best_unit.x, best_unit.y)
|
|
||||||
end
|
|
||||||
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
|
@ -83,6 +83,7 @@
|
||||||
[/side]
|
[/side]
|
||||||
|
|
||||||
{SOTBE_TRACK {JOURNEY_06_NEW} }
|
{SOTBE_TRACK {JOURNEY_06_NEW} }
|
||||||
|
{ENABLE_AI_COMMAND_CA_TRANSPORT_S6}
|
||||||
|
|
||||||
[event]
|
[event]
|
||||||
name=prestart
|
name=prestart
|
||||||
|
|
|
@ -199,3 +199,30 @@
|
||||||
[/unstore_unit]
|
[/unstore_unit]
|
||||||
[/event]
|
[/event]
|
||||||
#enddef
|
#enddef
|
||||||
|
|
||||||
|
#define ENABLE_AI_COMMAND_CA_TRANSPORT_S6
|
||||||
|
[lua]
|
||||||
|
code = <<
|
||||||
|
local helper = wesnoth.require "helper"
|
||||||
|
|
||||||
|
function wesnoth.custom_synced_commands.ship_unload(cfg)
|
||||||
|
|
||||||
|
local unit = wesnoth.get_unit(cfg.x, cfg.y)
|
||||||
|
unit.variables.landed = 'yes'
|
||||||
|
unit.variables.destination_x = 1
|
||||||
|
unit.variables.destination_y = 30
|
||||||
|
|
||||||
|
local locs = helper.child_array(cfg, "dst")
|
||||||
|
|
||||||
|
local l2_type = helper.rand('Swordsman,Javelineer,Pikeman')
|
||||||
|
wesnoth.put_unit({ side = wesnoth.current.side, type = l2_type, moves = 2 }, locs[1].x, locs[1].y)
|
||||||
|
|
||||||
|
for i = 2, #locs do
|
||||||
|
local l1_type = helper.rand('Fencer,Mage,Cavalryman,Bowman,Spearman')
|
||||||
|
wesnoth.put_unit({ side = wesnoth.current.side, type = l1_type, moves = 2 }, locs[i].x, locs[i].y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
>>
|
||||||
|
[/lua]
|
||||||
|
#enddef
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
wesnoth.dofile 'lua/backwards-compatibility.lua'
|
wesnoth.dofile 'lua/backwards-compatibility.lua'
|
||||||
wesnoth.dofile 'lua/wml-tags.lua'
|
wesnoth.dofile 'lua/wml-tags.lua'
|
||||||
wesnoth.dofile 'lua/feeding.lua'
|
wesnoth.dofile 'lua/feeding.lua'
|
||||||
|
wesnoth.dofile 'lua/custom_command.lua'
|
||||||
>>
|
>>
|
||||||
[/lua]
|
[/lua]
|
||||||
|
|
||||||
|
|
20
data/lua/custom_command.lua
Normal file
20
data/lua/custom_command.lua
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
local helper = wesnoth.require "helper"
|
||||||
|
local T = helper.set_wml_tag_metatable {}
|
||||||
|
|
||||||
|
wesnoth.custom_synced_commands = {}
|
||||||
|
|
||||||
|
function wesnoth.game_events.on_synced_command(cfg)
|
||||||
|
local handler = wesnoth.custom_synced_commands[cfg.name]
|
||||||
|
local data = helper.get_child(cfg, "data")
|
||||||
|
if handler then
|
||||||
|
handler(data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function wesnoth.register_synced_command(name, handler)
|
||||||
|
wesnoth.custom_synced_commands[name] = handler
|
||||||
|
end
|
||||||
|
|
||||||
|
function wesnoth.invoke_synced_command(name, data)
|
||||||
|
wesnoth.wml_actions.do_command { T.custom_command { name=name, T.data(data) } }
|
||||||
|
end
|
|
@ -968,7 +968,7 @@ void synced_command_result::do_execute()
|
||||||
}
|
}
|
||||||
s << lua_code_;
|
s << lua_code_;
|
||||||
|
|
||||||
synced_context::run_in_synced_context_if_not_already("lua_ai", replay_helper::get_lua_ai(s.str()));
|
//synced_context::run_in_synced_context_if_not_already("lua_ai", replay_helper::get_lua_ai(s.str()));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
set_gamestate_changed();
|
set_gamestate_changed();
|
||||||
|
|
|
@ -273,6 +273,12 @@ static int cfun_ai_check_stopunit(lua_State *L)
|
||||||
|
|
||||||
static int ai_synced_command(lua_State *L, bool exec)
|
static int ai_synced_command(lua_State *L, bool exec)
|
||||||
{
|
{
|
||||||
|
#if 1
|
||||||
|
(void)L;
|
||||||
|
(void)exec;
|
||||||
|
ERR_LUA << "synced_command was removed, use wesnoth.wml_actions.do_command with [custom_command] instead\n";
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
const char *lua_code = luaL_checkstring(L, 1);
|
const char *lua_code = luaL_checkstring(L, 1);
|
||||||
int side = get_readonly_context(L).get_side();
|
int side = get_readonly_context(L).get_side();
|
||||||
map_location location;
|
map_location location;
|
||||||
|
@ -283,6 +289,7 @@ static int ai_synced_command(lua_State *L, bool exec)
|
||||||
|
|
||||||
ai::synced_command_result_ptr synced_command_result = ai::actions::execute_synced_command_action(side,exec,std::string(lua_code),location);
|
ai::synced_command_result_ptr synced_command_result = ai::actions::execute_synced_command_action(side,exec,std::string(lua_code),location);
|
||||||
return transform_ai_action(L,synced_command_result);
|
return transform_ai_action(L,synced_command_result);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cfun_ai_execute_synced_command(lua_State *L)
|
static int cfun_ai_execute_synced_command(lua_State *L)
|
||||||
|
|
|
@ -281,7 +281,7 @@ WML_HANDLER_FUNCTION(do_command,, cfg)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const std::set<std::string> allowed_tags {"attack", "move", "recruit", "recall", "disband", "fire_event", "lua_ai"};
|
static const std::set<std::string> allowed_tags {"attack", "move", "recruit", "recall", "disband", "fire_event", "custom_command"};
|
||||||
|
|
||||||
const bool is_too_early = resources::gamedata->phase() != game_data::START && resources::gamedata->phase() != game_data::PLAY;
|
const bool is_too_early = resources::gamedata->phase() != game_data::START && resources::gamedata->phase() != game_data::PLAY;
|
||||||
const bool is_unsynced_too_early = resources::gamedata->phase() != game_data::PLAY;
|
const bool is_unsynced_too_early = resources::gamedata->phase() != game_data::PLAY;
|
||||||
|
|
|
@ -4395,6 +4395,17 @@ bool game_lua_kernel::run_event(const game_events::queued_event& ev)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void game_lua_kernel::custom_command(const config& cfg)
|
||||||
|
{
|
||||||
|
lua_State *L = mState;
|
||||||
|
|
||||||
|
if (!luaW_getglobal(L, "wesnoth", "game_events", "on_synced_command")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
luaW_pushconfig(L, cfg);
|
||||||
|
luaW_pcall(L, 1, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies its upvalue as an effect
|
* Applies its upvalue as an effect
|
||||||
* Arg 1: The unit to apply to
|
* Arg 1: The unit to apply to
|
||||||
|
|
|
@ -200,6 +200,7 @@ public:
|
||||||
void save_game(config & level);
|
void save_game(config & level);
|
||||||
void load_game(const config& level);
|
void load_game(const config& level);
|
||||||
bool run_event(const game_events::queued_event&);
|
bool run_event(const game_events::queued_event&);
|
||||||
|
void custom_command(const config&);
|
||||||
void push_builtin_effect();
|
void push_builtin_effect();
|
||||||
void set_wml_action(const std::string&, game_events::wml_action::handler);
|
void set_wml_action(const std::string&, game_events::wml_action::handler);
|
||||||
void set_wml_condition(const std::string&, bool(*)(const vconfig&));
|
void set_wml_condition(const std::string&, bool(*)(const vconfig&));
|
||||||
|
|
|
@ -344,11 +344,10 @@ SYNCED_COMMAND_HANDLER_FUNCTION(fire_event, child, use_undo, /*show*/, /*error_
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SYNCED_COMMAND_HANDLER_FUNCTION(lua_ai, child, /*use_undo*/, /*show*/, /*error_handler*/)
|
SYNCED_COMMAND_HANDLER_FUNCTION(custom_command, child, /*use_undo*/, /*show*/, /*error_handler*/)
|
||||||
{
|
{
|
||||||
const std::string &lua_code = child["code"];
|
|
||||||
assert(resources::lua_kernel);
|
assert(resources::lua_kernel);
|
||||||
resources::lua_kernel->run(lua_code.c_str());
|
resources::lua_kernel->custom_command(child);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue