The Battle for Wesnoth  1.19.23+dev
synced_commands.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2025
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"
31 #include "game_events/pump.hpp"
32 #include "map/map.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, spectator)
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  spectator.error("Missing leader location for recruitment.\n");
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  spectator.error(errbuf.str());
87  }
88 
89  // Get the unit_type ID.
90  std::string type_id = child["type"];
91  if ( type_id.empty() ) {
92  spectator.error("Recruitment is missing a unit type.");
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  spectator.error(errbuf.str());
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  spectator.error(errbuf.str());
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  spectator.error(errbuf.str());
122  }
123 
124  actions::recruit_unit(*u_type, current_team_num, loc, from);
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();
129  return true;
130 }
131 
132 SYNCED_COMMAND_HANDLER_FUNCTION(recall, child, spectator)
133 {
134  int current_team_num = resources::controller->current_side();
135  team &current_team = resources::gameboard->get_team(current_team_num);
136 
137  const std::string& unit_id = child["value"];
139  map_location from(child.child_or_empty("from"), resources::gamedata);
140 
141  if(!actions::recall_unit(unit_id, current_team, loc, from, map_location::direction::indeterminate)) {
142  spectator.error("illegal recall: unit_id '" + unit_id + "' could not be found within the recall list.\n");
143  //when recall_unit returned false nothing happened so we can safety return false;
144  return false;
145  }
146  return true;
147 }
148 
149 SYNCED_COMMAND_HANDLER_FUNCTION(attack, child, spectator)
150 {
151  const auto destination = child.optional_child("destination");
152  const auto source = child.optional_child("source");
153  //check_checksums(*cfg);
154 
155  if (!destination) {
156  spectator.error("no destination found in attack\n");
157  return false;
158  }
159 
160  if (!source) {
161  spectator.error("no source found in attack \n");
162  return false;
163  }
164 
165  //we must get locations by value instead of by references, because the iterators
166  //may become invalidated later
167  const map_location src(source.value(), resources::gamedata);
168  const map_location dst(destination.value(), resources::gamedata);
169 
170  int weapon_num = child["weapon"].to_int();
171  // having defender_weapon in the replay fixes a bug (OOS) where one player (or observer) chooses a different defensive weapon.
172  // Xan pointed out this was a possibility: we calculate defense weapon
173  // now based on attack_prediction code, but this uses floating point
174  // calculations, which means that in the case where results are close,
175  // rounding differences can mean that both ends choose different weapons.
176  int def_weapon_num = child["defender_weapon"].to_int(-2);
177  if (def_weapon_num == -2) {
178  // Let's not gratuitously destroy backwards compatibility.
179  LOG_REPLAY << "Old data, having to guess weapon";
180  def_weapon_num = -1;
181  }
182 
184  if (!u.valid()) {
185  spectator.error("unfound location for source of attack\n");
186  return false;
187  }
188 
189  if (child.has_attribute("attacker_type")) {
190  const std::string &att_type_id = child["attacker_type"];
191  if (u->type_id() != att_type_id) {
192  WRN_REPLAY << "unexpected attacker type: " << att_type_id << "(game state gives: " << u->type_id() << ")";
193  }
194  }
195 
196  if (static_cast<unsigned>(weapon_num) >= u->attacks().size()) {
197  spectator.error("illegal weapon type in attack\n");
198  return false;
199  }
200 
202 
203  if (!tgt.valid()) {
204  std::stringstream errbuf;
205  errbuf << "unfound defender for attack: " << src << " -> " << dst << '\n';
206  spectator.error(errbuf.str());
207  return false;
208  }
209 
210  if (child.has_attribute("defender_type")) {
211  const std::string &def_type_id = child["defender_type"];
212  if (tgt->type_id() != def_type_id) {
213  WRN_REPLAY << "unexpected defender type: " << def_type_id << "(game state gives: " << tgt->type_id() << ")";
214  }
215  }
216 
217  if (def_weapon_num >= static_cast<int>(tgt->attacks().size())) {
218 
219  spectator.error("illegal defender weapon type in attack\n");
220  return false;
221  }
222 
223  DBG_REPLAY << "Attacker XP (before attack): " << u->experience();
224 
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, spectator)
232 {
233 
234  team& current_team = resources::controller->current_team();
235 
236  const std::string& unit_id = child["value"];
237  std::size_t old_size = current_team.recall_list().size();
238 
239  // Find the unit in the recall list.
240  unit_ptr dismissed_unit = current_team.recall_list().find_if_matches_id(unit_id);
241  if (!dismissed_unit) {
242  spectator.error("illegal disband\n");
243  return false;
244  }
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  assert(old_size != current_team.recall_list().size());
251  return true;
252 }
253 
254 SYNCED_COMMAND_HANDLER_FUNCTION(move, child, spectator)
255 {
256  team& current_team = resources::controller->current_team();
257 
258  std::vector<map_location> steps;
259 
260  try {
261  steps = read_locations(child);
262  } catch (const std::invalid_argument&) {
263  WRN_REPLAY << "Warning: Path data contained something which could not be parsed to a sequence of locations:" << "\n config = " << child.debug();
264  return false;
265  }
266 
267  if(steps.empty())
268  {
269  WRN_REPLAY << "Warning: Missing path data found in [move]";
270  return false;
271  }
272 
273  const map_location& src = steps.front();
274  const map_location& dst = steps.back();
275 
276  if (src == dst) {
277  WRN_REPLAY << "Warning: Move with identical source and destination. Skipping...";
278  return false;
279  }
280 
281  // The nominal destination should appear to be unoccupied.
283  if ( u.valid() ) {
284  WRN_REPLAY << "Warning: Move destination " << dst << " appears occupied.";
285  // We'll still proceed with this movement, though, since
286  // an event might intervene.
287  // 'event' doesn't mean wml event but rather it means 'hidden' units form the movers point of view.
288  }
289 
291  if (!u.valid()) {
292  std::stringstream errbuf;
293  errbuf << "unfound location for source of movement: "
294  << src << " -> " << dst << '\n';
295  spectator.error(errbuf.str());
296  return false;
297  }
298 
299  bool skip_sighted = child["skip_sighted"] == "all";
300  bool skip_ally_sighted = child["skip_sighted"] == "only_ally";
301 
302  actions::execute_move_unit(steps, skip_sighted, skip_ally_sighted, dynamic_cast<actions::move_unit_spectator*>(&spectator));
303 
304  return true;
305 }
306 
308 {
309  if(const auto last_select = child.optional_child("last_select"))
310  {
311  //the select event cannot clear the undo stack.
312  resources::game_events->pump().fire("select", map_location(last_select.value(), resources::gamedata));
313  }
314  const std::string &event_name = child["raise"];
315  if (const auto source = child.optional_child("source")) {
316  synced_context::block_undo(std::get<0>(resources::game_events->pump().fire(event_name, map_location(source.value(), resources::gamedata))));
317  } else {
318  synced_context::block_undo(std::get<0>(resources::game_events->pump().fire(event_name)));
319  }
320 
321  return true;
322 }
323 
324 SYNCED_COMMAND_HANDLER_FUNCTION(custom_command, child, /*spectator*/)
325 {
326  assert(resources::lua_kernel);
327  resources::lua_kernel->custom_command(child["name"], child.child_or_empty("data"));
328 
329  return true;
330 }
331 
332 SYNCED_COMMAND_HANDLER_FUNCTION(auto_shroud, child, /*spectator*/)
333 {
334  team &current_team = resources::controller->current_team();
335 
336  bool active = child["active"].to_bool();
337  bool block_undo = child["block_undo"].to_bool();
338  if(active && !current_team.auto_shroud_updates()) {
339  block_undo |= resources::undo_stack->commit_vision();
340  }
341  current_team.set_auto_shroud_updates(active);
343  if(block_undo) {
345  }
346  return true;
347 }
348 
349 SYNCED_COMMAND_HANDLER_FUNCTION(update_shroud, /*child*/, spectator)
350 {
351  // When "updating shroud now" is used.
352  // Updates fog/shroud based on the undo stack, then updates stack as needed.
353  // This may fire events and change the game state.
354 
355  team &current_team = resources::controller->current_team();
356  if(current_team.auto_shroud_updates()) {
357  spectator.error("Team has DSU disabled but we found an explicit shroud update");
358  }
359  bool res = resources::undo_stack->commit_vision();
360  if(res) {
362  }
363  return true;
364 }
365 
366 namespace
367 {
368  void debug_notification(const std::string& text, bool message_is_command = false)
369  {
371  auto& current_team = controller.current_team();
372  static bool ignore = false;
373  bool show_long_message = controller.is_replay() || !current_team.is_local();
374 
375  std::string message;
376  utils::string_map i18n_vars = {{ "player", current_team.current_player() }};
377 
378  if(i18n_vars["player"].empty()) {
379  i18n_vars["player"] = _("(unknown player)");
380  }
381 
382  if(message_is_command) {
383  i18n_vars["command"] = text;
384  message = VGETTEXT("The :$command debug command was used during $player’s turn", i18n_vars);
385  } else {
386  message = VGETTEXT(text.c_str(), i18n_vars);
387  }
388 
389  if(show_long_message && !ignore) {
391  std::stringstream sbuilder;
392  sbuilder << _("A player used a debug command during the game. If this is unexpected, it is possible the player in question is cheating.")
393  << "\n\n"
394  << _("Details:") << "\n"
395  << message
396  << "\n\n"
397  << _("Do you wish to save the game before continuing?");
398  savegame::oos_savegame save(controller.get_saved_game(), ignore);
399  save.set_title(_("Debug Command Used"));
400  save.save_game_interactive(sbuilder.str(), savegame::savegame::YES_NO); // can throw quit_game_exception
401  }
402  else {
403  display::announce_options announce_options;
404  display::get_singleton()->announce(message, font::NORMAL_COLOR, announce_options);
405  }
406  }
407 
408  void debug_cmd_notification(const std::string& command)
409  {
410  debug_notification(command, true);
411  }
412 }
413 
414 SYNCED_COMMAND_HANDLER_FUNCTION(debug_terrain, child, /*spectator*/)
415 {
417  debug_cmd_notification("terrain");
418 
419  map_location loc(child);
420  const std::string& terrain_type = child["terrain_type"];
421  const std::string& mode_str = child["mode_str"];
422 
423  bool result = resources::gameboard->change_terrain(loc, terrain_type, mode_str, false);
424  if(result) {
428  }
429  return true;
430 }
431 
432 SYNCED_COMMAND_HANDLER_FUNCTION(debug_unit, child, /*spectator*/)
433 {
435  debug_cmd_notification("unit");
436  map_location loc(child);
437  const std::string name = child["name"];
438  const std::string value = child["value"];
439 
441  if (i == resources::gameboard->units().end()) {
442  return false;
443  }
444  if (name == "advances" ) {
445  int int_value = 0;
446  try {
447  int_value = std::stoi(value);
448  } catch (const std::invalid_argument&) {
449  WRN_REPLAY << "Warning: Invalid unit advancement argument: " << value;
450  return false;
451  }
452  for (int levels=0; levels<int_value; levels++) {
453  i->set_experience(i->max_experience());
454 
455  advance_unit_at(advance_unit_params(loc).force_dialog(true));
457  if (!i.valid()) {
458  break;
459  }
460  }
461  } else if (name == "status" ) {
462  for (std::string status : utils::split(value)) {
463  bool add = true;
464  if (status.length() >= 1 && status[0] == '-') {
465  add = false;
466  status = status.substr(1);
467  }
468  if (status.empty()) {
469  continue;
470  }
471  i->set_state(status, add);
472  }
473  } else {
474  config cfg;
475  i->write(cfg);
476  cfg[name] = value;
477 
478  // Attempt to create a new unit. If there are error (such an invalid type key), exit.
479  try{
480  unit_ptr new_u = unit::create(cfg, true);
481  new_u->set_location(loc);
482  // Don't remove the unit until after we've verified there are no errors in creating the new one,
483  // or else the unit would simply be removed from the map with no replacement.
485  resources::whiteboard->on_kill_unit();
487  } catch(const unit_type::error& e) {
488  ERR_REPLAY << e.what(); // TODO: more appropriate error message log
489  return false;
490  }
491  }
492  if (name == "fail") { //testcase for bug #18488
493  assert(i.valid());
494  }
497 
498  return true;
499 }
500 
501 SYNCED_COMMAND_HANDLER_FUNCTION(debug_create_unit, child, spectator)
502 {
504 
505  debug_notification(N_("A unit was created using debug mode during $player’s turn"));
506  map_location loc(child);
507  resources::whiteboard->on_kill_unit();
508  const std::string& variation = child["variation"].str();
509  const unit_race::GENDER gender = string_gender(child["gender"], unit_race::NUM_GENDERS);
510  const unit_type *u_type = unit_types.find(child["type"]);
511  if (!u_type) {
512  spectator.error("Invalid unit type");
513  return false;
514  }
515 
516  const int side_num = resources::controller
518 
519  // Create the unit.
520  unit_ptr created = unit::create(*u_type, side_num, true, gender, variation);
521  created->new_turn();
522 
523  unit_map::unit_iterator unit_it;
524 
525  // Add the unit to the board.
526  std::tie(unit_it, std::ignore) = resources::gameboard->units().replace(loc, created);
527 
529  resources::game_events->pump().fire("unit_placed", loc);
531 
532  // Village capture?
533  if ( resources::gameboard->map().is_village(loc) )
534  actions::get_village(loc, created->side());
535 
536  // Update fog/shroud.
537  // Not checking auto_shroud_updates() here since :create is not undoable. (#2196)
538  actions::shroud_clearer clearer;
539  clearer.clear_unit(loc, *created);
540  clearer.fire_events();
541  if (unit_it.valid() ) // In case sighted events messed with the unit.
542  actions::actor_sighted(*unit_it);
543 
544  return true;
545 }
546 
548 {
550  debug_cmd_notification("lua");
551  resources::lua_kernel->run(child["code"].str().c_str(), "debug command");
553 
554  return true;
555 }
556 
557 SYNCED_COMMAND_HANDLER_FUNCTION(debug_teleport, child, /*spectator*/)
558 {
560  debug_cmd_notification("teleport");
561 
562  const map_location teleport_from(child["teleport_from_x"].to_int(), child["teleport_from_y"].to_int(), wml_loc());
563  const map_location teleport_to(child["teleport_to_x"].to_int(), child["teleport_to_y"].to_int(), wml_loc());
564 
565  const unit_map::iterator unit_iter = resources::gameboard->units().find(teleport_from);
566  if(unit_iter != resources::gameboard->units().end()) {
567  if(unit_iter.valid()) {
568  actions::teleport_unit_from_replay({teleport_from, teleport_to}, false, false, false);
569  }
571  }
572 
573  return true;
574 }
575 
576 SYNCED_COMMAND_HANDLER_FUNCTION(debug_kill, child, /*spectator*/)
577 {
579  debug_cmd_notification("kill");
580 
581  const map_location loc(child["x"].to_int(), child["y"].to_int(), wml_loc());
583  if (i != resources::gameboard->units().end()) {
584  const int dying_side = i->side();
585  resources::controller->pump().fire("last_breath", loc, loc);
586  if (i.valid()) {
588  }
590  if (i.valid()) {
591  i->set_hitpoints(0);
592  }
593  resources::controller->pump().fire("die", loc, loc);
594  if (i.valid()) {
596  }
597  resources::whiteboard->on_kill_unit();
598  actions::recalculate_fog(dying_side);
599  }
600  return true;
601 }
602 
603 SYNCED_COMMAND_HANDLER_FUNCTION(debug_next_level, child, /*spectator*/)
604 {
606 
607  debug_cmd_notification("next_level");
608 
609  std::string next_level = child["next_level"];
610  if (!next_level.empty())
613  e.transient.carryover_report = false;
614  e.prescenario_save = true;
615  e.transient.linger_mode = false;
616  e.proceed_to_next_level = true;
617  e.is_victory = true;
618 
621 
622  return true;
623 }
624 
625 SYNCED_COMMAND_HANDLER_FUNCTION(debug_turn_limit, child, /*spectator*/)
626 {
628 
629  debug_cmd_notification("turn_limit");
630 
631  resources::tod_manager->set_number_of_turns(child["turn_limit"].to_int(-1));
633  return true;
634 }
635 
636 SYNCED_COMMAND_HANDLER_FUNCTION(debug_turn, child, /*spectator*/)
637 {
639 
640  debug_cmd_notification("turn");
641 
642  resources::tod_manager->set_turn(child["turn"].to_int(1), resources::gamedata);
643 
646 
647  return true;
648 }
649 
650 SYNCED_COMMAND_HANDLER_FUNCTION(debug_set_var, child, /*spectator*/)
651 {
653 
654  debug_cmd_notification("set_var");
655 
656  try {
657  resources::gamedata->set_variable(child["name"],child["value"]);
658  }
659  catch(const invalid_variablename_exception&) {
660  // command_failed(_("Variable not found"));
661  return false;
662  }
663  return true;
664 }
665 
666 SYNCED_COMMAND_HANDLER_FUNCTION(debug_gold, child, /*spectator*/)
667 {
669 
670  debug_cmd_notification("gold");
671 
672  resources::controller->current_team().spend_gold(-child["gold"].to_int(0));
674  return true;
675 }
676 
677 
678 SYNCED_COMMAND_HANDLER_FUNCTION(debug_event, child, /*spectator*/)
679 {
681 
682  debug_cmd_notification("throw");
683 
684  resources::controller->pump().fire(child["eventname"]);
686 
687  return true;
688 }
689 
690 
691 SYNCED_COMMAND_HANDLER_FUNCTION(debug_fog, /*child*/, /*spectator*/)
692 {
694 
695  debug_cmd_notification("fog");
696 
697  team& current_team = resources::controller->current_team();
698  current_team.set_fog(!current_team.uses_fog());
699  actions::recalculate_fog(current_team.side());
700 
703 
704  return true;
705 }
706 
707 
708 SYNCED_COMMAND_HANDLER_FUNCTION(debug_shroud, /*child*/, /*spectator*/)
709 {
711 
712  debug_cmd_notification("shroud");
713 
714  team& current_team = resources::controller->current_team();
715  current_team.set_shroud(!current_team.uses_shroud());
716  actions::clear_shroud(current_team.side());
717 
720 
721  return true;
722 }
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:1461
Various functions that implement attacks and attack calculations.
map_location loc
Definition: move.cpp:172
Various functions related to moving units.
void advance_unit_at(const advance_unit_params &params)
Various functions that implement advancements of units.
Class to encapsulate fog/shroud clearing and the resultant sighted events.
Definition: vision.hpp:72
game_events::pump_result_t fire_events()
Fires the sighted events that were earlier recorded by fog/shroud clearing.
Definition: vision.cpp:541
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,...
Definition: vision.cpp:330
void add_dismissal(const unit_const_ptr &u)
Adds a dismissal to the undo stack.
Definition: undo.cpp:88
bool commit_vision()
Updates fog/shroud based on the undo stack, then updates stack as needed.
Definition: undo.cpp:153
void add_auto_shroud(bool turned_on)
Adds an auto-shroud toggle to the undo stack.
Definition: undo.cpp:79
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:157
void recalculate_minimap()
Schedule the minimap for recalculation.
Definition: display.cpp:1458
void redraw_minimap()
Schedule the minimap to be redrawn.
Definition: display.cpp:1479
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:2963
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:1442
void queue_rerender()
Marks everything for rendering including all tiles and sidebar.
Definition: display.cpp:2141
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:102
bool change_terrain(const map_location &loc, const std::string &t, const std::string &mode, bool replace_if_failed)
Definition: game_board.cpp:317
team & get_team(int i)
Definition: game_board.hpp:92
unit_map::iterator find_visible_unit(const map_location &loc, const team &current_team, bool see_all=false)
Definition: game_board.cpp:185
virtual const unit_map & units() const override
Definition: game_board.hpp:107
void set_next_scenario(const std::string &next_scenario)
Definition: game_data.hpp:131
void set_variable(const std::string &varname, const config::attribute_value &value)
does nothing if varname is no valid variable name.
Definition: game_data.cpp:88
void invalidate_unit()
Function to invalidate that unit status displayed on the sidebar.
static game_display * get_singleton()
void new_turn()
Update lighting settings.
void needs_rebuild(bool b)
Sets whether the screen (map visuals) needs to be rebuilt.
bool maybe_rebuild()
Rebuilds the screen if needs_rebuild(true) was previously called, and resets the flag.
game_events::wml_event_pump & pump()
Definition: manager.cpp:257
void flush_messages()
Flushes WML messages and errors.
Definition: pump.cpp:521
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:399
void custom_command(const std::string &, const config &)
void run(char const *prog, const std::string &name, int nArgs=0)
Runs a plain script.
void set_end_level_data(const end_level_data &data)
int current_side() const
Returns the number of the side whose turn it is.
bool is_skipping_replay() const
virtual void force_end_turn()=0
game_events::wml_event_pump & pump()
std::size_t size() const
Get the number of units on the list.
unit_ptr find_if_matches_id(const std::string &unit_id)
Find a unit by id.
void erase_if_matches_id(const std::string &unit_id)
Erase any unit with this id.
synced_command(const std::string &tag, handler function)
static map & registry()
using static function variable instead of static member variable to prevent static initialization fia...
std::map< std::string, handler > map
static void block_undo(bool do_block=true, bool clear_undo=true)
set this to false to prevent clearing the undo stack, this is important when we cannot change the gam...
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:74
bool uses_shroud() const
Definition: team.hpp:341
int side() const
Definition: team.hpp:179
void set_shroud(bool shroud)
Definition: team.hpp:349
bool auto_shroud_updates() const
Definition: team.hpp:363
void set_auto_shroud_updates(bool value)
Definition: team.hpp:364
int gold() const
Definition: team.hpp:180
void set_fog(bool fog)
Definition: team.hpp:350
void spend_gold(const int amount)
Definition: team.hpp:218
bool uses_fog() const
Definition: team.hpp:342
recall_list_manager & recall_list()
Definition: team.hpp:239
void set_turn(const int num, game_data *vars=nullptr, const bool increase_limit_if_needed=true)
Dynamically change the current turn number.
void set_number_of_turns(int num)
unit_iterator find(std::size_t id)
Definition: map.cpp:302
umap_retval_pair_t replace(const map_location &l, const unit_ptr &p)
Works like unit_map::add; but l is emptied first, if needed.
Definition: map.cpp:216
std::size_t erase(const map_location &l)
Erases the unit at location l, if any.
Definition: map.cpp:289
umap_retval_pair_t insert(const unit_ptr &p)
Inserts the unit pointed to by p into the map.
Definition: map.cpp:135
@ NUM_GENDERS
Definition: race.hpp:28
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:1253
A single unit type that the player may recruit.
Definition: types.hpp:43
unit_type_error error
Definition: types.hpp:49
int cost() const
Definition: types.hpp:176
static unit_ptr create(const config &cfg, bool use_traits=false, const vconfig *vcfg=nullptr)
Initializes a unit from a config.
Definition: unit.hpp:107
Various functions related to the creation of units (recruits, recalls, and placed units).
const config * cfg
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
std::size_t i
Definition: function.cpp:1031
#define N_(String)
Definition: gettext.hpp:105
static std::string _(const char *str)
Definition: gettext.hpp:97
std::vector< map_location > read_locations(const config &cfg)
Parse x,y keys of a config into a vector of locations.
Definition: location.cpp:475
Standard logging facilities (interface).
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:466
void teleport_unit_from_replay(const std::vector< map_location > &steps, bool continued_move, bool skip_ally_sighted, bool show_move)
Teleports a unit across the board.
Definition: move.cpp:1408
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:746
bool recall_unit(const std::string &id, team &current_team, const map_location &loc, const map_location &from, map_location::direction facing)
Recalls the unit with the indicated ID for the provided team.
Definition: create.cpp:740
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:614
void recruit_unit(const unit_type &u_type, int side_num, const map_location &loc, const map_location &from)
Recruits a unit of the given type for the given side.
Definition: create.cpp:717
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:221
void recalculate_fog(int side)
Function that recalculates the fog of war.
Definition: vision.cpp:697
void execute_move_unit(const std::vector< map_location > &steps, bool continued_move, bool skip_ally_sighted, move_unit_spectator *move_spectator)
Moves a unit across the board.
Definition: move.cpp:1384
void pump()
Process all events currently in the queue.
Definition: events.cpp:480
const color_t NORMAL_COLOR
void show(const gui2::tracked_drawable &target)
Displays the fps report popup for the given tracked_drawable.
Definition: fps_report.cpp:131
bool fire_event(const ui_event event, const std::vector< std::pair< widget *, ui_event >> &event_chain, widget *dispatcher, widget *w, F &&... params)
Helper function for fire_event.
std::string tag(std::string_view tag, Args &&... data)
Wraps the given data in the specified tag.
Definition: markup.hpp:45
::tod_manager * tod_manager
Definition: resources.cpp:29
game_board * gameboard
Definition: resources.cpp:20
game_data * gamedata
Definition: resources.cpp:22
game_events::manager * game_events
Definition: resources.cpp:24
actions::undo_list * undo_stack
Definition: resources.cpp:32
game_lua_kernel * lua_kernel
Definition: resources.cpp:25
play_controller * controller
Definition: resources.cpp:21
std::shared_ptr< wb::manager > whiteboard
Definition: resources.cpp:33
void unit_die(const map_location &loc, unit &loser, const const_attack_ptr &attack, const const_attack_ptr &secondary_attack, const map_location &winner_loc, const unit_ptr &winner)
Show a unit fading out.
Definition: udisplay.cpp:574
void unit_recruited(const map_location &loc, const map_location &leader_loc)
Definition: udisplay.cpp:801
int stoi(std::string_view str)
Same interface as std::stoi and meant as a drop in replacement, except:
Definition: charconv.hpp:156
std::map< std::string, t_string > string_map
std::vector< std::string > split(const config_attribute_value &val)
auto * find(Container &container, const Value &value)
Convenience wrapper for using find on a container without needing to comare to end()
Definition: general.hpp:141
std::shared_ptr< unit > unit_ptr
Definition: ptr.hpp:26
Define the game's event mechanism.
unit_race::GENDER string_gender(const std::string &str, unit_race::GENDER def)
Definition: race.cpp:147
rect dst
Location on the final composed sheet.
rect src
Non-transparent portion of the surface to compose.
advances the unit at loc if it has enough experience, maximum 20 times.
Definition: advancement.hpp:39
Holds options for calls to function 'announce' (announce).
Definition: display.hpp:601
Additional information on the game outcome which can be provided by WML.
Encapsulates the map of the game.
Definition: location.hpp:46
bool valid() const
Definition: location.hpp:111
bool valid() const
Definition: map.hpp:273
#define WRN_REPLAY
#define DBG_REPLAY
static lg::log_domain log_replay("replay")
#define LOG_REPLAY
#define ERR_REPLAY
SYNCED_COMMAND_HANDLER_FUNCTION(recruit, child, spectator)
unit_type_data unit_types
Definition: types.cpp:1494
Display units performing various actions: moving, attacking, and dying.
Various functions that implement the undoing (and redoing) of in-game commands.
#define e