The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
goal.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2009 - 2025
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 */
19
20#include "ai/composite/goal.hpp"
21
23#include "ai/lua/core.hpp"
24#include "ai/lua/lua_object.hpp"
25#include "game_board.hpp"
26#include "log.hpp"
27#include "map/location.hpp"
28#include "resources.hpp"
30#include "terrain/filter.hpp"
31#include "units/unit.hpp"
32#include "units/map.hpp"
33#include "units/filter.hpp"
34
35#include <set>
36#include <sstream>
37
38namespace ai {
39
40static lg::log_domain log_ai_goal("ai/goal");
41#define DBG_AI_GOAL LOG_STREAM(debug, log_ai_goal)
42#define LOG_AI_GOAL LOG_STREAM(info, log_ai_goal)
43#define ERR_AI_GOAL LOG_STREAM(err, log_ai_goal)
44
46 : readonly_context_proxy(), cfg_(cfg), ok_(true)
47{
49}
50
52{
53 LOG_AI_GOAL << "side " << get_side() << " : " << " created goal with name=[" << cfg_["name"] << "]";
54}
55
56// In this case, the API is intended to cause an error with this specific type.
57// NOLINTNEXTLINE(performance-unnecessary-value-param)
58void goal::on_create(std::shared_ptr<ai::lua_ai_context>)
59{
61}
62
64{
65 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. ";
66 ok_ = false;
67}
68
70{
71}
72
73void goal::add_targets(std::back_insert_iterator< std::vector< target >> /*target_list*/)
74{
75}
76
78{
79 return cfg_;
80}
81
82std::string goal::get_id() const
83{
84 return cfg_["id"];
85}
86
87std::string goal::get_name() const
88{
89 return cfg_["id"];
90}
91
92std::string goal::get_engine() const
93{
94 return cfg_["engine"];
95}
96
98{
99 cfg_ = cfg;
100 on_create();
101 return true;
102}
103
104bool goal::ok() const
105{
106 return ok_;
107}
108
109bool goal::active() const
110{
111 return is_active(cfg_["time_of_day"],cfg_["turns"]);
112}
113
115{
117 if (!cfg_["engine"].empty() && cfg_["engine"] != "cpp") {
118 unrecognized();
119 value_ = 0;
120 return;
121 }
122 if (const config::attribute_value *v = cfg_.get("value")) {
123 value_ = v->to_double(0);
124 }
125}
126
127void target_unit_goal::add_targets(std::back_insert_iterator< std::vector< target >> target_list)
128{
129 if (!(this)->active()) {
130 return;
131 }
132
133 auto criteria = cfg_.optional_child("criteria");
134 if (!criteria) return;
135
136 //find the enemy leaders and explicit targets
137 const unit_filter ufilt{ vconfig(*criteria) };
138 for (const unit &u : resources::gameboard->units()) {
139 if (ufilt( u )) {
140 LOG_AI_GOAL << "found explicit target unit at ... " << u.get_location() << " with value: " << value();
141 *target_list = target(u.get_location(), value(), ai_target::type::xplicit);
142 }
143 }
144
145}
146
148 : goal(context,cfg)
149 , value_(0.0)
150{
151}
152
154{
156 if (!cfg_["engine"].empty() && cfg_["engine"] != "cpp") {
157 unrecognized();
158 value_ = 0;
159 return;
160 }
161 if (cfg_.has_attribute("value")) {
162 value_ = cfg_["value"].to_double(0);
163 }
164 auto criteria = cfg_.optional_child("criteria");
165 if (criteria) {
166 filter_ptr_.reset(new terrain_filter(vconfig(*criteria),resources::filter_con, false));
167 }
168}
169
170void target_location_goal::add_targets(std::back_insert_iterator< std::vector< target >> target_list)
171{
172 if (!(this)->active()) {
173 return;
174 }
175
176 if (!filter_ptr_) return;
177
178 std::set<map_location> items;
179 filter_ptr_->get_locations(items);
180 for (const map_location &loc : items)
181 {
182 LOG_AI_GOAL << "found explicit target location ... " << loc << " with value: " << value();
183 *target_list = target(loc, value(), ai_target::type::xplicit);
184 }
185
186}
187
189 : goal(context,cfg)
190 , filter_ptr_()
191 , value_(0.0)
192{
193}
194
196{
198 if (!cfg_["engine"].empty() && cfg_["engine"] != "cpp") {
199 unrecognized();
200 value_ = 0;
201 return;
202 }
203 if (const config::attribute_value *v = cfg_.get("value")) {
204 value_ = v->to_double(0);
205 }
206 if (const config::attribute_value *v = cfg_.get("protect_radius")) {
207 radius_ = (*v).to_int(1);
208 }
209
210 if (radius_<1) {
211 radius_=20;
212 }
213 auto criteria = cfg_.optional_child("criteria");
214 if (criteria) {
215 filter_ptr_.reset(new terrain_filter(vconfig(*criteria), resources::filter_con, false));
216 }
217
218}
219
220void protect_goal::add_targets(std::back_insert_iterator< std::vector< target >> target_list)
221{
222 std::string goal_type;
223 if (protect_unit_) {
224 goal_type = "protect_unit";
225 } else {
226 goal_type ="protect_location";
227 }
228
229 if (!(this)->active()) {
230 LOG_AI_GOAL << "skipping " << goal_type << " goal - not active";
231 return;
232 }
233
234 auto criteria = cfg_.optional_child("criteria");
235 if (!criteria) {
236 LOG_AI_GOAL << "skipping " << goal_type << " goal - no criteria given";
237 return;
238 } else {
239 DBG_AI_GOAL << "side " << get_side() << ": "<< goal_type << " goal with criteria" << std::endl << cfg_.mandatory_child("criteria");
240 }
241
243
244 std::set<map_location> items;
245 if (protect_unit_) {
246 const unit_filter ufilt{ vconfig(*criteria) };
247 for (const unit &u : units)
248 {
249 // 'protect_unit' can be set to any unit of any side -> exclude hidden units
250 // unless they are visible to the AI side (e.g. allies with shared vision).
251 // As is done in other parts of the AI, units under fog/shroud count as visible to the AI.
252 if (ufilt(u)
253 && (!u.invisible(u.get_location()) || u.is_visible_to_team(current_team(), false)))
254 {
255 DBG_AI_GOAL << "side " << get_side() << ": in " << goal_type << ": " << u.get_location() << " should be protected";
256 items.insert(u.get_location());
257 }
258 }
259 } else {
260 filter_ptr_->get_locations(items);
261 }
262 DBG_AI_GOAL << "side " << get_side() << ": searching for threats in "+goal_type+" goal";
263 // Look for directions to protect a specific location or specific unit.
264 for (const map_location &loc : items)
265 {
266 for (const unit &u : units)
267 {
268 int distance = distance_between(u.get_location(), loc);
269 if (current_team().is_enemy(u.side()) && distance < radius_ &&
270 !u.invisible(u.get_location()))
271 {
272 DBG_AI_GOAL << "side " << get_side() << ": in " << goal_type << ": found threat target. " << u.get_location() << " is a threat to "<< loc;
273 *target_list = target(u.get_location(),
274 value_ * static_cast<double>(radius_ - distance) /
275 radius_, ai_target::type::threat);
276 }
277 }
278 }
279
280}
281
282protect_goal::protect_goal(readonly_context &context, const config &cfg, bool protect_unit)
283 : goal(context,cfg)
284 , filter_ptr_()
285 , protect_unit_(protect_unit)
286 , radius_(20) //this default radius is taken from old code
287 , value_(1.0) //this default value taken from old code
288{
289}
290
292 : goal(context, cfg)
293 , code_()
294 , handler_()
295{
296 if (cfg.has_attribute("code")) {
297 code_ = cfg["code"].str();
298 }
299 else
300 {
301 ERR_AI_GOAL << "side " << get_side() << " : Error creating Lua goal (missing code= key)";
302 }
303}
304
305void lua_goal::on_create(std::shared_ptr<ai::lua_ai_context> l_ctx)
306{
307 handler_.reset(resources::lua_kernel->create_lua_ai_action_handler(code_.c_str(), *l_ctx));
308}
309
310void lua_goal::add_targets(std::back_insert_iterator< std::vector< target >> target_list)
311{
312 std::shared_ptr<lua_object<std::vector<target>>> l_obj = std::make_shared<lua_object<std::vector<target>>>();
313 config c(cfg_.child_or_empty("args"));
314 const config empty_cfg;
315 handler_->handle(c, empty_cfg, true, l_obj);
316
317 std::vector < target > targets = *(l_obj->get());
318
319 for (target tg : targets)
320 {
321 *target_list = tg;
322 }
323}
324
325// This is defined in the source file so that it can easily access the logger
326bool goal_factory::is_duplicate(const std::string& name)
327{
328 if (get_list().find(name) != get_list().end()) {
329 ERR_AI_GOAL << "Error: Attempt to double-register goal " << name;
330 return true;
331 }
332 return false;
333}
334
335} //end of namespace ai
static bool is_enemy(std::size_t side, std::size_t other_side)
map_location loc
Definition move.cpp:172
std::unique_ptr< PangoAttribute, void(*)(PangoAttribute *)> value_
static factory_map & get_list()
Definition goal.hpp:158
bool is_duplicate(const std::string &name)
Definition goal.cpp:326
bool ok_
Definition goal.hpp:66
bool redeploy(const config &cfg)
Definition goal.cpp:97
virtual config to_config() const
Definition goal.cpp:77
virtual ~goal()
Definition goal.cpp:69
void unrecognized()
Definition goal.cpp:63
virtual std::string get_engine() const
Definition goal.cpp:92
virtual std::string get_name() const
Definition goal.cpp:87
config cfg_
Definition goal.hpp:65
virtual void add_targets(std::back_insert_iterator< std::vector< target > > target_list)
Definition goal.cpp:73
virtual void on_create()
Definition goal.cpp:51
virtual std::string get_id() const
Definition goal.cpp:82
goal(readonly_context &context, const config &cfg)
Definition goal.cpp:45
bool active() const
Definition goal.cpp:109
bool ok() const
Definition goal.cpp:104
virtual void add_targets(std::back_insert_iterator< std::vector< target > > target_list)
Definition goal.cpp:310
std::string code_
Definition goal.hpp:147
lua_goal(readonly_context &context, const config &cfg)
Definition goal.cpp:291
std::shared_ptr< lua_ai_action_handler > handler_
Definition goal.hpp:148
std::shared_ptr< terrain_filter > filter_ptr_
Definition goal.hpp:118
virtual void add_targets(std::back_insert_iterator< std::vector< target > > target_list)
Definition goal.cpp:220
bool protect_unit_
Definition goal.hpp:119
protect_goal(readonly_context &context, const config &cfg, bool protect_unit)
Definition goal.cpp:282
virtual void on_create()
Definition goal.cpp:195
double value_
Definition goal.hpp:121
virtual const team & current_team() const override
Definition contexts.hpp:447
virtual bool is_active(const std::string &time_of_day, const std::string &turns) const override
Definition contexts.hpp:748
void init_readonly_context_proxy(readonly_context &target)
Definition contexts.hpp:431
virtual side_number get_side() const override
Get the side number.
Definition contexts.hpp:393
std::shared_ptr< terrain_filter > filter_ptr_
Definition goal.hpp:99
target_location_goal(readonly_context &context, const config &cfg)
Definition goal.cpp:188
double value() const
Definition goal.hpp:95
virtual void add_targets(std::back_insert_iterator< std::vector< target > > target_list)
Definition goal.cpp:170
virtual void on_create()
Definition goal.cpp:153
virtual void on_create()
Definition goal.cpp:114
double value() const
Definition goal.hpp:79
virtual void add_targets(std::back_insert_iterator< std::vector< target > > target_list)
Definition goal.cpp:127
target_unit_goal(readonly_context &context, const config &cfg)
Definition goal.cpp:147
Variant for storing WML attributes.
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
optional_config_impl< config > optional_child(std::string_view key, int n=0)
Equivalent to mandatory_child, but returns an empty optional if the nth child was not found.
Definition config.cpp:380
const attribute_value * get(std::string_view key) const
Returns a pointer to the attribute with the given key or nullptr if it does not exist.
Definition config.cpp:665
bool has_attribute(std::string_view key) const
Definition config.cpp:157
const config & child_or_empty(std::string_view key) const
Returns the first child with the given key, or an empty config if there is none.
Definition config.cpp:390
config & mandatory_child(std::string_view key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
Definition config.cpp:362
virtual const unit_map & units() const override
Container associating units to locations.
Definition map.hpp:98
This class represents a single unit of a specific type.
Definition unit.hpp:39
A variable-expanding proxy for the config class.
Definition variable.hpp:45
Default AI contexts.
const config * cfg
#define ERR_AI_GOAL
Definition goal.cpp:43
#define LOG_AI_GOAL
Definition goal.cpp:42
#define DBG_AI_GOAL
Definition goal.cpp:41
std::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.cpp:584
Standard logging facilities (interface).
Lua object(value) wrapper implementation.
A small explanation about what's going on here: Each action has access to two game_info objects First...
Definition actions.cpp:59
static lg::log_domain log_ai_goal("ai/goal")
game_board * gameboard
Definition resources.cpp:20
game_lua_kernel * lua_kernel
Definition resources.cpp:25
filter_context * filter_con
Definition resources.cpp:23
Encapsulates the map of the game.
Definition location.hpp:46
#define c