The Battle for Wesnoth  1.15.0-dev
synced_commands.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 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 #include "synced_commands.hpp"
15 #include <cassert>
16 
17 #include "log.hpp"
18 #include "map/location.hpp"
19 #include "game_data.hpp"
20 #include "units/unit.hpp"
21 #include "team.hpp"
22 #include "play_controller.hpp"
23 #include "actions/create.hpp"
24 #include "actions/advancement.hpp"
25 #include "actions/attack.hpp"
26 #include "actions/move.hpp"
27 #include "actions/undo.hpp"
28 #include "preferences/general.hpp"
29 #include "preferences/game.hpp"
30 #include "game_events/pump.hpp"
31 #include "map/map.hpp"
32 #include "units/helper.hpp"
33 #include "recall_list_manager.hpp"
34 #include "resources.hpp"
35 #include "savegame.hpp"
37 #include "formula/string_utils.hpp"
38 #include "units/types.hpp"
39 #include "units/udisplay.hpp"
40 #include "whiteboard/manager.hpp"
41 #include "font/standard_colors.hpp"
42 
43 static lg::log_domain log_replay("replay");
44 #define DBG_REPLAY LOG_STREAM(debug, log_replay)
45 #define LOG_REPLAY LOG_STREAM(info, log_replay)
46 #define WRN_REPLAY LOG_STREAM(warn, log_replay)
47 #define ERR_REPLAY LOG_STREAM(err, log_replay)
48 
49 
50 /**
51  * @param[in] tag The replay tag for this action.
52  * @param[in] function The callback for this action.
53  */
54 synced_command::synced_command(const std::string & tag, handler function)
55 {
56  assert(registry().find( tag ) == registry().end());
57  registry()[tag] = function;
58 }
59 
61 {
62  //Use a pointer to ensure that this object is not destructed when the program ends.
63  static map* instance = new map();
64  return *instance;
65 }
66 
67 
68 SYNCED_COMMAND_HANDLER_FUNCTION(recruit, child, use_undo, show, error_handler)
69 {
70  int current_team_num = resources::controller->current_side();
71  team &current_team = resources::gameboard->get_team(current_team_num);
72 
74  map_location from(child.child_or_empty("from"), resources::gamedata);
75  // Validate "from".
76  if ( !from.valid() ) {
77  // This will be the case for AI recruits in replays saved
78  // before 1.11.2, so it is not more severe than a warning.
79  // EDIT: we broke compatibility with 1.11.2 anyway so we should give an error.
80  error_handler("Missing leader location for recruitment.\n", false);
81  }
82  else if ( resources::gameboard->units().find(from) == resources::gameboard->units().end() ) {
83  // Sync problem?
84  std::stringstream errbuf;
85  errbuf << "Recruiting leader not found at " << from << ".\n";
86  error_handler(errbuf.str(), false);
87  }
88 
89  // Get the unit_type ID.
90  std::string type_id = child["type"];
91  if ( type_id.empty() ) {
92  error_handler("Recruitment is missing a unit type.", true);
93  return false;
94  }
95 
96  const unit_type *u_type = unit_types.find(type_id);
97  if (!u_type) {
98  std::stringstream errbuf;
99  errbuf << "Recruiting illegal unit: '" << type_id << "'.\n";
100  error_handler(errbuf.str(), true);
101  return false;
102  }
103 
104  const std::string res = actions::find_recruit_location(current_team_num, loc, from, type_id);
105  if(!res.empty())
106  {
107  std::stringstream errbuf;
108  errbuf << "cannot recruit unit: " << res << "\n";
109  error_handler(errbuf.str(), true);
110  return false;
111  //we are already oos because the unit wasn't created, no need to keep the bookkeeping right...
112  }
113  const int beginning_gold = current_team.gold();
114 
115 
116 
117  if ( u_type->cost() > beginning_gold ) {
118  std::stringstream errbuf;
119  errbuf << "unit '" << type_id << "' is too expensive to recruit: "
120  << u_type->cost() << "/" << beginning_gold << "\n";
121  error_handler(errbuf.str(), false);
122  }
123 
124  actions::recruit_unit(*u_type, current_team_num, loc, from, show, use_undo);
125 
126  LOG_REPLAY << "recruit: team=" << current_team_num << " '" << type_id << "' at (" << loc
127  << ") cost=" << u_type->cost() << " from gold=" << beginning_gold << ' '
128  << "-> " << current_team.gold() << "\n";
129  return true;
130 }
131 
132 SYNCED_COMMAND_HANDLER_FUNCTION(recall, child, use_undo, show, error_handler)
133 {
134 
135  int current_team_num = resources::controller->current_side();
136  team &current_team = resources::gameboard->get_team(current_team_num);
137 
138  const std::string& unit_id = child["value"];
139  map_location loc(child, resources::gamedata);
140  map_location from(child.child_or_empty("from"), resources::gamedata);
141 
142  if ( !actions::recall_unit(unit_id, current_team, loc, from, map_location::NDIRECTIONS, show, use_undo) ) {
143  error_handler("illegal recall: unit_id '" + unit_id + "' could not be found within the recall list.\n", true);
144  //when recall_unit returned false nothing happened so we can safety return false;
145  return false;
146  }
147  return true;
148 }
149 
150 SYNCED_COMMAND_HANDLER_FUNCTION(attack, child, /*use_undo*/, show, error_handler)
151 {
152  const config &destination = child.child("destination");
153  const config &source = child.child("source");
154  //check_checksums(*cfg);
155 
156  if (!destination) {
157  error_handler("no destination found in attack\n", true);
158  return false;
159  }
160 
161  if (!source) {
162  error_handler("no source found in attack \n", true);
163  return false;
164  }
165 
166  //we must get locations by value instead of by references, because the iterators
167  //may become invalidated later
168  const map_location src(source, resources::gamedata);
169  const map_location dst(destination, resources::gamedata);
170 
171  int weapon_num = child["weapon"];
172  // having defender_weapon in the replay fixes a bug (OOS) where one player (or observer) chooses a different defensive weapon.
173  // Xan pointed out this was a possibility: we calculate defense weapon
174  // now based on attack_prediction code, but this uses floating point
175  // calculations, which means that in the case where results are close,
176  // rounding differences can mean that both ends choose different weapons.
177  int def_weapon_num = child["defender_weapon"].to_int(-2);
178  if (def_weapon_num == -2) {
179  // Let's not gratuitously destroy backwards compatibility.
180  LOG_REPLAY << "Old data, having to guess weapon\n";
181  def_weapon_num = -1;
182  }
183 
185  if (!u.valid()) {
186  error_handler("unfound location for source of attack\n", true);
187  return false;
188  }
189 
190  if (child.has_attribute("attacker_type")) {
191  const std::string &att_type_id = child["attacker_type"];
192  if (u->type_id() != att_type_id) {
193  WRN_REPLAY << "unexpected attacker type: " << att_type_id << "(game state gives: " << u->type_id() << ")" << std::endl;
194  }
195  }
196 
197  if (static_cast<unsigned>(weapon_num) >= u->attacks().size()) {
198  error_handler("illegal weapon type in attack\n", true);
199  return false;
200  }
201 
203 
204  if (!tgt.valid()) {
205  std::stringstream errbuf;
206  errbuf << "unfound defender for attack: " << src << " -> " << dst << '\n';
207  error_handler(errbuf.str(), true);
208  return false;
209  }
210 
211  if (child.has_attribute("defender_type")) {
212  const std::string &def_type_id = child["defender_type"];
213  if (tgt->type_id() != def_type_id) {
214  WRN_REPLAY << "unexpected defender type: " << def_type_id << "(game state gives: " << tgt->type_id() << ")" << std::endl;
215  }
216  }
217 
218  if (def_weapon_num >= static_cast<int>(tgt->attacks().size())) {
219 
220  error_handler("illegal defender weapon type in attack\n", true);
221  return false;
222  }
223 
224  DBG_REPLAY << "Attacker XP (before attack): " << u->experience() << "\n";
225 
227  attack_unit_and_advance(src, dst, weapon_num, def_weapon_num, show);
228  return true;
229 }
230 
231 SYNCED_COMMAND_HANDLER_FUNCTION(disband, child, /*use_undo*/, /*show*/, error_handler)
232 {
233 
234  int current_team_num = resources::controller->current_side();
235  team &current_team = resources::gameboard->get_team(current_team_num);
236 
237  const std::string& unit_id = child["value"];
238  std::size_t old_size = current_team.recall_list().size();
239 
240  // Find the unit in the recall list.
241  unit_ptr dismissed_unit = current_team.recall_list().find_if_matches_id(unit_id);
242  assert(dismissed_unit);
243  //add dismissal to the undo stack
244  resources::undo_stack->add_dismissal(dismissed_unit);
245 
246  current_team.recall_list().erase_if_matches_id(unit_id);
247 
248  if (old_size == current_team.recall_list().size()) {
249  error_handler("illegal disband\n", true);
250  return false;
251  }
252  return true;
253 }
254 
255 SYNCED_COMMAND_HANDLER_FUNCTION(move, child, use_undo, show, error_handler)
256 {
257  int current_team_num = resources::controller->current_side();
258  team &current_team = resources::gameboard->get_team(current_team_num);
259 
260  std::vector<map_location> steps;
261 
262  try {
263  read_locations(child,steps);
264  } catch (const std::invalid_argument&) {
265  WRN_REPLAY << "Warning: Path data contained something which could not be parsed to a sequence of locations:" << "\n config = " << child.debug() << std::endl;
266  return false;
267  }
268 
269  if(steps.empty())
270  {
271  WRN_REPLAY << "Warning: Missing path data found in [move]" << std::endl;
272  return false;
273  }
274 
275  const map_location& src = steps.front();
276  const map_location& dst = steps.back();
277 
278  if (src == dst) {
279  WRN_REPLAY << "Warning: Move with identical source and destination. Skipping..." << std::endl;
280  return false;
281  }
282 
283  // The nominal destination should appear to be unoccupied.
285  if ( u.valid() ) {
286  WRN_REPLAY << "Warning: Move destination " << dst << " appears occupied." << std::endl;
287  // We'll still proceed with this movement, though, since
288  // an event might intervene.
289  // 'event' doesn't mean wml event but rather it means 'hidden' units form the movers point of view.
290  }
291 
292  u = resources::gameboard->units().find(src);
293  if (!u.valid()) {
294  std::stringstream errbuf;
295  errbuf << "unfound location for source of movement: "
296  << src << " -> " << dst << '\n';
297  error_handler(errbuf.str(), true);
298  return false;
299  }
300  bool skip_sighted = false;
301  bool skip_ally_sighted = false;
302  if(child["skip_sighted"] == "all")
303  {
304  skip_sighted = true;
305  }
306  else if(child["skip_sighted"] == "only_ally")
307  {
308  skip_ally_sighted = true;
309  }
310 
311  bool show_move = show;
312  if ( current_team.is_local_ai() || current_team.is_network_ai())
313  {
314  show_move = show_move && !preferences::skip_ai_moves();
315  }
316  actions::move_unit_from_replay(steps, use_undo ? resources::undo_stack : nullptr, skip_sighted, skip_ally_sighted, show_move);
317 
318  return true;
319 }
320 
321 SYNCED_COMMAND_HANDLER_FUNCTION(fire_event, child, use_undo, /*show*/, /*error_handler*/)
322 {
323  bool undoable = true;
324 
325  if(const config &last_select = child.child("last_select"))
326  {
327  //the select event cannot clear the undo stack.
329  }
330  const std::string &event_name = child["raise"];
331  if (const config &source = child.child("source")) {
332  undoable = undoable & !std::get<0>(resources::game_events->pump().fire(event_name, map_location(source, resources::gamedata)));
333  } else {
334  undoable = undoable & !std::get<0>(resources::game_events->pump().fire(event_name));
335  }
336 
337  // Not clearing the undo stack here causes OOS because we added an entry to the replay but no entry to the undo stack.
338  if(use_undo) {
339  if(!undoable || !synced_context::can_undo()) {
341  } else {
343  }
344  }
345  return true;
346 }
347 
348 SYNCED_COMMAND_HANDLER_FUNCTION(custom_command, child, use_undo, /*show*/, /*error_handler*/)
349 {
350  assert(resources::lua_kernel);
351  resources::lua_kernel->custom_command(child["name"], child.child_or_empty("data"));
352  if(use_undo) {
353  if(!synced_context::can_undo()) {
355  } else {
357  }
358  }
359  return true;
360 }
361 
362 SYNCED_COMMAND_HANDLER_FUNCTION(auto_shroud, child, use_undo, /*show*/, /*error_handler*/)
363 {
364  assert(use_undo);
365  team &current_team = resources::controller->current_team();
366 
367  bool active = child["active"].to_bool();
368  // We cannot update shroud here like 'if(active) resources::undo_stack->commit_vision();'.
369  // because the undo.cpp code assumes exactly 1 entry in the undo stack per entry in the replay.
370  // And doing so would create a second entry in the undo stack for this 'auto_shroud' entry.
371  current_team.set_auto_shroud_updates(active);
373  return true;
374 }
375 
376 /** from resources::undo_stack->commit_vision(bool is_replay):
377  * Updates fog/shroud based on the undo stack, then updates stack as needed.
378  * Call this when "updating shroud now".
379  * This may fire events and change the game state.
380  * @param[in] is_replay Set to true when this is called during a replay.
381  *
382  * This means it is a synced command like any other.
383  */
384 
385 SYNCED_COMMAND_HANDLER_FUNCTION(update_shroud, /*child*/, use_undo, /*show*/, error_handler)
386 {
387  assert(use_undo);
388  team &current_team = resources::controller->current_team();
389  if(current_team.auto_shroud_updates()) {
390  error_handler("Team has DSU disabled but we found an explicit shroud update", false);
391  }
394  return true;
395 }
396 
397 namespace
398 {
399  void debug_notification(const std::string& text, bool message_is_command = false)
400  {
402  auto& current_team = controller.current_team();
403  static bool ignore = false;
404  bool show_long_message = controller.is_replay() || !current_team.is_local();
405 
406  std::string message;
407  utils::string_map i18n_vars = {{ "player", current_team.current_player() }};
408 
409  if(message_is_command) {
410  i18n_vars["command"] = text;
411  message = VGETTEXT("The :$command debug command was used during $player’s turn", i18n_vars);
412  } else {
413  message = VGETTEXT(text.c_str(), i18n_vars);
414  }
415 
416  if(show_long_message && !ignore) {
418  std::stringstream sbuilder;
419  sbuilder << _("A player used a debug command during the game. If this is unexpected, it is possible the player in question is cheating.")
420  << "\n\n"
421  << _("Details:") << "\n"
422  << message
423  << "\n\n"
424  << _("Do you wish to save the game before continuing?");
425  savegame::oos_savegame save(controller.get_saved_game(), ignore);
426  save.set_title(_("Debug Command Used"));
427  save.save_game_interactive(sbuilder.str(), savegame::savegame::YES_NO); // can throw quit_game_exception
428  }
429  else {
430  display::announce_options announce_options;
431  display::get_singleton()->announce(message, font::NORMAL_COLOR, announce_options);
432  }
433  }
434 
435  void debug_cmd_notification(const std::string& command)
436  {
437  debug_notification(command, true);
438  }
439 }
440 
441 SYNCED_COMMAND_HANDLER_FUNCTION(debug_unit, child, use_undo, /*show*/, /*error_handler*/)
442 {
443  if(use_undo) {
445  }
446  debug_cmd_notification("unit");
447  map_location loc(child);
448  const std::string name = child["name"];
449  const std::string value = child["value"];
450 
452  if (i == resources::gameboard->units().end()) {
453  return false;
454  }
455  if (name == "advances" ) {
456  int int_value = std::stoi(value);
457  for (int levels=0; levels<int_value; levels++) {
458  i->set_experience(i->max_experience());
459 
460  advance_unit_at(advance_unit_params(loc).force_dialog(true));
461  i = resources::gameboard->units().find(loc);
462  if (!i.valid()) {
463  break;
464  }
465  }
466  } else if (name == "status" ) {
467  for (std::string status : utils::split(value)) {
468  bool add = true;
469  if (status.length() >= 1 && status[0] == '-') {
470  add = false;
471  status = status.substr(1);
472  }
473  if (status.empty()) {
474  continue;
475  }
476  i->set_state(status, add);
477  }
478  } else {
479  config cfg;
480  i->write(cfg);
481  cfg[name] = value;
482 
483  // Attempt to create a new unit. If there are error (such an invalid type key), exit.
484  try{
485  unit_ptr new_u = unit::create(cfg, true);
486  new_u->set_location(loc);
487  // Don't remove the unit until after we've verified there are no errors in creating the new one,
488  // or else the unit would simply be removed from the map with no replacement.
490  resources::whiteboard->on_kill_unit();
492  } catch(const unit_type::error& e) {
493  ERR_REPLAY << e.what() << std::endl; // TODO: more appropriate error message log
494  return false;
495  }
496  }
497  if (name == "fail") { //testcase for bug #18488
498  assert(i.valid());
499  }
502 
503  return true;
504 }
505 
506 SYNCED_COMMAND_HANDLER_FUNCTION(debug_create_unit, child, use_undo, /*show*/, error_handler)
507 {
508  if(use_undo) {
510  }
511 
512  debug_notification(N_("A unit was created using debug mode during $player’s turn"));
513  map_location loc(child);
514  resources::whiteboard->on_kill_unit();
515  const unit_race::GENDER gender = string_gender(child["gender"], unit_race::NUM_GENDERS);
516  const unit_type *u_type = unit_types.find(child["type"]);
517  if (!u_type) {
518  error_handler("Invalid unit type", true);
519  return false;
520  }
521 
522  const int side_num = resources::controller
524 
525  // Create the unit.
526  unit_ptr created = unit::create(*u_type, side_num, true, gender);
527  created->new_turn();
528 
529  unit_map::unit_iterator unit_it;
530 
531  // Add the unit to the board.
532  std::tie(unit_it, std::ignore) = resources::gameboard->units().replace(loc, created);
533 
535  resources::game_events->pump().fire("unit_placed", loc);
537 
538  // Village capture?
539  if ( resources::gameboard->map().is_village(loc) )
540  actions::get_village(loc, created->side());
541 
542  // Update fog/shroud.
543  // Not checking auto_shroud_updates() here since :create is not undoable. (#2196)
544  actions::shroud_clearer clearer;
545  clearer.clear_unit(loc, *created);
546  clearer.fire_events();
547  if (unit_it.valid() ) // In case sighted events messed with the unit.
548  actions::actor_sighted(*unit_it);
549 
550  return true;
551 }
552 
553 SYNCED_COMMAND_HANDLER_FUNCTION(debug_lua, child, use_undo, /*show*/, /*error_handler*/)
554 {
555  if(use_undo) {
557  }
558  debug_cmd_notification("lua");
559  resources::lua_kernel->run(child["code"].str().c_str(), "debug command");
561 
562  return true;
563 }
564 
565 SYNCED_COMMAND_HANDLER_FUNCTION(debug_kill, child, use_undo, /*show*/, /*error_handler*/)
566 {
567  if (use_undo) {
569  }
570  debug_cmd_notification("kill");
571 
572  const map_location loc(child["x"].to_int(), child["y"].to_int(), wml_loc());
574  if (i != resources::gameboard->units().end()) {
575  const int dying_side = i->side();
576  resources::controller->pump().fire("last_breath", loc, loc);
577  if (i.valid()) {
578  unit_display::unit_die(loc, *i);
579  }
581  if (i.valid()) {
582  i->set_hitpoints(0);
583  }
584  resources::controller->pump().fire("die", loc, loc);
585  if (i.valid()) {
587  }
588  resources::whiteboard->on_kill_unit();
589  actions::recalculate_fog(dying_side);
590  }
591  return true;
592 }
593 
594 SYNCED_COMMAND_HANDLER_FUNCTION(debug_next_level, child, use_undo, /*show*/, /*error_handler*/)
595 {
596  if(use_undo) {
598  }
599 
600  debug_cmd_notification("next_level");
601 
602  std::string next_level = child["next_level"];
603  if (!next_level.empty())
604  resources::gamedata->set_next_scenario(next_level);
606  e.transient.carryover_report = false;
607  e.prescenario_save = true;
608  e.transient.linger_mode = false;
609  e.proceed_to_next_level = true;
610  e.is_victory = true;
611 
614 
615  return true;
616 }
617 
618 SYNCED_COMMAND_HANDLER_FUNCTION(debug_turn_limit, child, use_undo, /*show*/, /*error_handler*/)
619 {
620  if(use_undo) {
622  }
623 
624  debug_cmd_notification("turn_limit");
625 
626  resources::tod_manager->set_number_of_turns(child["turn_limit"].to_int(-1));
628  return true;
629 }
630 
631 SYNCED_COMMAND_HANDLER_FUNCTION(debug_turn, child, use_undo, /*show*/, /*error_handler*/)
632 {
633  if(use_undo) {
635  }
636 
637  debug_cmd_notification("turn");
638 
639  resources::tod_manager->set_turn(child["turn"].to_int(1), resources::gamedata);
640 
643 
644  return true;
645 }
646 
647 SYNCED_COMMAND_HANDLER_FUNCTION(debug_set_var, child, use_undo, /*show*/, /*error_handler*/)
648 {
649  if(use_undo) {
651  }
652 
653  debug_cmd_notification("set_var");
654 
655  try {
656  resources::gamedata->set_variable(child["name"],child["value"]);
657  }
658  catch(const invalid_variablename_exception&) {
659  // command_failed(_("Variable not found"));
660  return false;
661  }
662  return true;
663 }
664 
665 SYNCED_COMMAND_HANDLER_FUNCTION(debug_gold, child, use_undo, /*show*/, /*error_handler*/)
666 {
667  if(use_undo) {
669  }
670 
671  debug_cmd_notification("gold");
672 
673  resources::controller->current_team().spend_gold(-child["gold"].to_int(0));
675  return true;
676 }
677 
678 
679 SYNCED_COMMAND_HANDLER_FUNCTION(debug_event, child, use_undo, /*show*/, /*error_handler*/)
680 {
681  if(use_undo) {
683  }
684 
685  debug_cmd_notification("throw");
686 
687  resources::controller->pump().fire(child["eventname"]);
689 
690  return true;
691 }
692 
693 
694 SYNCED_COMMAND_HANDLER_FUNCTION(debug_fog, /*child*/, use_undo, /*show*/, /*error_handler*/)
695 {
696  if(use_undo) {
698  }
699 
700  debug_cmd_notification("fog");
701 
702  team& current_team = resources::controller->current_team();
703  current_team.set_fog(!current_team.uses_fog());
704  actions::recalculate_fog(current_team.side());
705 
708 
709  return true;
710 }
711 
712 
713 SYNCED_COMMAND_HANDLER_FUNCTION(debug_shroud, /*child*/, use_undo, /*show*/, /*error_handler*/)
714 {
715  if(use_undo) {
717  }
718 
719  debug_cmd_notification("shroud");
720 
721  team& current_team = resources::controller->current_team();
722  current_team.set_shroud(!current_team.uses_shroud());
723  actions::clear_shroud(current_team.side());
724 
727 
728  return true;
729 }
bool is_local_ai() const
Definition: team.hpp:267
void clear()
Clears the stack of undoable (and redoable) actions.
Definition: undo.cpp:220
play_controller * controller
Definition: resources.cpp:21
bool recall_unit(const std::string &id, team &current_team, const map_location &loc, const map_location &from, map_location::DIRECTION facing, bool show, bool use_undo)
Recalls the unit with the indicated ID for the provided team.
Definition: create.cpp:740
void read_locations(const config &cfg, std::vector< map_location > &locs)
Parse x,y keys of a config into a vector of locations.
Definition: location.cpp:485
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
::tod_manager * tod_manager
Definition: resources.cpp:29
void set_shroud(bool shroud)
Definition: team.hpp:324
#define ERR_REPLAY
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:88
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
Definition: types.cpp:1275
std::map< std::string, t_string > string_map
virtual const unit_map & units() const override
Definition: game_board.hpp:114
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:2977
umap_retval_pair_t insert(unit_ptr p)
Inserts the unit pointed to by p into the map.
Definition: map.cpp:135
Various functions that implement attacks and attack calculations.
void set_turn(const int num, game_data *vars=nullptr, const bool increase_limit_if_needed=true)
Dynamically change the current turn number.
static map & registry()
using static function variable instead of static member variable to prevent static initialization fia...
game_events::wml_event_pump & pump()
void redraw_everything()
Invalidates entire screen, including all tiles and sidebar.
Definition: display.cpp:2374
void invalidate_unit()
Function to invalidate that unit status displayed on the sidebar.
synced_command(const std::string &tag, handler function)
bool is_network_ai() const
Definition: team.hpp:269
unit_type_data unit_types
Definition: types.cpp:1452
std::map< std::string, handler > map
bool prescenario_save
Should a prescenario be created the next game?
std::size_t erase(const map_location &l)
Erases the unit at location l, if any.
Definition: map.cpp:298
void custom_command(const std::string &, const config &)
#define WRN_REPLAY
-file sdl_utils.hpp
void redraw_minimap()
Schedule the minimap to be redrawn.
Definition: display.hpp:622
std::vector< std::string > split(const std::string &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
void new_turn()
Update lighting settings.
static unit_ptr create(const config &cfg, bool use_traits=false, const vconfig *vcfg=nullptr)
Initializes a unit from a config.
Definition: unit.hpp:122
std::vector< std::pair< const std::string *, const stats * > > levels
Stats (and name) for each scenario. The pointers are never nullptr.
Definition: statistics.hpp:114
A single unit type that the player may recruit.
Definition: types.hpp:42
game_data * gamedata
Definition: resources.cpp:22
bool uses_fog() const
Definition: team.hpp:317
int gold() const
Definition: team.hpp:189
bool clear_unit(const map_location &view_loc, team &view_team, std::size_t viewer_id, int sight_range, bool slowed, const movetype::terrain_costs &costs, const map_location &real_loc, const std::set< map_location > *known_units=nullptr, std::size_t *enemy_count=nullptr, std::size_t *friend_count=nullptr, move_unit_spectator *spectator=nullptr, bool instant=true)
Clears shroud (and fog) around the provided location for view_team based on sight_range, costs, and slowed.
Definition: vision.cpp:330
static const char * name(const std::vector< SDL_Joystick *> &joysticks, const std::size_t index)
Definition: joystick.cpp:48
umap_retval_pair_t replace(const map_location &l, unit_ptr p)
Works like unit_map::add; but l is emptied first, if needed.
Definition: map.cpp:225
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
void recruit_unit(const unit_type &u_type, int side_num, const map_location &loc, const map_location &from, bool show, bool use_undo)
Recruits a unit of the given type for the given side.
Definition: create.cpp:708
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:89
team & get_team(int i)
Definition: game_board.hpp:104
Various functions that implement advancements of units.
bool linger_mode
Should linger mode be invoked?
unit_ptr find_if_matches_id(const std::string &unit_id)
Find a unit by id.
int cost() const
Definition: types.hpp:158
bool uses_shroud() const
Definition: team.hpp:316
#define LOG_REPLAY
void recalculate_minimap()
Schedule the minimap for recalculation.
Definition: display.hpp:616
game_board * gameboard
Definition: resources.cpp:20
void unit_die(const map_location &loc, unit &loser, const_attack_ptr attack, const_attack_ptr secondary_attack, const map_location &winner_loc, unit *winner)
Show a unit fading out.
Definition: udisplay.cpp:569
unit_race::GENDER string_gender(const std::string &str, unit_race::GENDER def)
Definition: race.cpp:141
void recalculate_fog(int side)
Function that recalculates the fog of war.
Definition: vision.cpp:705
void set_variable(const std::string &varname, const t_string &value)
does nothing if varname is no valid variable name.
Definition: game_data.cpp:84
void flush_messages()
Flushes WML messages and errors.
Definition: pump.cpp:607
static bool can_undo()
void spend_gold(const int amount)
Definition: team.hpp:208
bool carryover_report
Should a summary of the scenario outcome be displayed?
const char * what() const noexcept
Definition: exceptions.hpp:37
void commit_vision()
Updates fog/shroud based on the undo stack, then updates stack as needed.
Definition: undo.cpp:243
#define DBG_REPLAY
void set_fog(bool fog)
Definition: team.hpp:325
game_events::manager * game_events
Definition: resources.cpp:24
SYNCED_COMMAND_HANDLER_FUNCTION(recruit, child, use_undo, show, error_handler)
void erase_if_matches_id(const std::string &unit_id)
Erase any unit with this id.
advances the unit at loc if it has enough experience, maximum 20 times.
Definition: advancement.hpp:38
const color_t NORMAL_COLOR
virtual void force_end_turn()=0
Encapsulates the map of the game.
Definition: location.hpp:42
bool auto_shroud_updates() const
Definition: team.hpp:336
Various functions related to moving units.
unit_iterator find(std::size_t id)
Definition: map.cpp:311
std::shared_ptr< wb::manager > whiteboard
Definition: resources.cpp:33
Various functions related to the creation of units (recruits, recalls, and placed units)...
void set_end_level_data(const end_level_data &data)
void run(char const *prog, const std::string &name, int nArgs=0)
Runs a plain script.
void add_dismissal(const unit_const_ptr u)
Adds a dismissal to the undo stack.
Definition: undo.cpp:165
transient_end_level transient
bool fire_event(const ui_event event, std::vector< std::pair< widget *, ui_event >> &event_chain, widget *dispatcher, widget *w, F &&... params)
Helper function for fire_event.
std::size_t i
Definition: function.cpp:933
void set_number_of_turns(int num)
void announce(const std::string &msg, const color_t &color=font::GOOD_COLOR, const announce_options &options=announce_options())
Announce a message prominently.
Definition: display.cpp:1748
Holds options for calls to function &#39;announce&#39; (announce).
Definition: display.hpp:588
Define the game&#39;s event mechanism.
bool proceed_to_next_level
whether to proceed to the next scenario, equals is_victory in sp.
Additional information on the game outcome which can be provided by WML.
#define N_(String)
Definition: gettext.hpp:97
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
void advance_unit_at(const advance_unit_params &params)
static void save(LexState *ls, int c)
Definition: llex.cpp:57
pump_result_t fire(const std::string &event, const entity_location &loc1=entity_location::null_entity, const entity_location &loc2=entity_location::null_entity, const config &data=config())
Function to fire an event.
Definition: pump.cpp:486
std::size_t move_unit_from_replay(const std::vector< map_location > &steps, undo_list *undo_stack, bool continued_move, bool skip_ally_sighted, bool show_move)
Moves a unit across the board.
Definition: move.cpp:1292
std::size_t size() const
Get the number of units on the list.
bool clear_shroud(int side, bool reset_fog, bool fire_events)
Function that will clear shroud (and fog) based on current unit positions.
Definition: vision.cpp:754
void add_update_shroud()
Adds a shroud update to the undo stack.
Definition: undo.cpp:205
game_events::pump_result_t get_village(const map_location &loc, int side, bool *action_timebonus, bool fire_event)
Makes it so the village at the given location is owned by the given side.
Definition: move.cpp:139
boost::intrusive_ptr< unit > unit_ptr
Definition: ptr.hpp:29
bool find(E event, F functor)
Tests whether an event handler is available.
void unit_recruited(const map_location &loc, const map_location &leader_loc)
Definition: udisplay.cpp:730
Various functions that implement the undoing (and redoing) of in-game commands.
std::string find_recruit_location(const int side, map_location &recruit_location, map_location &recruited_from, const std::string &unit_type)
Finds a location on which to place a unit.
Definition: create.cpp:464
Standard logging facilities (interface).
int current_side() const
Returns the number of the side whose turn it is.
void add_dummy()
Adds an auto-shroud toggle to the undo stack.
Definition: undo.cpp:154
recall_list_manager & recall_list()
Definition: team.hpp:215
game_lua_kernel * lua_kernel
Definition: resources.cpp:25
Class to encapsulate fog/shroud clearing and the resultant sighted events.
Definition: vision.hpp:57
void set_auto_shroud_updates(bool value)
Definition: team.hpp:337
#define e
void add_auto_shroud(bool turned_on)
Adds an auto-shroud toggle to the undo stack.
Definition: undo.cpp:146
actions::undo_list * undo_stack
Definition: resources.cpp:32
game_events::wml_event_pump & pump()
Definition: manager.cpp:229
static lg::log_domain log_replay("replay")
int side() const
Definition: team.hpp:188
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
bool valid() const
Definition: map.hpp:276
std::string custom_command()
Definition: game.cpp:948
unit_map::iterator find_visible_unit(const map_location &loc, const team &current_team, bool see_all=false)
Definition: game_board.cpp:168
Display units performing various actions: moving, attacking, and dying.
bool skip_ai_moves()
Definition: game.cpp:748
void attack_unit_and_advance(const map_location &attacker, const map_location &defender, int attack_with, int defend_with, bool update_display, const ai::unit_advancements_aspect &ai_advancement)
Performs an attack, and advanced the units afterwards.
Definition: attack.cpp:1547
game_events::pump_result_t actor_sighted(const unit &target, const std::vector< int > *cache)
Fires sighted events for the sides that can see target.
Definition: vision.cpp:622
static game_display * get_singleton()
void show(const std::string &window_id, const t_string &message, const point &mouse, const SDL_Rect &source_rect)
Shows a tip.
Definition: tooltip.cpp:154