wesnoth/src/ai/composite/component.cpp
Celtic Minstrel 3ac7f8d970 NULL -> nullptr
A few cases of NULL were missed, since changing them led to errors
(Mainly instances where it was passed to a boost::function)
2016-03-31 00:42:38 -04:00

285 lines
6.5 KiB
C++

/*
Copyright (C) 2009 - 2016 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* Composite AI component
* @file
*/
#include "ai/composite/component.hpp"
#include "ai/composite/engine.hpp"
#include "ai/composite/property_handler.hpp"
#include "config.hpp"
#include "log.hpp"
#include "units/unit.hpp"
#include "ai/formula/ai.hpp"
#include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>
#include <boost/foreach.hpp>
namespace pathfind {
struct pathfind;
} //of namespace pathfind
namespace ai {
static lg::log_domain log_ai_component("ai/component");
#define DBG_AI_COMPONENT LOG_STREAM(debug, log_ai_component)
#define LOG_AI_COMPONENT LOG_STREAM(info, log_ai_component)
#define ERR_AI_COMPONENT LOG_STREAM(err, log_ai_component)
/*
[modify_ai]
path = "stage[fallback]
action = "change"
[stage]...[/stage]
[/modify_ai]
[modify_ai]
component = "aspect[avoid].facet[zzz]"
action = "change"
[facet]...[/facet]
[/modify_ai]
[modify_ai]
path = "aspect[aggression].facet[zzzz]
action = "delete"
[/modify_ai]
[modify_ai]
component = "aspect[aggression].facet"
action = "add"
[facet]...[/facet]
[/modify_ai]
*/
component* component::get_child(const path_element &child)
{
std::map<std::string, property_handler_ptr>::iterator i = property_handlers_.find(child.property);
if (i!=property_handlers_.end()) {
return i->second->handle_get(child);
}
return nullptr;
}
bool component::add_child(const path_element &child, const config &cfg)
{
std::map<std::string, property_handler_ptr>::iterator i = property_handlers_.find(child.property);
if (i!=property_handlers_.end()) {
return i->second->handle_add(child,cfg);
}
return false;
}
bool component::change_child(const path_element &child, const config &cfg)
{
std::map<std::string, property_handler_ptr>::iterator i = property_handlers_.find(child.property);
if (i!=property_handlers_.end()) {
return i->second->handle_change(child,cfg);
}
return false;
}
bool component::delete_child(const path_element &child)
{
std::map<std::string, property_handler_ptr>::iterator i = property_handlers_.find(child.property);
if (i!=property_handlers_.end()) {
return i->second->handle_delete(child);
}
return false;
}
std::vector<component*> component::get_children(const std::string &type)
{
property_handler_map::iterator i = property_handlers_.find(type);
if (i!=property_handlers_.end()) {
return i->second->handle_get_children();
}
return std::vector<component*>();
}
std::vector<std::string> component::get_children_types()
{
std::vector<std::string> types;
BOOST_FOREACH(property_handler_map::value_type &ph, property_handlers_) {
types.push_back(ph.first);
}
return types;
}
property_handler_map& component::property_handlers()
{
return property_handlers_;
}
static component *find_component(component *root, const std::string &path, path_element &tail)
{
if (root==nullptr) {
return nullptr;
}
//match path elements in [modify_ai] tag
boost::regex re("([^\\.^\\[]+)(\\[(\\d*)\\]|\\[([^\\]]+)\\]|())");
int const sub_matches[] = {1,3,4};
boost::sregex_token_iterator i(path.begin(), path.end(), re, sub_matches);
boost::sregex_token_iterator j;
component *c = root;
std::vector< path_element > elements;
while(i != j)
{
path_element pe;
pe.property = *i++;
std::string position = *i++;
pe.id = *i++;
if (position.empty()) {
pe.position = -2;
} else {
try {
pe.position = boost::lexical_cast<int>(position);
} catch (boost::bad_lexical_cast){
pe.position = -2;
}
}
//DBG_AI_COMPONENT << "adding path element: "<< pe << std::endl;
elements.push_back(pe);
}
if (elements.size()<1) {
return nullptr;
}
std::vector< path_element >::iterator k_max = elements.end()-1;
for (std::vector< path_element >::iterator k = elements.begin(); k!=k_max; ++k) {
//not last
c = c->get_child(*k);
if (c==nullptr) {
return nullptr;
}
}
tail = *k_max;
return c;
}
bool component_manager::add_component(component *root, const std::string &path, const config &cfg)
{
path_element tail;
component *c = find_component(root,path,tail);
if (c==nullptr) {
return false;
}
const config &ch = cfg.child(tail.property);
if (!ch) {
return false;
}
return c->add_child(tail, ch);
}
bool component_manager::change_component(component *root, const std::string &path, const config &cfg)
{
path_element tail;
component *c = find_component(root,path,tail);
if (c==nullptr) {
return false;
}
const config &ch = cfg.child(tail.property);
if (!ch) {
return false;
}
return c->change_child(tail,ch);
}
bool component_manager::delete_component(component *root, const std::string &path)
{
path_element tail;
component *c = find_component(root,path,tail);
if (c==nullptr) {
return false;
}
return c->delete_child(tail);
}
static void print_component(component *root, const std::string &type, std::stringstream &s, int offset)
{
std::stringstream offset_ss;
for (int i=0;i<offset;++i) {
offset_ss<<" ";
}
const std::string &offset_str = offset_ss.str();
const std::vector<std::string> &t_list = root->get_children_types();
s << offset_str << type<<"["<<root->get_id() <<"] "<<root->get_engine()<<" "<<root->get_name()<< std::endl;
BOOST_FOREACH(std::string t, t_list) {
std::vector<component*> c_list = root->get_children(t);
BOOST_FOREACH(component *c, c_list) {
print_component(c,t,s,offset+1);
}
}
}
std::string component_manager::print_component_tree(component *root, const std::string &path)
{
path_element tail;
component *c;
if (!path.empty()) {
c = find_component(root,path,tail);
if (c==nullptr) {
ERR_AI_COMPONENT << "unable to find component" <<std::endl;
return "";
}
} else {
c = root;
}
std::stringstream s;
print_component(c, "", s, 0);
return s.str();
}
component* component_manager::get_component(component *root, const std::string &path)
{
if(!path.empty()) {
path_element tail;
return find_component(root, path, tail);
}
return nullptr;
}
} //end of namespace ai
std::ostream &operator<<(std::ostream &o, const ai::path_element &e)
{
o << "property["<<e.property<<"] id["<<e.id <<"] position["<<e.position<<"]"<<std::endl;
return o;
}