The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
teambuilder.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2016 by Chris Beck <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 #include "teambuilder.hpp"
15 
16 #include "actions/create.hpp"
17 #include "config.hpp"
18 #include "game_board.hpp"
19 #include "log.hpp"
20 #include "map/map.hpp"
21 #include "team.hpp"
22 #include "units/unit.hpp"
23 #include "units/map.hpp"
24 #include "resources.hpp"
25 #include "gettext.hpp"
26 #include "game_errors.hpp"
27 #include "formula/string_utils.hpp"
28 
29 #include <deque>
30 #include <vector>
31 
32 static lg::log_domain log_engine_tc("engine/team_construction");
33 #define ERR_NG_TC LOG_STREAM(err, log_engine_tc)
34 #define WRN_NG_TC LOG_STREAM(warn, log_engine_tc)
35 #define LOG_NG_TC LOG_STREAM(info, log_engine_tc)
36 #define DBG_NG_TC LOG_STREAM(debug, log_engine_tc)
37 
38 class team_builder {
39 public:
40  team_builder(const config& side_cfg, std::vector<team>& teams,
41  const config& level, game_board& board)
42  : gold_info_ngold_(0)
43  , leader_configs_()
44  , level_(level)
45  , board_(board)
46  , player_exists_(false)
47  , seen_ids_()
48  , side_(0)
49  , side_cfg_(side_cfg)
50  , t_(nullptr)
51  , teams_(teams)
52  , unit_configs_()
53  {
54  }
55 
57  {
58  //initialize the context variables and flags, find relevant tags, set up everything
59  init();
60 
61  //find out the correct qty of gold and handle gold carryover.
62  gold();
63 
64  //create a new instance of team and push it to back of resources::teams vector
65  new_team();
66 
67  assert(t_!=nullptr);
68 
69  //set team objectives if necessary
70  objectives();
71 
72  // If the game state specifies additional units that can be recruited by the player, add them.
74 
75  //place leader
76  leader();
77 
78  //prepare units, populate obvious recall lists elements
79  prepare_units();
80 
81  }
82 
83 
85  {
86  //place units
87  //this is separate stage because we need to place units only after every other team is constructed
88  place_units();
89 
90  }
91 
92 protected:
93 
95  std::deque<config> leader_configs_;
96  //only used for objectives
97  const config &level_;
99  //only used for debug message
101  std::set<std::string> seen_ids_;
102  int side_;
105  std::vector<team> &teams_;
106  std::vector<const config*> unit_configs_;
107 
108  void log_step(const char *s) const
109  {
110  LOG_NG_TC << "team "<<side_<<" construction: "<< s << std::endl;
111  }
112 
113 
114  void init()
115  {
116  side_ = side_cfg_["side"].to_int(1);
117  if (side_ == 0) // Otherwise falls into the next error, with a very confusing message
118  throw config::error("Side number 0 encountered. Side numbers start at 1");
119  if (unsigned(side_ - 1) >= teams_.size()) {
120  std::stringstream ss;
121  ss << "Side number " << side_ << " higher than number of sides (" << teams_.size() << ")";
122  throw config::error(ss.str());
123  }
124  if (teams_[side_ - 1].side() != 0) {
125  std::stringstream ss;
126  ss << "Duplicate definition of side " << side_;
127  throw config::error(ss.str());
128  }
129  t_ = &teams_[side_ - 1];
130 
131  log_step("init");
132 
133  //track whether a [player] tag with persistence information exists (in addition to the [side] tag)
134  player_exists_ = false;
135 
136  if(board_.map().empty()) {
137  throw game::load_game_failed("Map not found");
138  }
139 
140  DBG_NG_TC << "snapshot: "<< (player_exists_ ? "true" : "false") <<std::endl;
141 
142  unit_configs_.clear();
143  seen_ids_.clear();
144 
145  }
146 
147 
148  void gold()
149  {
150  log_step("gold");
151 
152  gold_info_ngold_ = side_cfg_["gold"];
153 
154  DBG_NG_TC << "set gold to '" << gold_info_ngold_ << "'\n";
155  }
156 
157 
158  void new_team()
159  {
160  log_step("new team");
161  t_->build(side_cfg_, board_.map(), gold_info_ngold_);
162  }
163 
164 
165  void objectives()
166  {
167  log_step("objectives");
168  // If this team has no objectives, set its objectives
169  // to the level-global "objectives"
170  // this is only used by the default mp 'Defeat enemy leader' objectives
171  if (t_->objectives().empty())
172  t_->set_objectives(level_["objectives"], false);
173  }
174 
175 
177  {
178  log_step("previous recruits");
179  // If the game state specifies units that
180  // can be recruited for the player, add them.
181  if (!side_cfg_) return;
182  if (const config::attribute_value *v = side_cfg_.get("previous_recruits")) {
183  for (const std::string &rec : utils::split(*v)) {
184  DBG_NG_TC << "adding previous recruit: " << rec << '\n';
185  t_->add_recruit(rec);
186  }
187  }
188  }
189 
190 
191 
192 
193  void handle_unit(const config &u, const char *origin)
194  {
195  DBG_NG_TC
196  << "unit from "<<origin
197  << ": type=["<<u["type"]
198  << "] id=["<<u["id"]
199  << "] placement=["<<u["placement"]
200  << "] x=["<<u["x"]
201  << "] y=["<<u["y"]
202  <<"]"<< std::endl;
203 
204  if (u["type"].empty()) {
205  WRN_NG_TC << "warning: when building level, skipping a unit (id=[" << u["id"] << "]) from " << origin
206  << " with no type information,\n"
207  << "for side:\n" << side_cfg_.debug() << std::endl;
208 
209  return ;
210  }
211 
212  const std::string &id = u["id"];
213  if (!id.empty()) {
214  if ( seen_ids_.find(id)!=seen_ids_.end() ) {
215  //seen before
216  config u_tmp = u;
217  u_tmp["side"] = std::to_string(side_);
218  t_->recall_list().add(unit_ptr(new unit(u_tmp,true)));
219  } else {
220  //not seen before
221  unit_configs_.push_back(&u);
222  seen_ids_.insert(id);
223  }
224 
225  } else {
226  unit_configs_.push_back(&u);
227  }
228  }
229 
231  {
232  // Make a persistent copy of the config.
233  leader_configs_.push_back(leader);
234  config & stored = leader_configs_.back();
235 
236  // Remove the attributes used to define a side.
237  for (const std::string & attr : team::attributes) {
238  stored.remove_attribute(attr);
239  }
240 
241  // Provide some default values, if not specified.
242  config::attribute_value &a1 = stored["canrecruit"];
243  if (a1.blank()) a1 = true;
244  config::attribute_value &a2 = stored["placement"];
245  if (a2.blank()) a2 = "map,leader";
246 
247  // Add the leader to the list of units to create.
248  handle_unit(stored, "leader_cfg");
249  }
250 
251  void leader()
252  {
253  log_step("leader");
254  // If this side tag describes the leader of the side, we can simply add it to front of unit queue
255  // there was a hack: if this side tag describes the leader of the side,
256  // we may replace the leader with someone from recall list who can recruit, but take positioning from [side]
257  // this hack shall be removed, since it messes up with 'multiple leaders'
258 
259  // If this side tag describes the leader of the side
260  if (side_cfg_.has_attribute("type") && side_cfg_["type"] != "null" ) {
261  handle_leader(side_cfg_);
262  }
263  for (const config &l : side_cfg_.child_range("leader")) {
264  handle_leader(l);
265  }
266  }
267 
268 
270  {
271  //if this is a start-of-scenario save then playcampaign.cpp merged
272  //units in [replay_start][side] merged with [side] already
273  //units that are in '[scenario][side]' are 'first'
274 
275  //for create-or-recall semantics to work: for each unit with non-empty
276  //id, unconditionally put OTHER, later, units with same id directly to
277  //recall list, not including them in unit_configs_
278  for (const config &su : side_cfg_.child_range("unit")) {
279  handle_unit(su, "side_cfg");
280  }
281  }
282 
283 
284  void place_units()
285  {
286  log_step("place units");
287  unit_creator uc(*t_, board_.map().starting_position(side_), &board_);
288  uc
289  .allow_add_to_recall(true)
290  .allow_discover(true)
291  .allow_get_village(false)
292  .allow_invalidate(false)
293  .allow_rename_side(true)
294  .allow_show(false);
295 
296  for (const config *u : unit_configs_) {
297  uc.add_unit(*u);
298  }
299  }
300 
301 };
302 
304  std::vector<team>& teams,
305  const config& level, game_board& board)
306 {
307  return team_builder_ptr(new team_builder(side_cfg, teams, level, board));
308 }
309 
311 {
312  tb_ptr->build_team_stage_one();
313 }
314 
316 {
317  tb_ptr->build_team_stage_two();
318 }
child_itors child_range(const std::string &key)
Definition: config.cpp:613
unit_creator & allow_rename_side(bool b)
void remove_attribute(const std::string &key)
Definition: config.cpp:534
Game board class.
Definition: game_board.hpp:55
std::deque< config > leader_configs_
Definition: teambuilder.cpp:95
void build_team_stage_two(team_builder_ptr tb_ptr)
void place_units()
Definition: unit.hpp:95
GLint level
Definition: glew.h:1220
void set_objectives(const t_string &new_objectives, bool silently=false)
Definition: team.cpp:560
unit_creator & allow_invalidate(bool b)
unit_creator & allow_show(bool b)
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:29
void log_step(const char *s) const
Error used when game loading fails.
Definition: game_errors.hpp:30
#define LOG_NG_TC
Definition: teambuilder.cpp:35
const t_string & objectives() const
Definition: team.hpp:244
unit_creator & allow_discover(bool b)
void build_team_stage_two()
Definition: teambuilder.cpp:84
void build(const config &cfg, const gamemap &map, int gold=default_team_gold_)
Definition: team.cpp:306
std::vector< team > & teams_
std::string debug() const
Definition: config.cpp:1438
void add_recruit(const std::string &)
Definition: team.cpp:413
-file sdl_utils.hpp
std::vector< const config * > unit_configs_
Definitions for the interface to Wesnoth Markup Language (WML).
unit_creator & allow_add_to_recall(bool b)
Variant for storing WML attributes.
Definition: config.hpp:223
GLdouble l
Definition: glew.h:6966
bool blank() const
Tests for an attribute that was never set.
Definition: config.cpp:367
static const boost::container::flat_set< std::string > attributes
Stores the attributes recognized by [side].
Definition: team.hpp:180
static std::vector< team > *& teams
Definition: team.cpp:50
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:50
#define WRN_NG_TC
Definition: teambuilder.cpp:34
map_location starting_position(int side) const
Definition: map.cpp:421
void objectives()
static lg::log_domain log_engine_tc("engine/team_construction")
const GLdouble * v
Definition: glew.h:1359
bool empty() const
Tell if the map is of 0 size.
Definition: map.hpp:157
void previous_recruits()
void handle_leader(const config &leader)
int gold_info_ngold_
Definition: teambuilder.cpp:94
void build_team_stage_one()
Definition: teambuilder.cpp:56
const config & level_
Definition: teambuilder.cpp:97
Various functions related to the creation of units (recruits, recalls, and placed units)...
void prepare_units()
boost::shared_ptr< team_builder > team_builder_ptr
Definition: teambuilder.hpp:27
unit_creator & allow_get_village(bool b)
void handle_unit(const config &u, const char *origin)
game_board & board_
Definition: teambuilder.cpp:98
void build_team_stage_one(team_builder_ptr tb_ptr)
team_builder_ptr create_team_builder(const config &side_cfg, std::vector< team > &teams, const config &level, game_board &board)
const attribute_value * get(const std::string &key) const
Returns a pointer to the attribute with the given key or nullptr if it does not exist.
Definition: config.cpp:935
virtual const gamemap & map() const
Definition: game_board.hpp:98
std::set< std::string > seen_ids_
void add_unit(const config &cfg, const vconfig *vcfg=nullptr)
adds a unit on map without firing any events (so, usable during team construction in gamestatus) ...
boost::intrusive_ptr< unit > unit_ptr
Definition: ptr.hpp:29
bool has_attribute(const std::string &key) const
Definition: config.cpp:514
Standard logging facilities (interface).
recall_list_manager & recall_list()
Definition: team.hpp:220
void add(const unit_ptr &ptr)
Add a unit to the list.
std::vector< std::string > split(std::string const &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
const config & side_cfg_
#define DBG_NG_TC
Definition: teambuilder.cpp:36
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
GLdouble s
Definition: glew.h:1358
GLsizei const GLcharARB ** string
Definition: glew.h:4503
bool empty() const
Definition: tstring.hpp:166
team_builder(const config &side_cfg, std::vector< team > &teams, const config &level, game_board &board)
Definition: teambuilder.cpp:40