The Battle for Wesnoth  1.19.1+dev
stage_unit_formulas.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2024
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 "game_board.hpp"
27 #include "log.hpp"
28 #include "resources.hpp"
29 #include "units/unit.hpp"
31 
32 static lg::log_domain log_formula_ai("ai/stage/unit_formulas");
33 #define LOG_AI LOG_STREAM(info, log_formula_ai)
34 #define WRN_AI LOG_STREAM(warn, log_formula_ai)
35 #define ERR_AI LOG_STREAM(err, log_formula_ai)
36 
37 namespace ai {
38 
40  ai_context &context
41  , const config &cfg
42  , formula_ai &fai)
43  : stage(context,cfg), fai_(fai)
44 {
45 
46 }
47 
48 
50 {
51 }
52 
54 {
55  //execute units formulas first
56  wfl::unit_formula_set units_with_formulas;
57 
58  unit_map &units_ = resources::gameboard->units();
59 
60  for(unit_map::unit_iterator i = units_.begin() ; i != units_.end() ; ++i)
61  {
62  if (i->side() == get_side()) {
63  if (i->formula_manager().has_formula() || i->formula_manager().has_loop_formula()) {
64  int priority = 0;
65  if (i->formula_manager().has_priority_formula()) {
66  try {
67  wfl::const_formula_ptr priority_formula(fai_.create_optional_formula(i->formula_manager().get_priority_formula()));
68  if (priority_formula) {
70  callable.add("me", wfl::variant(std::make_shared<wfl::unit_callable>(*i)));
71  priority = (wfl::formula::evaluate(priority_formula, callable)).as_int();
72  } else {
73  WRN_AI << "priority formula skipped, maybe it's empty or incorrect";
74  }
75  } catch(wfl::formula_error& e) {
76  if(e.filename == "formula")
77  e.line = 0;
78  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()) + ")");
79 
80  priority = 0;
81  } catch(const wfl::type_error& e) {
82  priority = 0;
83  ERR_AI << "formula type error while evaluating unit priority formula " << e.message;
84  }
85  }
86 
87  units_with_formulas.insert( wfl::unit_formula_pair( i, priority ) );
88  }
89  }
90  }
91 
92  for(wfl::unit_formula_set::iterator pair_it = units_with_formulas.begin() ; pair_it != units_with_formulas.end() ; ++pair_it)
93  {
94  unit_map::iterator i = pair_it->first;
95 
96  if( i.valid() ) {
97 
98  if (i->formula_manager().has_formula()) {
99  try {
100  wfl::const_formula_ptr formula(fai_.create_optional_formula(i->formula_manager().get_formula()));
101  if (formula) {
103  callable.add("me", wfl::variant(std::make_shared<wfl::unit_callable>(*i)));
104  fai_.make_action(formula, callable);
105  } else {
106  WRN_AI << "unit formula skipped, maybe it's empty or incorrect";
107  }
108  }
109  catch(wfl::formula_error& e) {
110  if(e.filename == "formula") {
111  e.line = 0;
112  }
113  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()) + ")");
114  }
115  }
116  }
117 
118  if( i.valid() ) {
119  if (i->formula_manager().has_loop_formula())
120  {
121  try {
122  wfl::const_formula_ptr loop_formula(fai_.create_optional_formula(i->formula_manager().get_loop_formula()));
123  if (loop_formula) {
125  callable.add("me", wfl::variant(std::make_shared<wfl::unit_callable>(*i)));
126  while ( !fai_.make_action(loop_formula, callable).is_empty() && i.valid() )
127  {
128  }
129  } else {
130  WRN_AI << "Loop formula skipped, maybe it's empty or incorrect";
131  }
132  } catch(wfl::formula_error& e) {
133  if (e.filename == "formula") {
134  e.line = 0;
135  }
136  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()) + ")");
137  }
138  }
139  }
140  }
141  return false;
142 }
143 
144 
146 {
147  //we have no state on our own
148 }
149 
150 
152 {
153  config cfg = stage::to_config();
154  //we have no state on our own
155  return cfg;
156 }
157 
158 } // end of namespace ai
wfl::variant make_action(wfl::const_formula_ptr formula_, const wfl::formula_callable &variables)
Definition: ai.cpp:176
void handle_exception(const wfl::formula_error &e) const
Definition: ai.cpp:107
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:133
virtual side_number get_side() const override
Get the side number.
Definition: contexts.hpp:396
config to_config() const
serialize
bool do_play_stage()
Play the turn - implementation.
void on_create()
Initialization.
stage_unit_formulas(ai_context &context, const config &cfg, formula_ai &fai)
virtual config to_config() const
serialize
Definition: stage.cpp:65
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
virtual const unit_map & units() const override
Definition: game_board.hpp:106
Container associating units to locations.
Definition: map.hpp:98
unit_iterator end()
Definition: map.hpp:428
unit_iterator begin()
Definition: map.hpp:418
formula_callable_ptr fake_ptr()
Definition: callable.hpp:42
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
map_formula_callable & add(const std::string &key, const variant &value)
Definition: callable.hpp:253
bool is_empty() const
Definition: variant.cpp:262
Defines formula ai.
std::size_t i
Definition: function.cpp:968
Standard logging facilities (interface).
A small explanation about what's going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:59
game_board * gameboard
Definition: resources.cpp:20
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
std::shared_ptr< const formula > const_formula_ptr
Definition: formula_fwd.hpp:24
std::multiset< unit_formula_pair, unit_formula_compare > unit_formula_set
Definition: ai.hpp:56
std::pair< unit_map::unit_iterator, int > unit_formula_pair
Definition: ai.hpp:46
#define ERR_AI
#define WRN_AI
static lg::log_domain log_formula_ai("ai/stage/unit_formulas")
Stage which executes unit formulas.
#define e