The Battle for Wesnoth  1.17.0-dev
synced_commands.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2021
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "synced_commands.hpp"
17 #include <cassert>
18 
19 #include "log.hpp"
20 #include "map/location.hpp"
21 #include "game_data.hpp"
22 #include "units/unit.hpp"
23 #include "team.hpp"
24 #include "play_controller.hpp"
25 #include "actions/create.hpp"
26 #include "actions/advancement.hpp"
27 #include "actions/attack.hpp"
28 #include "actions/move.hpp"
29 #include "actions/undo.hpp"
30 #include "preferences/general.hpp"
31 #include "preferences/game.hpp"
32 #include "game_events/pump.hpp"
33 #include "map/map.hpp"
34 #include "units/helper.hpp"
35 #include "recall_list_manager.hpp"
36 #include "resources.hpp"
37 #include "savegame.hpp"
39 #include "formula/string_utils.hpp"
40 #include "units/types.hpp"
41 #include "units/udisplay.hpp"
42 #include "whiteboard/manager.hpp"
43 #include "font/standard_colors.hpp"
44 
45 static lg::log_domain log_replay("replay");
46 #define DBG_REPLAY LOG_STREAM(debug, log_replay)
47 #define LOG_REPLAY LOG_STREAM(info, log_replay)
48 #define WRN_REPLAY LOG_STREAM(warn, log_replay)
49 #define ERR_REPLAY LOG_STREAM(err, log_replay)
50 
51 
52 /**
53  * @param[in] tag The replay tag for this action.
54  * @param[in] function The callback for this action.
55  */
56 synced_command::synced_command(const std::string & tag, handler function)
57 {
58  assert(registry().find( tag ) == registry().end());
59  registry()[tag] = function;
60 }
61 
63 {
64  //Use a pointer to ensure that this object is not destructed when the program ends.
65  static map* instance = new map();
66  return *instance;
67 }
68 
69 
70 SYNCED_COMMAND_HANDLER_FUNCTION(recruit, child, use_undo, show, error_handler)
71 {
72  int current_team_num = resources::controller->current_side();
73  team &current_team = resources::gameboard->get_team(current_team_num);
74 
76  map_location from(child.child_or_empty("from"), resources::gamedata);
77  // Validate "from".
78  if ( !from.valid() ) {
79  // This will be the case for AI recruits in replays saved
80  // before 1.11.2, so it is not more severe than a warning.
81  // EDIT: we broke compatibility with 1.11.2 anyway so we should give an error.
82  error_handler("Missing leader location for recruitment.\n");
83  }
84  else if ( resources::gameboard->units().find(from) == resources::gameboard->units().end() ) {
85  // Sync problem?
86  std::stringstream errbuf;
87  errbuf << "Recruiting leader not found at " << from << ".\n";
88  error_handler(errbuf.str());
89  }
90 
91  // Get the unit_type ID.
92  std::string type_id = child["type"];
93  if ( type_id.empty() ) {
94  error_handler("Recruitment is missing a unit type.");
95  return false;
96  }
97 
98  const unit_type *u_type = unit_types.find(type_id);
99  if (!u_type) {
100  std::stringstream errbuf;
101  errbuf << "Recruiting illegal unit: '" << type_id << "'.\n";
102  error_handler(errbuf.str());
103  return false;
104  }
105 
106  const std::string res = actions::find_recruit_location(current_team_num, loc, from, type_id);
107  if(!res.empty())
108  {
109  std::stringstream errbuf;
110  errbuf << "cannot recruit unit: " << res << "\n";
111  error_handler(errbuf.str());
112  return false;
113  //we are already oos because the unit wasn't created, no need to keep the bookkeeping right...
114  }
115  const int beginning_gold = current_team.gold();
116 
117 
118 
119  if ( u_type->cost() > beginning_gold ) {
120  std::stringstream errbuf;
121  errbuf << "unit '" << type_id << "' is too expensive to recruit: "
122  << u_type->cost() << "/" << beginning_gold << "\n";
123  error_handler(errbuf.str());
124  }
125 
126  actions::recruit_unit(*u_type, current_team_num, loc, from, show, use_undo);
127 
128  LOG_REPLAY << "recruit: team=" << current_team_num << " '" << type_id << "' at (" << loc
129  << ") cost=" << u_type->cost() << " from gold=" << beginning_gold << ' '
130  << "-> " << current_team.gold() << "\n";
131  return true;
132 }
133 
134 SYNCED_COMMAND_HANDLER_FUNCTION(recall, child, use_undo, show, error_handler)
135 {
136 
137  int current_team_num = resources::controller->current_side();
138  team &current_team = resources::gameboard->get_team(current_team_num);
139 
140  const std::string& unit_id = child["value"];
141  map_location loc(child, resources::gamedata);
142  map_location from(child.child_or_empty("from"), resources::gamedata);
143 
144  if ( !actions::recall_unit(unit_id, current_team, loc, from, map_location::NDIRECTIONS, show, use_undo) ) {
145  error_handler("illegal recall: unit_id '" + unit_id + "' could not be found within the recall list.\n");
146  //when recall_unit returned false nothing happened so we can safety return false;
147  return false;
148  }
149  return true;
150 }
151 
152 SYNCED_COMMAND_HANDLER_FUNCTION(attack, child, /*use_undo*/, show, error_handler)
153 {
154  const auto destination = child.optional_child("destination");
155  const auto source = child.optional_child("source");
156  //check_checksums(*cfg);
157 
158  if (!destination) {
159  error_handler("no destination found in attack\n");
160  return false;
161  }
162 
163  if (!source) {
164  error_handler("no source found in attack \n");
165  return false;
166  }
167 
168  //we must get locations by value instead of by references, because the iterators
169  //may become invalidated later
170  const map_location src(source.value(), resources::gamedata);
171  const map_location dst(destination.value(), resources::gamedata);
172 
173  int weapon_num = child["weapon"];
174  // having defender_weapon in the replay fixes a bug (OOS) where one player (or observer) chooses a different defensive weapon.
175  // Xan pointed out this was a possibility: we calculate defense weapon
176  // now based on attack_prediction code, but this uses floating point
177  // calculations, which means that in the case where results are close,
178  // rounding differences can mean that both ends choose different weapons.
179  int def_weapon_num = child["defender_weapon"].to_int(-2);
180  if (def_weapon_num == -2) {
181  // Let's not gratuitously destroy backwards compatibility.
182  LOG_REPLAY << "Old data, having to guess weapon\n";
183  def_weapon_num = -1;
184  }
185 
187  if (!u.valid()) {
188  error_handler("unfound location for source of attack\n");
189  return false;
190  }
191 
192  if (child.has_attribute("attacker_type")) {
193  const std::string &att_type_id = child["attacker_type"];
194  if (u->type_id() != att_type_id) {
195  WRN_REPLAY << "unexpected attacker type: " << att_type_id << "(game state gives: " << u->type_id() << ")" << std::endl;
196  }
197  }
198 
199  if (static_cast<unsigned>(weapon_num) >= u->attacks().size()) {
200  error_handler("illegal weapon type in attack\n");
201  return false;
202  }
203 
205 
206  if (!tgt.valid()) {
207  std::stringstream errbuf;
208  errbuf << "unfound defender for attack: " << src << " -> " << dst << '\n';
209  error_handler(errbuf.str());
210  return false;
211  }
212 
213  if (child.has_attribute("defender_type")) {
214  const std::string &def_type_id = child["defender_type"];
215  if (tgt->type_id() != def_type_id) {
216  WRN_REPLAY << "unexpected defender type: " << def_type_id << "(game state gives: " << tgt->type_id() << ")" << std::endl;
217  }
218  }
219 
220  if (def_weapon_num >= static_cast<int>(tgt->attacks().size())) {
221 
222  error_handler("illegal defender weapon type in attack\n");
223  return false;
224  }
225 
226  DBG_REPLAY << "Attacker XP (before attack): " << u->experience() << "\n";
227 
229  attack_unit_and_advance(src, dst, weapon_num, def_weapon_num, show);
230  return true;
231 }
232 
233 SYNCED_COMMAND_HANDLER_FUNCTION(disband, child, /*use_undo*/, /*show*/, error_handler)
234 {
235 
236  int current_team_num = resources::controller->current_side();
237  team &current_team = resources::gameboard->get_team(current_team_num);
238 
239  const std::string& unit_id = child["value"];
240  std::size_t old_size = current_team.recall_list().size();
241 
242  // Find the unit in the recall list.
243  unit_ptr dismissed_unit = current_team.recall_list().find_if_matches_id(unit_id);
244  assert(dismissed_unit);
245  //add dismissal to the undo stack
246  resources::undo_stack->add_dismissal(dismissed_unit);
247 
248  current_team.recall_list().erase_if_matches_id(unit_id);
249 
250  if (old_size == current_team.recall_list().size()) {
251  error_handler("illegal disband\n");
252  return false;
253  }
254  return true;
255 }
256 
257 SYNCED_COMMAND_HANDLER_FUNCTION(move, child, use_undo, show, error_handler)
258 {
259  int current_team_num = resources::controller->current_side();
260  team &current_team = resources::gameboard->get_team(current_team_num);
261 
262  std::vector<map_location> steps;
263 
264  try {
265  read_locations(child,steps);
266  } catch (const std::invalid_argument&) {
267  WRN_REPLAY << "Warning: Path data contained something which could not be parsed to a sequence of locations:" << "\n config = " << child.debug() << std::endl;
268  return false;
269  }
270 
271  if(steps.empty())
272  {
273  WRN_REPLAY << "Warning: Missing path data found in [move]" << std::endl;
274  return false;
275  }
276 
277  const map_location& src = steps.front();
278  const map_location& dst = steps.back();
279 
280  if (src == dst) {
281  WRN_REPLAY << "Warning: Move with identical source and destination. Skipping..." << std::endl;
282  return false;
283  }
284 
285  // The nominal destination should appear to be unoccupied.
287  if ( u.valid() ) {
288  WRN_REPLAY << "Warning: Move destination " << dst << " appears occupied." << std::endl;
289  // We'll still proceed with this movement, though, since
290  // an event might intervene.
291  // 'event' doesn't mean wml event but rather it means 'hidden' units form the movers point of view.
292  }
293 
294  u = resources::gameboard->units().find(src);
295  if (!u.valid()) {
296  std::stringstream errbuf;
297  errbuf << "unfound location for source of movement: "
298  << src << " -> " << dst << '\n';
299  error_handler(errbuf.str());
300  return false;
301  }
302  bool skip_sighted = false;
303  bool skip_ally_sighted = false;
304  if(child["skip_sighted"] == "all")
305  {
306  skip_sighted = true;
307  }
308  else if(child["skip_sighted"] == "only_ally")
309  {
310  skip_ally_sighted = true;
311  }
312 
313  bool show_move = show;
314  if ( current_team.is_local_ai() || current_team.is_network_ai())
315  {
316  show_move = show_move && !preferences::skip_ai_moves();
317  }
318  actions::move_unit_from_replay(steps, use_undo ? resources::undo_stack : nullptr, skip_sighted, skip_ally_sighted, show_move);
319 
320  return true;
321 }
322 
323 SYNCED_COMMAND_HANDLER_FUNCTION(fire_event, child, use_undo, /*show*/, /*error_handler*/)
324 {
325  bool undoable = true;
326 
327  if(const auto last_select = child.optional_child("last_select"))
328  {
329  //the select event cannot clear the undo stack.
330  resources::game_events->pump().fire("select", map_location(last_select.value(), resources::gamedata));
331  }
332  const std::string &event_name = child["raise"];
333  if (const auto source = child.optional_child("source")) {
334  undoable = undoable & !std::get<0>(resources::game_events->pump().fire(event_name, map_location(source.value(), resources::gamedata)));
335  } else {
336  undoable = undoable & !std::get<0>(resources::game_events->pump().fire(event_name));
337  }
338 
339  // Not clearing the undo stack here causes OOS because we added an entry to the replay but no entry to the undo stack.
340  if(use_undo) {
341  if(!undoable || !synced_context::can_undo()) {
343  } else {
345  }
346  }
347  return true;
348 }
349 
350 SYNCED_COMMAND_HANDLER_FUNCTION(custom_command, child, use_undo, /*show*/, /*error_handler*/)
351 {
352  assert(resources::lua_kernel);
353  resources::lua_kernel->custom_command(child["name"], child.child_or_empty("data"));
354  if(use_undo) {
355  if(!synced_context::can_undo()) {
357  } else {
359  }
360  }
361  return true;
362 }
363 
364 SYNCED_COMMAND_HANDLER_FUNCTION(auto_shroud, child, use_undo, /*show*/, /*error_handler*/)
365 {
366  assert(use_undo);
367  team &current_team = resources::controller->current_team();
368 
369  bool active = child["active"].to_bool();
370  // We cannot update shroud here like 'if(active) resources::undo_stack->commit_vision();'.
371  // because the undo.cpp code assumes exactly 1 entry in the undo stack per entry in the replay.
372  // And doing so would create a second entry in the undo stack for this 'auto_shroud' entry.
373  current_team.set_auto_shroud_updates(active);
375  return true;
376 }
377 
378 /** from resources::undo_stack->commit_vision(bool is_replay):
379  * Updates fog/shroud based on the undo stack, then updates stack as needed.
380  * Call this when "updating shroud now".
381  * This may fire events and change the game state.
382  *
383  * This means it is a synced command like any other.
384  */
385 
386 SYNCED_COMMAND_HANDLER_FUNCTION(update_shroud, /*child*/, use_undo, /*show*/, error_handler)
387 {
388  assert(use_undo);
389  team &current_team = resources::controller->current_team();
390  if(current_team.auto_shroud_updates()) {
391  error_handler("Team has DSU disabled but we found an explicit shroud update");
392  }
395  return true;
396 }
397 
398 namespace
399 {
400  void debug_notification(const std::string& text, bool message_is_command = false)
401  {
403  auto& current_team = controller.current_team();
404  static bool ignore = false;
405  bool show_long_message = controller.is_replay() || !current_team.is_local();
406 
407  std::string message;
408  utils::string_map i18n_vars = {{ "player", current_team.current_player() }};
409 
410  if(i18n_vars["player"].empty()) {
411  i18n_vars["player"] = _("(unknown player)");
412  }
413 
414  if(message_is_command) {
415  i18n_vars["command"] = text;
416  message = VGETTEXT("The :$command debug command was used during $player’s turn", i18n_vars);
417  } else {
418  message = VGETTEXT(text.c_str(), i18n_vars);
419  }
420 
421  if(show_long_message && !ignore) {
423  std::stringstream sbuilder;
424  sbuilder << _("A player used a debug command during the game. If this is unexpected, it is possible the player in question is cheating.")
425  << "\n\n"
426  << _("Details:") << "\n"
427  << message
428  << "\n\n"
429  << _("Do you wish to save the game before continuing?");
430  savegame::oos_savegame save(controller.get_saved_game(), ignore);
431  save.set_title(_("Debug Command Used"));
432  save.save_game_interactive(sbuilder.str(), savegame::savegame::YES_NO); // can throw quit_game_exception
433  }
434  else {
435  display::announce_options announce_options;
436  display::get_singleton()->announce(message, font::NORMAL_COLOR, announce_options);
437  }
438  }
439 
440  void debug_cmd_notification(const std::string& command)
441  {
442  debug_notification(command, true);
443  }
444 }
445 
446 SYNCED_COMMAND_HANDLER_FUNCTION(debug_terrain, child, use_undo, /*show*/, /*error_handler*/)
447 {
448  if(use_undo) {
450  }
451  debug_cmd_notification("terrain");
452 
453  map_location loc(child);
454  const std::string& terrain_type = child["terrain_type"];
455  const std::string& mode_str = child["mode_str"];
456 
457  bool result = resources::gameboard->change_terrain(loc, terrain_type, mode_str, false);
458  if(result) {
462  }
463  return true;
464 }
465 
466 SYNCED_COMMAND_HANDLER_FUNCTION(debug_unit, child, use_undo, /*show*/, /*error_handler*/)
467 {
468  if(use_undo) {
470  }
471  debug_cmd_notification("unit");
472  map_location loc(child);
473  const std::string name = child["name"];
474  const std::string value = child["value"];
475 
477  if (i == resources::gameboard->units().end()) {
478  return false;
479  }
480  if (name == "advances" ) {
481  int int_value = std::stoi(value);
482  for (int levels=0; levels<int_value; levels++) {
483  i->set_experience(i->max_experience());
484 
485  advance_unit_at(advance_unit_params(loc).force_dialog(true));
486  i = resources::gameboard->units().find(loc);
487  if (!i.valid()) {
488  break;
489  }
490  }
491  } else if (name == "status" ) {
492  for (std::string status : utils::split(value)) {
493  bool add = true;
494  if (status.length() >= 1 && status[0] == '-') {
495  add = false;
496  status = status.substr(1);
497  }
498  if (status.empty()) {
499  continue;
500  }
501  i->set_state(status, add);
502  }
503  } else {
504  config cfg;
505  i->write(cfg);
506  cfg[name] = value;
507 
508  // Attempt to create a new unit. If there are error (such an invalid type key), exit.
509  try{
510  unit_ptr new_u = unit::create(cfg, true);
511  new_u->set_location(loc);
512  // Don't remove the unit until after we've verified there are no errors in creating the new one,
513  // or else the unit would simply be removed from the map with no replacement.
515  resources::whiteboard->on_kill_unit();
517  } catch(const unit_type::error& e) {
518  ERR_REPLAY << e.what() << std::endl; // TODO: more appropriate error message log
519  return false;
520  }
521  }
522  if (name == "fail") { //testcase for bug #18488
523  assert(i.valid());
524  }
527 
528  return true;
529 }
530 
531 SYNCED_COMMAND_HANDLER_FUNCTION(debug_create_unit, child, use_undo, /*show*/, error_handler)
532 {
533  if(use_undo) {
535  }
536 
537  debug_notification(N_("A unit was created using debug mode during $player’s turn"));
538  map_location loc(child);
539  resources::whiteboard->on_kill_unit();
540  const std::string& variation = child["variation"].str();
541  const unit_race::GENDER gender = string_gender(child["gender"], unit_race::NUM_GENDERS);
542  const unit_type *u_type = unit_types.find(child["type"]);
543  if (!u_type) {
544  error_handler("Invalid unit type");
545  return false;
546  }
547 
548  const int side_num = resources::controller
550 
551  // Create the unit.
552  unit_ptr created = unit::create(*u_type, side_num, true, gender, variation);
553  created->new_turn();
554 
555  unit_map::unit_iterator unit_it;
556 
557  // Add the unit to the board.
558  std::tie(unit_it, std::ignore) = resources::gameboard->units().replace(loc, created);
559 
561  resources::game_events->pump().fire("unit_placed", loc);
563 
564  // Village capture?
565  if ( resources::gameboard->map().is_village(loc) )
566  actions::get_village(loc, created->side());
567 
568  // Update fog/shroud.
569  // Not checking auto_shroud_updates() here since :create is not undoable. (#2196)
570  actions::shroud_clearer clearer;
571  clearer.clear_unit(loc, *created);
572  clearer.fire_events();
573  if (unit_it.valid() ) // In case sighted events messed with the unit.
574  actions::actor_sighted(*unit_it);
575 
576  return true;
577 }
578 
579 SYNCED_COMMAND_HANDLER_FUNCTION(debug_lua, child, use_undo, /*show*/, /*error_handler*/)
580 {
581  if(use_undo) {
583  }
584  debug_cmd_notification("lua");
585  resources::lua_kernel->run(child["code"].str().c_str(), "debug command");
587 
588  return true;
589 }
590 
591 SYNCED_COMMAND_HANDLER_FUNCTION(debug_kill, child, use_undo, /*show*/, /*error_handler*/)
592 {
593  if (use_undo) {
595  }
596  debug_cmd_notification("kill");
597 
598  const map_location loc(child["x"].to_int(), child["y"].to_int(), wml_loc());
600  if (i != resources::gameboard->units().end()) {
601  const int dying_side = i->side();
602  resources::controller->pump().fire("last_breath", loc, loc);
603  if (i.valid()) {
604  unit_display::unit_die(loc, *i);
605  }
607  if (i.valid()) {
608  i->set_hitpoints(0);
609  }
610  resources::controller->pump().fire("die", loc, loc);
611  if (i.valid()) {
613  }
614  resources::whiteboard->on_kill_unit();
615  actions::recalculate_fog(dying_side);
616  }
617  return true;
618 }
619 
620 SYNCED_COMMAND_HANDLER_FUNCTION(debug_next_level, child, use_undo, /*show*/, /*error_handler*/)
621 {
622  if(use_undo) {
624  }
625 
626  debug_cmd_notification("next_level");
627 
628  std::string next_level = child["next_level"];
629  if (!next_level.empty())
630  resources::gamedata->set_next_scenario(next_level);
632  e.transient.carryover_report = false;
633  e.prescenario_save = true;
634  e.transient.linger_mode = false;
635  e.proceed_to_next_level = true;
636  e.is_victory = true;
637 
640 
641  return true;
642 }
643 
644 SYNCED_COMMAND_HANDLER_FUNCTION(debug_turn_limit, child, use_undo, /*show*/, /*error_handler*/)
645 {
646  if(use_undo) {
648  }
649 
650  debug_cmd_notification("turn_limit");
651 
652  resources::tod_manager->set_number_of_turns(child["turn_limit"].to_int(-1));
654  return true;
655 }
656 
657 SYNCED_COMMAND_HANDLER_FUNCTION(debug_turn, child, use_undo, /*show*/, /*error_handler*/)
658 {
659  if(use_undo) {
661  }
662 
663  debug_cmd_notification("turn");
664 
665  resources::tod_manager->set_turn(child["turn"].to_int(1), resources::gamedata);
666 
669 
670  return true;
671 }
672 
673 SYNCED_COMMAND_HANDLER_FUNCTION(debug_set_var, child, use_undo, /*show*/, /*error_handler*/)
674 {
675  if(use_undo) {
677  }
678 
679  debug_cmd_notification("set_var");
680 
681  try {
682  resources::gamedata->set_variable(child["name"],child["value"]);
683  }
684  catch(const invalid_variablename_exception&) {
685  // command_failed(_("Variable not found"));
686  return false;
687  }
688  return true;
689 }
690 
691 SYNCED_COMMAND_HANDLER_FUNCTION(debug_gold, child, use_undo, /*show*/, /*error_handler*/)
692 {
693  if(use_undo) {
695  }
696 
697  debug_cmd_notification("gold");
698 
699  resources::controller->current_team().spend_gold(-child["gold"].to_int(0));
701  return true;
702 }
703 
704 
705 SYNCED_COMMAND_HANDLER_FUNCTION(debug_event, child, use_undo, /*show*/, /*error_handler*/)
706 {
707  if(use_undo) {
709  }
710 
711  debug_cmd_notification("throw");
712 
713  resources::controller->pump().fire(child["eventname"]);
715 
716  return true;
717 }
718 
719 
720 SYNCED_COMMAND_HANDLER_FUNCTION(debug_fog, /*child*/, use_undo, /*show*/, /*error_handler*/)
721 {
722  if(use_undo) {
724  }
725 
726  debug_cmd_notification("fog");
727 
728  team& current_team = resources::controller->current_team();
729  current_team.set_fog(!current_team.uses_fog());
730  actions::recalculate_fog(current_team.side());
731 
734 
735  return true;
736 }
737 
738 
739 SYNCED_COMMAND_HANDLER_FUNCTION(debug_shroud, /*child*/, use_undo, /*show*/, /*error_handler*/)
740 {
741  if(use_undo) {
743  }
744 
745  debug_cmd_notification("shroud");
746 
747  team& current_team = resources::controller->current_team();
748  current_team.set_shroud(!current_team.uses_shroud());
749  actions::clear_shroud(current_team.side());
750 
753 
754  return true;
755 }
bool is_local_ai() const
Definition: team.hpp:280
void clear()
Clears the stack of undoable (and redoable) actions.
Definition: undo.cpp:221
play_controller * controller
Definition: resources.cpp:22
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:443
::tod_manager * tod_manager
Definition: resources.cpp:30
void set_shroud(bool shroud)
Definition: team.hpp:338
#define ERR_REPLAY
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:92
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:1262
std::map< std::string, t_string > string_map
virtual const unit_map & units() const override
Definition: game_board.hpp:112
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:3026
umap_retval_pair_t insert(unit_ptr p)
Inserts the unit pointed to by p into the map.
Definition: map.cpp:134
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:2419
void invalidate_unit()
Function to invalidate that unit status displayed on the sidebar.
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:737
synced_command(const std::string &tag, handler function)
bool is_network_ai() const
Definition: team.hpp:282
unit_type_data unit_types
Definition: types.cpp:1481
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:297
void custom_command(const std::string &, const config &)
#define WRN_REPLAY
static std::string _(const char *str)
Definition: gettext.hpp:93
void redraw_minimap()
Schedule the minimap to be redrawn.
Definition: display.hpp:625
std::shared_ptr< unit > unit_ptr
Definition: ptr.hpp:26
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:190
std::vector< std::pair< const std::string *, const stats * > > levels
Stats (and name) for each scenario.
Definition: statistics.hpp:136
A single unit type that the player may recruit.
Definition: types.hpp:45
game_data * gamedata
Definition: resources.cpp:23
bool uses_fog() const
Definition: team.hpp:331
int gold() const
Definition: team.hpp:201
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:332
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:224
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:72
team & get_team(int i)
Definition: game_board.hpp:97
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:175
bool uses_shroud() const
Definition: team.hpp:330
#define LOG_REPLAY
void recalculate_minimap()
Schedule the minimap for recalculation.
Definition: display.hpp:619
game_board * gameboard
Definition: resources.cpp:21
unit_race::GENDER string_gender(const std::string &str, unit_race::GENDER def)
Definition: race.cpp:149
void recalculate_fog(int side)
Function that recalculates the fog of war.
Definition: vision.cpp:712
void set_variable(const std::string &varname, const t_string &value)
does nothing if varname is no valid variable name.
Definition: game_data.cpp:85
void flush_messages()
Flushes WML messages and errors.
Definition: pump.cpp:602
static bool can_undo()
void spend_gold(const int amount)
Definition: team.hpp:220
bool carryover_report
Should a summary of the scenario outcome be displayed?
const char * what() const noexcept
Definition: exceptions.hpp:36
void needs_rebuild(bool b)
Sets whether the screen (map visuals) needs to be rebuilt.
void commit_vision()
Updates fog/shroud based on the undo stack, then updates stack as needed.
Definition: undo.cpp:244
#define DBG_REPLAY
void set_fog(bool fog)
Definition: team.hpp:339
game_events::manager * game_events
Definition: resources.cpp:25
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:43
const color_t NORMAL_COLOR
virtual void force_end_turn()=0
Encapsulates the map of the game.
Definition: location.hpp:38
bool auto_shroud_updates() const
Definition: team.hpp:351
Various functions related to moving units.
unit_iterator find(std::size_t id)
Definition: map.cpp:310
std::shared_ptr< wb::manager > whiteboard
Definition: resources.cpp:34
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:166
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:967
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:1780
void attack_unit_and_advance(const map_location &attacker, const map_location &defender, int attack_with, int defend_with, bool update_display)
Performs an attack, and advanced the units afterwards.
Definition: attack.cpp:1566
Holds options for calls to function &#39;announce&#39; (announce).
Definition: display.hpp:591
void unit_die(const map_location &loc, unit &loser, const_attack_ptr attack, const_attack_ptr secondary_attack, const map_location &winner_loc, unit_ptr winner)
Show a unit fading out.
Definition: udisplay.cpp:574
Define the game&#39;s event mechanism.
bool proceed_to_next_level
whether to proceed to the next scenario, equals is_victory in sp.
bool change_terrain(const map_location &loc, const std::string &t, const std::string &mode, bool replace_if_failed)
Definition: game_board.cpp:325
Additional information on the game outcome which can be provided by WML.
#define N_(String)
Definition: gettext.hpp:101
#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:481
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:1273
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:761
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:709
void add_update_shroud()
Adds a shroud update to the undo stack.
Definition: undo.cpp:206
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:140
std::vector< std::string > split(const config_attribute_value &val)
void unit_recruited(const map_location &loc, const map_location &leader_loc)
Definition: udisplay.cpp:801
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:467
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:155
recall_list_manager & recall_list()
Definition: team.hpp:227
game_lua_kernel * lua_kernel
Definition: resources.cpp:26
Class to encapsulate fog/shroud clearing and the resultant sighted events.
Definition: vision.hpp:72
void set_auto_shroud_updates(bool value)
Definition: team.hpp:352
#define e
void add_auto_shroud(bool turned_on)
Adds an auto-shroud toggle to the undo stack.
Definition: undo.cpp:147
actions::undo_list * undo_stack
Definition: resources.cpp:33
game_events::wml_event_pump & pump()
Definition: manager.cpp:230
static lg::log_domain log_replay("replay")
int side() const
Definition: team.hpp:200
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:61
bool valid() const
Definition: map.hpp:274
std::string custom_command()
Definition: game.cpp:940
unit_map::iterator find_visible_unit(const map_location &loc, const team &current_team, bool see_all=false)
Definition: game_board.cpp:183
Display units performing various actions: moving, attacking, and dying.
bool skip_ai_moves()
Definition: game.cpp:745
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:629
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:140
bool maybe_rebuild()
Rebuilds the screen if needs_rebuild(true) was previously called, and resets the flag.