The Battle for Wesnoth  1.19.7+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 - 2024
3  by Chris Beck <render787@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "teambuilder.hpp"
17 
18 #include "actions/create.hpp"
19 #include "game_board.hpp"
20 #include "game_errors.hpp"
21 #include "log.hpp"
22 #include "map/map.hpp"
24 #include "team.hpp"
25 #include "units/type_error.hpp"
26 #include "units/unit.hpp"
27 
28 #include <vector>
29 
30 static lg::log_domain log_engine_tc("engine/team_construction");
31 #define ERR_NG_TC LOG_STREAM(err, log_engine_tc)
32 #define WRN_NG_TC LOG_STREAM(warn, log_engine_tc)
33 #define LOG_NG_TC LOG_STREAM(info, log_engine_tc)
34 #define DBG_NG_TC LOG_STREAM(debug, log_engine_tc)
35 
36 team_builder::team_builder(const config& side_cfg, team& to_build, const config& level, game_board& board, int num)
37  : leader_configs_()
38  , level_(level)
39  , board_(board)
40  , seen_ids_()
41  , side_(num)
42  , side_cfg_(side_cfg)
43  , team_(to_build)
44  , unit_configs_()
45 {
46 }
47 
49 {
50  // initialize the context variables and flags, find relevant tags, set up everything
51  init();
52 
53  // builds the team for the given side
54  new_team();
55 
56  // set team objectives if necessary
57  objectives();
58 
59  // If the game state specifies additional units that can be recruited by the player, add them.
61 
62 }
63 
65 {
66  // place leader
67  leader();
68 
69  // prepare units, populate obvious recall lists elements
70  prepare_units();
71 }
72 
74 {
75  // place units
76  // this is separate stage because we need to place units only after every other team is constructed
77  place_units();
78 }
79 
80 void team_builder::log_step(const char* s) const
81 {
82  LOG_NG_TC << "team " << side_ << " construction: " << s;
83 }
84 
86 {
87  if(side_cfg_["side"].to_int(side_) != side_) {
88  ERR_NG_TC << "found invalid side=" << side_cfg_["side"].to_int(side_) << " in definition of side number " << side_;
89  }
90 
91  log_step("init");
92 
93  if(board_.map().empty()) {
94  throw game::load_game_failed("Map not found");
95  }
96 
97  unit_configs_.clear();
98  seen_ids_.clear();
99 }
100 
101 
103 {
104  log_step("new team");
106 }
107 
109 {
110  log_step("objectives");
111  // If this team has no objectives, set its objectives
112  // to the level-global "objectives"
113  // this is only used by the default mp 'Defeat enemy leader' objectives
114  if(team_.objectives().empty()) {
115  team_.set_objectives(level_["objectives"], false);
116  }
117 }
118 
120 {
121  log_step("previous recruits");
122 
123  if(const config::attribute_value* v = side_cfg_.get("previous_recruits")) {
124  for(const std::string& rec : utils::split(*v)) {
125  DBG_NG_TC << "adding previous recruit: " << rec;
126  team_.add_recruit(rec);
127  }
128  }
129 }
130 
131 void team_builder::handle_unit(const config& u, const char* origin)
132 {
133  DBG_NG_TC
134  << "unit from " << origin << ": "
135  << "type=[" << u["type"] << "] "
136  << "id=[" << u["id"] << "] "
137  << "placement=[" << u["placement"] << "] "
138  << "x=[" << u["x"] << "] "
139  << "y=[" << u["y"] << "]";
140 
141  if(u["type"].empty()) {
142  WRN_NG_TC
143  << "when building level, skipping a unit (id=[" << u["id"] << "]) from " << origin
144  << " with no type information,\n"
145  << "for side:\n"
146  << side_cfg_.debug();
147 
148  return;
149  }
150 
151  const std::string& id = u["id"];
152  if(!id.empty()) {
153  if(seen_ids_.find(id) != seen_ids_.end()) {
154  // seen before
155  config u_tmp = u;
156  u_tmp["side"] = std::to_string(side_);
157  team_.recall_list().add(unit::create(u_tmp, true));
158  } else {
159  // not seen before
160  unit_configs_.push_back(&u);
161  seen_ids_.insert(id);
162  }
163  } else {
164  unit_configs_.push_back(&u);
165  }
166 }
167 
169 {
170  // Make a persistent copy of the config.
171  leader_configs_.push_back(leader);
172  config& stored = leader_configs_.back();
173 
174  // Provide some default values, if not specified.
175  config::attribute_value& a1 = stored["canrecruit"];
176  if(a1.blank()) {
177  a1 = true;
178  }
179 
180  config::attribute_value& a2 = stored["placement"];
181  if(a2.blank()) {
182  a2 = "map,leader";
183  }
184 
185  // Add the leader to the list of units to create.
186  handle_unit(stored, "leader_cfg");
187 }
188 
190 {
191  log_step("leader");
192  for(const config& l : side_cfg_.child_range("leader")) {
193  handle_leader(l);
194  }
195 }
196 
198 {
199  // if this is a start-of-scenario save then playcampaign.cpp merged
200  // units in [replay_start][side] merged with [side] already
201  // units that are in '[scenario][side]' are 'first'
202 
203  // for create-or-recall semantics to work: for each unit with non-empty
204  // id, unconditionally put OTHER, later, units with same id directly to
205  // recall list, not including them in unit_configs_
206  for(const config& su : side_cfg_.child_range("unit")) {
207  handle_unit(su, "side_cfg");
208  }
209 }
210 
212 {
213  log_step("place units");
215  uc.allow_add_to_recall(true)
216  .allow_discover(true)
217  .allow_get_village(false)
218  .allow_invalidate(false)
219  .allow_rename_side(true)
220  .allow_show(false);
221 
222  for(const config* u : unit_configs_) {
223  try {
224  uc.add_unit(*u);
225  } catch(const unit_type_error& e) {
226  ERR_NG_TC << e.what();
227  }
228  }
229 }
Variant for storing WML attributes.
bool blank() const
Tests for an attribute that was never set.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:158
child_itors child_range(config_key_type key)
Definition: config.cpp:272
std::string debug() const
Definition: config.cpp:1240
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:685
Game board class.
Definition: game_board.hpp:47
virtual const gamemap & map() const override
Definition: game_board.hpp:97
map_location starting_position(int side) const
Definition: map.cpp:324
bool empty() const
Tell if the map is of 0 size.
Definition: map.hpp:65
void add(const unit_ptr &ptr, int pos=-1)
Add a unit to the list.
bool empty() const
Definition: tstring.hpp:195
std::deque< config > leader_configs_
Definition: teambuilder.hpp:52
team_builder(const config &side_cfg, team &to_build, const config &level, game_board &board, int num)
Definition: teambuilder.cpp:36
void build_team_stage_three()
Handles the third stage of team initialization (unit placement).
Definition: teambuilder.cpp:73
void handle_leader(const config &leader)
const config & side_cfg_
Definition: teambuilder.hpp:58
void objectives()
void build_team_stage_two()
Handles the second stage of team initialization ((some) unit construction).
Definition: teambuilder.cpp:64
void prepare_units()
std::set< std::string > seen_ids_
Definition: teambuilder.hpp:56
std::vector< const config * > unit_configs_
Definition: teambuilder.hpp:60
void previous_recruits()
void build_team_stage_one()
Handles the first stage of team initialization (everything except unit construction).
Definition: teambuilder.cpp:48
void handle_unit(const config &u, const char *origin)
const config & level_
Definition: teambuilder.hpp:54
void place_units()
void log_step(const char *s) const
Definition: teambuilder.cpp:80
game_board & board_
Definition: teambuilder.hpp:55
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:75
void build(const config &cfg, const gamemap &map)
Definition: team.cpp:355
const t_string & objectives() const
Definition: team.hpp:231
void set_objectives(const t_string &new_objectives, bool silently=false)
Definition: team.cpp:631
void add_recruit(const std::string &)
Definition: team.cpp:469
recall_list_manager & recall_list()
Definition: team.hpp:206
unit_creator & allow_invalidate(bool b)
unit_creator & allow_get_village(bool b)
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)
unit_creator & allow_discover(bool b)
unit_creator & allow_show(bool b)
unit_creator & allow_rename_side(bool b)
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:201
Various functions related to the creation of units (recruits, recalls, and placed units).
Standard logging facilities (interface).
std::vector< std::string > split(const config_attribute_value &val)
Error used when game loading fails.
Definition: game_errors.hpp:31
#define WRN_NG_TC
Definition: teambuilder.cpp:32
#define LOG_NG_TC
Definition: teambuilder.cpp:33
#define ERR_NG_TC
Definition: teambuilder.cpp:31
static lg::log_domain log_engine_tc("engine/team_construction")
#define DBG_NG_TC
Definition: teambuilder.cpp:34
static map_location::direction s
#define e