The Battle for Wesnoth  1.19.0-dev
synced_commands.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2024
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/game.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, 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");
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());
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.");
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());
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());
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());
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();
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");
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 auto destination = child.optional_child("destination");
153  const auto source = child.optional_child("source");
154  //check_checksums(*cfg);
155 
156  if (!destination) {
157  error_handler("no destination found in attack\n");
158  return false;
159  }
160 
161  if (!source) {
162  error_handler("no source found in attack \n");
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.value(), resources::gamedata);
169  const map_location dst(destination.value(), 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";
181  def_weapon_num = -1;
182  }
183 
185  if (!u.valid()) {
186  error_handler("unfound location for source of attack\n");
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() << ")";
194  }
195  }
196 
197  if (static_cast<unsigned>(weapon_num) >= u->attacks().size()) {
198  error_handler("illegal weapon type in attack\n");
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());
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() << ")";
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");
221  return false;
222  }
223 
224  DBG_REPLAY << "Attacker XP (before attack): " << u->experience();
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  if (!dismissed_unit) {
243  error_handler("illegal disband\n");
244  return false;
245  }
246  //add dismissal to the undo stack
247  resources::undo_stack->add_dismissal(dismissed_unit);
248 
249  current_team.recall_list().erase_if_matches_id(unit_id);
250 
251  if (old_size == current_team.recall_list().size()) {
252  error_handler("illegal disband\n");
253  return false;
254  }
255  return true;
256 }
257 
258 SYNCED_COMMAND_HANDLER_FUNCTION(move, child, use_undo, show, error_handler)
259 {
260  int current_team_num = resources::controller->current_side();
261  team &current_team = resources::gameboard->get_team(current_team_num);
262 
263  std::vector<map_location> steps;
264 
265  try {
266  read_locations(child,steps);
267  } catch (const std::invalid_argument&) {
268  WRN_REPLAY << "Warning: Path data contained something which could not be parsed to a sequence of locations:" << "\n config = " << child.debug();
269  return false;
270  }
271 
272  if(steps.empty())
273  {
274  WRN_REPLAY << "Warning: Missing path data found in [move]";
275  return false;
276  }
277 
278  const map_location& src = steps.front();
279  const map_location& dst = steps.back();
280 
281  if (src == dst) {
282  WRN_REPLAY << "Warning: Move with identical source and destination. Skipping...";
283  return false;
284  }
285 
286  // The nominal destination should appear to be unoccupied.
288  if ( u.valid() ) {
289  WRN_REPLAY << "Warning: Move destination " << dst << " appears occupied.";
290  // We'll still proceed with this movement, though, since
291  // an event might intervene.
292  // 'event' doesn't mean wml event but rather it means 'hidden' units form the movers point of view.
293  }
294 
295  u = resources::gameboard->units().find(src);
296  if (!u.valid()) {
297  std::stringstream errbuf;
298  errbuf << "unfound location for source of movement: "
299  << src << " -> " << dst << '\n';
300  error_handler(errbuf.str());
301  return false;
302  }
303  bool skip_sighted = false;
304  bool skip_ally_sighted = false;
305  if(child["skip_sighted"] == "all")
306  {
307  skip_sighted = true;
308  }
309  else if(child["skip_sighted"] == "only_ally")
310  {
311  skip_ally_sighted = true;
312  }
313 
314  bool show_move = show;
315  if ( current_team.is_local_ai() || current_team.is_network_ai())
316  {
317  show_move = show_move && !preferences::skip_ai_moves();
318  }
319  actions::move_unit_from_replay(steps, use_undo ? resources::undo_stack : nullptr, skip_sighted, skip_ally_sighted, show_move);
320 
321  return true;
322 }
323 
324 SYNCED_COMMAND_HANDLER_FUNCTION(fire_event, child, use_undo, /*show*/, /*error_handler*/)
325 {
326  bool undoable = true;
327 
328  if(const auto last_select = child.optional_child("last_select"))
329  {
330  //the select event cannot clear the undo stack.
331  resources::game_events->pump().fire("select", map_location(last_select.value(), resources::gamedata));
332  }
333  const std::string &event_name = child["raise"];
334  if (const auto source = child.optional_child("source")) {
335  undoable = undoable & !std::get<0>(resources::game_events->pump().fire(event_name, map_location(source.value(), resources::gamedata)));
336  } else {
337  undoable = undoable & !std::get<0>(resources::game_events->pump().fire(event_name));
338  }
339 
340  // Not clearing the undo stack here causes OOS because we added an entry to the replay but no entry to the undo stack.
341  if(use_undo) {
342  if(!undoable || synced_context::undo_blocked()) {
344  } else {
346  }
347  }
348  return true;
349 }
350 
351 SYNCED_COMMAND_HANDLER_FUNCTION(custom_command, child, use_undo, /*show*/, /*error_handler*/)
352 {
353  assert(resources::lua_kernel);
354  resources::lua_kernel->custom_command(child["name"], child.child_or_empty("data"));
355  if(use_undo) {
358  } else {
360  }
361  }
362  return true;
363 }
364 
365 SYNCED_COMMAND_HANDLER_FUNCTION(auto_shroud, child, use_undo, /*show*/, /*error_handler*/)
366 {
367  assert(use_undo);
368  team &current_team = resources::controller->current_team();
369 
370  bool active = child["active"].to_bool();
371  if(active && !current_team.auto_shroud_updates()) {
373  }
374  current_team.set_auto_shroud_updates(active);
375  if(resources::undo_stack->can_undo()) {
377  }
378  return true;
379 }
380 
381 SYNCED_COMMAND_HANDLER_FUNCTION(update_shroud, /*child*/, use_undo, /*show*/, error_handler)
382 {
383  // When "updating shroud now" is used.
384  // Updates fog/shroud based on the undo stack, then updates stack as needed.
385  // This may fire events and change the game state.
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");
391  }
392  bool res = resources::undo_stack->commit_vision();
394  if(res) {
396  }
397  return true;
398 }
399 
400 namespace
401 {
402  void debug_notification(const std::string& text, bool message_is_command = false)
403  {
405  auto& current_team = controller.current_team();
406  static bool ignore = false;
407  bool show_long_message = controller.is_replay() || !current_team.is_local();
408 
409  std::string message;
410  utils::string_map i18n_vars = {{ "player", current_team.current_player() }};
411 
412  if(i18n_vars["player"].empty()) {
413  i18n_vars["player"] = _("(unknown player)");
414  }
415 
416  if(message_is_command) {
417  i18n_vars["command"] = text;
418  message = VGETTEXT("The :$command debug command was used during $player’s turn", i18n_vars);
419  } else {
420  message = VGETTEXT(text.c_str(), i18n_vars);
421  }
422 
423  if(show_long_message && !ignore) {
425  std::stringstream sbuilder;
426  sbuilder << _("A player used a debug command during the game. If this is unexpected, it is possible the player in question is cheating.")
427  << "\n\n"
428  << _("Details:") << "\n"
429  << message
430  << "\n\n"
431  << _("Do you wish to save the game before continuing?");
432  savegame::oos_savegame save(controller.get_saved_game(), ignore);
433  save.set_title(_("Debug Command Used"));
434  save.save_game_interactive(sbuilder.str(), savegame::savegame::YES_NO); // can throw quit_game_exception
435  }
436  else {
437  display::announce_options announce_options;
438  display::get_singleton()->announce(message, font::NORMAL_COLOR, announce_options);
439  }
440  }
441 
442  void debug_cmd_notification(const std::string& command)
443  {
444  debug_notification(command, true);
445  }
446 }
447 
448 SYNCED_COMMAND_HANDLER_FUNCTION(debug_terrain, child, use_undo, /*show*/, /*error_handler*/)
449 {
450  if(use_undo) {
452  }
453  debug_cmd_notification("terrain");
454 
455  map_location loc(child);
456  const std::string& terrain_type = child["terrain_type"];
457  const std::string& mode_str = child["mode_str"];
458 
459  bool result = resources::gameboard->change_terrain(loc, terrain_type, mode_str, false);
460  if(result) {
464  }
465  return true;
466 }
467 
468 SYNCED_COMMAND_HANDLER_FUNCTION(debug_unit, child, use_undo, /*show*/, /*error_handler*/)
469 {
470  if(use_undo) {
472  }
473  debug_cmd_notification("unit");
474  map_location loc(child);
475  const std::string name = child["name"];
476  const std::string value = child["value"];
477 
479  if (i == resources::gameboard->units().end()) {
480  return false;
481  }
482  if (name == "advances" ) {
483  int int_value = 0;
484  try {
485  int_value = std::stoi(value);
486  } catch (const std::invalid_argument&) {
487  WRN_REPLAY << "Warning: Invalid unit advancement argument: " << value;
488  return false;
489  }
490  for (int levels=0; levels<int_value; levels++) {
491  i->set_experience(i->max_experience());
492 
493  advance_unit_at(advance_unit_params(loc).force_dialog(true));
494  i = resources::gameboard->units().find(loc);
495  if (!i.valid()) {
496  break;
497  }
498  }
499  } else if (name == "status" ) {
500  for (std::string status : utils::split(value)) {
501  bool add = true;
502  if (status.length() >= 1 && status[0] == '-') {
503  add = false;
504  status = status.substr(1);
505  }
506  if (status.empty()) {
507  continue;
508  }
509  i->set_state(status, add);
510  }
511  } else {
512  config cfg;
513  i->write(cfg);
514  cfg[name] = value;
515 
516  // Attempt to create a new unit. If there are error (such an invalid type key), exit.
517  try{
518  unit_ptr new_u = unit::create(cfg, true);
519  new_u->set_location(loc);
520  // Don't remove the unit until after we've verified there are no errors in creating the new one,
521  // or else the unit would simply be removed from the map with no replacement.
523  resources::whiteboard->on_kill_unit();
525  } catch(const unit_type::error& e) {
526  ERR_REPLAY << e.what(); // TODO: more appropriate error message log
527  return false;
528  }
529  }
530  if (name == "fail") { //testcase for bug #18488
531  assert(i.valid());
532  }
535 
536  return true;
537 }
538 
539 SYNCED_COMMAND_HANDLER_FUNCTION(debug_create_unit, child, use_undo, /*show*/, error_handler)
540 {
541  if(use_undo) {
543  }
544 
545  debug_notification(N_("A unit was created using debug mode during $player’s turn"));
546  map_location loc(child);
547  resources::whiteboard->on_kill_unit();
548  const std::string& variation = child["variation"].str();
549  const unit_race::GENDER gender = string_gender(child["gender"], unit_race::NUM_GENDERS);
550  const unit_type *u_type = unit_types.find(child["type"]);
551  if (!u_type) {
552  error_handler("Invalid unit type");
553  return false;
554  }
555 
556  const int side_num = resources::controller
558 
559  // Create the unit.
560  unit_ptr created = unit::create(*u_type, side_num, true, gender, variation);
561  created->new_turn();
562 
563  unit_map::unit_iterator unit_it;
564 
565  // Add the unit to the board.
566  std::tie(unit_it, std::ignore) = resources::gameboard->units().replace(loc, created);
567 
569  resources::game_events->pump().fire("unit_placed", loc);
571 
572  // Village capture?
573  if ( resources::gameboard->map().is_village(loc) )
574  actions::get_village(loc, created->side());
575 
576  // Update fog/shroud.
577  // Not checking auto_shroud_updates() here since :create is not undoable. (#2196)
578  actions::shroud_clearer clearer;
579  clearer.clear_unit(loc, *created);
580  clearer.fire_events();
581  if (unit_it.valid() ) // In case sighted events messed with the unit.
582  actions::actor_sighted(*unit_it);
583 
584  return true;
585 }
586 
587 SYNCED_COMMAND_HANDLER_FUNCTION(debug_lua, child, use_undo, /*show*/, /*error_handler*/)
588 {
589  if(use_undo) {
591  }
592  debug_cmd_notification("lua");
593  resources::lua_kernel->run(child["code"].str().c_str(), "debug command");
595 
596  return true;
597 }
598 
599 SYNCED_COMMAND_HANDLER_FUNCTION(debug_kill, child, use_undo, /*show*/, /*error_handler*/)
600 {
601  if (use_undo) {
603  }
604  debug_cmd_notification("kill");
605 
606  const map_location loc(child["x"].to_int(), child["y"].to_int(), wml_loc());
608  if (i != resources::gameboard->units().end()) {
609  const int dying_side = i->side();
610  resources::controller->pump().fire("last_breath", loc, loc);
611  if (i.valid()) {
612  unit_display::unit_die(loc, *i);
613  }
615  if (i.valid()) {
616  i->set_hitpoints(0);
617  }
618  resources::controller->pump().fire("die", loc, loc);
619  if (i.valid()) {
621  }
622  resources::whiteboard->on_kill_unit();
623  actions::recalculate_fog(dying_side);
624  }
625  return true;
626 }
627 
628 SYNCED_COMMAND_HANDLER_FUNCTION(debug_next_level, child, use_undo, /*show*/, /*error_handler*/)
629 {
630  if(use_undo) {
632  }
633 
634  debug_cmd_notification("next_level");
635 
636  std::string next_level = child["next_level"];
637  if (!next_level.empty())
640  e.transient.carryover_report = false;
641  e.prescenario_save = true;
642  e.transient.linger_mode = false;
643  e.proceed_to_next_level = true;
644  e.is_victory = true;
645 
648 
649  return true;
650 }
651 
652 SYNCED_COMMAND_HANDLER_FUNCTION(debug_turn_limit, child, use_undo, /*show*/, /*error_handler*/)
653 {
654  if(use_undo) {
656  }
657 
658  debug_cmd_notification("turn_limit");
659 
660  resources::tod_manager->set_number_of_turns(child["turn_limit"].to_int(-1));
662  return true;
663 }
664 
665 SYNCED_COMMAND_HANDLER_FUNCTION(debug_turn, child, use_undo, /*show*/, /*error_handler*/)
666 {
667  if(use_undo) {
669  }
670 
671  debug_cmd_notification("turn");
672 
673  resources::tod_manager->set_turn(child["turn"].to_int(1), resources::gamedata);
674 
677 
678  return true;
679 }
680 
681 SYNCED_COMMAND_HANDLER_FUNCTION(debug_set_var, child, use_undo, /*show*/, /*error_handler*/)
682 {
683  if(use_undo) {
685  }
686 
687  debug_cmd_notification("set_var");
688 
689  try {
690  resources::gamedata->set_variable(child["name"],child["value"]);
691  }
692  catch(const invalid_variablename_exception&) {
693  // command_failed(_("Variable not found"));
694  return false;
695  }
696  return true;
697 }
698 
699 SYNCED_COMMAND_HANDLER_FUNCTION(debug_gold, child, use_undo, /*show*/, /*error_handler*/)
700 {
701  if(use_undo) {
703  }
704 
705  debug_cmd_notification("gold");
706 
707  resources::controller->current_team().spend_gold(-child["gold"].to_int(0));
709  return true;
710 }
711 
712 
713 SYNCED_COMMAND_HANDLER_FUNCTION(debug_event, child, use_undo, /*show*/, /*error_handler*/)
714 {
715  if(use_undo) {
717  }
718 
719  debug_cmd_notification("throw");
720 
721  resources::controller->pump().fire(child["eventname"]);
723 
724  return true;
725 }
726 
727 
728 SYNCED_COMMAND_HANDLER_FUNCTION(debug_fog, /*child*/, use_undo, /*show*/, /*error_handler*/)
729 {
730  if(use_undo) {
732  }
733 
734  debug_cmd_notification("fog");
735 
736  team& current_team = resources::controller->current_team();
737  current_team.set_fog(!current_team.uses_fog());
738  actions::recalculate_fog(current_team.side());
739 
742 
743  return true;
744 }
745 
746 
747 SYNCED_COMMAND_HANDLER_FUNCTION(debug_shroud, /*child*/, use_undo, /*show*/, /*error_handler*/)
748 {
749  if(use_undo) {
751  }
752 
753  debug_cmd_notification("shroud");
754 
755  team& current_team = resources::controller->current_team();
756  current_team.set_shroud(!current_team.uses_shroud());
757  actions::clear_shroud(current_team.side());
758 
761 
762  return true;
763 }
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:1556
Various functions that implement attacks and attack calculations.
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:148
bool commit_vision()
Updates fog/shroud based on the undo stack, then updates stack as needed.
Definition: undo.cpp:224
void clear()
Clears the stack of undoable (and redoable) actions.
Definition: undo.cpp:201
void add_dummy()
Adds an auto-shroud toggle to the undo stack.
Definition: undo.cpp:140
void add_auto_shroud(bool turned_on)
Adds an auto-shroud toggle to the undo stack.
Definition: undo.cpp:135
void add_update_shroud()
Adds a shroud update to the undo stack.
Definition: undo.cpp:188
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
void recalculate_minimap()
Schedule the minimap for recalculation.
Definition: display.cpp:1652
void redraw_minimap()
Schedule the minimap to be redrawn.
Definition: display.cpp:1673
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:3137
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:1636
void queue_rerender()
Marks everything for rendering including all tiles and sidebar.
Definition: display.cpp:2320
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:95
bool change_terrain(const map_location &loc, const std::string &t, const std::string &mode, bool replace_if_failed)
Definition: game_board.cpp:327
team & get_team(int i)
Definition: game_board.hpp:91
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:106
void set_next_scenario(const std::string &next_scenario)
Definition: game_data.hpp:131
void set_variable(const std::string &varname, const t_string &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:253
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.
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 bool undo_blocked()
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:74
bool uses_shroud() const
Definition: team.hpp:303
int side() const
Definition: team.hpp:174
void set_shroud(bool shroud)
Definition: team.hpp:311
bool auto_shroud_updates() const
Definition: team.hpp:324
void set_auto_shroud_updates(bool value)
Definition: team.hpp:325
int gold() const
Definition: team.hpp:175
bool is_network_ai() const
Definition: team.hpp:256
bool is_local_ai() const
Definition: team.hpp:254
void set_fog(bool fog)
Definition: team.hpp:312
void spend_gold(const int amount)
Definition: team.hpp:194
bool uses_fog() const
Definition: team.hpp:304
recall_list_manager & recall_list()
Definition: team.hpp:201
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)
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:216
unit_iterator find(std::size_t id)
Definition: map.cpp:302
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(unit_ptr p)
Inserts the unit pointed to by p into the map.
Definition: map.cpp:135
@ NUM_GENDERS
Definition: race.hpp:27
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:1266
A single unit type that the player may recruit.
Definition: types.hpp:43
int cost() const
Definition: types.hpp:172
static unit_ptr create(const config &cfg, bool use_traits=false, const vconfig *vcfg=nullptr)
Initializes a unit from a config.
Definition: unit.hpp:201
Various functions related to the creation of units (recruits, recalls, and placed units).
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
std::size_t i
Definition: function.cpp:968
#define N_(String)
Definition: gettext.hpp:101
static std::string _(const char *str)
Definition: gettext.hpp:93
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:442
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 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:716
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:749
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
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:617
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:744
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
void recalculate_fog(int side)
Function that recalculates the fog of war.
Definition: vision.cpp:700
void pump()
Process all events currently in the queue.
Definition: events.cpp:478
const color_t NORMAL_COLOR
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:79
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 custom_command()
Definition: game.cpp:923
bool skip_ai_moves()
Definition: game.cpp:728
::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_recruited(const map_location &loc, const map_location &leader_loc)
Definition: udisplay.cpp:800
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:570
std::map< std::string, t_string > string_map
std::vector< std::string > split(const config_attribute_value &val)
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:150
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:605
Additional information on the game outcome which can be provided by WML.
Encapsulates the map of the game.
Definition: location.hpp:38
bool valid() const
Definition: location.hpp:89
bool valid() const
Definition: map.hpp:273
#define WRN_REPLAY
SYNCED_COMMAND_HANDLER_FUNCTION(recruit, child, use_undo, show, error_handler)
#define DBG_REPLAY
static lg::log_domain log_replay("replay")
#define LOG_REPLAY
#define ERR_REPLAY
unit_type_data unit_types
Definition: types.cpp:1485
Display units performing various actions: moving, attacking, and dying.
Various functions that implement the undoing (and redoing) of in-game commands.
#define e