The Battle for Wesnoth  1.13.10+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
goal.cpp
Go to the documentation of this file.
1 
2 /*
3  Copyright (C) 2009 - 2017 by Yurii Chernyi <terraninfo@terraninfo.net>
4  Part of the Battle for Wesnoth Project http://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  */
19 
20 #include "ai/composite/goal.hpp"
21 
22 #include "ai/default/contexts.hpp"
23 #include "ai/lua/core.hpp"
24 #include "ai/lua/lua_object.hpp"
25 #include "ai/manager.hpp"
26 #include "filter_context.hpp"
27 #include "game_board.hpp"
28 #include "log.hpp"
29 #include "map/location.hpp"
30 #include "resources.hpp"
32 #include "terrain/filter.hpp"
33 #include "units/unit.hpp"
34 #include "units/map.hpp"
35 #include "units/filter.hpp"
36 #include "wml_exception.hpp"
37 
38 #include <set>
39 #include <sstream>
40 
41 namespace ai {
42 
43 static lg::log_domain log_ai_goal("ai/goal");
44 #define DBG_AI_GOAL LOG_STREAM(debug, log_ai_goal)
45 #define LOG_AI_GOAL LOG_STREAM(info, log_ai_goal)
46 #define ERR_AI_GOAL LOG_STREAM(err, log_ai_goal)
47 
48 goal::goal(readonly_context &context, const config &cfg)
49  : readonly_context_proxy(), cfg_(cfg), ok_(true)
50 {
52 }
53 
54 
55 
57 {
58  LOG_AI_GOAL << "side " << get_side() << " : " << " created goal with name=[" << cfg_["name"] << "]" << std::endl;
59 }
60 
61 void goal::on_create(std::shared_ptr<ai::lua_ai_context>)
62 {
63  unrecognized();
64 }
65 
67 {
68  ERR_AI_GOAL << "side " << get_side() << " : " << " tried to create goal with name=[" << cfg_["name"] << "], but the [" << cfg_["engine"] << "] engine did not recognize that type of goal. " << std::endl;
69  ok_ = false;
70 }
71 
72 
74 {
75 }
76 
77 
78 void goal::add_targets(std::back_insert_iterator< std::vector< target > > /*target_list*/)
79 {
80 }
81 
82 
83 
85 {
86  return cfg_;
87 }
88 
90 {
91  return cfg_["id"];
92 }
93 
95 {
96  return cfg_["id"];
97 }
98 
100 {
101  return cfg_["engine"];
102 }
103 
104 
105 bool goal::redeploy(const config &cfg)
106 {
107  cfg_ = cfg;
108  on_create();
109  return true;
110 }
111 
112 
113 bool goal::ok() const
114 {
115  return ok_;
116 }
117 
118 
119 bool goal::active() const
120 {
121  return is_active(cfg_["time_of_day"],cfg_["turns"]);
122 }
123 
124 
126 {
127  goal::on_create();
128  if (!cfg_["engine"].empty() && cfg_["engine"] != "cpp") {
129  unrecognized();
130  value_ = 0;
131  return;
132  }
133  if (const config::attribute_value *v = cfg_.get("value")) {
134  value_ = v->to_double(0);
135  }
136 }
137 
138 void target_unit_goal::add_targets(std::back_insert_iterator< std::vector< target > > target_list)
139 {
140  if (!(this)->active()) {
141  return;
142  }
143 
144  const config &criteria = cfg_.child("criteria");
145  if (!criteria) return;
146 
147  //find the enemy leaders and explicit targets
148  const unit_filter ufilt(vconfig(criteria), resources::filter_con);
149  for (const unit &u : resources::gameboard->units()) {
150  if (ufilt( u )) {
151  LOG_AI_GOAL << "found explicit target unit at ... " << u.get_location() << " with value: " << value() << "\n";
152  *target_list = target(u.get_location(), value(), target::TYPE::EXPLICIT);
153  }
154  }
155 
156 
157 }
158 
159 
161  : goal(context,cfg)
162  , value_(0.0)
163 {
164 }
165 
166 
168 {
169  goal::on_create();
170  if (!cfg_["engine"].empty() && cfg_["engine"] != "cpp") {
171  unrecognized();
172  value_ = 0;
173  return;
174  }
175  if (cfg_.has_attribute("value")) {
176  value_ = cfg_["value"].to_double(0);
177  }
178  const config &criteria = cfg_.child("criteria");
179  if (criteria) {
181  }
182 }
183 
184 void target_location_goal::add_targets(std::back_insert_iterator< std::vector< target > > target_list)
185 {
186  if (!(this)->active()) {
187  return;
188  }
189 
190  if (!filter_ptr_) return;
191 
192  std::set<map_location> items;
193  filter_ptr_->get_locations(items);
194  for (const map_location &loc : items)
195  {
196  LOG_AI_GOAL << "found explicit target location ... " << loc << " with value: " << value() << std::endl;
197  *target_list = target(loc, value(), target::TYPE::EXPLICIT);
198  }
199 
200 }
201 
203  : goal(context,cfg)
204  , filter_ptr_()
205  , value_(0.0)
206 {
207 }
208 
209 
210 
212 {
213  goal::on_create();
214  if (!cfg_["engine"].empty() && cfg_["engine"] != "cpp") {
215  unrecognized();
216  value_ = 0;
217  return;
218  }
219  if (const config::attribute_value *v = cfg_.get("value")) {
220  value_ = v->to_double(0);
221  }
222  if (const config::attribute_value *v = cfg_.get("protect_radius")) {
223  radius_ = (*v).to_int(1);
224  }
225 
226  if (radius_<1) {
227  radius_=20;
228  }
229  const config &criteria = cfg_.child("criteria");
230  if (criteria) {
232  }
233 
234 
235 }
236 
237 
238 void protect_goal::add_targets(std::back_insert_iterator< std::vector< target > > target_list)
239 {
240  std::string goal_type;
241  if (protect_unit_) {
242  goal_type = "protect_unit";
243  } else {
244  goal_type ="protect_location";
245  }
246 
247  if (!(this)->active()) {
248  LOG_AI_GOAL << "skipping " << goal_type << " goal - not active" << std::endl;
249  return;
250  }
251 
252  const config &criteria = cfg_.child("criteria");
253  if (!criteria) {
254  LOG_AI_GOAL << "skipping " << goal_type << " goal - no criteria given" << std::endl;
255  return;
256  } else {
257  DBG_AI_GOAL << "side " << get_side() << ": "<< goal_type << " goal with criteria" << std::endl << cfg_.child("criteria") << std::endl;
258  }
259 
261 
262  std::set<map_location> items;
263  if (protect_unit_) {
264  const unit_filter ufilt(vconfig(criteria), resources::filter_con);
265  for (const unit &u : units)
266  {
267  //TODO: we will protect hidden units, by not testing for invisibility to current side
268  if (ufilt(u)) {
269  DBG_AI_GOAL << "side " << get_side() << ": in " << goal_type << ": " << u.get_location() << " should be protected\n";
270  items.insert(u.get_location());
271  }
272  }
273  } else {
274  filter_ptr_->get_locations(items);
275  }
276  DBG_AI_GOAL << "side " << get_side() << ": seaching for threats in "+goal_type+" goal" << std::endl;
277  // Look for directions to protect a specific location or specific unit.
278  for (const map_location &loc : items)
279  {
280  for (const unit &u : units)
281  {
282  int distance = distance_between(u.get_location(), loc);
283  if (current_team().is_enemy(u.side()) && distance < radius_ &&
284  !u.invisible(u.get_location(), *resources::gameboard))
285  {
286  DBG_AI_GOAL << "side " << get_side() << ": in " << goal_type << ": found threat target. " << u.get_location() << " is a threat to "<< loc << '\n';
287  *target_list = target(u.get_location(),
288  value_ * double(radius_ - distance) /
289  radius_, target::TYPE::THREAT);
290  }
291  }
292  }
293 
294 
295 }
296 
297 
298 protect_goal::protect_goal(readonly_context &context, const config &cfg, bool protect_unit)
299  : goal(context,cfg)
300  , filter_ptr_()
301  , protect_unit_(protect_unit)
302  , radius_(20) //this default radius is taken from old code
303  , value_(1.0) //this default value taken from old code
304 {
305 }
306 
308  : goal(context, cfg)
309  , code_()
310  , handler_()
311 {
312  if (cfg.has_attribute("code")) {
313  code_ = cfg["code"].str();
314  }
315  else
316  {
317  ERR_AI_GOAL << "side " << get_side() << " : Error creating Lua goal (missing code= key)" << std::endl;
318  }
319 }
320 
321 void lua_goal::on_create(std::shared_ptr<ai::lua_ai_context> l_ctx)
322 {
323  handler_.reset(resources::lua_kernel->create_lua_ai_action_handler(code_.c_str(), *l_ctx));
324 }
325 
326 void lua_goal::add_targets(std::back_insert_iterator< std::vector< target > > target_list)
327 {
328  std::shared_ptr<lua_object<std::vector<target>>> l_obj = std::make_shared<lua_object<std::vector<target>>>();
329  config c(cfg_.child_or_empty("args"));
330  handler_->handle(c, true, l_obj);
331  try {
332  std::vector < target > targets = *(l_obj->get());
333 
334  for (target tg : targets)
335  {
336  *target_list = tg;
337  }
338  } catch(bad_enum_cast& e) {
339  ERR_AI_GOAL << "A Lua goal returned a target of an unknown type (\"" << e.value() << "\"; unfortunately, the engine cannot recover from this error. As a result, all targets returned by the goal have been lost.\n";
340  }
341 
342 }
343 
344 
345 // This is defined in the source file so that it can easily access the logger
347 {
348  if (get_list().find(name) != get_list().end()) {
349  ERR_AI_GOAL << "Error: Attempt to double-register goal " << name << std::endl;
350  return true;
351  }
352  return false;
353 }
354 
355 
356 } //end of namespace ai
static std::unique_ptr< class sdl_event_handler > handler_
Definition: handler.cpp:62
virtual void add_targets(std::back_insert_iterator< std::vector< target > > target_list)
Definition: goal.cpp:138
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:400
virtual void add_targets(std::back_insert_iterator< std::vector< target > > target_list)
Definition: goal.cpp:238
virtual const unit_map & units() const
Definition: game_board.hpp:97
std::vector< char_t > string
This class represents a single unit of a specific type.
Definition: unit.hpp:100
virtual bool is_active(const std::string &time_of_day, const std::string &turns) const override
Definition: contexts.hpp:888
Variant for storing WML attributes.
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
static lg::log_domain log_ai_goal("ai/goal")
target_location_goal(readonly_context &context, const config &cfg)
Definition: goal.cpp:202
bool is_enemy(int n) const
Definition: team.hpp:241
static factory_map & get_list()
Definition: goal.hpp:183
goal(readonly_context &context, const config &cfg)
Definition: goal.cpp:48
virtual void on_create()
Definition: goal.cpp:167
config cfg_
Definition: goal.hpp:78
std::shared_ptr< lua_ai_action_handler > handler_
Definition: goal.hpp:172
const std::vector< std::string > items
Lua object(value) wrapper implementation.
virtual std::string get_engine() const
Definition: goal.cpp:99
std::shared_ptr< terrain_filter > filter_ptr_
Definition: goal.hpp:140
virtual void on_create()
Definition: goal.cpp:211
double value_
Definition: goal.hpp:143
A small explanation about what's going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:58
virtual void on_create()
Definition: goal.cpp:56
bool ok_
Definition: goal.hpp:79
size_t distance_between(const map_location &a, const map_location &b)
Function which gives the number of hexes between two tiles (i.e.
Definition: location.hpp:382
filter_context * filter_con
Definition: resources.cpp:23
bool active() const
Definition: goal.cpp:119
void unrecognized()
Definition: goal.cpp:66
game_board * gameboard
Definition: resources.cpp:20
virtual void add_targets(std::back_insert_iterator< std::vector< target > > target_list)
Definition: goal.cpp:184
bool protect_unit_
Definition: goal.hpp:141
Managing the AIs lifecycle - headers.
lua_goal(readonly_context &context, const config &cfg)
Definition: goal.cpp:307
virtual config to_config() const
Definition: goal.cpp:84
Encapsulates the map of the game.
Definition: location.hpp:40
bool has_attribute(config_key_type key) const
Definition: config.cpp:196
virtual std::string get_id() const
Definition: goal.cpp:89
bool redeploy(const config &cfg)
Definition: goal.cpp:105
virtual const team & current_team() const override
Definition: contexts.hpp:536
std::shared_ptr< terrain_filter > filter_ptr_
Definition: goal.hpp:118
std::string code_
Definition: goal.hpp:171
const config & child_or_empty(config_key_type key) const
Returns the first child with the given key, or an empty config if there is none.
Definition: config.cpp:433
virtual void add_targets(std::back_insert_iterator< std::vector< target > > target_list)
Definition: goal.cpp:78
Default AI contexts.
const char * value() const NOEXCEPT
Definition: make_enum.hpp:114
virtual void add_targets(std::back_insert_iterator< std::vector< target > > target_list)
Definition: goal.cpp:326
virtual side_number get_side() const override
Get the side number.
Definition: contexts.hpp:477
#define ERR_AI_GOAL
Definition: goal.cpp:46
virtual std::string get_name() const
Definition: goal.cpp:94
protect_goal(readonly_context &context, const config &cfg, bool protect_unit)
Definition: goal.cpp:298
double value() const
Definition: goal.hpp:114
const attribute_value * get(config_key_type key) const
Returns a pointer to the attribute with the given key or nullptr if it does not exist.
Definition: config.cpp:672
bool find(E event, F functor)
Tests whether an event handler is available.
virtual void on_create()
Definition: goal.cpp:125
A variable-expanding proxy for the config class.
Definition: variable.hpp:42
Standard logging facilities (interface).
target_unit_goal(readonly_context &context, const config &cfg)
Definition: goal.cpp:160
#define DBG_AI_GOAL
Definition: goal.cpp:44
bool is_duplicate(const std::string &name)
Definition: goal.cpp:346
game_lua_kernel * lua_kernel
Definition: resources.cpp:25
Container associating units to locations.
Definition: map.hpp:99
#define LOG_AI_GOAL
Definition: goal.cpp:45
static const char * name(const std::vector< SDL_Joystick * > &joysticks, const size_t index)
Definition: joystick.cpp:48
#define e
double value() const
Definition: goal.hpp:95
bool ok() const
Definition: goal.cpp:113
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
mock_char c
unit_map * units
Definition: resources.cpp:34
virtual ~goal()
Definition: goal.cpp:73
void init_readonly_context_proxy(readonly_context &target)
Definition: contexts.hpp:518