diff --git a/projectfiles/CodeBlocks/wesnoth.cbp b/projectfiles/CodeBlocks/wesnoth.cbp
index 44b6e44fea8a..56c2c01b97d3 100644
--- a/projectfiles/CodeBlocks/wesnoth.cbp
+++ b/projectfiles/CodeBlocks/wesnoth.cbp
@@ -1000,6 +1000,7 @@
+
diff --git a/projectfiles/VC9/wesnoth.vcproj b/projectfiles/VC9/wesnoth.vcproj
index 153050349f2b..4d3cfab02df8 100644
--- a/projectfiles/VC9/wesnoth.vcproj
+++ b/projectfiles/VC9/wesnoth.vcproj
@@ -21052,6 +21052,10 @@
RelativePath="..\..\src\team.hpp"
>
+
+
diff --git a/src/gamestatus.cpp b/src/gamestatus.cpp
index 108dda58fccc..43a4f7d38e02 100644
--- a/src/gamestatus.cpp
+++ b/src/gamestatus.cpp
@@ -21,7 +21,6 @@
#include "gamestatus.hpp"
-#include "actions/create.hpp"
#include "carryover.hpp"
#include "filesystem.hpp"
#include "formula_string_utils.hpp"
@@ -36,6 +35,7 @@
#include "serialization/binary_or_text.hpp"
#include "statistics.hpp"
#include "team.hpp"
+#include "teambuilder.hpp"
#include "unit.hpp"
#include "unit_id.hpp"
#include "wesconfig.h"
@@ -62,12 +62,6 @@ static lg::log_domain log_engine("engine");
#define LOG_NG LOG_STREAM(info, log_engine)
#define DBG_NG LOG_STREAM(debug, log_engine)
-static lg::log_domain log_engine_tc("engine/team_construction");
-#define ERR_NG_TC LOG_STREAM(err, log_engine_tc)
-#define WRN_NG_TC LOG_STREAM(warn, log_engine_tc)
-#define LOG_NG_TC LOG_STREAM(info, log_engine_tc)
-#define DBG_NG_TC LOG_STREAM(debug, log_engine_tc)
-
static lg::log_domain log_enginerefac("enginerefac");
#define LOG_RG LOG_STREAM(info, log_enginerefac)
@@ -75,292 +69,6 @@ static lg::log_domain log_enginerefac("enginerefac");
/// The default difficulty setting for campaigns.
const std::string DEFAULT_DIFFICULTY("NORMAL");
-
-class team_builder {
-public:
- team_builder(const config& side_cfg,
- const std::string &save_id, std::vector& teams,
- const config& level, gamemap& map, unit_map& units,
- const config &starting_pos)
- : gold_info_ngold_(0)
- , leader_configs_()
- , level_(level)
- , map_(map)
- , player_exists_(false)
- , save_id_(save_id)
- , seen_ids_()
- , side_(0)
- , side_cfg_(side_cfg)
- , starting_pos_(starting_pos)
- , t_(NULL)
- , teams_(teams)
- , unit_configs_()
- , units_(units)
- {
- }
-
- void build_team_stage_one()
- {
- //initialize the context variables and flags, find relevant tags, set up everything
- init();
-
- //find out the correct qty of gold and handle gold carryover.
- gold();
-
- //create a new instance of team and push it to back of resources::teams vector
- new_team();
-
- assert(t_!=NULL);
-
- //set team objectives if necessary
- objectives();
-
- // If the game state specifies additional units that can be recruited by the player, add them.
- previous_recruits();
-
- //place leader
- leader();
-
- //prepare units, populate obvious recall lists elements
- prepare_units();
-
- }
-
-
- void build_team_stage_two()
- {
- //place units
- //this is separate stage because we need to place units only after every other team is constructed
- place_units();
-
- }
-
-protected:
-
- int gold_info_ngold_;
- std::deque leader_configs_;
- const config &level_;
- gamemap &map_;
- bool player_exists_;
- const std::string save_id_;
- std::set seen_ids_;
- int side_;
- const config &side_cfg_;
- const config &starting_pos_;
- team *t_;
- std::vector &teams_;
- std::vector unit_configs_;
- unit_map &units_;
-
-
- void log_step(const char *s) const
- {
- LOG_NG_TC << "team "<= teams_.size()) {
- std::stringstream ss;
- ss << "Side number " << side_ << " higher than number of sides (" << teams_.size() << ")";
- throw config::error(ss.str());
- }
- if (teams_[side_ - 1].side() != 0) {
- std::stringstream ss;
- ss << "Duplicate definition of side " << side_;
- throw config::error(ss.str());
- }
- t_ = &teams_[side_ - 1];
-
- log_step("init");
-
- //track whether a [player] tag with persistence information exists (in addition to the [side] tag)
- player_exists_ = false;
-
- if(map_.empty()) {
- throw game::load_game_failed("Map not found");
- }
-
- DBG_NG_TC << "save id: "<< save_id_ <build(side_cfg_, map_, gold_info_ngold_);
- //t_->set_gold_add(gold_info_add_);
- }
-
-
- void objectives()
- {
- log_step("objectives");
- // If this team has no objectives, set its objectives
- // to the level-global "objectives"
- if (t_->objectives().empty())
- t_->set_objectives(level_["objectives"], false);
- }
-
-
- void previous_recruits()
- {
- log_step("previous recruits");
- // If the game state specifies units that
- // can be recruited for the player, add them.
- if (!side_cfg_) return;
- if (const config::attribute_value *v = side_cfg_.get("previous_recruits")) {
- BOOST_FOREACH(const std::string &rec, utils::split(*v)) {
- DBG_NG_TC << "adding previous recruit: " << rec << '\n';
- t_->add_recruit(rec);
- }
- }
- }
-
-
-
-
- void handle_unit(const config &u, const char *origin)
- {
- DBG_NG_TC
- << "unit from "<recall_list().add(UnitPtr(new unit(u_tmp,true)));
- } else {
- //not seen before
- unit_configs_.push_back(&u);
- seen_ids_.insert(id);
- }
-
- } else {
- unit_configs_.push_back(&u);
- }
- }
-
- void handle_leader(const config &leader)
- {
- // Make a persistent copy of the config.
- leader_configs_.push_back(leader);
- config & stored = leader_configs_.back();
-
- // Remove the attributes used to define a side.
- BOOST_FOREACH( const std::string & attr , team::attributes) {
- stored.remove_attribute(attr);
- }
-
- // Provide some default values, if not specified.
- config::attribute_value &a1 = stored["canrecruit"];
- if (a1.blank()) a1 = true;
- config::attribute_value &a2 = stored["placement"];
- if (a2.blank()) a2 = "map,leader";
-
- // Add the leader to the list of units to create.
- handle_unit(stored, "leader_cfg");
- }
-
- void leader()
- {
- log_step("leader");
- // If this side tag describes the leader of the side, we can simply add it to front of unit queue
- // there was a hack: if this side tag describes the leader of the side,
- // we may replace the leader with someone from recall list who can recruit, but take positioning from [side]
- // this hack shall be removed, since it messes up with 'multiple leaders'
-
- // If this side tag describes the leader of the side
- if (!side_cfg_["no_leader"].to_bool() && side_cfg_["controller"] != "null") {
- if (side_cfg_["type"] == "random") {
- std::vector types = utils::split(side_cfg_["random_leader"]);
- if (types.empty())
- types = utils::split(side_cfg_["leader"]);
- if (types.empty()) {
- utils::string_map i18n_symbols;
- i18n_symbols["faction"] = side_cfg_["name"];
- throw config::error(vgettext("Unable to find a leader type for faction $faction", i18n_symbols));
- }
- const int choice = rand() % types.size();
- config leader = side_cfg_;
- leader["type"] = types[choice];
- handle_leader(leader);
- } else
- handle_leader(side_cfg_);
- }
- BOOST_FOREACH(const config &l, side_cfg_.child_range("leader")) {
- handle_leader(l);
- }
- }
-
-
- void prepare_units()
- {
- //if this is a start-of-scenario save then playcampaign.cpp merged
- //units in [replay_start][side] merged with [side] already
- //units that are in '[scenario][side]' are 'first'
-
- //for create-or-recall semantics to work: for each unit with non-empty
- //id, unconditionally put OTHER, later, units with same id directly to
- //recall list, not including them in unit_configs_
- BOOST_FOREACH(const config &su, side_cfg_.child_range("unit")) {
- handle_unit(su, "side_cfg");
- }
- }
-
-
- void place_units()
- {
- log_step("place units");
- unit_creator uc(*t_,map_.starting_position(side_));
- uc
- .allow_add_to_recall(true)
- .allow_discover(true)
- .allow_get_village(true)
- .allow_invalidate(false)
- .allow_rename_side(true)
- .allow_show(false);
-
- BOOST_FOREACH(const config *u, unit_configs_) {
- uc.add_unit(*u);
- }
-
- // Find the first leader and use its name as the player name.
- unit_map::iterator u = resources::units->find_first_leader(t_->side());
- if ((u != resources::units->end()) && t_->current_player().empty())
- t_->set_current_player(u->name());
-
- }
-
-};
-
game_data::game_data()
: scoped_variables()
, last_selected(map_location::null_location())
diff --git a/src/teambuilder.hpp b/src/teambuilder.hpp
new file mode 100644
index 000000000000..fd8c9183727a
--- /dev/null
+++ b/src/teambuilder.hpp
@@ -0,0 +1,323 @@
+/*
+ Copyright (C) 2014 by Chris Beck
+ 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.
+*/
+
+#ifndef INCL_TEAMBUILDER_HPP_
+#define INCL_TEAMBUILDER_HPP_
+
+#include "actions/create.hpp"
+#include "config.hpp"
+#include "game_board.hpp"
+#include "log.hpp"
+#include "map.hpp"
+#include "team.hpp"
+#include "unit.hpp"
+#include "unit_map.hpp"
+
+#include
+
+#include
+#include
+
+static lg::log_domain log_engine_tc("engine/team_construction");
+#define ERR_NG_TC LOG_STREAM(err, log_engine_tc)
+#define WRN_NG_TC LOG_STREAM(warn, log_engine_tc)
+#define LOG_NG_TC LOG_STREAM(info, log_engine_tc)
+#define DBG_NG_TC LOG_STREAM(debug, log_engine_tc)
+
+class team_builder {
+public:
+ team_builder(const config& side_cfg,
+ const std::string &save_id, std::vector& teams,
+ const config& level, gamemap& map, unit_map& units,
+ const config &starting_pos)
+ : gold_info_ngold_(0)
+ , leader_configs_()
+ , level_(level)
+ , map_(map)
+ , player_exists_(false)
+ , save_id_(save_id)
+ , seen_ids_()
+ , side_(0)
+ , side_cfg_(side_cfg)
+ , starting_pos_(starting_pos)
+ , t_(NULL)
+ , teams_(teams)
+ , unit_configs_()
+ , units_(units)
+ {
+ }
+
+ void build_team_stage_one()
+ {
+ //initialize the context variables and flags, find relevant tags, set up everything
+ init();
+
+ //find out the correct qty of gold and handle gold carryover.
+ gold();
+
+ //create a new instance of team and push it to back of resources::teams vector
+ new_team();
+
+ assert(t_!=NULL);
+
+ //set team objectives if necessary
+ objectives();
+
+ // If the game state specifies additional units that can be recruited by the player, add them.
+ previous_recruits();
+
+ //place leader
+ leader();
+
+ //prepare units, populate obvious recall lists elements
+ prepare_units();
+
+ }
+
+
+ void build_team_stage_two()
+ {
+ //place units
+ //this is separate stage because we need to place units only after every other team is constructed
+ place_units();
+
+ }
+
+protected:
+
+ int gold_info_ngold_;
+ std::deque leader_configs_;
+ const config &level_;
+ gamemap &map_;
+ bool player_exists_;
+ const std::string save_id_;
+ std::set seen_ids_;
+ int side_;
+ const config &side_cfg_;
+ const config &starting_pos_;
+ team *t_;
+ std::vector &teams_;
+ std::vector unit_configs_;
+ unit_map &units_;
+
+
+ void log_step(const char *s) const
+ {
+ LOG_NG_TC << "team "<= teams_.size()) {
+ std::stringstream ss;
+ ss << "Side number " << side_ << " higher than number of sides (" << teams_.size() << ")";
+ throw config::error(ss.str());
+ }
+ if (teams_[side_ - 1].side() != 0) {
+ std::stringstream ss;
+ ss << "Duplicate definition of side " << side_;
+ throw config::error(ss.str());
+ }
+ t_ = &teams_[side_ - 1];
+
+ log_step("init");
+
+ //track whether a [player] tag with persistence information exists (in addition to the [side] tag)
+ player_exists_ = false;
+
+ if(map_.empty()) {
+ throw game::load_game_failed("Map not found");
+ }
+
+ DBG_NG_TC << "save id: "<< save_id_ <build(side_cfg_, map_, gold_info_ngold_);
+ //t_->set_gold_add(gold_info_add_);
+ }
+
+
+ void objectives()
+ {
+ log_step("objectives");
+ // If this team has no objectives, set its objectives
+ // to the level-global "objectives"
+ if (t_->objectives().empty())
+ t_->set_objectives(level_["objectives"], false);
+ }
+
+
+ void previous_recruits()
+ {
+ log_step("previous recruits");
+ // If the game state specifies units that
+ // can be recruited for the player, add them.
+ if (!side_cfg_) return;
+ if (const config::attribute_value *v = side_cfg_.get("previous_recruits")) {
+ BOOST_FOREACH(const std::string &rec, utils::split(*v)) {
+ DBG_NG_TC << "adding previous recruit: " << rec << '\n';
+ t_->add_recruit(rec);
+ }
+ }
+ }
+
+
+
+
+ void handle_unit(const config &u, const char *origin)
+ {
+ DBG_NG_TC
+ << "unit from "<recall_list().add(UnitPtr(new unit(u_tmp,true)));
+ } else {
+ //not seen before
+ unit_configs_.push_back(&u);
+ seen_ids_.insert(id);
+ }
+
+ } else {
+ unit_configs_.push_back(&u);
+ }
+ }
+
+ void handle_leader(const config &leader)
+ {
+ // Make a persistent copy of the config.
+ leader_configs_.push_back(leader);
+ config & stored = leader_configs_.back();
+
+ // Remove the attributes used to define a side.
+ BOOST_FOREACH( const std::string & attr , team::attributes) {
+ stored.remove_attribute(attr);
+ }
+
+ // Provide some default values, if not specified.
+ config::attribute_value &a1 = stored["canrecruit"];
+ if (a1.blank()) a1 = true;
+ config::attribute_value &a2 = stored["placement"];
+ if (a2.blank()) a2 = "map,leader";
+
+ // Add the leader to the list of units to create.
+ handle_unit(stored, "leader_cfg");
+ }
+
+ void leader()
+ {
+ log_step("leader");
+ // If this side tag describes the leader of the side, we can simply add it to front of unit queue
+ // there was a hack: if this side tag describes the leader of the side,
+ // we may replace the leader with someone from recall list who can recruit, but take positioning from [side]
+ // this hack shall be removed, since it messes up with 'multiple leaders'
+
+ // If this side tag describes the leader of the side
+ if (!side_cfg_["no_leader"].to_bool() && side_cfg_["controller"] != "null") {
+ if (side_cfg_["type"] == "random") {
+ std::vector types = utils::split(side_cfg_["random_leader"]);
+ if (types.empty())
+ types = utils::split(side_cfg_["leader"]);
+ if (types.empty()) {
+ utils::string_map i18n_symbols;
+ i18n_symbols["faction"] = side_cfg_["name"];
+ throw config::error(vgettext("Unable to find a leader type for faction $faction", i18n_symbols));
+ }
+ const int choice = rand() % types.size();
+ config leader = side_cfg_;
+ leader["type"] = types[choice];
+ handle_leader(leader);
+ } else
+ handle_leader(side_cfg_);
+ }
+ BOOST_FOREACH(const config &l, side_cfg_.child_range("leader")) {
+ handle_leader(l);
+ }
+ }
+
+
+ void prepare_units()
+ {
+ //if this is a start-of-scenario save then playcampaign.cpp merged
+ //units in [replay_start][side] merged with [side] already
+ //units that are in '[scenario][side]' are 'first'
+
+ //for create-or-recall semantics to work: for each unit with non-empty
+ //id, unconditionally put OTHER, later, units with same id directly to
+ //recall list, not including them in unit_configs_
+ BOOST_FOREACH(const config &su, side_cfg_.child_range("unit")) {
+ handle_unit(su, "side_cfg");
+ }
+ }
+
+
+ void place_units()
+ {
+ log_step("place units");
+ unit_creator uc(*t_,map_.starting_position(side_));
+ uc
+ .allow_add_to_recall(true)
+ .allow_discover(true)
+ .allow_get_village(true)
+ .allow_invalidate(false)
+ .allow_rename_side(true)
+ .allow_show(false);
+
+ BOOST_FOREACH(const config *u, unit_configs_) {
+ uc.add_unit(*u);
+ }
+
+ // Find the first leader and use its name as the player name.
+ unit_map::iterator u = resources::units->find_first_leader(t_->side());
+ if ((u != resources::units->end()) && t_->current_player().empty())
+ t_->set_current_player(u->name());
+
+ }
+
+};
+
+#endif