The Battle for Wesnoth  1.17.10+dev
stage_unit_formulas.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2022
3  by Yurii Chernyi <terraninfo@terraninfo.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /**
17  * @file
18  * Defines formula ai unit formulas stage
19  * */
20 
21 
23 #include "ai/formula/ai.hpp"
24 
25 #include "formula/formula.hpp"
26 #include "formula/function.hpp"
27 #include "game_board.hpp"
28 #include "log.hpp"
29 #include "resources.hpp"
30 #include "units/unit.hpp"
32 
33 static lg::log_domain log_formula_ai("ai/stage/unit_formulas");
34 #define LOG_AI LOG_STREAM(info, log_formula_ai)
35 #define WRN_AI LOG_STREAM(warn, log_formula_ai)
36 #define ERR_AI LOG_STREAM(err, log_formula_ai)
37 
38 namespace ai {
39 
41  ai_context &context
42  , const config &cfg
43  , formula_ai &fai)
44  : stage(context,cfg), fai_(fai)
45 {
46 
47 }
48 
49 
51 {
52 }
53 
55 {
56  //execute units formulas first
57  wfl::unit_formula_set units_with_formulas;
58 
59  unit_map &units_ = resources::gameboard->units();
60 
61  for(unit_map::unit_iterator i = units_.begin() ; i != units_.end() ; ++i)
62  {
63  if (i->side() == get_side()) {
64  if (i->formula_manager().has_formula() || i->formula_manager().has_loop_formula()) {
65  int priority = 0;
66  if (i->formula_manager().has_priority_formula()) {
67  try {
68  wfl::const_formula_ptr priority_formula(fai_.create_optional_formula(i->formula_manager().get_priority_formula()));
69  if (priority_formula) {
71  callable.add("me", wfl::variant(std::make_shared<wfl::unit_callable>(*i)));
72  priority = (wfl::formula::evaluate(priority_formula, callable)).as_int();
73  } else {
74  WRN_AI << "priority formula skipped, maybe it's empty or incorrect";
75  }
76  } catch(wfl::formula_error& e) {
77  if(e.filename == "formula")
78  e.line = 0;
79  fai_.handle_exception( e, "Unit priority formula error for unit: '" + i->type_id() + "' standing at (" + std::to_string(i->get_location().wml_x()) + "," + std::to_string(i->get_location().wml_y()) + ")");
80 
81  priority = 0;
82  } catch(const wfl::type_error& e) {
83  priority = 0;
84  ERR_AI << "formula type error while evaluating unit priority formula " << e.message;
85  }
86  }
87 
88  units_with_formulas.insert( wfl::unit_formula_pair( i, priority ) );
89  }
90  }
91  }
92 
93  for(wfl::unit_formula_set::iterator pair_it = units_with_formulas.begin() ; pair_it != units_with_formulas.end() ; ++pair_it)
94  {
95  unit_map::iterator i = pair_it->first;
96 
97  if( i.valid() ) {
98 
99  if (i->formula_manager().has_formula()) {
100  try {
101  wfl::const_formula_ptr formula(fai_.create_optional_formula(i->formula_manager().get_formula()));
102  if (formula) {
104  callable.add("me", wfl::variant(std::make_shared<wfl::unit_callable>(*i)));
105  fai_.make_action(formula, callable);
106  } else {
107  WRN_AI << "unit formula skipped, maybe it's empty or incorrect";
108  }
109  }
110  catch(wfl::formula_error& e) {
111  if(e.filename == "formula") {
112  e.line = 0;
113  }
114  fai_.handle_exception( e, "Unit formula error for unit: '" + i->type_id() + "' standing at (" + std::to_string(i->get_location().wml_x()) + "," + std::to_string(i->get_location().wml_y()) + ")");
115  }
116  }
117  }
118 
119  if( i.valid() ) {
120  if (i->formula_manager().has_loop_formula())
121  {
122  try {
123  wfl::const_formula_ptr loop_formula(fai_.create_optional_formula(i->formula_manager().get_loop_formula()));
124  if (loop_formula) {
126  callable.add("me", wfl::variant(std::make_shared<wfl::unit_callable>(*i)));
127  while ( !fai_.make_action(loop_formula, callable).is_empty() && i.valid() )
128  {
129  }
130  } else {
131  WRN_AI << "Loop formula skipped, maybe it's empty or incorrect";
132  }
133  } catch(wfl::formula_error& e) {
134  if (e.filename == "formula") {
135  e.line = 0;
136  }
137  fai_.handle_exception( e, "Unit loop formula error for unit: '" + i->type_id() + "' standing at (" + std::to_string(i->get_location().wml_x()) + "," + std::to_string(i->get_location().wml_y()) + ")");
138  }
139  }
140  }
141  }
142  return false;
143 }
144 
145 
147 {
148  //we have no state on our own
149 }
150 
151 
153 {
154  config cfg = stage::to_config();
155  //we have no state on our own
156  return cfg;
157 }
158 
159 } // end of namespace ai
Defines formula ai.
unit_iterator end()
Definition: map.hpp:429
void handle_exception(const wfl::formula_error &e) const
Definition: ai.cpp:117
virtual const unit_map & units() const override
Definition: game_board.hpp:113
static variant evaluate(const const_formula_ptr &f, const formula_callable &variables, formula_debugger *fdb=nullptr, variant default_res=variant(0))
Definition: formula.hpp:40
std::string filename
Definition: formula.hpp:108
unit_iterator begin()
Definition: map.hpp:419
Stage which executes unit formulas.
std::multiset< unit_formula_pair, unit_formula_compare > unit_formula_set
Definition: ai.hpp:59
A small explanation about what&#39;s going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:61
#define ERR_AI
#define WRN_AI
map_formula_callable & add(const std::string &key, const variant &value)
Definition: callable.hpp:253
game_board * gameboard
Definition: resources.cpp:21
std::size_t i
Definition: function.cpp:967
formula_callable_ptr fake_ptr()
Definition: callable.hpp:42
virtual side_number get_side() const override
Get the side number.
Definition: contexts.hpp:403
std::shared_ptr< const formula > const_formula_ptr
Definition: formula_fwd.hpp:24
virtual config to_config() const
serialize
Definition: stage.cpp:67
stage_unit_formulas(ai_context &context, const config &cfg, formula_ai &fai)
static lg::log_domain log_formula_ai("ai/stage/unit_formulas")
std::pair< unit_map::unit_iterator, int > unit_formula_pair
Definition: ai.hpp:49
bool do_play_stage()
Play the turn - implementation.
void on_create()
Initialization.
Standard logging facilities (interface).
std::string message
Definition: exceptions.hpp:30
Container associating units to locations.
Definition: map.hpp:98
#define e
config to_config() const
serialize
wfl::formula_ptr create_optional_formula(const std::string &formula_string) const
Create a new formula from the string, using the symbol table which is stored in the AI...
Definition: ai.cpp:143
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:60
bool valid() const
Definition: map.hpp:274
wfl::variant make_action(wfl::const_formula_ptr formula_, const wfl::formula_callable &variables)
Definition: ai.cpp:186
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
bool is_empty() const
Definition: variant.cpp:265