The Battle for Wesnoth  1.15.11+dev
teambuilder.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2018 by Chris Beck <render787@gmail.com>
3  Part of the Battle for Wesnoth Project https://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 
15 #include "teambuilder.hpp"
16 
17 #include "actions/create.hpp"
18 #include "game_board.hpp"
19 #include "game_errors.hpp"
20 #include "gettext.hpp"
21 #include "log.hpp"
22 #include "map/map.hpp"
24 #include "team.hpp"
25 #include "units/map.hpp"
26 #include "units/type_error.hpp"
27 #include "units/unit.hpp"
28 
29 #include <vector>
30 
31 static lg::log_domain log_engine_tc("engine/team_construction");
32 #define ERR_NG_TC LOG_STREAM(err, log_engine_tc)
33 #define WRN_NG_TC LOG_STREAM(warn, log_engine_tc)
34 #define LOG_NG_TC LOG_STREAM(info, log_engine_tc)
35 #define DBG_NG_TC LOG_STREAM(debug, log_engine_tc)
36 
37 team_builder::team_builder(const config& side_cfg, team& to_build, const config& level, game_board& board, int num)
38  : gold_info_ngold_(0)
39  , leader_configs_()
40  , level_(level)
41  , board_(board)
42  , player_exists_(false)
43  , seen_ids_()
44  , side_(num)
45  , side_cfg_(side_cfg)
46  , team_(to_build)
47  , unit_configs_()
48 {
49 }
50 
52 {
53  // initialize the context variables and flags, find relevant tags, set up everything
54  init();
55 
56  // find out the correct qty of gold and handle gold carryover.
57  gold();
58 
59  // builds the team for the given side
60  new_team();
61 
62  // set team objectives if necessary
63  objectives();
64 
65  // If the game state specifies additional units that can be recruited by the player, add them.
67 
68  // place leader
69  leader();
70 
71  // prepare units, populate obvious recall lists elements
72  prepare_units();
73 }
74 
76 {
77  // place units
78  // this is separate stage because we need to place units only after every other team is constructed
79  place_units();
80 }
81 
82 void team_builder::log_step(const char* s) const
83 {
84  LOG_NG_TC << "team " << side_ << " construction: " << s << std::endl;
85 }
86 
88 {
89  if(side_cfg_["side"].to_int(side_) != side_) {
90  ERR_NG_TC << "found invalid side=" << side_cfg_["side"].to_int(side_) << " in definition of side number " << side_ << std::endl;
91  }
92 
93  log_step("init");
94 
95  // track whether a [player] tag with persistence information exists (in addition to the [side] tag)
96  player_exists_ = false;
97 
98  if(board_.map().empty()) {
99  throw game::load_game_failed("Map not found");
100  }
101 
102  DBG_NG_TC << "snapshot: " << utils::bool_string(player_exists_) << std::endl;
103 
104  unit_configs_.clear();
105  seen_ids_.clear();
106 }
107 
109 {
110  log_step("gold");
111 
112  gold_info_ngold_ = side_cfg_["gold"];
113 
114  DBG_NG_TC << "set gold to '" << gold_info_ngold_ << "'\n";
115 }
116 
118 {
119  log_step("new team");
121 }
122 
124 {
125  log_step("objectives");
126  // If this team has no objectives, set its objectives
127  // to the level-global "objectives"
128  // this is only used by the default mp 'Defeat enemy leader' objectives
129  if(team_.objectives().empty()) {
130  team_.set_objectives(level_["objectives"], false);
131  }
132 }
133 
135 {
136  log_step("previous recruits");
137  // If the game state specifies units that
138  // can be recruited for the player, add them.
139  if(!side_cfg_) {
140  return;
141  }
142 
143  if(const config::attribute_value* v = side_cfg_.get("previous_recruits")) {
144  for(const std::string& rec : utils::split(*v)) {
145  DBG_NG_TC << "adding previous recruit: " << rec << '\n';
146  team_.add_recruit(rec);
147  }
148  }
149 }
150 
151 void team_builder::handle_unit(const config& u, const char* origin)
152 {
153  DBG_NG_TC
154  << "unit from " << origin << ": "
155  << "type=[" << u["type"] << "] "
156  << "id=[" << u["id"] << "] "
157  << "placement=[" << u["placement"] << "] "
158  << "x=[" << u["x"] << "] "
159  << "y=[" << u["y"] << "]"
160  << std::endl;
161 
162  if(u["type"].empty()) {
163  WRN_NG_TC
164  << "when building level, skipping a unit (id=[" << u["id"] << "]) from " << origin
165  << " with no type information,\n"
166  << "for side:\n"
167  << side_cfg_.debug() << std::endl;
168 
169  return;
170  }
171 
172  const std::string& id = u["id"];
173  if(!id.empty()) {
174  if(seen_ids_.find(id) != seen_ids_.end()) {
175  // seen before
176  config u_tmp = u;
177  u_tmp["side"] = std::to_string(side_);
178  team_.recall_list().add(unit::create(u_tmp, true));
179  } else {
180  // not seen before
181  unit_configs_.push_back(&u);
182  seen_ids_.insert(id);
183  }
184  } else {
185  unit_configs_.push_back(&u);
186  }
187 }
188 
190 {
191  // Make a persistent copy of the config.
192  leader_configs_.push_back(leader);
193  config& stored = leader_configs_.back();
194 
195  // Remove the attributes used to define a side.
196  for(const std::string& attr : team::attributes) {
197  stored.remove_attribute(attr);
198  }
199 
200  // Provide some default values, if not specified.
201  config::attribute_value& a1 = stored["canrecruit"];
202  if(a1.blank()) {
203  a1 = true;
204  }
205 
206  config::attribute_value& a2 = stored["placement"];
207  if(a2.blank()) {
208  a2 = "map,leader";
209  }
210 
211  // Add the leader to the list of units to create.
212  handle_unit(stored, "leader_cfg");
213 }
214 
216 {
217  log_step("leader");
218  // If this side tag describes the leader of the side, we can simply add it to front of unit queue
219  // there was a hack: if this side tag describes the leader of the side,
220  // we may replace the leader with someone from recall list who can recruit, but take positioning from [side]
221  // this hack shall be removed, since it messes up with 'multiple leaders'
222 
223  // If this side tag describes the leader of the side
224  if(!side_cfg_["type"].empty() && side_cfg_["type"] != "null") {
226  }
227 
228  for(const config& l : side_cfg_.child_range("leader")) {
229  handle_leader(l);
230  }
231 }
232 
234 {
235  // if this is a start-of-scenario save then playcampaign.cpp merged
236  // units in [replay_start][side] merged with [side] already
237  // units that are in '[scenario][side]' are 'first'
238 
239  // for create-or-recall semantics to work: for each unit with non-empty
240  // id, unconditionally put OTHER, later, units with same id directly to
241  // recall list, not including them in unit_configs_
242  for(const config& su : side_cfg_.child_range("unit")) {
243  handle_unit(su, "side_cfg");
244  }
245 }
246 
248 {
249  log_step("place units");
251  uc.allow_add_to_recall(true)
252  .allow_discover(true)
253  .allow_get_village(false)
254  .allow_invalidate(false)
255  .allow_rename_side(true)
256  .allow_show(false);
257 
258  for(const config* u : unit_configs_) {
259  try {
260  uc.add_unit(*u);
261  } catch(const unit_type_error& e) {
262  ERR_NG_TC << e.what() << "\n";
263  }
264  }
265 }
unit_creator & allow_rename_side(bool b)
Game board class.
Definition: game_board.hpp:50
std::deque< config > leader_configs_
Definition: teambuilder.hpp:51
void place_units()
map_location starting_position(int side) const
Definition: map.cpp:319
void set_objectives(const t_string &new_objectives, bool silently=false)
Definition: team.cpp:642
unit_creator & allow_invalidate(bool b)
unit_creator & allow_show(bool b)
Variant for storing WML attributes.
Error used when game loading fails.
Definition: game_errors.hpp:30
static const std::set< std::string > attributes
Stores the attributes recognized by [side].
Definition: team.hpp:176
child_itors child_range(config_key_type key)
Definition: config.cpp:356
#define LOG_NG_TC
Definition: teambuilder.cpp:34
unit_creator & allow_discover(bool b)
team_builder(const config &side_cfg, team &to_build, const config &level, game_board &board, int num)
Definition: teambuilder.cpp:37
const attribute_value * get(config_key_type key) const
Returns a pointer to the attribute with the given key or nullptr if it does not exist.
Definition: config.cpp:766
virtual const gamemap & map() const override
Definition: game_board.hpp:101
void build_team_stage_two()
Handles the second stage of team initialization (unit placement).
Definition: teambuilder.cpp:75
void build(const config &cfg, const gamemap &map, int gold=default_team_gold_)
Definition: team.cpp:353
void add_recruit(const std::string &)
Definition: team.cpp:478
void remove_attribute(config_key_type key)
Definition: config.cpp:229
std::vector< const config * > unit_configs_
Definition: teambuilder.hpp:61
unit_creator & allow_add_to_recall(bool b)
static unit_ptr create(const config &cfg, bool use_traits=false, const vconfig *vcfg=nullptr)
Initializes a unit from a config.
Definition: unit.hpp:189
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
#define WRN_NG_TC
Definition: teambuilder.cpp:33
bool player_exists_
Definition: teambuilder.hpp:56
void objectives()
static lg::log_domain log_engine_tc("engine/team_construction")
bool blank() const
Tests for an attribute that was never set.
void previous_recruits()
void handle_leader(const config &leader)
#define ERR_NG_TC
Definition: teambuilder.cpp:32
int gold_info_ngold_
Definition: teambuilder.hpp:50
void log_step(const char *s) const
Definition: teambuilder.cpp:82
const char * what() const noexcept
Definition: exceptions.hpp:35
void build_team_stage_one()
Handles the first stage of team initialization (everything except unit placement).
Definition: teambuilder.cpp:51
const config & level_
Definition: teambuilder.hpp:53
Various functions related to the creation of units (recruits, recalls, and placed units)...
void prepare_units()
unit_creator & allow_get_village(bool b)
static map_location::DIRECTION s
void handle_unit(const config &u, const char *origin)
const t_string & objectives() const
Definition: team.hpp:248
std::string bool_string(const bool value)
Converts a bool value to &#39;true&#39; or &#39;false&#39;.
game_board & board_
Definition: teambuilder.hpp:54
std::set< std::string > seen_ids_
Definition: teambuilder.hpp:57
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) ...
bool empty() const
Definition: tstring.hpp:186
std::vector< std::string > split(const config_attribute_value &val)
void add(const unit_ptr &ptr, int pos=-1)
Add a unit to the list.
Standard logging facilities (interface).
recall_list_manager & recall_list()
Definition: team.hpp:223
bool empty() const
Tell if the map is of 0 size.
Definition: map.hpp:64
#define e
const config & side_cfg_
Definition: teambuilder.hpp:59
#define DBG_NG_TC
Definition: teambuilder.cpp:35
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:59
std::string debug() const
Definition: config.cpp:1322