57 #include <boost/intrusive_ptr.hpp>
58 #include <boost/lexical_cast.hpp>
59 #include <boost/shared_ptr.hpp>
68 #define DBG_AI LOG_STREAM(debug, log_formula_ai)
69 #define LOG_AI LOG_STREAM(info, log_formula_ai)
70 #define WRN_AI LOG_STREAM(warn, log_formula_ai)
71 #define ERR_AI LOG_STREAM(err, log_formula_ai)
87 if( type ==
"movement") {
89 }
else if( type ==
"attack") {
92 ERR_AI <<
"Unknown candidate action type: " << type << std::endl;
95 handle_exception(e,
"Error while registering candidate action '" + name +
"'");
101 return recursion_counter_.get_count();
111 recursion_counter_(context.get_recursion_count()),
113 infinite_loop_guardian_(),
115 function_table_(*this)
119 LOG_AI <<
"creating new formula ai"<< std::endl;
129 LOG_AI << failed_operation <<
": " << e.
formula << std::endl;
197 throw formula_error(
"null formula passed to make_action",
"",
"formula",0);
200 const variant var = formula_->evaluate(variables);
206 ERR_AI <<
"skipped execution of action because ai context is not set correctly" << std::endl;
225 if( dst_un != units_.
end() ) {
229 int best_rating = 100;
233 for(
size_t n = 0;
n != 6; ++
n) {
238 if(units_.
find(adj[n]) != units_.
end()) {
243 unsigned int difference = abs(
int(preferred - n));
244 if(difference > NDIRECTIONS/2) {
245 difference = NDIRECTIONS - difference;
248 const int rating = difference * 2;
249 if(rating < best_rating || res.
valid() ==
false) {
250 best_rating = rating;
274 std::stack<variant> vars;
283 std::vector<variant> made_moves;
289 while( !vars.empty() ) {
291 if(vars.top().is_null()) {
305 const move_callable* move = try_convert_variant<move_callable>(action);
307 const attack_callable* attack = try_convert_variant<attack_callable>(action);
308 const attack_analysis* _attack_analysis = try_convert_variant<attack_analysis>(action);
309 const recruit_callable* recruit_command = try_convert_variant<recruit_callable>(action);
310 const recall_callable* recall_command = try_convert_variant<recall_callable>(action);
311 const set_var_callable* set_var_command = try_convert_variant<set_var_callable>(action);
312 const set_unit_var_callable* set_unit_var_command = try_convert_variant<set_unit_var_callable>(action);
313 const fallback_callable* fallback_command = try_convert_variant<fallback_callable>(action);
315 if( move || move_partial ) {
323 if ( !move_result->is_ok() ) {
325 LOG_AI <<
"ERROR #" << move_result->get_status() <<
" while executing 'move' formula function\n" << std::endl;
330 move_result->get_status(), move_result->get_unit_location()));
333 LOG_AI <<
"ERROR #" << move_result->get_status() <<
" while executing 'move_partial' formula function\n" << std::endl;
338 move_result->get_status(), move_result->get_unit_location()));
343 if( move_result->is_gamestate_changed() )
344 made_moves.push_back(action);
346 bool gamestate_changed =
false;
349 if( attack->move_from() != attack->src() ) {
351 gamestate_changed |= move_result->is_gamestate_changed();
353 if (!move_result->is_ok()) {
355 LOG_AI <<
"ERROR #" << move_result->get_status() <<
" while executing 'attack' formula function\n" << std::endl;
360 move_result->get_status(), move_result->get_unit_location()));
365 if (!move_result || move_result->is_ok() ) {
368 gamestate_changed |= attack_result->is_gamestate_changed();
369 if (!attack_result->is_ok()) {
372 LOG_AI <<
"ERROR #" << attack_result->get_status() <<
" while executing 'attack' formula function\n" << std::endl;
381 if (gamestate_changed) {
382 made_moves.push_back(action);
384 }
else if(_attack_analysis) {
387 assert(_attack_analysis->movements.empty() ==
false);
391 if (!unit.valid() || unit->attacks_left() == 0)
394 const map_location& move_from = _attack_analysis->movements.front().first;
395 const map_location& att_src = _attack_analysis->movements.front().second;
399 unit = units.
find(att_dst);
400 if ( unit == units.
end() )
404 if( move_from != att_src ) {
406 unit = units.
find(att_src);
407 if ( unit != units.
end() ) {
414 if(units.
count(att_src)) {
417 made_moves.push_back(action);
418 }
else if(recall_command) {
422 if( recall_result->is_ok() ) {
423 recall_result->execute();
426 if (!recall_result->is_ok()) {
431 recall_result->get_status()));
433 LOG_AI <<
"ERROR #" <<recall_result->get_status() <<
" while executing 'recall' formula function\n"<<std::endl;
435 ERR_AI <<
"ERROR #" <<recall_result->get_status() <<
" while executing 'recall' formula function\n"<<std::endl;
439 if( recall_result->is_gamestate_changed() ) {
440 made_moves.push_back(action);
443 }
else if(recruit_command) {
448 if( recruit_result->is_ok() )
449 recruit_result->execute();
451 if (!recruit_result->is_ok()) {
456 recruit_result->get_status()));
458 LOG_AI <<
"ERROR #" <<recruit_result->get_status() <<
" while executing 'recruit' formula function\n"<<std::endl;
460 ERR_AI <<
"ERROR #" <<recruit_result->get_status() <<
" while executing 'recruit' formula function\n"<<std::endl;
466 if( recruit_result->is_gamestate_changed() )
467 made_moves.push_back(action);
469 }
else if(set_var_command) {
471 LOG_AI <<
"Setting variable: " << set_var_command->key() <<
" -> " << set_var_command->value().to_debug_string() <<
"\n";
472 vars_.
add(set_var_command->key(), set_var_command->value());
473 made_moves.push_back(action);
476 ERR_AI <<
"ERROR #" << 5001 <<
" while executing 'set_var' formula function" << std::endl;
481 }
else if(set_unit_var_command) {
487 }
else if( (unit = units.
find(set_unit_var_command->loc())) == units.
end() ) {
489 }
else if (unit->side() !=
get_side()) {
494 LOG_AI <<
"Setting unit variable: " << set_unit_var_command->key() <<
" -> " << set_unit_var_command->value().to_debug_string() <<
"\n";
495 unit->formula_manager().add_formula_var(set_unit_var_command->key(), set_unit_var_command->value());
496 made_moves.push_back(action);
498 ERR_AI <<
"ERROR #" << status <<
" while executing 'set_unit_var' formula function" << std::endl;
506 made_moves.push_back(action);
509 ERR_AI <<
"ERROR #" << 5001 <<
" while executing 'continue' formula keyword" << std::endl;
516 }
else if(fallback_command) {
529 if( safe_call && (error !=
variant() || made_moves.empty() || made_moves.back() != action) ){
539 callable.
add(
"error", error);
545 vars.push(backup_result[ backup_result.
num_elements() -
n ]);
548 vars.push(backup_result);
569 template<
typename Container>
570 variant villages_from_set(
const Container& villages,
571 const std::set<map_location>* exclude=
nullptr) {
572 std::vector<variant> vars;
574 if(exclude && exclude->count(loc)) {
588 if(key ==
"aggression")
592 }
else if(key ==
"attack_depth")
596 }
else if(key ==
"avoid")
598 std::set<map_location> av_locs;
600 return villages_from_set(av_locs);
602 }
else if(key ==
"caution")
606 }
else if(key ==
"grouping")
610 }
else if(key ==
"leader_aggression")
614 }
else if(key ==
"leader_ignores_keep")
618 }
else if(key ==
"leader_value")
622 }
else if(key ==
"passive_leader")
626 }
else if(key ==
"passive_leader_shares_keep")
630 }
else if(key ==
"recruitment_pattern")
633 std::vector<variant> vars;
639 }
else if(key ==
"scout_village_targeting")
643 }
else if(key ==
"support_villages")
647 }
else if(key ==
"village_value")
651 }
else if(key ==
"villages_per_scout")
655 }
else if(key ==
"attacks")
659 }
else if(key ==
"turn")
663 }
else if(key ==
"time_of_day")
667 }
else if(key ==
"my_side")
671 }
else if(key ==
"my_side_number")
675 }
else if(key ==
"teams")
677 std::vector<variant> vars;
679 vars.push_back(
variant(
new team_callable(*
i)));
683 }
else if(key ==
"allies")
685 std::vector<variant> vars;
692 }
else if(key ==
"enemies")
694 std::vector<variant> vars;
701 }
else if(key ==
"my_recruits")
703 std::vector<variant> vars;
708 if(recruits.empty()) {
711 for(std::set<std::string>::const_iterator
i = recruits.begin();
i != recruits.end(); ++
i)
721 }
else if(key ==
"recruits_of_side")
723 std::vector<variant> vars;
724 std::vector< std::vector< variant> > tmp;
730 std::vector<variant>
v;
733 const std::set<std::string>& recruits = (*resources::teams)[
i].recruits();
734 if(recruits.empty()) {
737 for(std::set<std::string>::const_iterator str_it = recruits.begin(); str_it != recruits.end(); ++str_it)
747 for(
size_t i = 0;
i<tmp.size(); ++
i)
748 vars.push_back(
variant( &tmp[
i] ));
751 }
else if(key ==
"units")
753 std::vector<variant> vars;
759 }
else if(key ==
"units_of_side")
761 std::vector<variant> vars;
762 std::vector< std::vector< variant> > tmp;
765 std::vector<variant>
v;
768 for(
const unit &u : units) {
771 for(
size_t i = 0;
i<tmp.size(); ++
i)
772 vars.push_back(
variant( &tmp[
i] ));
775 }
else if(key ==
"my_units")
777 std::vector<variant> vars;
785 }
else if(key ==
"enemy_units")
787 std::vector<variant> vars;
790 if (!
i->incapacitated()) {
797 }
else if(key ==
"my_moves")
801 }
else if(key ==
"my_attacks")
804 }
else if(key ==
"enemy_moves")
808 }
else if(key ==
"my_leader")
811 if(i == units.
end()) {
816 }
else if(key ==
"recall_list")
818 std::vector<variant> tmp;
826 }
else if(key ==
"vars")
829 }
else if(key ==
"keeps")
832 }
else if(key ==
"map")
835 }
else if(key ==
"villages")
838 }
else if(key ==
"villages_of_side")
840 std::vector<variant> vars;
845 for(
size_t i = 0;
i<vars.size(); ++
i)
851 }
else if(key ==
"my_villages")
855 }
else if(key ==
"enemy_and_unowned_villages")
898 std::vector<variant> vars;
905 for(
size_t n = 0;
n != 6; ++
n) {
924 move_map::const_iterator
i;
925 std::pair<move_map::const_iterator,
928 unit_moves =
get_srcdst().equal_range(unit_A);
929 for(i = unit_moves.first; i != unit_moves.second; ++i) {
945 const t_string &formula_str = func[
"formula"];
984 fai_ca->update_callable_map( callable );
990 set_var_counter_(), set_unit_var_counter_(), continue_counter_()
1000 set_var_counter_ = 0;
1001 set_unit_var_counter_ = 0;
1002 continue_counter_ = 0;
1007 if(set_var_counter_ >= MAX_CALLS)
1015 if(set_unit_var_counter_ >= MAX_CALLS)
1018 set_unit_var_counter_++;
1023 if(continue_counter_ >= MAX_CALLS)
1026 continue_counter_++;
1036 DBG_AI <<
"formula_ai::to_config(): "<<
cfg_<<std::endl;
1048 i->second.serialize_to_string(str);
1050 WRN_AI <<
"variable ["<<
i->first <<
"] is not serializable - it will not be persisted across savegames"<<std::endl;
1055 ai_vars[
i->first] = str;
const expression_ptr & get_backup() const
virtual side_number get_side() const
Get the side number.
size_t num_elements() const
child_itors child_range(const std::string &key)
plain_route a_star_search(const map_location &src, const map_location &dst, double stop_at, const cost_calculator *calc, const size_t width, const size_t height, const teleport_map *teleports, bool border)
::tod_manager * tod_manager
boost::shared_ptr< formula > formula_ptr
Defines formula ai candidate actions - headers.
virtual double get_caution() const
virtual recall_result_ptr check_recall_action(const std::string &id, const map_location &where=map_location::null_location(), const map_location &from=map_location::null_location())=0
void add_function(const std::string &name, formula_function_ptr fcn)
size_t count(const map_location &loc) const
const std::set< std::string > & recruits() const
unit_iterator find_leader(int side)
GLuint GLuint GLsizei GLenum type
static l_noret error(LoadState *S, const char *why)
Managing the AI-Game interaction - AI actions and their results.
virtual double get_leader_value() const
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
bool is_enemy(int n) const
game_logic::candidate_action_ptr ca_ptr
attribute_map::value_type attribute
const variant & get_main() const
virtual std::string get_grouping() const
void build_all(unit_type::BUILD_STATUS status)
Makes sure the all unit_types are built to the specified level.
boost::shared_ptr< game_logic::base_candidate_action > candidate_action_ptr
unit_type_data unit_types
DIRECTION get_relative_dir(const map_location &loc, map_location::RELATIVE_DIR_MODE mode) const
GLint GLint GLint GLint GLint GLint y
virtual int get_villages_per_scout() const
void clear_children(const std::string &key)
virtual double get_leader_aggression() const
static const int MAX_COUNTER_VALUE
virtual double get_scout_village_targeting() const
A small explanation about what's going on here: Each action has access to two game_info objects First...
static void remove_gamestate_observer(events::observer *event_observer)
Removes an observer of game events except ai_user_interact event and ai_sync_network event...
virtual double get_aggression() const
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
std::vector< team > * teams
Structure which holds a single route between one location and another.
virtual int get_attack_depth() const
GLubyte GLubyte GLubyte GLubyte w
config & add_child(const std::string &key)
virtual bool get_leader_ignores_keep() const
Managing the AIs lifecycle - headers.
virtual const move_map & get_srcdst() const
virtual bool get_passive_leader_shares_keep() const
iterator end()
end iterator
virtual attack_result_ptr execute_attack_action(const map_location &attacker_loc, const map_location &defender_loc, int attacker_weapon)=0
virtual const move_map & get_enemy_dstsrc() const
virtual const move_map & get_enemy_srcdst() const
Encapsulates the map of the game.
const map_location & dst() const
void get_locations(std::set< map_location > &locs, bool with_border=false) const
static config unit_moves(reports::context &rc, const unit *u)
virtual bool get_support_villages() const
Game information for the AI.
virtual bool get_passive_leader() const
const std::string & as_string() const
void set_backup_result(const variant &v)
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
GLint GLint GLint GLint GLint x
DIRECTION
Valid directions which can be moved in our hexagonal world.
virtual recruit_result_ptr check_recruit_action(const std::string &unit_name, const map_location &where=map_location::null_location(), const map_location &from=map_location::null_location())=0
boost::shared_ptr< std::vector< unit_const_ptr > > units_
GLuint const GLchar * name
virtual const team & current_team() const
display_chat_manager & get_chat_manager()
std::string to_debug_string(std::vector< const game_logic::formula_callable * > *seen=nullptr, bool verbose=false) const
virtual double get_village_value() const
static void add_gamestate_observer(events::observer *event_observer)
Adds observer of game events except ai_user_interact event and ai_sync_network event.
config & child(const std::string &key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Standard logging facilities (interface).
recall_list_manager & recall_list()
Container associating units to locations.
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
std::vector< std::string > split(std::string const &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
unit_iterator find(size_t id)
const teleport_map get_teleport_locations(const unit &u, const team &viewing_team, bool see_all, bool ignore_units)
void serialize_from_string(const std::string &str)
const map_location & src() const
A config object defines a single node in a WML file, with access to child nodes.
virtual const std::vector< std::string > get_recruitment_pattern() const
void add_chat_message(const time_t &time, const std::string &speaker, int side, const std::string &msg, events::chat_handler::MESSAGE_TYPE type, bool bell)
virtual const terrain_filter & get_avoid() const
This module contains various pathfinding functions and utilities.
GLsizei const GLcharARB ** string
virtual const move_map & get_dstsrc() const
virtual const variant & get_attacks_as_variant() const
void init_readonly_context_proxy(readonly_context &target)
virtual move_result_ptr execute_move_action(const map_location &from, const map_location &to, bool remove_movement=true, bool unreach_is_ok=false)=0