The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
game_board.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 
15 #include "config.hpp"
16 #include "game_board.hpp"
17 #include "game_preferences.hpp"
18 #include "log.hpp"
19 #include "map/map.hpp"
20 #include "recall_list_manager.hpp"
21 #include "terrain/type_data.hpp"
22 #include "units/unit.hpp"
23 
24 #include <set>
25 #include <vector>
26 
27 static lg::log_domain log_engine("enginerefac");
28 #define DBG_RG LOG_STREAM(debug, log_engine)
29 #define LOG_RG LOG_STREAM(info, log_engine)
30 #define WRN_RG LOG_STREAM(warn, log_engine)
31 #define ERR_RG LOG_STREAM(err, log_engine)
32 
33 static lg::log_domain log_engine_enemies("engine/enemies");
34 #define DBG_EE LOG_STREAM(debug, log_engine_enemies)
35 
37  : teams_()
38  , map_(new gamemap(tdata, level))
39  , unit_id_manager_(level["next_underlying_unit_id"])
40  , units_()
41 {
42 }
43 
45  : teams_(other.teams_)
46  , map_(new gamemap(*(other.map_)))
47  , unit_id_manager_(other.unit_id_manager_)
48  , units_(other.units_) {}
49 
51 
52 
53 //TODO: Fix this so that we swap pointers to maps, and also fix replace_map to use scoped_ptr::reset.
54 // However, then anytime gameboard is overwritten, resources::gamemap must be updated. So might want to
55 // just get rid of resources::gamemap and replace with resources::gameboard->map() at that point.
56 void swap(game_board & one, game_board & other) {
57  std::swap(one.teams_, other.teams_);
58  std::swap(one.units_, other.units_);
60  one.map_.swap(other.map_);
61 }
62 
64 {
65  swap(*this, other);
66  return(*this);
67 }
68 
69 void game_board::new_turn(int player_num) {
70  for (unit & i : units_) {
71  if (i.side() == player_num) {
72  i.new_turn();
73  }
74  }
75 }
76 
77 void game_board::end_turn(int player_num) {
78  for (unit & i : units_) {
79  if (i.side() == player_num) {
80  i.end_turn();
81  }
82  }
83 }
84 
86  for (unit & i : units_) {
87  i.set_user_end_turn(true);
88  }
89 }
90 
92  for (unit_map::iterator it = units_.begin(); it != units_.end(); it++) {
93  unit_ptr un = it.get_shared_ptr();
94  if (teams_[un->side() - 1].persistent()) {
95  un->new_turn();
96  un->new_scenario();
97  }
98  }
99 }
100 
101 void game_board::check_victory(bool & continue_level, bool & found_player, bool & found_network_player, bool & cleared_villages, std::set<unsigned> & not_defeated, bool remove_from_carryover_on_defeat)
102 {
103  continue_level = true;
104  found_player = false;
105  found_network_player = false;
106  cleared_villages = false;
107 
108  not_defeated = std::set<unsigned>();
109 
110  for (const unit & i : units())
111  {
112  DBG_EE << "Found a unit: " << i.id() << " on side " << i.side() << std::endl;
113  const team& tm = teams()[i.side()-1];
114  DBG_EE << "That team's defeat condition is: " << tm.defeat_condition() << std::endl;
115  if (i.can_recruit() && tm.defeat_condition() == team::DEFEAT_CONDITION::NO_LEADER) {
116  not_defeated.insert(i.side());
117  } else if (tm.defeat_condition() == team::DEFEAT_CONDITION::NO_UNITS) {
118  not_defeated.insert(i.side());
119  }
120  }
121 
122  for (team& tm : teams_)
123  {
124  if(tm.defeat_condition() == team::DEFEAT_CONDITION::NEVER)
125  {
126  not_defeated.insert(tm.side());
127  }
128  // Clear villages for teams that have no leader and
129  // mark side as lost if it should be removed from carryover.
130  if (not_defeated.find(tm.side()) == not_defeated.end())
131  {
132  tm.clear_villages();
133  // invalidate_all() is overkill and expensive but this code is
134  // run rarely so do it the expensive way.
135  cleared_villages = true;
136 
137  if (remove_from_carryover_on_defeat)
138  {
139  tm.set_lost(true);
140  }
141  }
142  else if(remove_from_carryover_on_defeat)
143  {
144  tm.set_lost(false);
145  }
146  }
147 
148  for (std::set<unsigned>::iterator n = not_defeated.begin(); n != not_defeated.end(); ++n) {
149  size_t side = *n - 1;
150 
151  DBG_EE << "Side " << (side+1) << " is a not-defeated team" << std::endl;
152 
154  for (++m; m != not_defeated.end(); ++m) {
155  if (teams()[side].is_enemy(*m)) {
156  return;
157  }
158  DBG_EE << "Side " << (side+1) << " and " << *m << " are not enemies." << std::endl;
159  }
160 
161  if (teams()[side].is_local_human()) {
162  found_player = true;
163  }
164 
165  if (teams()[side].is_network_human()) {
166  found_network_player = true;
167  }
168  }
169 
170  continue_level = false;
171 }
172 
174  const team& current_team, bool see_all)
175 {
176  if (!map_->on_board(loc)) return units_.end();
177  unit_map::iterator u = units_.find(loc);
178  if (!u.valid() || !u->is_visible_to_team(current_team, *map_, see_all))
179  return units_.end();
180  return u;
181 }
182 
183 bool game_board::has_visible_unit(const map_location & loc, const team& current_team, bool see_all) const
184 {
185  if (!map_->on_board(loc)) return false;
187  if (!u.valid() || !u->is_visible_to_team(current_team, *map_, see_all))
188  return false;
189  return true;
190 }
191 
193  const team &current_team, bool see_all)
194 {
195  unit_map::iterator ui = find_visible_unit(loc, current_team, see_all);
196  if (ui == units_.end()) return nullptr;
197  return &*ui;
198 }
199 
200 void game_board::side_drop_to(int side_num, team::CONTROLLER ctrl, team::PROXY_CONTROLLER proxy) {
201  team &tm = teams_[side_num-1];
202 
203  tm.change_controller(ctrl);
204  tm.change_proxy(proxy);
205  tm.set_local(true);
206 
207  tm.set_current_player(ctrl.to_string() + std::to_string(side_num));
208 
209  unit_map::iterator leader = units_.find_leader(side_num);
210  if (leader.valid()) leader->rename(ctrl.to_string() + std::to_string(side_num));
211 }
212 
213 void game_board::side_change_controller(int side_num, bool is_local, const std::string& pname) {
214  team &tm = teams_[side_num-1];
215 
216  tm.set_local(is_local);
217 
218  if (pname.empty() || !tm.is_human()) {
219  return;
220  }
221 
222  tm.set_current_player(pname);
223 
224  unit_map::iterator leader = units_.find_leader(side_num);
225  if (leader.valid()) {
226  leader->rename(pname);
227  }
228 }
229 
231 {
232  switch(t.defeat_condition().v)
233  {
234  case team::DEFEAT_CONDITION::ALWAYS:
235  return true;
236  case team::DEFEAT_CONDITION::NO_LEADER:
237  return !units_.find_leader(t.side()).valid();
238  case team::DEFEAT_CONDITION::NO_UNITS:
239  for (const unit& u : units_)
240  {
241  if(u.side() == t.side())
242  return false;
243  }
244  return true;
245  case team::DEFEAT_CONDITION::NEVER:
246  default:
247  return false;
248  }
249 }
250 
252 {
253  teams_[u->side()-1].recall_list().add(u);
254  return true;
255 }
256 
257 
258 boost::optional<std::string> game_board::replace_map(const gamemap & newmap) {
259  boost::optional<std::string> ret = boost::optional<std::string> ();
260 
261  /* Remember the locations where a village is owned by a side. */
262  std::map<map_location, int> villages;
263  for(const auto& village : map_->villages()) {
264  const int owner = village_owner(village);
265  if(owner != -1) {
266  villages[village] = owner;
267  }
268  }
269 
270  for (unit_map::iterator itor = units_.begin(); itor != units_.end(); ) {
271  if (!newmap.on_board(itor->get_location())) {
272  if (!try_add_unit_to_recall_list(itor->get_location(), itor.get_shared_ptr())) {
273  *ret = std::string("replace_map: Cannot add a unit that would become off-map to the recall list\n");
274  }
275  units_.erase(itor++);
276  } else {
277  ++itor;
278  }
279  }
280 
281  /* Disown villages that are no longer villages. */
282  for(const auto& village : villages) {
283  if(!newmap.is_village(village.first)) {
284  teams_[village.second].lose_village(village.first);
285  }
286  }
287 
288  *map_ = newmap;
289  return ret;
290 }
291 
292 
293 
294 void game_board::overlay_map(const gamemap & mask_map, const config & cfg, map_location loc, bool border) {
295  map_->overlay(mask_map, cfg, loc.x, loc.y, border);
296 }
297 
299  const std::string & mode_str, bool replace_if_failed)
300 {
301  //Code internalized from the implementation in lua.cpp
303  if (terrain == t_translation::NONE_TERRAIN) return false;
304 
306 
307  if (mode_str == "base") mode = terrain_type_data::BASE;
308  else if (mode_str == "overlay") mode = terrain_type_data::OVERLAY;
309 
310  /*
311  * When a hex changes from a village terrain to a non-village terrain, and
312  * a team owned that village it loses that village. When a hex changes from
313  * a non-village terrain to a village terrain and there is a unit on that
314  * hex it does not automatically capture the village. The reason for not
315  * capturing villages it that there are too many choices to make; should a
316  * unit loose its movement points, should capture events be fired. It is
317  * easier to do this as wanted by the author in WML.
318  */
319 
321  old_t = map_->get_terrain(loc),
322  new_t = map_->tdata()->merge_terrains(old_t, terrain, mode, replace_if_failed);
323  if (new_t == t_translation::NONE_TERRAIN) return false;
324  preferences::encountered_terrains().insert(new_t);
325 
326  if (map_->tdata()->is_village(old_t) && !map_->tdata()->is_village(new_t)) {
327  int owner = village_owner(loc);
328  if (owner != -1)
329  teams_[owner].lose_village(loc);
330  }
331 
332  map_->set_terrain(loc, new_t);
333 
334  for(const t_translation::t_terrain &ut : map_->underlying_union_terrain(loc)) {
336  }
337  return true;
338 }
339 
341 {
342  cfg["next_underlying_unit_id"] = unit_id_manager_.get_save_id();
343  for(std::vector<team>::const_iterator t = teams_.begin(); t != teams_.end(); ++t) {
344  int side_num = t - teams_.begin() + 1;
345 
346  config& side = cfg.add_child("side");
347  t->write(side);
348  side["no_leader"] = true;
349  side["side"] = std::to_string(side_num);
350 
351  //current units
352  {
353  for (const unit & i : units_) {
354  if (i.side() == side_num) {
355  config& u = side.add_child("unit");
356  i.get_location().write(u);
357  i.write(u);
358  }
359  }
360  }
361  //recall list
362  {
363  for (const unit_const_ptr & j : t->recall_list()) {
364  config& u = side.add_child("unit");
365  j->write(u);
366  }
367  }
368  }
369 
370  //write the map
371  cfg["map_data"] = map_->write();
372 }
373 
375  : m_(m), loc_(loc), temp_(m_.extract(loc))
376 {
377  u.clone();
378  m_.add(loc, u);
379 }
380 
382  : m_(b.units_), loc_(loc), temp_(m_.extract(loc))
383 {
384  u.clone();
385  m_.add(loc, u);
386 }
387 
389 {
390  try {
391  m_.erase(loc_);
392  if(temp_) {
393  m_.insert(temp_);
394  }
395  } catch (...) {}
396 }
397 
399  : m_(m), loc_(loc), temp_(m_.extract(loc))
400 {
401 }
402 
404  : m_(b.units_), loc_(loc), temp_(m_.extract(loc))
405 {
406 }
407 
409 {
410  try {
411  if(temp_) {
412  m_.insert(temp_);
413  }
414  } catch (...) {}
415 }
416 
417 /**
418  * Constructor
419  * This version will change the unit's current movement to @a new_moves while
420  * the unit is moved (and restored to its previous value upon this object's
421  * destruction).
422  */
424  const map_location& dst, int new_moves)
425  : m_(m), src_(src), dst_(dst), old_moves_(-1),
426  temp_(src == dst ? unit_ptr() : m_.extract(dst))
427 {
428  std::pair<unit_map::iterator, bool> move_result = m_.move(src_, dst_);
429 
430  // Set the movement.
431  if ( move_result.second )
432  {
433  old_moves_ = move_result.first->movement_left(true);
434  move_result.first->set_movement(new_moves);
435  }
436 }
437 
439  const map_location& dst, int new_moves)
440  : m_(b.units_), src_(src), dst_(dst), old_moves_(-1),
441  temp_(src == dst ? unit_ptr() : m_.extract(dst))
442 {
443  std::pair<unit_map::iterator, bool> move_result = m_.move(src_, dst_);
444 
445  // Set the movement.
446  if ( move_result.second )
447  {
448  old_moves_ = move_result.first->movement_left(true);
449  move_result.first->set_movement(new_moves);
450  }
451 }
452 
453 /**
454  * Constructor
455  * This version does not change (nor restore) the unit's movement.
456  */
458  const map_location& dst)
459  : m_(m), src_(src), dst_(dst), old_moves_(-1),
460  temp_(src == dst ? unit_ptr() : m_.extract(dst))
461 {
462  m_.move(src_, dst_);
463 }
464 
466  const map_location& dst)
467  : m_(b.units_), src_(src), dst_(dst), old_moves_(-1),
468  temp_(src == dst ? unit_ptr() : m_.extract(dst))
469 {
470  m_.move(src_, dst_);
471 }
472 
474 {
475  try {
476  std::pair<unit_map::iterator, bool> move_result = m_.move(dst_, src_);
477 
478  // Restore the movement?
479  if ( move_result.second && old_moves_ >= 0 )
480  move_result.first->set_movement(old_moves_);
481 
482  // Restore the extracted unit?
483  if(temp_) {
484  m_.insert(temp_);
485  }
486  } catch (...) {}
487 }
488 
void set_all_units_user_end_turn()
Definition: game_board.cpp:85
Game board class.
Definition: game_board.hpp:55
virtual const unit_map & units() const
Definition: game_board.hpp:99
unit_iterator end()
Definition: map.hpp:311
void heal_all_survivors()
Definition: game_board.cpp:91
Definition: unit.hpp:95
n_unit::id_manager unit_id_manager_
Definition: game_board.hpp:62
GLint level
Definition: glew.h:1220
void write_config(config &cfg) const
Definition: game_board.cpp:340
size_t get_save_id() const
Used for saving id to savegame.
Definition: id.cpp:44
unit_iterator find_leader(int side)
Definition: map.cpp:297
variant map_
Definition: formula.cpp:306
#define DBG_EE
Definition: game_board.cpp:34
const t_terrain NONE_TERRAIN
Definition: translation.hpp:56
bool is_village(const map_location &loc) const
Definition: map.cpp:68
const map_location src_
Definition: game_board.hpp:215
boost::scoped_ptr< gamemap > map_
Definition: game_board.hpp:61
unit_iterator begin()
Definition: map.hpp:308
void overlay_map(const gamemap &o, const config &cfg, map_location loc, bool border)
Definition: game_board.cpp:294
int village_owner(const map_location &loc) const
Given the location of a village, will return the 0-based index of the team that currently owns it...
virtual const std::vector< team > & teams() const
Definition: game_board.hpp:97
DEFEAT_CONDITION defeat_condition() const
Definition: team.hpp:339
GLenum src
Definition: glew.h:2392
void change_controller(const std::string &new_controller)
Definition: team.hpp:275
GLenum mode
Definition: glew.h:2390
GLdouble GLdouble t
Definition: glew.h:1366
void set_current_player(const std::string &player)
Definition: team.hpp:222
Definitions for the interface to Wesnoth Markup Language (WML).
t_terrain read_terrain_code(const std::string &str, const t_layer filler)
Reads a single terrain from a string.
bool team_is_defeated(const team &t) const
Calculates whether a team is defeated.
Definition: game_board.cpp:230
virtual ~game_board()
Definition: game_board.cpp:50
map_location loc_
GLdouble GLdouble GLdouble b
Definition: glew.h:6966
unit_map units_
Definition: game_board.hpp:63
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:50
static lg::log_domain log_engine_enemies("engine/enemies")
bool is_human() const
Definition: team.hpp:264
virtual ~temporary_unit_remover()
Definition: game_board.cpp:408
game_board & operator=(game_board other)
Definition: game_board.cpp:63
std::vector< team > teams_
Definition: game_board.hpp:58
temporary_unit_remover(unit_map &m, const map_location &loc)
Definition: game_board.cpp:398
unit * get_visible_unit(const map_location &loc, const team &current_team, bool see_all=false)
Definition: game_board.cpp:192
std::pair< unit_iterator, bool > insert(unit_ptr p)
Adds the unit to the map.
Definition: map.cpp:126
void side_drop_to(int side_num, team::CONTROLLER ctrl, team::PROXY_CONTROLLER proxy=team::PROXY_CONTROLLER::PROXY_HUMAN)
Definition: game_board.cpp:200
friend void swap(game_board &one, game_board &other)
Definition: game_board.cpp:56
void set_local(bool local)
Definition: team.hpp:272
GLenum GLenum dst
Definition: glew.h:2392
std::set< t_translation::t_terrain > & encountered_terrains()
Encapsulates the map of the game.
Definition: map.hpp:37
config & add_child(const std::string &key)
Definition: config.cpp:743
void check_victory(bool &, bool &, bool &, bool &, std::set< unsigned > &, bool)
Definition: game_board.cpp:101
virtual ~temporary_unit_mover()
Definition: game_board.cpp:473
static const ::config * terrain
The terrain used to create the cache.
Definition: minimap.cpp:135
std::pair< unit_iterator, bool > add(const map_location &l, const unit &u)
Adds a copy of unit u at location l of the map.
Definition: map.cpp:70
temporary_unit_placer(unit_map &m, const map_location &loc, unit &u)
Definition: game_board.cpp:374
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:47
Encapsulates the map of the game.
Definition: location.hpp:38
void end_turn(int pnum)
Definition: game_board.cpp:77
virtual ~temporary_unit_placer()
Definition: game_board.cpp:388
bool has_visible_unit(const map_location &loc, const team &team, bool see_all=false) const
Definition: game_board.cpp:183
unit & clone(bool is_temporary=true)
Mark this unit as clone so it can be inserted to unit_map.
Definition: unit.cpp:2368
std::map< std::string, tfilter >::iterator itor
Definition: filter.cpp:199
void change_proxy(PROXY_CONTROLLER proxy)
Definition: team.hpp:292
size_t i
Definition: function.cpp:1057
bool change_terrain(const map_location &loc, const std::string &t, const std::string &mode, bool replace_if_failed)
Definition: game_board.cpp:298
int side() const
Definition: team.hpp:193
boost::shared_ptr< std::vector< unit_const_ptr > > units_
Definition: dialogs.cpp:100
std::pair< unit_iterator, bool > move(const map_location &src, const map_location &dst)
Moves a unit from location src to location dst.
Definition: map.cpp:79
game_board(const tdata_cache &tdata, const config &level)
Definition: game_board.cpp:36
size_t erase(const map_location &l)
Erases the unit at location l, if any.
Definition: map.cpp:277
GLint GLint GLsizei GLsizei GLsizei GLint border
Definition: glew.h:1222
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition: map.cpp:467
temporary_unit_mover(unit_map &m, const map_location &src, const map_location &dst, int new_moves)
Constructor This version will change the unit's current movement to new_moves while the unit is moved...
Definition: game_board.cpp:423
boost::optional< std::string > replace_map(const gamemap &r)
Definition: game_board.cpp:258
GLclampd n
Definition: glew.h:5903
const GLdouble * m
Definition: glew.h:6968
GLenum pname
Definition: glew.h:1656
void swap(game_board &one, game_board &other)
Definition: game_board.cpp:56
const map_location dst_
Definition: game_board.hpp:216
Standard logging facilities (interface).
Container associating units to locations.
Definition: map.hpp:90
void new_turn(int pnum)
Definition: game_board.cpp:69
const map_location loc_
Definition: game_board.hpp:170
unit_iterator find(size_t id)
Definition: map.cpp:285
bool valid() const
Definition: map.hpp:229
static lg::log_domain log_engine("enginerefac")
bool try_add_unit_to_recall_list(const map_location &loc, const unit_ptr u)
Definition: game_board.cpp:251
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
GLsizei const GLcharARB ** string
Definition: glew.h:4503
unit_map::iterator find_visible_unit(const map_location &loc, const team &current_team, bool see_all=false)
Definition: game_board.cpp:173
void side_change_controller(int side_num, bool is_local, const std::string &pname="")
Definition: game_board.cpp:213
const std::string valid
Little parts of regex templates used to parse Wml annoations.