The Battle for Wesnoth  1.15.0+dev
carryover.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
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 "carryover.hpp"
16 
17 #include "config.hpp"
18 #include "log.hpp"
19 #include "team.hpp"
20 #include "units/unit.hpp"
21 #include <cassert>
22 
23 static lg::log_domain log_engine("engine");
24 #define LOG_NG LOG_STREAM(info, log_engine)
25 #define ERR_NG LOG_STREAM(err, log_engine)
26 
28  : add_(!side["carryover_add"].empty() ? side["carryover_add"].to_bool() : side["add"].to_bool())
29  , current_player_(side["current_player"])
30  , gold_(!side["carryover_gold"].empty() ? side["carryover_gold"].to_int() : side["gold"].to_int())
31  // if we load it from a snapshot we need to read the recruits from "recruits" and not from "previous_recruits".
32  , previous_recruits_(side.has_attribute("recruit") ? utils::set_split(side["recruit"]) :utils::set_split(side["previous_recruits"]))
33  , recall_list_()
34  , save_id_(side["save_id"])
35  , variables_(side.child_or_empty("variables"))
36 {
37  for(const config& u : side.child_range("unit")) {
38  recall_list_.push_back(u);
39  config& u_back = recall_list_.back();
40  u_back.remove_attributes("side", "goto_x", "goto_y", "x", "y", "hidden");
41  }
42 }
43 
44 carryover::carryover(const team& t, const int gold, const bool add)
45  : add_ (add)
46  , current_player_(t.current_player())
47  , gold_(gold)
48  , previous_recruits_(t.recruits())
49  , recall_list_()
50  , save_id_(t.save_id())
51  , variables_(t.variables())
52 {
53  for(const unit_const_ptr & u : t.recall_list()) {
54  recall_list_.emplace_back();
55  u->write(recall_list_.back());
56  }
57 }
58 
59 static const int default_gold_qty = 100;
60 
62 
63  int cfg_gold = side_cfg["gold"].to_int();
64 
65  if(side_cfg["gold"].empty()) {
66  cfg_gold = default_gold_qty;
67  side_cfg["gold"] = cfg_gold;
68  }
69 
70  if(add_ && gold_ > 0){
71  side_cfg["gold"] = cfg_gold + gold_;
72  }
73  else if(gold_ > cfg_gold){
74  side_cfg["gold"] = gold_;
75  }
76  side_cfg.child_or_add("variables").swap(variables_);
77  variables_.clear();
78  gold_ = 0;
79 }
80 
82  std::string can_recruit_str = utils::join(previous_recruits_, ",");
83  previous_recruits_.clear();
84  side_cfg["previous_recruits"] = can_recruit_str;
85 }
86 
88  for(const config & u_cfg : recall_list_) {
89  side_cfg.add_child("unit", u_cfg);
90  }
91  recall_list_.clear();
92 }
93 
94 std::string carryover::get_recruits(bool erase){
95  // Join the previous recruits into a string.
96  std::string can_recruit_str = utils::join(previous_recruits_);
97  if ( erase )
98  // Clear the previous recruits.
99  previous_recruits_.clear();
100 
101  return can_recruit_str;
102 }
103 
104 const std::string carryover::to_string(){
105  std::string side = "";
106  side.append("Side " + save_id_ + ": gold " + std::to_string(gold_) + " recruits " + get_recruits(false) + " units ");
107  for(const config & u_cfg : recall_list_) {
108  side.append(u_cfg["name"].str() + ", ");
109  }
110  return side;
111 }
112 
114  config& side = cfg.add_child("side");
115  side["save_id"] = save_id_;
116  side["gold"] = gold_;
117  side["add"] = add_;
118  side["current_player"] = current_player_;
119  side["previous_recruits"] = get_recruits(false);
120  side.add_child("variables", variables_);
121  for(const config & u_cfg : recall_list_) {
122  side.add_child("unit", u_cfg);
123  }
124 }
125 
126 carryover_info::carryover_info(const config& cfg, bool from_snpashot)
127  : carryover_sides_()
128  , variables_(cfg.child_or_empty("variables"))
129  , rng_(cfg)
130  , wml_menu_items_()
131  , next_scenario_(cfg["next_scenario"])
132  , next_underlying_unit_id_(cfg["next_underlying_unit_id"].to_int(0))
133 {
134  for(const config& side : cfg.child_range("side"))
135  {
136  if(side["lost"].to_bool(false) || !side["persistent"].to_bool(true) || side["save_id"].empty())
137  {
138  //this shouldn't happen outside a snpshot.
139  if(!from_snpashot) {
140  ERR_NG << "found invalid carryover data in saved game, lost='" << side["lost"] << "' persistent='" << side["persistent"] << "' save_id='" << side["save_id"] << "'\n";
141  }
142  continue;
143  }
144  this->carryover_sides_.emplace_back(side);
145  }
146  for(const config& item : cfg.child_range("menu_item"))
147  {
148  if(item["persistent"].to_bool(true)) {
149  wml_menu_items_.push_back(new config(item));
150  }
151  }
152 }
153 
154 std::vector<carryover>& carryover_info::get_all_sides() {
155  return carryover_sides_;
156 }
157 
159  carryover_sides_.emplace_back(cfg);
160 }
161 
162 void carryover_info::remove_side(const std::string& id) {
164  it != carryover_sides_.end(); ++it) {
165 
166  if (it->get_save_id() == id) {
167  carryover_sides_.erase(it);
168  break;
169  }
170  }
171 }
172 
174 {
175  save_id_equals(const std::string& val) : value (val) {}
176  bool operator () (carryover& v2) const
177  {
178  return value == v2.get_save_id();
179  }
180 
181  std::string value;
182 };
183 
185  if(side_cfg["save_id"].empty()){
186  side_cfg["save_id"] = side_cfg["id"];
187  }
188  std::vector<carryover>::iterator iside = std::find_if(
189  carryover_sides_.begin(),
190  carryover_sides_.end(),
191  save_id_equals(side_cfg["save_id"])
192  );
193  if(iside != carryover_sides_.end())
194  {
195  iside->transfer_all_gold_to(side_cfg);
196  iside->transfer_all_recalls_to(side_cfg);
197  iside->transfer_all_recruits_to(side_cfg);
198  carryover_sides_.erase(iside);
199  return;
200  }
201  else
202  {
203  //if no carryover was found for this side, check if starting gold is defined
204  if(!side_cfg.has_attribute("gold") || side_cfg["gold"].empty()){
205  side_cfg["gold"] = default_gold_qty;
206  }
207  }
208 }
209 
211 {
212  if(!level.has_attribute("next_underlying_unit_id"))
213  {
214  level["next_underlying_unit_id"] = next_underlying_unit_id_;
215  }
216 
217  //if the game has been loaded from a snapshot, variables_ is empty since we cleared it below.
218  level.child_or_add("variables").append(std::move(variables_));
219 
220  config::attribute_value & seed_value = level["random_seed"];
221  if ( seed_value.empty() ) {
222  seed_value = rng_.get_random_seed_str();
223  level["random_calls"] = rng_.get_random_calls();
224  }
225 
226  if(!level.has_child("menu_item")){
227  for(config& item : wml_menu_items_)
228  {
229  level.add_child("menu_item").swap(item);
230  }
231  }
232 
233  next_scenario_ = "";
234  variables_.clear();
235  wml_menu_items_.clear();
236 
237 }
238 
240 {
241  config cfg;
242  cfg["next_underlying_unit_id"] = next_underlying_unit_id_;
243  cfg["next_scenario"] = next_scenario_;
244 
245  for(carryover& c : carryover_sides_) {
246  c.to_config(cfg);
247  }
248 
249  cfg["random_seed"] = rng_.get_random_seed_str();
250  cfg["random_calls"] = rng_.get_random_calls();
251 
252  cfg.add_child("variables", variables_);
253  for(const config& item : wml_menu_items_)
254  {
255  cfg.add_child("menu_item", item);
256  }
257  return cfg;
258 }
259 
260 carryover* carryover_info::get_side(const std::string& save_id){
261  for(carryover& side : carryover_sides_) {
262  if(side.get_save_id() == save_id){
263  return &side;
264  }
265  }
266  return nullptr;
267 }
268 
269 
271 {
272  for(const carryover & old_side : old_carryover.carryover_sides_)
273  {
274  std::vector<carryover>::iterator iside = std::find_if(
275  carryover_sides_.begin(),
276  carryover_sides_.end(),
277  save_id_equals(old_side.get_save_id())
278  );
279  //add the side if don't already have it.
280  if(iside == carryover_sides_.end())
281  {
282  this->carryover_sides_.push_back(old_side);
283  }
284  }
285 }
boost::intrusive_ptr< const unit > unit_const_ptr
Definition: ptr.hpp:30
bool empty() const
Tests for an attribute that either was never set or was set to "".
void add_side(const config &cfg)
Definition: carryover.cpp:158
const std::string & get_save_id() const
Definition: carryover.hpp:42
void append(const config &cfg)
Append data from another config object to this one.
Definition: config.cpp:287
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::vector< carryover > & get_all_sides()
Definition: carryover.cpp:154
boost::ptr_vector< config > wml_menu_items_
Definition: carryover.hpp:103
Variant for storing WML attributes.
const config to_config()
Definition: carryover.cpp:239
bool has_attribute(config_key_type key) const
Definition: config.cpp:213
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
Definition: config.cpp:412
void transfer_all_recalls_to(config &side_cfg)
Definition: carryover.cpp:87
child_itors child_range(config_key_type key)
Definition: config.cpp:362
void remove_attributes(T... keys)
Definition: config.hpp:487
std::string save_id_
Definition: carryover.hpp:57
void merge_old_carryover(const carryover_info &old_carryover)
Definition: carryover.cpp:270
config & child_or_add(config_key_type key)
Definition: config.cpp:466
config variables_
Definition: carryover.hpp:101
void clear()
Definition: config.cpp:863
-file sdl_utils.hpp
void transfer_to(config &level)
Definition: carryover.cpp:210
Definitions for the interface to Wesnoth Markup Language (WML).
std::string get_random_seed_str() const
Definition: mt_rng.cpp:99
std::set< std::string > previous_recruits_
Definition: carryover.hpp:52
int next_underlying_unit_id_
Definition: carryover.hpp:105
void transfer_all_to(config &side_cfg)
Definition: carryover.cpp:184
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
void swap(config &cfg)
Definition: config.cpp:1377
std::vector< config > recall_list_
Definition: carryover.hpp:56
save_id_equals(const std::string &val)
Definition: carryover.cpp:175
config variables_
Definition: carryover.hpp:58
void erase(const std::string &key)
Definition: general.cpp:220
void transfer_all_gold_to(config &side_cfg)
Definition: carryover.cpp:61
std::vector< carryover > carryover_sides_
Definition: carryover.hpp:100
carryover * get_side(const std::string &save_id)
Definition: carryover.cpp:260
#define ERR_NG
Definition: carryover.cpp:25
std::string current_player_
Definition: carryover.hpp:50
std::string next_scenario_
the scenario coming next (for campaigns)
Definition: carryover.hpp:104
unsigned int get_random_calls() const
Definition: mt_rng.hpp:55
const std::string to_string()
Definition: carryover.cpp:104
bool add_
Definition: carryover.hpp:49
std::string get_recruits(bool erase=false)
Definition: carryover.cpp:94
void transfer_all_recruits_to(config &side_cfg)
Definition: carryover.cpp:81
randomness::mt_rng rng_
Definition: carryover.hpp:102
static lg::log_domain log_engine("engine")
config & add_child(config_key_type key)
Definition: config.cpp:476
std::string value
Definition: carryover.cpp:181
double t
Definition: astarsearch.cpp:64
Standard logging facilities (interface).
void remove_side(const std::string &id)
Definition: carryover.cpp:162
recall_list_manager & recall_list()
Definition: team.hpp:215
std::set< std::string > set_split(const std::string &val, const char c=',', const int flags=REMOVE_EMPTY|STRIP_SPACES)
Splits a (comma-)separated string into a set of pieces.
void to_config(config &cfg)
Definition: carryover.cpp:113
static const int default_gold_qty
Definition: carryover.cpp:59
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
mock_char c
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
bool empty() const
Definition: config.cpp:884
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:371