The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
game_state.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 "game_state.hpp"
16 
17 #include "actions/undo.hpp"
18 #include "game_board.hpp"
19 #include "game_data.hpp"
20 #include "game_events/manager.hpp"
21 #include "log.hpp"
22 #include "map/map.hpp"
23 #include "pathfind/pathfind.hpp"
24 #include "pathfind/teleport.hpp"
25 #include "play_controller.hpp"
26 #include "game_preferences.hpp"
28 #include "reports.hpp"
30 #include "teambuilder.hpp"
31 #include "units/unit.hpp"
32 #include "whiteboard/manager.hpp"
34 
35 #include "utils/functional.hpp"
36 #include <boost/make_shared.hpp>
37 #include <boost/shared_ptr.hpp>
38 #include <SDL_timer.h>
39 
40 #include <algorithm>
41 #include <set>
42 
43 static lg::log_domain log_engine("engine");
44 #define LOG_NG LOG_STREAM(info, log_engine)
45 #define DBG_NG LOG_STREAM(debug, log_engine)
46 
48  gamedata_(level),
49  board_(tdata, level),
50  tod_manager_(level),
51  pathfind_manager_(),
52  reports_(new reports()),
53  lua_kernel_(),
54  events_manager_(new game_events::manager()),
55  undo_stack_(new actions::undo_list(level.child("undo_stack"))),
56  player_number_(level["playing_team"].to_int() + 1),
57  init_side_done_(level["init_side_done"].to_bool(false)),
58  start_event_fired_(!level["playing_team"].empty()),
59  server_request_number_(level["server_request_number"].to_int()),
60  first_human_team_(-1)
61 {
62  if(const config& endlevel_cfg = level.child("end_level_data")) {
63  end_level_data el_data;
64  el_data.read(endlevel_cfg);
65  el_data.transient.carryover_report = false;
66  end_level_data_ = el_data;
67  }
68 }
70  gamedata_(level),
71  board_(board),
72  tod_manager_(level),
73  pathfind_manager_(new pathfind::manager(level)),
74  reports_(new reports()),
75  lua_kernel_(new game_lua_kernel(nullptr, *this, pc, *reports_)),
76  events_manager_(new game_events::manager()),
77  player_number_(level["playing_team"].to_int() + 1),
78  end_level_data_(),
79  init_side_done_(level["init_side_done"].to_bool(false)),
80  first_human_team_(-1)
81 {
82  events_manager_->read_scenario(level);
83  if(const config& endlevel_cfg = level.child("end_level_data")) {
84  end_level_data el_data;
85  el_data.read(endlevel_cfg);
86  el_data.transient.carryover_report = false;
87  end_level_data_ = el_data;
88  }
89 }
90 
91 
93 
94 static int placing_score(const config& side, const gamemap& map, const map_location& pos)
95 {
96  int positions = 0, liked = 0;
97  const t_translation::t_list terrain = t_translation::read_list(side["terrain_liked"]);
98 
99  for(int i = pos.x-8; i != pos.x+8; ++i) {
100  for(int j = pos.y-8; j != pos.y+8; ++j) {
101  const map_location pos(i,j);
102  if(map.on_board(pos)) {
103  ++positions;
104  if(std::count(terrain.begin(),terrain.end(),map[pos])) {
105  ++liked;
106  }
107  }
108  }
109  }
110 
111  return (100*liked)/positions;
112 }
113 
114 struct placing_info {
115 
117  side(0),
118  score(0),
119  pos()
120  {
121  }
122 
123  int side, score;
125 };
126 
127 static bool operator<(const placing_info& a, const placing_info& b) { return a.score > b.score; }
128 
129 
131 {
132  std::vector<placing_info> placings;
133 
134  int num_pos = board_.map().num_valid_starting_positions();
135 
136  int side_num = 1;
137  for(const config &side : level.child_range("side"))
138  {
139  for(int p = 1; p <= num_pos; ++p) {
141  int score = placing_score(side, board_.map(), pos);
143  obj.side = side_num;
144  obj.score = score;
145  obj.pos = pos;
146  placings.push_back(obj);
147  }
148  ++side_num;
149  }
150 
151  std::stable_sort(placings.begin(),placings.end());
152  std::set<int> placed;
153  std::set<map_location> positions_taken;
154 
155  for (std::vector<placing_info>::const_iterator i = placings.begin(); i != placings.end() && int(placed.size()) != side_num - 1; ++i) {
156  if(placed.count(i->side) == 0 && positions_taken.count(i->pos) == 0) {
157  placed.insert(i->side);
158  positions_taken.insert(i->pos);
159  board_.map_->set_starting_position(i->side,i->pos);
160  LOG_NG << "placing side " << i->side << " at " << i->pos << std::endl;
161  }
162  }
163 }
164 
166 {
167  events_manager_->read_scenario(level);
168  gui2::tloadscreen::progress("init teams");
169  if (level["modify_placing"].to_bool()) {
170  LOG_NG << "modifying placing..." << std::endl;
172  }
173 
174  LOG_NG << "initialized time of day regions... " << (SDL_GetTicks() - pc.ticks()) << std::endl;
175  for (const config &t : level.child_range("time_area")) {
177  }
178 
179  LOG_NG << "initialized teams... " << (SDL_GetTicks() - pc.ticks()) << std::endl;
180 
181  board_.teams_.resize(level.child_count("side"));
182 
183  std::vector<team_builder_ptr> team_builders;
184 
185  int team_num = 0;
186  for (const config &side : level.child_range("side"))
187  {
188  if (first_human_team_ == -1) {
189  const std::string &controller = side["controller"];
190  if (controller == "human") {
191  first_human_team_ = team_num;
192  }
193  }
195  board_.teams_, level, board_);
196  ++team_num;
197  build_team_stage_one(tb_ptr);
198  team_builders.push_back(tb_ptr);
199  }
200  {
201  //sync traits of start units and the random start time.
203 
205 
206  for(team_builder_ptr tb_ptr : team_builders)
207  {
208  build_team_stage_two(tb_ptr);
209  }
210  for(size_t i = 0; i < board_.teams_.size(); i++) {
211  // Labels from players in your ignore list default to hidden
212  if(preferences::is_ignored(board_.teams_[i].current_player())) {
213  std::string label_cat = "side:" + std::to_string(i + 1);
214  board_.hidden_label_categories_ref().push_back(label_cat);
215  }
216  }
217  }
218 
219  pathfind_manager_.reset(new pathfind::manager(level));
220 
221  lua_kernel_.reset(new game_lua_kernel(nullptr, *this, pc, *reports_));
222 }
223 
225 {
226  lua_kernel_->set_game_display(gd);
227 }
228 
229 void game_state::write(config& cfg) const
230 {
231  cfg["init_side_done"] = init_side_done_;
232  if(gamedata_.phase() == game_data::PLAY) {
233  cfg["playing_team"] = player_number_ - 1;
234  }
235  cfg["server_request_number"] = server_request_number_;
236  //Call the lua save_game functions
237  lua_kernel_->save_game(cfg);
238 
239  //Write the game events.
240  events_manager_->write_events(cfg);
241 
242  //Write the map, unit_map, and teams info
243  board_.write_config(cfg);
244 
245  //Write the tod manager, and time areas
247 
248  //write out the current state of the map
249  cfg.merge_with(pathfind_manager_->to_config());
250 
251  //Write the game data, including wml vars
253 
254  // Preserve the undo stack so that fog/shroud clearing is kept accurate.
255  undo_stack_->write(cfg.add_child("undo_stack"));
256 
257  if(end_level_data_.get_ptr() != nullptr) {
258  end_level_data_->write(cfg.add_child("end_level_data"));
259  }
260 }
261 
262 namespace {
263  struct castle_cost_calculator : pathfind::cost_calculator
264  {
265  castle_cost_calculator(const gamemap& map, const team & view_team) :
266  map_(map),
267  viewer_(view_team),
268  use_shroud_(view_team.uses_shroud())
269  {}
270 
271  virtual double cost(const map_location& loc, const double) const
272  {
273  if(!map_.is_castle(loc))
274  return 10000;
275 
276  if ( use_shroud_ && viewer_.shrouded(loc) )
277  return 10000;
278 
279  return 1;
280  }
281 
282  private:
283  const gamemap& map_;
284  const team& viewer_;
285  const bool use_shroud_; // Allows faster checks when shroud is disabled.
286  };
287 }//anonymous namespace
288 
289 
290 /**
291  * Checks to see if a leader at @a leader_loc could recruit somewhere.
292  * This takes into account terrain, shroud (for side @a side), and the presence
293  * of visible units.
294  * The behavior for an invalid @a side is subject to change for future needs.
295  */
296 bool game_state::can_recruit_from(const map_location& leader_loc, int side) const
297 {
298  const gamemap& map = board_.map();
299 
300  if( !map.is_keep(leader_loc) )
301  return false;
302 
303  if ( side < 1 || board_.teams().size() < static_cast<size_t>(side) ) {
304  // Invalid side specified.
305  // Currently this cannot happen, but it could conceivably be used in
306  // the future to request that shroud and visibility be ignored. Until
307  // that comes to pass, just return.
308  return false;
309  }
310 
311  return pathfind::find_vacant_tile(leader_loc, pathfind::VACANT_CASTLE, nullptr,
312  &(board_.teams())[side-1])
314 }
315 
316 bool game_state::can_recruit_from(const unit& leader) const
317 {
318  return can_recruit_from(leader.get_location(), leader.side());
319 }
320 
321 
322 /**
323  * Checks to see if a leader at @a leader_loc could recruit on @a recruit_loc.
324  * This takes into account terrain, shroud (for side @a side), and whether or
325  * not there is already a visible unit at recruit_loc.
326  * The behavior for an invalid @a side is subject to change for future needs.
327  */
328 bool game_state::can_recruit_on(const map_location& leader_loc, const map_location& recruit_loc, int side) const
329 {
330  const gamemap& map = board_.map();
331 
332  if( !map.is_castle(recruit_loc) )
333  return false;
334 
335  if( !map.is_keep(leader_loc) )
336  return false;
337 
338  if ( side < 1 || board_.teams().size() < static_cast<size_t>(side) ) {
339  // Invalid side specified.
340  // Currently this cannot happen, but it could conceivably be used in
341  // the future to request that shroud and visibility be ignored. Until
342  // that comes to pass, just return.
343  return false;
344  }
345  const team & view_team = board_.teams()[side-1];
346 
347  if ( view_team.shrouded(recruit_loc) )
348  return false;
349 
350  if ( board_.has_visible_unit(recruit_loc, view_team) )
351  return false;
352 
353  castle_cost_calculator calc(map, view_team);
354  // The limit computed in the third argument is more than enough for
355  // any convex castle on the map. Strictly speaking it could be
356  // reduced to sqrt(map.w()**2 + map.h()**2).
358  pathfind::a_star_search(leader_loc, recruit_loc, map.w()+map.h(), &calc,
359  map.w(), map.h());
360  return !rt.steps.empty();
361 }
362 
363 bool game_state::can_recruit_on(const unit& leader, const map_location& recruit_loc) const
364 {
365  return can_recruit_on(leader.get_location(), recruit_loc, leader.side());
366 }
367 
369 {
370  unit_map::const_iterator leader = board_.units().find(hex);
371  if ( leader != board_.units().end() ) {
372  return leader->can_recruit() && leader->side() == side && can_recruit_from(*leader);
373  } else {
374  // Look for a leader who can recruit on last_hex.
375  for ( leader = board_.units().begin(); leader != board_.units().end(); ++leader) {
376  if ( leader->can_recruit() && leader->side() == side && can_recruit_on(*leader, hex) ) {
377  return true;
378  }
379  }
380  }
381  // No leader found who can recruit at last_hex.
382  return false;
383 }
384 
386 {
387  return this->events_manager_->wml_menu_items_;
388 }
389 
391 {
392  return this->events_manager_->wml_menu_items_;
393 }
void read(const config &cfg)
child_itors child_range(const std::string &key)
Definition: config.cpp:613
Game board class.
Definition: game_board.hpp:55
plain_route a_star_search(const map_location &src, const map_location &dst, double stop_at, const cost_calculator *calc, const size_t width, const size_t height, const teleport_map *teleports, bool border)
PHASE phase() const
Definition: game_data.hpp:78
virtual const unit_map & units() const
Definition: game_board.hpp:99
unit_iterator end()
Definition: map.hpp:311
int ticks() const
const map_location & get_location() const
Definition: unit.hpp:286
void build_team_stage_two(team_builder_ptr tb_ptr)
const rand_rng::mt_rng & rng() const
Definition: game_data.hpp:67
Definition: unit.hpp:95
t_list read_list(const std::string &str, const t_layer filler)
Reads a list of terrains from a string, when reading the.
GLint level
Definition: glew.h:1220
bool shrouded(const map_location &loc) const
Definition: team.cpp:567
void write_config(config &cfg) const
Definition: game_board.cpp:340
int pos
Definition: formula.cpp:800
std::vector< std::string > & hidden_label_categories_ref()
rng * generator
This generator is automatically synced during synced context.
Definition: random_new.cpp:52
variant map_
Definition: formula.cpp:306
map_location find_vacant_tile(const map_location &loc, VACANT_TILE_TYPE vacancy, const unit *pass_check, const team *shroud_check, const game_board *board)
Function that will find a location on the board that is as near to loc as possible, but which is unoccupied by any units.
Definition: pathfind.cpp:56
int first_human_team_
Definition: game_state.hpp:72
int server_request_number_
Definition: game_state.hpp:66
boost::scoped_ptr< gamemap > map_
Definition: game_board.hpp:61
bool can_recruit_on(const map_location &leader_loc, const map_location &recruit_loc, int side) const
Checks to see if a leader at leader_loc could recruit on recruit_loc.
Definition: game_state.cpp:328
unit_iterator begin()
Definition: map.hpp:308
boost::scoped_ptr< pathfind::manager > pathfind_manager_
Definition: game_state.hpp:51
virtual const std::vector< team > & teams() const
Definition: game_board.hpp:97
int side() const
Definition: unit.hpp:201
GLdouble GLdouble t
Definition: glew.h:1366
game_state(const config &level, play_controller &, const tdata_cache &tdata)
Definition: game_state.cpp:47
bool init_side_done_
Definition: game_state.hpp:63
RAII class to use rng_deterministic in the current scope.
Unit and team statistics.
config to_config() const
boost::scoped_ptr< game_lua_kernel > lua_kernel_
Definition: game_state.hpp:53
GLdouble GLdouble GLdouble b
Definition: glew.h:6966
void merge_with(const config &c)
Merge config 'c' into this config, overwriting this config's values.
Definition: config.cpp:1350
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:50
std::vector< map_location > steps
Definition: pathfind.hpp:135
bool side_can_recruit_on(int side, map_location loc) const
Checks if any of the sides leaders can recruit at a location.
Definition: game_state.cpp:368
map_location starting_position(int side) const
Definition: map.cpp:421
std::vector< team > teams_
Definition: game_board.hpp:58
Structure which holds a single route between one location and another.
Definition: pathfind.hpp:132
boost::scoped_ptr< game_events::manager > events_manager_
Definition: game_state.hpp:54
void write_snapshot(config &cfg) const
Definition: game_data.cpp:134
int w() const
Effective map width.
Definition: map.hpp:105
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:7319
Encapsulates the map of the game.
Definition: map.hpp:37
config & add_child(const std::string &key)
Definition: config.cpp:743
GLhandleARB obj
Definition: glew.h:4486
tod_manager tod_manager_
Definition: game_state.hpp:50
boost::scoped_ptr< actions::undo_list > undo_stack_
undo_stack_ is never nullptr.
Definition: game_state.hpp:58
bool carryover_report
Should a summary of the scenario outcome be displayed?
static const map_location & null_location()
Definition: location.hpp:195
GLfloat GLfloat p
Definition: glew.h:12766
static const ::config * terrain
The terrain used to create the cache.
Definition: minimap.cpp:135
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
static int placing_score(const config &side, const gamemap &map, const map_location &pos)
Definition: game_state.cpp:94
GLuint GLuint GLsizei count
Definition: glew.h:1221
bool is_ignored(const std::string &nick)
#define LOG_NG
Definition: game_state.cpp:44
Encapsulates the map of the game.
Definition: location.hpp:38
Domain specific events.
Definition: action_wml.cpp:93
static void progress(const char *stage_name=nullptr)
Definition: loadscreen.cpp:128
transient_end_level transient
bool has_visible_unit(const map_location &loc, const team &team, bool see_all=false) const
Definition: game_board.cpp:183
void write(config &cfg) const
Definition: game_state.cpp:229
int h() const
Effective map height.
Definition: map.hpp:108
A container of wml_menu_item.
t_possible_end_level_data end_level_data_
Definition: game_state.hpp:62
static bool operator<(const placing_info &a, const placing_info &b)
Definition: game_state.cpp:127
size_t i
Definition: function.cpp:1057
bool can_recruit_from(const map_location &leader_loc, int side) const
Checks to see if a leader at leader_loc could recruit somewhere.
Definition: game_state.cpp:296
game_data gamedata_
Definition: game_state.hpp:48
Additional information on the game outcome which can be provided by WML.
bool is_castle(const map_location &loc) const
Definition: map.cpp:72
void build_team_stage_one(team_builder_ptr tb_ptr)
void init(const config &level, play_controller &)
Definition: game_state.cpp:165
unsigned child_count(const std::string &key) const
Definition: config.cpp:635
team_builder_ptr create_team_builder(const config &side_cfg, std::vector< team > &teams, const config &level, game_board &board)
virtual const gamemap & map() const
Definition: game_board.hpp:98
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition: map.cpp:467
void set_game_display(game_display *)
Definition: game_state.cpp:224
virtual double cost(const map_location &loc, const double so_far) const =0
void add_time_area(const gamemap &map, const config &cfg)
Adds a new local time area from config, making it follow its own time-of-day sequence.
config & child(const std::string &key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:658
game_board board_
Definition: game_state.hpp:49
int num_valid_starting_positions() const
Definition: map.cpp:426
map_location pos
Definition: game_state.cpp:124
Various functions that implement the undoing (and redoing) of in-game commands.
Standard logging facilities (interface).
int player_number_
Definition: game_state.hpp:59
static lg::log_domain log_engine("engine")
void place_sides_in_preferred_locations(const config &level)
Definition: game_state.cpp:130
void resolve_random(random_new::rng &r)
handles random_start_time, should be called before the game starts.
Definition: tod_manager.cpp:86
unit_iterator find(size_t id)
Definition: map.cpp:285
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
This module contains various pathfinding functions and utilities.
GLsizei const GLcharARB ** string
Definition: glew.h:4503
boost::scoped_ptr< reports > reports_
Definition: game_state.hpp:52
bool is_keep(const map_location &loc) const
Definition: map.cpp:74
std::vector< t_terrain > t_list
Definition: translation.hpp:75
game_events::wmi_container & get_wml_menu_items()
Definition: game_state.cpp:385