Allow filter formulas to use a number of previously FormulaAI-exclusive functions
This commit is contained in:
parent
3f3a176f57
commit
4bd1fa7157
13 changed files with 422 additions and 356 deletions
|
@ -36,6 +36,10 @@ Version 1.13.8+dev:
|
|||
* Add owner key to terrain space callable, for villages
|
||||
* Location formulas in [tunnel] now have a teleport_unit variable
|
||||
* Fix a crash when attempting to call a non-existent function
|
||||
* The following previously FormulaAI-exclusive functions are now also available
|
||||
in filter formulas (SUF, SLF, SSF, SWF):
|
||||
adjacent_locs, location_in_radius, get_unit_type, unit_at, defense_on,
|
||||
chance_to_hit, movement_cost
|
||||
* WML Engine
|
||||
* If ai_algorithm is used in [modify_side][ai], it now replaces the whole AI
|
||||
with the contents of [modify_side][ai], instead of appending these parameters.
|
||||
|
|
|
@ -1088,6 +1088,12 @@
|
|||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Formula\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Formula\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\formula\function_gamestate.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Formula\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Formula\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Formula\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Formula\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\formula\string_utils.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Formula\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Formula\</ObjectFileName>
|
||||
|
@ -3596,6 +3602,7 @@
|
|||
<ClInclude Include="..\..\src\formula\debugger_fwd.hpp" />
|
||||
<ClInclude Include="..\..\src\formula\formula.hpp" />
|
||||
<ClInclude Include="..\..\src\formula\formula_fwd.hpp" />
|
||||
<ClInclude Include="..\..\src\formula\function_gamestate.hpp" />
|
||||
<ClInclude Include="..\..\src\formula\function.hpp" />
|
||||
<ClInclude Include="..\..\src\formula\string_utils.hpp" />
|
||||
<ClInclude Include="..\..\src\formula\tokenizer.hpp" />
|
||||
|
|
|
@ -1538,6 +1538,9 @@
|
|||
<ClCompile Include="..\..\src\preferences\lobby.cpp">
|
||||
<Filter>Preferences</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\formula\function_gamestate.cpp">
|
||||
<Filter>Formula</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\addon\client.hpp">
|
||||
|
@ -2982,6 +2985,9 @@
|
|||
<ClInclude Include="..\..\src\preferences\lobby.hpp">
|
||||
<Filter>Preferences</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\formula\function_gamestate.hpp">
|
||||
<Filter>Formula</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="..\..\src\tests\test_sdl_utils.hpp">
|
||||
|
|
|
@ -108,6 +108,7 @@ formula/debugger.cpp
|
|||
formula/debugger_fwd.cpp
|
||||
formula/formula.cpp
|
||||
formula/function.cpp
|
||||
formula/function_gamestate.cpp
|
||||
formula/string_utils.cpp
|
||||
formula/tokenizer.cpp
|
||||
formula/variant.cpp
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "ai/default/contexts.hpp"
|
||||
|
||||
#include "formula/function_gamestate.hpp"
|
||||
#include "attack_prediction.hpp"
|
||||
#include "filesystem.hpp"
|
||||
#include "game_board.hpp"
|
||||
|
@ -407,67 +408,6 @@ private:
|
|||
};
|
||||
|
||||
|
||||
class adjacent_locs_function : public function_expression {
|
||||
public:
|
||||
adjacent_locs_function(const args_list& args)
|
||||
: function_expression("adjacent_locs", args, 1, 1)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
|
||||
const map_location loc = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "adjacent_locs:location")).convert_to<location_callable>()->loc();
|
||||
map_location adj[6];
|
||||
get_adjacent_tiles(loc, adj);
|
||||
|
||||
std::vector<variant> v;
|
||||
for(int n = 0; n != 6; ++n) {
|
||||
if (resources::gameboard->map().on_board(adj[n]) )
|
||||
v.emplace_back(std::make_shared<location_callable>(adj[n]));
|
||||
}
|
||||
|
||||
return variant(v);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class locations_in_radius_function : public function_expression {
|
||||
public:
|
||||
locations_in_radius_function(const args_list& args)
|
||||
: function_expression("locations_in_radius", args, 2, 2)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
|
||||
const map_location loc = args()[0]->evaluate(variables,fdb).convert_to<location_callable>()->loc();
|
||||
|
||||
int range = args()[1]->evaluate(variables,fdb).as_int();
|
||||
|
||||
if( range < 0 )
|
||||
return variant();
|
||||
|
||||
if(!range)
|
||||
return variant(std::make_shared<location_callable>(loc));
|
||||
|
||||
std::vector<map_location> res;
|
||||
|
||||
get_tiles_in_radius( loc, range, res);
|
||||
|
||||
std::vector<variant> v;
|
||||
v.reserve(res.size()+1);
|
||||
v.emplace_back(std::make_shared<location_callable>(loc));
|
||||
|
||||
for(size_t n = 0; n != res.size(); ++n) {
|
||||
if (resources::gameboard->map().on_board(res[n]) )
|
||||
v.emplace_back(std::make_shared<location_callable>(res[n]));
|
||||
}
|
||||
|
||||
return variant(v);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** FormulaAI function to run fai script from file. Usable from in-game console.
|
||||
* arguments[0] - required file name, follows the usual wml convention
|
||||
*/
|
||||
|
@ -861,24 +801,6 @@ private:
|
|||
// formula_ai& ai_;
|
||||
//};
|
||||
|
||||
class get_unit_type_function : public function_expression {
|
||||
public:
|
||||
explicit get_unit_type_function(const args_list& args)
|
||||
: function_expression("get_unit_type", args, 1, 1)
|
||||
{}
|
||||
private:
|
||||
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
|
||||
const std::string type = args()[0]->evaluate(variables,add_debug_info(fdb,0,"get_unit_type:name")).as_string();
|
||||
|
||||
const unit_type *ut = unit_types.find(type);
|
||||
if(ut) {
|
||||
return variant(std::make_shared<unit_type_callable>(*ut));
|
||||
}
|
||||
|
||||
return variant();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class rate_action_function : public function_expression {
|
||||
|
@ -1273,28 +1195,6 @@ private:
|
|||
};
|
||||
|
||||
|
||||
class unit_at_function : public function_expression {
|
||||
public:
|
||||
unit_at_function(const args_list& args)
|
||||
: function_expression("unit_at", args, 1, 1)
|
||||
{}
|
||||
private:
|
||||
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
|
||||
variant loc_var = args()[0]->evaluate(variables,add_debug_info(fdb,0,"unit_at:location"));
|
||||
if (loc_var.is_null()) {
|
||||
return variant();
|
||||
}
|
||||
auto loc = loc_var.convert_to<location_callable>();
|
||||
const unit_map::const_iterator i = resources::gameboard->units().find(loc->loc());
|
||||
if(i != resources::gameboard->units().end()) {
|
||||
return variant(std::make_shared<unit_callable>(*i));
|
||||
} else {
|
||||
return variant();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class unit_moves_function : public function_expression {
|
||||
public:
|
||||
unit_moves_function(const args_list& args, const formula_ai& ai_object)
|
||||
|
@ -1347,144 +1247,6 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
class defense_on_function : public function_expression {
|
||||
public:
|
||||
defense_on_function(const args_list& args)
|
||||
: function_expression("defense_on", args, 2, 2)
|
||||
{}
|
||||
private:
|
||||
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
|
||||
variant u = args()[0]->evaluate(variables,add_debug_info(fdb,0,"defense_on:unit"));
|
||||
variant loc_var = args()[1]->evaluate(variables,add_debug_info(fdb,1,"defense_on:location"));
|
||||
if(u.is_null() || loc_var.is_null()) {
|
||||
return variant();
|
||||
}
|
||||
|
||||
auto u_call = u.try_convert<unit_callable>();
|
||||
auto u_type = u.try_convert<unit_type_callable>();
|
||||
const map_location& loc = loc_var.convert_to<location_callable>()->loc();
|
||||
|
||||
if (u_call)
|
||||
{
|
||||
const unit& un = u_call->get_unit();
|
||||
|
||||
if( un.total_movement() < un.movement_cost( (resources::gameboard->map())[loc]) )
|
||||
return variant();
|
||||
|
||||
if(!resources::gameboard->map().on_board(loc)) {
|
||||
return variant();
|
||||
}
|
||||
|
||||
return variant(100 - un.defense_modifier((resources::gameboard->map())[loc]));
|
||||
}
|
||||
|
||||
if (u_type)
|
||||
{
|
||||
const unit_type& un = u_type->get_unit_type();
|
||||
|
||||
if( un.movement() < un.movement_type().movement_cost((resources::gameboard->map())[loc]) )
|
||||
return variant();
|
||||
|
||||
if(!resources::gameboard->map().on_board(loc)) {
|
||||
return variant();
|
||||
}
|
||||
|
||||
return variant(100 - un.movement_type().defense_modifier((resources::gameboard->map())[loc]));
|
||||
}
|
||||
|
||||
return variant();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class chance_to_hit_function : public function_expression {
|
||||
public:
|
||||
chance_to_hit_function(const args_list& args)
|
||||
: function_expression("chance_to_hit", args, 2, 2)
|
||||
{}
|
||||
private:
|
||||
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
|
||||
variant u = args()[0]->evaluate(variables,add_debug_info(fdb,0,"chance_to_hit:unit"));
|
||||
variant loc_var = args()[1]->evaluate(variables,add_debug_info(fdb,1,"chance_to_hit:location"));
|
||||
if(u.is_null() || loc_var.is_null()) {
|
||||
return variant();
|
||||
}
|
||||
|
||||
auto u_call = u.try_convert<unit_callable>();
|
||||
auto u_type = u.try_convert<unit_type_callable>();
|
||||
const map_location& loc = loc_var.convert_to<location_callable>()->loc();
|
||||
|
||||
if (u_call)
|
||||
{
|
||||
const unit& un = u_call->get_unit();
|
||||
|
||||
if(!resources::gameboard->map().on_board(loc)) {
|
||||
return variant();
|
||||
}
|
||||
|
||||
return variant(un.defense_modifier((resources::gameboard->map())[loc]));
|
||||
}
|
||||
|
||||
if (u_type)
|
||||
{
|
||||
const unit_type& un = u_type->get_unit_type();
|
||||
|
||||
if(!resources::gameboard->map().on_board(loc)) {
|
||||
return variant();
|
||||
}
|
||||
|
||||
return variant(un.movement_type().defense_modifier((resources::gameboard->map())[loc]));
|
||||
}
|
||||
|
||||
return variant();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class movement_cost_function : public function_expression {
|
||||
public:
|
||||
movement_cost_function(const args_list& args)
|
||||
: function_expression("movement_cost", args, 2, 2)
|
||||
{}
|
||||
private:
|
||||
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
|
||||
variant u = args()[0]->evaluate(variables,add_debug_info(fdb,0,"movement_cost:unit"));
|
||||
variant loc_var = args()[1]->evaluate(variables,add_debug_info(fdb,0,"movement_cost:location"));
|
||||
if(u.is_null() || loc_var.is_null()) {
|
||||
return variant();
|
||||
}
|
||||
//we can pass to this function either unit_callable or unit_type callable
|
||||
auto u_call = u.try_convert<unit_callable>();
|
||||
auto u_type = u.try_convert<unit_type_callable>();
|
||||
const map_location& loc = loc_var.convert_to<location_callable>()->loc();
|
||||
|
||||
if (u_call)
|
||||
{
|
||||
const unit& un = u_call->get_unit();
|
||||
|
||||
if(!resources::gameboard->map().on_board(loc)) {
|
||||
return variant();
|
||||
}
|
||||
|
||||
return variant(un.movement_cost((resources::gameboard->map())[loc]));
|
||||
}
|
||||
|
||||
if (u_type)
|
||||
{
|
||||
const unit_type& un = u_type->get_unit_type();
|
||||
|
||||
if(!resources::gameboard->map().on_board(loc)) {
|
||||
return variant();
|
||||
}
|
||||
|
||||
return variant(un.movement_type().movement_cost((resources::gameboard->map())[loc]));
|
||||
}
|
||||
|
||||
return variant();
|
||||
}
|
||||
};
|
||||
|
||||
class is_avoided_location_function : public function_expression {
|
||||
public:
|
||||
is_avoided_location_function(const args_list& args, const formula_ai& ai_object)
|
||||
|
@ -1589,54 +1351,48 @@ public:
|
|||
|
||||
}
|
||||
|
||||
// First macro is for functions taking an additional formula_ai argument.
|
||||
// Functions using the second macro could potentially be made core.
|
||||
#define AI_FUNCTION(name) add_function(#name, formula_function_ptr( \
|
||||
// This macro is for functions taking an additional formula_ai argument.
|
||||
// Functions using the other macro could potentially be made core.
|
||||
#define DECLARE_FAI_FUNCTION(name) add_function(#name, formula_function_ptr( \
|
||||
new ai_formula_function<name##_function>(#name, ai)))
|
||||
#define FUNCTION(name) add_function(#name, formula_function_ptr( \
|
||||
new builtin_formula_function<name##_function>(#name)))
|
||||
|
||||
ai_function_symbol_table::ai_function_symbol_table(ai::formula_ai& ai) : function_symbol_table(std::make_shared<action_function_symbol_table>()) {
|
||||
FUNCTION(outcomes);
|
||||
//AI_FUNCTION(evaluate_for_position);
|
||||
FUNCTION(move);
|
||||
FUNCTION(move_partial);
|
||||
FUNCTION(attack);
|
||||
AI_FUNCTION(rate_action);
|
||||
FUNCTION(recall);
|
||||
FUNCTION(recruit);
|
||||
FUNCTION(get_unit_type);
|
||||
AI_FUNCTION(is_avoided_location);
|
||||
FUNCTION(is_village);
|
||||
AI_FUNCTION(is_unowned_village);
|
||||
FUNCTION(unit_at);
|
||||
AI_FUNCTION(unit_moves);
|
||||
FUNCTION(set_unit_var);
|
||||
FUNCTION(fallback);
|
||||
FUNCTION(units_can_reach);
|
||||
AI_FUNCTION(debug_label);
|
||||
FUNCTION(defense_on);
|
||||
FUNCTION(chance_to_hit);
|
||||
FUNCTION(movement_cost);
|
||||
FUNCTION(max_possible_damage);
|
||||
FUNCTION(max_possible_damage_with_retaliation);
|
||||
AI_FUNCTION(next_hop);
|
||||
FUNCTION(adjacent_locs);
|
||||
FUNCTION(locations_in_radius);
|
||||
FUNCTION(castle_locs);
|
||||
FUNCTION(timeofday_modifier);
|
||||
AI_FUNCTION(distance_to_nearest_unowned_village);
|
||||
AI_FUNCTION(shortest_path);
|
||||
AI_FUNCTION(simplest_path);
|
||||
AI_FUNCTION(nearest_keep);
|
||||
AI_FUNCTION(suitable_keep);
|
||||
FUNCTION(nearest_loc);
|
||||
AI_FUNCTION(find_shroud);
|
||||
AI_FUNCTION(close_enemies);
|
||||
FUNCTION(calculate_outcome);
|
||||
AI_FUNCTION(run_file);
|
||||
AI_FUNCTION(calculate_map_ownership);
|
||||
ai_function_symbol_table::ai_function_symbol_table(ai::formula_ai& ai)
|
||||
: function_symbol_table(std::make_shared<gamestate_function_symbol_table>(std::make_shared<action_function_symbol_table>()))
|
||||
{
|
||||
function_symbol_table& functions_table = *this;
|
||||
DECLARE_WFL_FUNCTION(outcomes);
|
||||
//DECLARE_FAI_FUNCTION(evaluate_for_position);
|
||||
DECLARE_WFL_FUNCTION(move);
|
||||
DECLARE_WFL_FUNCTION(move_partial);
|
||||
DECLARE_WFL_FUNCTION(attack);
|
||||
DECLARE_FAI_FUNCTION(rate_action);
|
||||
DECLARE_WFL_FUNCTION(recall);
|
||||
DECLARE_WFL_FUNCTION(recruit);
|
||||
DECLARE_FAI_FUNCTION(is_avoided_location);
|
||||
DECLARE_WFL_FUNCTION(is_village);
|
||||
DECLARE_FAI_FUNCTION(is_unowned_village);
|
||||
DECLARE_FAI_FUNCTION(unit_moves);
|
||||
DECLARE_WFL_FUNCTION(set_unit_var);
|
||||
DECLARE_WFL_FUNCTION(fallback);
|
||||
DECLARE_WFL_FUNCTION(units_can_reach);
|
||||
DECLARE_FAI_FUNCTION(debug_label);
|
||||
DECLARE_WFL_FUNCTION(max_possible_damage);
|
||||
DECLARE_WFL_FUNCTION(max_possible_damage_with_retaliation);
|
||||
DECLARE_FAI_FUNCTION(next_hop);
|
||||
DECLARE_WFL_FUNCTION(castle_locs);
|
||||
DECLARE_WFL_FUNCTION(timeofday_modifier);
|
||||
DECLARE_FAI_FUNCTION(distance_to_nearest_unowned_village);
|
||||
DECLARE_FAI_FUNCTION(shortest_path);
|
||||
DECLARE_FAI_FUNCTION(simplest_path);
|
||||
DECLARE_FAI_FUNCTION(nearest_keep);
|
||||
DECLARE_FAI_FUNCTION(suitable_keep);
|
||||
DECLARE_WFL_FUNCTION(nearest_loc);
|
||||
DECLARE_FAI_FUNCTION(find_shroud);
|
||||
DECLARE_FAI_FUNCTION(close_enemies);
|
||||
DECLARE_WFL_FUNCTION(calculate_outcome);
|
||||
DECLARE_FAI_FUNCTION(run_file);
|
||||
DECLARE_FAI_FUNCTION(calculate_map_ownership);
|
||||
}
|
||||
#undef FUNCTION
|
||||
#undef DECLARE_WFL_FUNCTION
|
||||
|
||||
}
|
||||
|
|
|
@ -1606,85 +1606,82 @@ std::set<std::string> function_symbol_table::get_function_names() const
|
|||
return res;
|
||||
}
|
||||
|
||||
#define FUNCTION(name) functions_table.add_function(#name, \
|
||||
formula_function_ptr(new builtin_formula_function<name##_function>(#name)))
|
||||
|
||||
std::shared_ptr<function_symbol_table> function_symbol_table::get_builtins() {
|
||||
static function_symbol_table functions_table(builtins_tag);
|
||||
|
||||
if(functions_table.empty()) {
|
||||
functions_table.parent = nullptr;
|
||||
using namespace builtins;
|
||||
FUNCTION(debug);
|
||||
FUNCTION(dir);
|
||||
FUNCTION(if);
|
||||
FUNCTION(switch);
|
||||
FUNCTION(abs);
|
||||
FUNCTION(min);
|
||||
FUNCTION(max);
|
||||
FUNCTION(choose);
|
||||
FUNCTION(debug_float);
|
||||
FUNCTION(debug_print);
|
||||
FUNCTION(debug_profile);
|
||||
FUNCTION(wave);
|
||||
FUNCTION(sort);
|
||||
FUNCTION(contains_string);
|
||||
FUNCTION(find_string);
|
||||
FUNCTION(reverse);
|
||||
FUNCTION(filter);
|
||||
FUNCTION(find);
|
||||
FUNCTION(map);
|
||||
FUNCTION(zip);
|
||||
FUNCTION(take_while);
|
||||
FUNCTION(reduce);
|
||||
FUNCTION(sum);
|
||||
FUNCTION(head);
|
||||
FUNCTION(tail);
|
||||
FUNCTION(size);
|
||||
FUNCTION(null);
|
||||
FUNCTION(ceil);
|
||||
FUNCTION(floor);
|
||||
FUNCTION(trunc);
|
||||
FUNCTION(frac);
|
||||
FUNCTION(sgn);
|
||||
FUNCTION(round);
|
||||
FUNCTION(as_decimal);
|
||||
FUNCTION(pair);
|
||||
FUNCTION(loc);
|
||||
FUNCTION(distance_between);
|
||||
FUNCTION(index_of);
|
||||
FUNCTION(keys);
|
||||
FUNCTION(values);
|
||||
FUNCTION(tolist);
|
||||
FUNCTION(tomap);
|
||||
FUNCTION(substring);
|
||||
FUNCTION(replace);
|
||||
FUNCTION(length);
|
||||
FUNCTION(concatenate);
|
||||
FUNCTION(sin);
|
||||
FUNCTION(cos);
|
||||
FUNCTION(tan);
|
||||
FUNCTION(asin);
|
||||
FUNCTION(acos);
|
||||
FUNCTION(atan);
|
||||
FUNCTION(sqrt);
|
||||
FUNCTION(cbrt);
|
||||
FUNCTION(root);
|
||||
FUNCTION(log);
|
||||
FUNCTION(exp);
|
||||
FUNCTION(pi);
|
||||
FUNCTION(hypot);
|
||||
FUNCTION(type);
|
||||
DECLARE_WFL_FUNCTION(debug);
|
||||
DECLARE_WFL_FUNCTION(dir);
|
||||
DECLARE_WFL_FUNCTION(if);
|
||||
DECLARE_WFL_FUNCTION(switch);
|
||||
DECLARE_WFL_FUNCTION(abs);
|
||||
DECLARE_WFL_FUNCTION(min);
|
||||
DECLARE_WFL_FUNCTION(max);
|
||||
DECLARE_WFL_FUNCTION(choose);
|
||||
DECLARE_WFL_FUNCTION(debug_float);
|
||||
DECLARE_WFL_FUNCTION(debug_print);
|
||||
DECLARE_WFL_FUNCTION(debug_profile);
|
||||
DECLARE_WFL_FUNCTION(wave);
|
||||
DECLARE_WFL_FUNCTION(sort);
|
||||
DECLARE_WFL_FUNCTION(contains_string);
|
||||
DECLARE_WFL_FUNCTION(find_string);
|
||||
DECLARE_WFL_FUNCTION(reverse);
|
||||
DECLARE_WFL_FUNCTION(filter);
|
||||
DECLARE_WFL_FUNCTION(find);
|
||||
DECLARE_WFL_FUNCTION(map);
|
||||
DECLARE_WFL_FUNCTION(zip);
|
||||
DECLARE_WFL_FUNCTION(take_while);
|
||||
DECLARE_WFL_FUNCTION(reduce);
|
||||
DECLARE_WFL_FUNCTION(sum);
|
||||
DECLARE_WFL_FUNCTION(head);
|
||||
DECLARE_WFL_FUNCTION(tail);
|
||||
DECLARE_WFL_FUNCTION(size);
|
||||
DECLARE_WFL_FUNCTION(null);
|
||||
DECLARE_WFL_FUNCTION(ceil);
|
||||
DECLARE_WFL_FUNCTION(floor);
|
||||
DECLARE_WFL_FUNCTION(trunc);
|
||||
DECLARE_WFL_FUNCTION(frac);
|
||||
DECLARE_WFL_FUNCTION(sgn);
|
||||
DECLARE_WFL_FUNCTION(round);
|
||||
DECLARE_WFL_FUNCTION(as_decimal);
|
||||
DECLARE_WFL_FUNCTION(pair);
|
||||
DECLARE_WFL_FUNCTION(loc);
|
||||
DECLARE_WFL_FUNCTION(distance_between);
|
||||
DECLARE_WFL_FUNCTION(index_of);
|
||||
DECLARE_WFL_FUNCTION(keys);
|
||||
DECLARE_WFL_FUNCTION(values);
|
||||
DECLARE_WFL_FUNCTION(tolist);
|
||||
DECLARE_WFL_FUNCTION(tomap);
|
||||
DECLARE_WFL_FUNCTION(substring);
|
||||
DECLARE_WFL_FUNCTION(replace);
|
||||
DECLARE_WFL_FUNCTION(length);
|
||||
DECLARE_WFL_FUNCTION(concatenate);
|
||||
DECLARE_WFL_FUNCTION(sin);
|
||||
DECLARE_WFL_FUNCTION(cos);
|
||||
DECLARE_WFL_FUNCTION(tan);
|
||||
DECLARE_WFL_FUNCTION(asin);
|
||||
DECLARE_WFL_FUNCTION(acos);
|
||||
DECLARE_WFL_FUNCTION(atan);
|
||||
DECLARE_WFL_FUNCTION(sqrt);
|
||||
DECLARE_WFL_FUNCTION(cbrt);
|
||||
DECLARE_WFL_FUNCTION(root);
|
||||
DECLARE_WFL_FUNCTION(log);
|
||||
DECLARE_WFL_FUNCTION(exp);
|
||||
DECLARE_WFL_FUNCTION(pi);
|
||||
DECLARE_WFL_FUNCTION(hypot);
|
||||
DECLARE_WFL_FUNCTION(type);
|
||||
}
|
||||
|
||||
return std::shared_ptr<function_symbol_table>(&functions_table, [](function_symbol_table*){});
|
||||
}
|
||||
|
||||
action_function_symbol_table::action_function_symbol_table() {
|
||||
action_function_symbol_table::action_function_symbol_table(std::shared_ptr<function_symbol_table> parent) : function_symbol_table(parent) {
|
||||
using namespace actions;
|
||||
function_symbol_table& functions_table = *this;
|
||||
FUNCTION(safe_call);
|
||||
FUNCTION(set_var);
|
||||
DECLARE_WFL_FUNCTION(safe_call);
|
||||
DECLARE_WFL_FUNCTION(set_var);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -154,9 +154,14 @@ public:
|
|||
|
||||
class action_function_symbol_table : public function_symbol_table {
|
||||
public:
|
||||
action_function_symbol_table();
|
||||
action_function_symbol_table(std::shared_ptr<function_symbol_table> parent = nullptr);
|
||||
};
|
||||
|
||||
/// Declares a function `name` in the local function table `functions_table`.
|
||||
/// The function must be defined by a `name_function` class which is accessible in the current scope.
|
||||
#define DECLARE_WFL_FUNCTION(name) functions_table.add_function(#name, \
|
||||
formula_function_ptr(new builtin_formula_function<name##_function>(#name)))
|
||||
|
||||
class wrapper_formula : public formula_expression {
|
||||
public:
|
||||
wrapper_formula()
|
||||
|
|
275
src/formula/function_gamestate.cpp
Normal file
275
src/formula/function_gamestate.cpp
Normal file
|
@ -0,0 +1,275 @@
|
|||
|
||||
#include "formula/function_gamestate.hpp"
|
||||
#include "formula/callable_objects.hpp"
|
||||
|
||||
#include "resources.hpp"
|
||||
#include "game_board.hpp"
|
||||
#include "map/map.hpp"
|
||||
#include "pathutils.hpp"
|
||||
|
||||
namespace wfl {
|
||||
|
||||
namespace gamestate {
|
||||
|
||||
class adjacent_locs_function : public function_expression
|
||||
{
|
||||
public:
|
||||
adjacent_locs_function(const args_list& args)
|
||||
: function_expression("adjacent_locs", args, 1, 1)
|
||||
{}
|
||||
|
||||
private:
|
||||
variant execute(const formula_callable& variables, formula_debugger *fdb) const
|
||||
{
|
||||
const map_location loc = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "adjacent_locs:location")).convert_to<location_callable>()->loc();
|
||||
map_location adj[6];
|
||||
get_adjacent_tiles(loc, adj);
|
||||
|
||||
std::vector<variant> v;
|
||||
for(int n = 0; n != 6; ++n) {
|
||||
if(resources::gameboard->map().on_board(adj[n])) {
|
||||
v.emplace_back(std::make_shared<location_callable>(adj[n]));
|
||||
}
|
||||
}
|
||||
|
||||
return variant(v);
|
||||
}
|
||||
};
|
||||
|
||||
class locations_in_radius_function : public function_expression
|
||||
{
|
||||
public:
|
||||
locations_in_radius_function(const args_list& args)
|
||||
: function_expression("locations_in_radius", args, 2, 2)
|
||||
{}
|
||||
|
||||
private:
|
||||
variant execute(const formula_callable& variables, formula_debugger *fdb) const
|
||||
{
|
||||
const map_location loc = args()[0]->evaluate(variables, fdb).convert_to<location_callable>()->loc();
|
||||
|
||||
int range = args()[1]->evaluate(variables, fdb).as_int();
|
||||
|
||||
if(range < 0) {
|
||||
return variant();
|
||||
}
|
||||
|
||||
if(!range) {
|
||||
return variant(std::make_shared<location_callable>(loc));
|
||||
}
|
||||
|
||||
std::vector<map_location> res;
|
||||
|
||||
get_tiles_in_radius(loc, range, res);
|
||||
|
||||
std::vector<variant> v;
|
||||
v.reserve(res.size() + 1);
|
||||
v.emplace_back(std::make_shared<location_callable>(loc));
|
||||
|
||||
for(size_t n = 0; n != res.size(); ++n) {
|
||||
if(resources::gameboard->map().on_board(res[n])) {
|
||||
v.emplace_back(std::make_shared<location_callable>(res[n]));
|
||||
}
|
||||
}
|
||||
|
||||
return variant(v);
|
||||
}
|
||||
};
|
||||
|
||||
class get_unit_type_function : public function_expression
|
||||
{
|
||||
public:
|
||||
explicit get_unit_type_function(const args_list& args)
|
||||
: function_expression("get_unit_type", args, 1, 1)
|
||||
{}
|
||||
private:
|
||||
variant execute(const formula_callable& variables, formula_debugger *fdb) const
|
||||
{
|
||||
const std::string type = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "get_unit_type:name")).as_string();
|
||||
|
||||
const unit_type *ut = unit_types.find(type);
|
||||
if(ut) {
|
||||
return variant(std::make_shared<unit_type_callable>(*ut));
|
||||
}
|
||||
|
||||
return variant();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class unit_at_function : public function_expression
|
||||
{
|
||||
public:
|
||||
unit_at_function(const args_list& args)
|
||||
: function_expression("unit_at", args, 1, 1)
|
||||
{}
|
||||
private:
|
||||
variant execute(const formula_callable& variables, formula_debugger *fdb) const
|
||||
{
|
||||
variant loc_var = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "unit_at:location"));
|
||||
if(loc_var.is_null()) {
|
||||
return variant();
|
||||
}
|
||||
auto loc = loc_var.convert_to<location_callable>();
|
||||
const unit_map::const_iterator i = resources::gameboard->units().find(loc->loc());
|
||||
if(i != resources::gameboard->units().end()) {
|
||||
return variant(std::make_shared<unit_callable>(*i));
|
||||
} else {
|
||||
return variant();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class defense_on_function : public function_expression
|
||||
{
|
||||
public:
|
||||
defense_on_function(const args_list& args)
|
||||
: function_expression("defense_on", args, 2, 2)
|
||||
{}
|
||||
private:
|
||||
variant execute(const formula_callable& variables, formula_debugger *fdb) const
|
||||
{
|
||||
variant u = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "defense_on:unit"));
|
||||
variant loc_var = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "defense_on:location"));
|
||||
if(u.is_null() || loc_var.is_null()) {
|
||||
return variant();
|
||||
}
|
||||
|
||||
auto u_call = u.try_convert<unit_callable>();
|
||||
auto u_type = u.try_convert<unit_type_callable>();
|
||||
const map_location& loc = loc_var.convert_to<location_callable>()->loc();
|
||||
|
||||
if(u_call) {
|
||||
const unit& un = u_call->get_unit();
|
||||
|
||||
if(un.total_movement() < un.movement_cost((resources::gameboard->map())[loc]))
|
||||
return variant();
|
||||
|
||||
if(!resources::gameboard->map().on_board(loc)) {
|
||||
return variant();
|
||||
}
|
||||
|
||||
return variant(100 - un.defense_modifier((resources::gameboard->map())[loc]));
|
||||
}
|
||||
|
||||
if(u_type) {
|
||||
const unit_type& un = u_type->get_unit_type();
|
||||
|
||||
if(un.movement() < un.movement_type().movement_cost((resources::gameboard->map())[loc]))
|
||||
return variant();
|
||||
|
||||
if(!resources::gameboard->map().on_board(loc)) {
|
||||
return variant();
|
||||
}
|
||||
|
||||
return variant(100 - un.movement_type().defense_modifier((resources::gameboard->map())[loc]));
|
||||
}
|
||||
|
||||
return variant();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class chance_to_hit_function : public function_expression
|
||||
{
|
||||
public:
|
||||
chance_to_hit_function(const args_list& args)
|
||||
: function_expression("chance_to_hit", args, 2, 2)
|
||||
{}
|
||||
private:
|
||||
variant execute(const formula_callable& variables, formula_debugger *fdb) const
|
||||
{
|
||||
variant u = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "chance_to_hit:unit"));
|
||||
variant loc_var = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "chance_to_hit:location"));
|
||||
if(u.is_null() || loc_var.is_null()) {
|
||||
return variant();
|
||||
}
|
||||
|
||||
auto u_call = u.try_convert<unit_callable>();
|
||||
auto u_type = u.try_convert<unit_type_callable>();
|
||||
const map_location& loc = loc_var.convert_to<location_callable>()->loc();
|
||||
|
||||
if(u_call) {
|
||||
const unit& un = u_call->get_unit();
|
||||
|
||||
if(!resources::gameboard->map().on_board(loc)) {
|
||||
return variant();
|
||||
}
|
||||
|
||||
return variant(un.defense_modifier((resources::gameboard->map())[loc]));
|
||||
}
|
||||
|
||||
if(u_type) {
|
||||
const unit_type& un = u_type->get_unit_type();
|
||||
|
||||
if(!resources::gameboard->map().on_board(loc)) {
|
||||
return variant();
|
||||
}
|
||||
|
||||
return variant(un.movement_type().defense_modifier((resources::gameboard->map())[loc]));
|
||||
}
|
||||
|
||||
return variant();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class movement_cost_function : public function_expression
|
||||
{
|
||||
public:
|
||||
movement_cost_function(const args_list& args)
|
||||
: function_expression("movement_cost", args, 2, 2)
|
||||
{}
|
||||
private:
|
||||
variant execute(const formula_callable& variables, formula_debugger *fdb) const
|
||||
{
|
||||
variant u = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "movement_cost:unit"));
|
||||
variant loc_var = args()[1]->evaluate(variables, add_debug_info(fdb, 0, "movement_cost:location"));
|
||||
if(u.is_null() || loc_var.is_null()) {
|
||||
return variant();
|
||||
}
|
||||
//we can pass to this function either unit_callable or unit_type callable
|
||||
auto u_call = u.try_convert<unit_callable>();
|
||||
auto u_type = u.try_convert<unit_type_callable>();
|
||||
const map_location& loc = loc_var.convert_to<location_callable>()->loc();
|
||||
|
||||
if(u_call) {
|
||||
const unit& un = u_call->get_unit();
|
||||
|
||||
if(!resources::gameboard->map().on_board(loc)) {
|
||||
return variant();
|
||||
}
|
||||
|
||||
return variant(un.movement_cost((resources::gameboard->map())[loc]));
|
||||
}
|
||||
|
||||
if(u_type) {
|
||||
const unit_type& un = u_type->get_unit_type();
|
||||
|
||||
if(!resources::gameboard->map().on_board(loc)) {
|
||||
return variant();
|
||||
}
|
||||
|
||||
return variant(un.movement_type().movement_cost((resources::gameboard->map())[loc]));
|
||||
}
|
||||
|
||||
return variant();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gamestate
|
||||
|
||||
gamestate_function_symbol_table::gamestate_function_symbol_table(std::shared_ptr<function_symbol_table> parent) : function_symbol_table(parent) {
|
||||
using namespace gamestate;
|
||||
function_symbol_table& functions_table = *this;
|
||||
DECLARE_WFL_FUNCTION(get_unit_type);
|
||||
DECLARE_WFL_FUNCTION(unit_at);
|
||||
DECLARE_WFL_FUNCTION(defense_on);
|
||||
DECLARE_WFL_FUNCTION(chance_to_hit);
|
||||
DECLARE_WFL_FUNCTION(movement_cost);
|
||||
DECLARE_WFL_FUNCTION(adjacent_locs);
|
||||
DECLARE_WFL_FUNCTION(locations_in_radius);
|
||||
}
|
||||
|
||||
}
|
11
src/formula/function_gamestate.hpp
Normal file
11
src/formula/function_gamestate.hpp
Normal file
|
@ -0,0 +1,11 @@
|
|||
|
||||
#include "formula/function.hpp"
|
||||
|
||||
namespace wfl {
|
||||
|
||||
class gamestate_function_symbol_table : public function_symbol_table {
|
||||
public:
|
||||
gamestate_function_symbol_table(std::shared_ptr<function_symbol_table> parent = nullptr);
|
||||
};
|
||||
|
||||
}
|
|
@ -32,6 +32,7 @@
|
|||
#include "variable.hpp"
|
||||
#include "formula/callable_objects.hpp"
|
||||
#include "formula/formula.hpp"
|
||||
#include "formula/function_gamestate.hpp"
|
||||
|
||||
static lg::log_domain log_engine_sf("engine/side_filter");
|
||||
#define ERR_NG LOG_STREAM(err, log_engine_sf)
|
||||
|
@ -228,7 +229,7 @@ bool side_filter::match_internal(const team &t) const
|
|||
if (cfg_.has_attribute("formula")) {
|
||||
try {
|
||||
const wfl::team_callable callable(t);
|
||||
const wfl::formula form(cfg_["formula"]);
|
||||
const wfl::formula form(cfg_["formula"], new wfl::gamestate_function_symbol_table);
|
||||
if(!form.evaluate(callable).as_bool()) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "variable.hpp"
|
||||
#include "formula/callable_objects.hpp"
|
||||
#include "formula/formula.hpp"
|
||||
#include "formula/function_gamestate.hpp"
|
||||
#include "scripting/game_lua_kernel.hpp"
|
||||
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
|
@ -333,7 +334,7 @@ bool terrain_filter::match_internal(const map_location& loc, const unit* ref_uni
|
|||
callable.add("teleport_unit", wfl::variant(ref));
|
||||
// It's not destroyed upon scope exit because the variant holds a reference
|
||||
}
|
||||
const wfl::formula form(cfg_["formula"]);
|
||||
const wfl::formula form(cfg_["formula"], new wfl::gamestate_function_symbol_table);
|
||||
if(!form.evaluate(callable).as_bool()) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "formula/callable_objects.hpp"
|
||||
#include "formula/formula.hpp"
|
||||
#include "formula/string_utils.hpp"
|
||||
#include "formula/function_gamestate.hpp"
|
||||
|
||||
#include "lexical_cast.hpp"
|
||||
#include "log.hpp"
|
||||
|
@ -138,7 +139,7 @@ static bool matches_simple_filter(const attack_type & attack, const config & fil
|
|||
if (!filter_formula.empty()) {
|
||||
try {
|
||||
const wfl::attack_type_callable callable(attack);
|
||||
const wfl::formula form(filter_formula);
|
||||
const wfl::formula form(filter_formula, new wfl::gamestate_function_symbol_table);
|
||||
if(!form.evaluate(callable).as_bool()) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "wml_exception.hpp" // needed for FAIL
|
||||
#include "formula/callable_objects.hpp"
|
||||
#include "formula/formula.hpp"
|
||||
#include "formula/function_gamestate.hpp"
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
|
@ -699,7 +700,7 @@ bool basic_unit_filter_impl::internal_matches_filter(const unit & u, const map_l
|
|||
callable.add("other", wfl::variant(secondary));
|
||||
// It's not destroyed upon scope exit because the variant holds a reference
|
||||
}
|
||||
const wfl::formula form(vcfg["formula"]);
|
||||
const wfl::formula form(vcfg["formula"], new wfl::gamestate_function_symbol_table);
|
||||
if(!form.evaluate(callable).as_bool()) {
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue