From ef880c80c6380bb19d13c14bfedfd8ed85168791 Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Sat, 27 Feb 2016 23:02:16 -0500 Subject: [PATCH] Allow adding and removing recruitment jobs (and limits) with [modify_ai] Also some minor syntax simplifications: - If no [recruit] tag is provided, a default is added (as if with importance=0 and no other attributes) - [pattern] and [total] tags expand to [recruit] with the attribute of the same name set to yes --- src/ai/recruitment/recruitment.cpp | 71 +++++++++++++++++++++++++++++- src/ai/recruitment/recruitment.hpp | 57 ++++++++++++++++++++++++ src/ai/registry.cpp | 4 +- 3 files changed, 129 insertions(+), 3 deletions(-) diff --git a/src/ai/recruitment/recruitment.cpp b/src/ai/recruitment/recruitment.cpp index 1434d08707e5..a5d57d17f6a7 100644 --- a/src/ai/recruitment/recruitment.cpp +++ b/src/ai/recruitment/recruitment.cpp @@ -42,10 +42,11 @@ #include "util.hpp" #include "variable.hpp" #include "wml_exception.hpp" +#include "config_assign.hpp" #include #include -#include +#include static lg::log_domain log_ai_recruitment("ai/recruitment"); #define LOG_AI_RECRUITMENT LOG_STREAM(info, log_ai_recruitment) @@ -1779,5 +1780,73 @@ int recruitment::recruit_situation_change_observer::gamestate_changed() { void recruitment::recruit_situation_change_observer::reset_gamestate_changed() { gamestate_changed_ = 0; } + +recruitment_aspect::recruitment_aspect(readonly_context &context, const config &cfg, const std::string &id) + : standard_aspect(context, cfg, id) +{ + config parsed_cfg(cfg.has_child("value") ? cfg.child("value") : cfg); + // First, transform simplified tags into [recruit] tags. + BOOST_FOREACH (config pattern, parsed_cfg.child_range("pattern")) { + parsed_cfg["pattern"] = true; + parsed_cfg.add_child("recruit", pattern); + } + parsed_cfg.clear_children("pattern"); + BOOST_FOREACH (config total, parsed_cfg.child_range("total")) { + parsed_cfg["total"] = true; + parsed_cfg.add_child("recruit", total); + } + parsed_cfg.clear_children("total"); + // Then, if there's no [recruit], add one. + if (!parsed_cfg.has_child("recruit")) { + parsed_cfg.add_child("recruit", config_of("importance", 0)); + } + // Finally, populate our lists + BOOST_FOREACH (config job, parsed_cfg.child_range("recruit")) { + create_job(jobs_, job); + } + BOOST_FOREACH (config lim, parsed_cfg.child_range("limit")) { + create_limit(limits_, lim); + } + boost::function2 >&, const config&> factory_jobs = + boost::bind(&recruitment_aspect::create_job,*this,_1,_2); + boost::function2 >&, const config&> factory_limits = + boost::bind(&recruitment_aspect::create_limit,*this,_1,_2); + register_vector_property(property_handlers(), "recruit", jobs_, factory_jobs); + register_vector_property(property_handlers(), "limit", limits_, factory_limits); +} + +void recruitment_aspect::recalculate() const { + config cfg; + BOOST_FOREACH (const boost::shared_ptr& job, jobs_) { + cfg.add_child("recruit", job->to_config()); + } + BOOST_FOREACH (const boost::shared_ptr& lim, limits_) { + cfg.add_child("limit", lim->to_config()); + } + *this->value_ = cfg; + this->valid_ = true; +} + +void recruitment_aspect::create_job(std::vector > &jobs, const config &job) { + boost::shared_ptr job_ptr(new recruit_job( + utils::split(job["type"]), + job["leader_id"], job["id"], + job["number"].to_int(-1), job["importance"].to_int(1), + job["total"].to_bool(false), + job["blocker"].to_bool(true), + job["pattern"].to_bool(true) + )); + jobs.push_back(job_ptr); +} + +void recruitment_aspect::create_limit(std::vector > &limits, const config &lim) { + boost::shared_ptr lim_ptr(new recruit_limit( + utils::split(lim["type"]), + lim["id"], + lim["max"].to_int(0) + )); + limits.push_back(lim_ptr); +} + } // namespace default_recruitment } // namespace ai diff --git a/src/ai/recruitment/recruitment.hpp b/src/ai/recruitment/recruitment.hpp index 8bd8bd47d837..e1085ccda692 100644 --- a/src/ai/recruitment/recruitment.hpp +++ b/src/ai/recruitment/recruitment.hpp @@ -21,6 +21,7 @@ #ifndef AI_DEFAULT_RECRUITMENT_HPP_INCLUDED #define AI_DEFAULT_RECRUITMENT_HPP_INCLUDED +#include "ai/composite/aspect.hpp" #include "ai/composite/rca.hpp" #include "units/unit.hpp" #include "units/map.hpp" @@ -113,6 +114,62 @@ struct cached_combat_value { } }; +struct recruit_job : public component { + std::vector types; + std::string leader, id; + int number, importance; + bool total, pattern, blocker; + recruit_job(std::vector t, std::string L, std::string id, int n, int i, bool s, bool p, bool b) + : types(t), leader(L), id(id) + , number(n), importance(i) + , total(s), pattern(p), blocker(b) + {} + config to_config() const { + config cfg; + cfg["number"] = number; + cfg["importance"] = importance; + cfg["total"] = total; + cfg["pattern"] = pattern; + cfg["blocker"] = blocker; + cfg["leader_id"] = leader; + cfg["id"] = id; + cfg["type"] = utils::join(types); + return cfg; + } + std::string get_id() const {return id;}; + std::string get_name() const {return "recruit_job";}; + std::string get_engine() const {return "cpp";}; +}; + +struct recruit_limit : public component { + std::vector types; + std::string id; + int limit; + recruit_limit(std::vector t, std::string id, int lim) + : types(t), id(id), limit(lim) + {} + config to_config() const { + config cfg; + cfg["max"] = limit; + cfg["id"] = id; + cfg["type"] = utils::join(types); + return cfg; + } + std::string get_id() const {return id;}; + std::string get_name() const {return "recruit_limit";}; + std::string get_engine() const {return "cpp";}; +}; + +class recruitment_aspect : public standard_aspect { + std::vector > jobs_; + std::vector > limits_; +public: + recruitment_aspect(readonly_context &context, const config &cfg, const std::string &id); + void recalculate() const; + void create_job(std::vector > &jobs, const config &job); + void create_limit(std::vector > &limits, const config &lim); +}; + typedef std::map > table_row; typedef std::map cache_table; diff --git a/src/ai/registry.cpp b/src/ai/registry.cpp index 41a53b1c8f31..8db2d10d458a 100644 --- a/src/ai/registry.cpp +++ b/src/ai/registry.cpp @@ -344,7 +344,7 @@ static register_aspect_factory< standard_aspect > static register_aspect_factory< standard_aspect > recruitment_diversity__standard_aspect_factory("recruitment_diversity*standard_aspect"); -static register_aspect_factory< standard_aspect > +static register_aspect_factory< default_recruitment::recruitment_aspect > recruitment_instructions__standard_aspect_factory("recruitment_instructions*standard_aspect"); static register_aspect_factory< standard_aspect< std::vector > > @@ -422,7 +422,7 @@ static register_aspect_factory< standard_aspect > static register_aspect_factory< standard_aspect > recruitment_diversity__standard_aspect_factory2("recruitment_diversity*"); -static register_aspect_factory< standard_aspect > +static register_aspect_factory< default_recruitment::recruitment_aspect > recruitment_instructions__standard_aspect_factory2("recruitment_instructions*"); static register_aspect_factory< standard_aspect< std::vector > >