The Battle for Wesnoth  1.15.0-dev
game_state.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 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 "preferences/game.hpp"
27 #include "random_deterministic.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 <SDL_timer.h>
37 
38 #include <algorithm>
39 #include <set>
40 
41 static lg::log_domain log_engine("engine");
42 #define LOG_NG LOG_STREAM(info, log_engine)
43 #define DBG_NG LOG_STREAM(debug, log_engine)
44 
46  gamedata_(level),
47  board_(tdata, level),
48  tod_manager_(level),
49  pathfind_manager_(new pathfind::manager(level)),
50  reports_(new reports()),
51  lua_kernel_(new game_lua_kernel(*this, pc, *reports_)),
52  ai_manager_(),
53  events_manager_(new game_events::manager()),
54  //TODO: this construct units (in dimiss undo action) but resrouces:: are not available yet,
55  // so we might want to move the innitialisation of undo_stack_ to game_state::init
56  undo_stack_(new actions::undo_list(level.child("undo_stack"))),
57  player_number_(level["playing_team"].to_int() + 1),
58  next_player_number_(level["next_player_number"].to_int(player_number_ + 1)),
59  init_side_done_(level["init_side_done"].to_bool(false)),
60  start_event_fired_(!level["playing_team"].empty()),
61  server_request_number_(level["server_request_number"].to_int()),
62  first_human_team_(-1)
63 {
64  lua_kernel_->load_core();
65  if(const config& endlevel_cfg = level.child("end_level_data")) {
66  end_level_data el_data;
67  el_data.read(endlevel_cfg);
68  el_data.transient.carryover_report = false;
69  end_level_data_ = el_data;
70  }
71 }
72 
74  gamedata_(level),
75  board_(board),
76  tod_manager_(level),
77  pathfind_manager_(new pathfind::manager(level)),
78  reports_(new reports()),
79  lua_kernel_(new game_lua_kernel(*this, pc, *reports_)),
80  ai_manager_(),
82  player_number_(level["playing_team"].to_int() + 1),
83  next_player_number_(level["next_player_number"].to_int(player_number_ + 1)),
85  init_side_done_(level["init_side_done"].to_bool(false)),
86  start_event_fired_(!level["playing_team"].empty()),
87  server_request_number_(level["server_request_number"].to_int()),
89 {
90  lua_kernel_->load_core();
91  events_manager_->read_scenario(level);
92  if(const config& endlevel_cfg = level.child("end_level_data")) {
93  end_level_data el_data;
94  el_data.read(endlevel_cfg);
95  el_data.transient.carryover_report = false;
96  end_level_data_ = el_data;
97  }
98 }
99 
100 
102 
103 static int placing_score(const config& side, const gamemap& map, const map_location& pos)
104 {
105  int positions = 0, liked = 0;
106  const t_translation::ter_list terrain = t_translation::read_list(side["terrain_liked"]);
107 
108  for(int i = -8; i != 8; ++i) {
109  for(int j = -8; j != +8; ++j) {
110  const map_location pos2 = pos.plus(i, j);
111  if(map.on_board(pos2)) {
112  ++positions;
113  if(std::count(terrain.begin(),terrain.end(),map[pos2])) {
114  ++liked;
115  }
116  }
117  }
118  }
119 
120  return (100*liked)/positions;
121 }
122 
123 struct placing_info {
124 
126  side(0),
127  score(0),
128  pos()
129  {
130  }
131 
132  int side, score;
134 };
135 
136 static bool operator<(const placing_info& a, const placing_info& b) { return a.score > b.score; }
137 
138 
140 {
141  std::vector<placing_info> placings;
142 
143  int num_pos = board_.map().num_valid_starting_positions();
144 
145  int side_num = 1;
146  for(const config &side : level.child_range("side"))
147  {
148  for(int p = 1; p <= num_pos; ++p) {
149  const map_location& pos = board_.map().starting_position(p);
150  int score = placing_score(side, board_.map(), pos);
151  placing_info obj;
152  obj.side = side_num;
153  obj.score = score;
154  obj.pos = pos;
155  placings.push_back(obj);
156  }
157  ++side_num;
158  }
159 
160  std::stable_sort(placings.begin(),placings.end());
161  std::set<int> placed;
162  std::set<map_location> positions_taken;
163 
164  for (std::vector<placing_info>::const_iterator i = placings.begin(); i != placings.end() && static_cast<int>(placed.size()) != side_num - 1; ++i) {
165  if(placed.count(i->side) == 0 && positions_taken.count(i->pos) == 0) {
166  placed.insert(i->side);
167  positions_taken.insert(i->pos);
168  board_.map_->set_starting_position(i->side,i->pos);
169  LOG_NG << "placing side " << i->side << " at " << i->pos << std::endl;
170  }
171  }
172 }
173 
175 {
176  events_manager_->read_scenario(level);
178  if (level["modify_placing"].to_bool()) {
179  LOG_NG << "modifying placing..." << std::endl;
181  }
182 
183  LOG_NG << "initialized time of day regions... " << (SDL_GetTicks() - pc.ticks()) << std::endl;
184  for (const config &t : level.child_range("time_area")) {
186  }
187 
188  LOG_NG << "initialized teams... " << (SDL_GetTicks() - pc.ticks()) << std::endl;
189 
190  board_.teams_.resize(level.child_count("side"));
191 
192  std::vector<team_builder_ptr> team_builders;
193 
194  int team_num = 0;
195  for (const config &side : level.child_range("side"))
196  {
197  if (first_human_team_ == -1) {
198  const std::string &controller = side["controller"];
199  if (controller == "human" && side["is_local"].to_bool(true)) {
200  first_human_team_ = team_num;
201  }
202  }
203  ++team_num;
205  board_.teams_, level, board_, team_num);
206  build_team_stage_one(tb_ptr);
207  team_builders.push_back(tb_ptr);
208  }
209  //Initialize the lua kernel before the units are created.
210  lua_kernel_->initialize(level);
211 
212  {
213  //sync traits of start units and the random start time.
215 
217 
218  for(team_builder_ptr tb_ptr : team_builders)
219  {
220  build_team_stage_two(tb_ptr);
221  }
222  for(std::size_t i = 0; i < board_.teams_.size(); i++) {
223  // Labels from players in your ignore list default to hidden
224  if(preferences::is_ignored(board_.teams_[i].current_player())) {
225  std::string label_cat = "side:" + std::to_string(i + 1);
226  board_.hidden_label_categories_ref().push_back(label_cat);
227  }
228  }
229  }
230 }
231 
233 {
234  lua_kernel_->set_game_display(gd);
235 }
236 
237 void game_state::write(config& cfg) const
238 {
239  cfg["init_side_done"] = init_side_done_;
240  if(gamedata_.phase() == game_data::PLAY) {
241  cfg["playing_team"] = player_number_ - 1;
242  cfg["next_player_number"] = next_player_number_;
243  }
244  cfg["server_request_number"] = server_request_number_;
245  //Call the lua save_game functions
246  lua_kernel_->save_game(cfg);
247 
248  //Write the game events.
249  events_manager_->write_events(cfg);
250 
251  //Write the map, unit_map, and teams info
252  board_.write_config(cfg);
253 
254  //Write the tod manager, and time areas
256 
257  //write out the current state of the map
258  cfg.merge_with(pathfind_manager_->to_config());
259 
260  //Write the game data, including wml vars
262 
263  // Preserve the undo stack so that fog/shroud clearing is kept accurate.
264  undo_stack_->write(cfg.add_child("undo_stack"));
265 
266  if(end_level_data_.get_ptr() != nullptr) {
267  end_level_data_->write(cfg.add_child("end_level_data"));
268  }
269 }
270 
271 namespace {
272  struct castle_cost_calculator : pathfind::cost_calculator
273  {
274  castle_cost_calculator(const gamemap& map, const team & view_team) :
275  map_(map),
276  viewer_(view_team),
277  use_shroud_(view_team.uses_shroud())
278  {}
279 
280  virtual double cost(const map_location& loc, const double) const
281  {
282  if(!map_.is_castle(loc))
283  return 10000;
284 
285  if ( use_shroud_ && viewer_.shrouded(loc) )
286  return 10000;
287 
288  return 1;
289  }
290 
291  private:
292  const gamemap& map_;
293  const team& viewer_;
294  const bool use_shroud_; // Allows faster checks when shroud is disabled.
295  };
296 }//anonymous namespace
297 
298 
299 /**
300  * Checks to see if a leader at @a leader_loc could recruit somewhere.
301  * This takes into account terrain, shroud (for side @a side), and the presence
302  * of visible units.
303  * The behavior for an invalid @a side is subject to change for future needs.
304  */
305 bool game_state::can_recruit_from(const map_location& leader_loc, int side) const
306 {
307  const gamemap& map = board_.map();
308 
309  if(!map.is_keep(leader_loc)) {
310  return false;
311  }
312 
313  try {
314  return pathfind::find_vacant_tile(leader_loc, pathfind::VACANT_CASTLE, nullptr, &board_.get_team(side))
316  } catch(const std::out_of_range&) {
317  // Invalid side specified.
318  // Currently this cannot happen, but it could conceivably be used in
319  // the future to request that shroud and visibility be ignored. Until
320  // that comes to pass, just return.
321  return false;
322  }
323 }
324 
325 bool game_state::can_recruit_from(const unit& leader) const
326 {
327  return can_recruit_from(leader.get_location(), leader.side());
328 }
329 
330 
331 /**
332  * Checks to see if a leader at @a leader_loc could recruit on @a recruit_loc.
333  * This takes into account terrain, shroud (for side @a side), and whether or
334  * not there is already a visible unit at recruit_loc.
335  * The behavior for an invalid @a side is subject to change for future needs.
336  */
337 bool game_state::can_recruit_on(const map_location& leader_loc, const map_location& recruit_loc, int side) const
338 {
339  const gamemap& map = board_.map();
340 
341  if(!map.is_castle(recruit_loc)) {
342  return false;
343  }
344 
345  if(!map.is_keep(leader_loc)) {
346  return false;
347  }
348 
349  try {
350  const team& view_team = board_.get_team(side);
351 
352  if(view_team.shrouded(recruit_loc)) {
353  return false;
354  }
355 
356  if(board_.has_visible_unit(recruit_loc, view_team)) {
357  return false;
358  }
359 
360  castle_cost_calculator calc(map, view_team);
361 
362  // The limit computed in the third argument is more than enough for
363  // any convex castle on the map. Strictly speaking it could be
364  // reduced to sqrt(map.w()**2 + map.h()**2).
366  pathfind::a_star_search(leader_loc, recruit_loc, map.w() + map.h(), calc, map.w(), map.h());
367 
368  return !rt.steps.empty();
369  } catch(const std::out_of_range&) {
370  // Invalid side specified.
371  // Currently this cannot happen, but it could conceivably be used in
372  // the future to request that shroud and visibility be ignored. Until
373  // that comes to pass, just return.
374  return false;
375  }
376 }
377 
378 bool game_state::can_recruit_on(const unit& leader, const map_location& recruit_loc) const
379 {
380  return can_recruit_on(leader.get_location(), recruit_loc, leader.side());
381 }
382 
384 {
385  unit_map::const_iterator leader = board_.units().find(hex);
386  if ( leader != board_.units().end() ) {
387  return leader->can_recruit() && leader->side() == side && can_recruit_from(*leader);
388  } else {
389  // Look for a leader who can recruit on last_hex.
390  for ( leader = board_.units().begin(); leader != board_.units().end(); ++leader) {
391  if ( leader->can_recruit() && leader->side() == side && can_recruit_on(*leader, hex) ) {
392  return true;
393  }
394  }
395  }
396  // No leader found who can recruit at last_hex.
397  return false;
398 }
399 
401 {
402  return this->events_manager_->wml_menu_items();
403 }
404 
406 {
407  return this->events_manager_->wml_menu_items();
408 }
const std::unique_ptr< reports > reports_
Definition: game_state.hpp:49
void read(const config &cfg)
std::unique_ptr< gamemap > map_
Definition: game_board.hpp:56
bool is_keep(const map_location &loc) const
Definition: map.cpp:70
const std::unique_ptr< actions::undo_list > undo_stack_
undo_stack_ is never nullptr.
Definition: game_state.hpp:56
Game board class.
Definition: game_board.hpp:50
config & child(config_key_type 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:423
int h() const
Effective map height.
Definition: map.hpp:93
unit_iterator end()
Definition: map.hpp:415
void build_team_stage_two(team_builder_ptr tb_ptr)
std::unique_ptr< game_lua_kernel > lua_kernel_
Definition: game_state.hpp:50
ter_list read_list(const std::string &str, const ter_layer filler)
Reads a list of terrains from a string, when reading the.
virtual const unit_map & units() const override
Definition: game_board.hpp:114
ai::manager ai_manager_
Definition: game_state.hpp:51
This class represents a single unit of a specific type.
Definition: unit.hpp:99
bool is_castle(const map_location &loc) const
Definition: map.cpp:68
static help_manager manager
The help manager.
Definition: help.cpp:34
std::vector< std::string > & hidden_label_categories_ref()
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:337
game_events::wmi_manager & get_wml_menu_items()
Definition: game_state.cpp:400
#define a
unsigned child_count(config_key_type key) const
Definition: config.cpp:394
int next_player_number_
Definition: game_state.hpp:58
const randomness::mt_rng & rng() const
Definition: game_data.hpp:65
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:54
int first_human_team_
Definition: game_state.hpp:70
child_itors child_range(config_key_type key)
Definition: config.cpp:366
int server_request_number_
Definition: game_state.hpp:64
static void progress(loading_stage stage=loading_stage::none)
void resolve_random(randomness::rng &r)
handles random_start_time, should be called before the game starts.
Definition: tod_manager.cpp:77
virtual const gamemap & map() const override
Definition: game_board.hpp:109
unit_iterator begin()
Definition: map.hpp:405
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition: map.cpp:367
bool init_side_done_
Definition: game_state.hpp:61
const std::unique_ptr< game_events::manager > events_manager_
Definition: game_state.hpp:52
Unit and team statistics.
#define b
void merge_with(const config &c)
Merge config &#39;c&#39; into this config, overwriting this config&#39;s values.
Definition: config.cpp:1120
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
team & get_team(int i)
Definition: game_board.hpp:104
map_location plus(int x_diff, int y_diff) const
Definition: location.hpp:164
std::vector< map_location > steps
Definition: pathfind.hpp:134
std::vector< team > teams_
Definition: game_board.hpp:53
bool uses_shroud() const
Definition: team.hpp:314
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:305
RAII class to use rng_deterministic in the current scope.
Structure which holds a single route between one location and another.
Definition: pathfind.hpp:131
Encapsulates the map of the game.
Definition: map.hpp:34
tod_manager tod_manager_
Definition: game_state.hpp:47
config to_config() const
int num_valid_starting_positions() const
Definition: map.cpp:326
std::unique_ptr< pathfind::manager > pathfind_manager_
Definition: game_state.hpp:48
bool carryover_report
Should a summary of the scenario outcome be displayed?
static int placing_score(const config &side, const gamemap &map, const map_location &pos)
Definition: game_state.cpp:103
bool has_visible_unit(const map_location &loc, const team &team, bool see_all=false) const
Definition: game_board.cpp:178
bool is_ignored(const std::string &nick)
Definition: game.cpp:306
#define LOG_NG
Definition: game_state.cpp:42
Encapsulates the map of the game.
Definition: location.hpp:42
Domain specific events.
Definition: action_wml.cpp:88
unit_iterator find(std::size_t id)
Definition: map.cpp:311
bool shrouded(const map_location &loc) const
Definition: team.cpp:632
int w() const
Effective map width.
Definition: map.hpp:90
transient_end_level transient
std::size_t i
Definition: function.cpp:933
mock_party p
std::shared_ptr< team_builder > team_builder_ptr
Definition: teambuilder.hpp:23
static bool operator<(const placing_info &a, const placing_info &b)
Definition: game_state.cpp:136
map_location starting_position(int side) const
Definition: map.cpp:321
boost::optional< end_level_data > end_level_data_
Definition: game_state.hpp:60
game_data gamedata_
Definition: game_state.hpp:45
Additional information on the game outcome which can be provided by WML.
game_state(const config &level, play_controller &, const ter_data_cache &tdata)
Definition: game_state.cpp:45
rng * generator
This generator is automatically synced during synced context.
Definition: random.cpp:60
void build_team_stage_one(team_builder_ptr tb_ptr)
void init(const config &level, play_controller &)
Definition: game_state.cpp:174
config & add_child(config_key_type key)
Definition: config.cpp:479
void write_config(config &cfg) const
Definition: game_board.cpp:334
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:383
void set_game_display(game_display *)
Definition: game_state.cpp:232
double t
Definition: astarsearch.cpp:63
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.
const map_location & get_location() const
The current map location this unit is at.
Definition: unit.hpp:1174
game_board board_
Definition: game_state.hpp:46
map_location pos
Definition: game_state.cpp:133
Various functions that implement the undoing (and redoing) of in-game commands.
Standard logging facilities (interface).
std::vector< terrain_code > ter_list
Definition: translation.hpp:77
int player_number_
Definition: game_state.hpp:57
static const map_location & null_location()
Definition: location.hpp:85
static lg::log_domain log_engine("engine")
team_builder_ptr create_team_builder(const config &side_cfg, std::vector< team > &teams, const config &level, game_board &board, int num)
int side() const
The side this unit belongs to.
Definition: unit.hpp:265
void place_sides_in_preferred_locations(const config &level)
Definition: game_state.cpp:139
void write_snapshot(config &cfg) const
Definition: game_data.cpp:126
plain_route a_star_search(const map_location &src, const map_location &dst, double stop_at, const cost_calculator &calc, const std::size_t width, const std::size_t height, const teleport_map *teleports, bool border)
PHASE phase() const
Definition: game_data.hpp:76
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
void write(config &cfg) const
Definition: game_state.cpp:237
This module contains various pathfinding functions and utilities.
bool start_event_fired_
Definition: game_state.hpp:62
std::shared_ptr< terrain_type_data > ter_data_cache