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  if(const auto last_select = child.optional_child("last_select"))
327  {
328  //the select event cannot clear the undo stack.
329  resources::game_events->pump().fire("select", map_location(last_select.value(), resources::gamedata));
330  }
331  const std::string &event_name = child["raise"];
332  if (const auto source = child.optional_child("source")) {
333  synced_context::block_undo(std::get<0>(resources::game_events->pump().fire(event_name, map_location(source.value(), resources::gamedata))));
334  } else {
335  synced_context::block_undo(std::get<0>(resources::game_events->pump().fire(event_name)));
336  }
337 
338  // Not clearing the undo stack here causes OOS because we added an entry to the replay but no entry to the undo stack.
339  if(use_undo) {
342  } else {
344  }
345  }
346  return true;
347 }
348 
349 SYNCED_COMMAND_HANDLER_FUNCTION(custom_command, child, use_undo, /*show*/, /*error_handler*/)
350 {
351  assert(resources::lua_kernel);
352  resources::lua_kernel->custom_command(child["name"], child.child_or_empty("data"));
353  if(use_undo) {
356  } else {
358  }
359  }
360  return true;
361 }
362 
363 SYNCED_COMMAND_HANDLER_FUNCTION(auto_shroud, child, use_undo, /*show*/, /*error_handler*/)
364 {
365  assert(use_undo);
366  team &current_team = resources::controller->current_team();
367 
368  bool active = child["active"].to_bool();
369  if(active && !current_team.auto_shroud_updates()) {
371  }
372  current_team.set_auto_shroud_updates(active);
373  if(resources::undo_stack->can_undo()) {
375  }
376  return true;
377 }
378 
379 SYNCED_COMMAND_HANDLER_FUNCTION(update_shroud, /*child*/, use_undo, /*show*/, error_handler)
380 {
381  // When "updating shroud now" is used.
382  // Updates fog/shroud based on the undo stack, then updates stack as needed.
383  // This may fire events and change the game state.
384 
385  assert(use_undo);
386  team &current_team = resources::controller->current_team();
387  if(current_team.auto_shroud_updates()) {
388  error_handler("Team has DSU disabled but we found an explicit shroud update");
389  }
390  bool res = resources::undo_stack->commit_vision();
392  if(res) {
394  }
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 = 0;
482  try {
483  int_value = std::stoi(value);
484  } catch (const std::invalid_argument&) {
485  WRN_REPLAY << "Warning: Invalid unit advancement argument: " << value;
486  return false;
487  }
488  for (int levels=0; levels<int_value; levels++) {
489  i->set_experience(i->max_experience());
490 
491  advance_unit_at(advance_unit_params(loc).force_dialog(true));
492  i = resources::gameboard->units().find(loc);
493  if (!i.valid()) {
494  break;
495  }
496  }
497  } else if (name == "status" ) {
498  for (std::string status : utils::split(value)) {
499  bool add = true;
500  if (status.length() >= 1 && status[0] == '-') {
501  add = false;
502  status = status.substr(1);
503  }
504  if (status.empty()) {
505  continue;
506  }
507  i->set_state(status, add);
508  }
509  } else {
510  config cfg;
511  i->write(cfg);
512  cfg[name] = value;
513 
514  // Attempt to create a new unit. If there are error (such an invalid type key), exit.
515  try{
516  unit_ptr new_u = unit::create(cfg, true);
517  new_u->set_location(loc);
518  // Don't remove the unit until after we've verified there are no errors in creating the new one,
519  // or else the unit would simply be removed from the map with no replacement.
521  resources::whiteboard->on_kill_unit();
523  } catch(const unit_type::error& e) {
524  ERR_REPLAY << e.what(); // TODO: more appropriate error message log
525  return false;
526  }
527  }
528  if (name == "fail") { //testcase for bug #18488
529  assert(i.valid());
530  }
533 
534  return true;
535 }
536 
537 SYNCED_COMMAND_HANDLER_FUNCTION(debug_create_unit, child, use_undo, /*show*/, error_handler)
538 {
539  if(use_undo) {
541  }
542 
543  debug_notification(N_("A unit was created using debug mode during $player’s turn"));
544  map_location loc(child);
545  resources::whiteboard->on_kill_unit();
546  const std::string& variation = child["variation"].str();
547  const unit_race::GENDER gender = string_gender(child["gender"], unit_race::NUM_GENDERS);
548  const unit_type *u_type = unit_types.find(child["type"]);
549  if (!u_type) {
550  error_handler("Invalid unit type");
551  return false;
552  }
553 
554  const int side_num = resources::controller
556 
557  // Create the unit.
558  unit_ptr created = unit::create(*u_type, side_num, true, gender, variation);
559  created->new_turn();
560 
561  unit_map::unit_iterator unit_it;
562 
563  // Add the unit to the board.
564  std::tie(unit_it, std::ignore) = resources::gameboard->units().replace(loc, created);
565 
567  resources::game_events->pump().fire("unit_placed", loc);
569 
570  // Village capture?
571  if ( resources::gameboard->map().is_village(loc) )
572  actions::get_village(loc, created->side());
573 
574  // Update fog/shroud.
575  // Not checking auto_shroud_updates() here since :create is not undoable. (#2196)
576  actions::shroud_clearer clearer;
577  clearer.clear_unit(loc, *created);
578  clearer.fire_events();
579  if (unit_it.valid() ) // In case sighted events messed with the unit.
580  actions::actor_sighted(*unit_it);
581 
582  return true;
583 }
584 
585 SYNCED_COMMAND_HANDLER_FUNCTION(debug_lua, child, use_undo, /*show*/, /*error_handler*/)
586 {
587  if(use_undo) {
589  }
590  debug_cmd_notification("lua");
591  resources::lua_kernel->run(child["code"].str().c_str(), "debug command");
593 
594  return true;
595 }
596 
597 SYNCED_COMMAND_HANDLER_FUNCTION(debug_teleport, child, use_undo, /*show*/, /*error_handler*/)
598 {
599  if(use_undo) {
601  }
602  debug_cmd_notification("teleport");
603 
604  const map_location teleport_from(child["teleport_from_x"].to_int(), child["teleport_from_y"].to_int(), wml_loc());
605  const map_location teleport_to(child["teleport_to_x"].to_int(), child["teleport_to_y"].to_int(), wml_loc());
606 
607  const unit_map::iterator unit_iter = resources::gameboard->units().find(teleport_from);
608  if(unit_iter != resources::gameboard->units().end()) {
609  if(unit_iter.valid()) {
610  actions::teleport_unit_from_replay({teleport_from, teleport_to}, false, false, false);
611  }
613  }
614 
615  return true;
616 }
617 
618 SYNCED_COMMAND_HANDLER_FUNCTION(debug_kill, child, use_undo, /*show*/, /*error_handler*/)
619 {
620  if (use_undo) {
622  }
623  debug_cmd_notification("kill");
624 
625  const map_location loc(child["x"].to_int(), child["y"].to_int(), wml_loc());
627  if (i != resources::gameboard->units().end()) {
628  const int dying_side = i->side();
629  resources::controller->pump().fire("last_breath", loc, loc);
630  if (i.valid()) {
631  unit_display::unit_die(loc, *i);
632  }
634  if (i.valid()) {
635  i->set_hitpoints(0);
636  }
637  resources::controller->pump().fire("die", loc, loc);
638  if (i.valid()) {
640  }
641  resources::whiteboard->on_kill_unit();
642  actions::recalculate_fog(dying_side);
643  }
644  return true;
645 }
646 
647 SYNCED_COMMAND_HANDLER_FUNCTION(debug_next_level, child, use_undo, /*show*/, /*error_handler*/)
648 {
649  if(use_undo) {
651  }
652 
653  debug_cmd_notification("next_level");
654 
655  std::string next_level = child["next_level"];
656  if (!next_level.empty())
659  e.transient.carryover_report = false;
660  e.prescenario_save = true;
661  e.transient.linger_mode = false;
662  e.proceed_to_next_level = true;
663  e.is_victory = true;
664 
667 
668  return true;
669 }
670 
671 SYNCED_COMMAND_HANDLER_FUNCTION(debug_turn_limit, child, use_undo, /*show*/, /*error_handler*/)
672 {
673  if(use_undo) {
675  }
676 
677  debug_cmd_notification("turn_limit");
678 
679  resources::tod_manager->set_number_of_turns(child["turn_limit"].to_int(-1));
681  return true;
682 }
683 
684 SYNCED_COMMAND_HANDLER_FUNCTION(debug_turn, child, use_undo, /*show*/, /*error_handler*/)
685 {
686  if(use_undo) {
688  }
689 
690  debug_cmd_notification("turn");
691 
692  resources::tod_manager->set_turn(child["turn"].to_int(1), resources::gamedata);
693 
696 
697  return true;
698 }
699 
700 SYNCED_COMMAND_HANDLER_FUNCTION(debug_set_var, child, use_undo, /*show*/, /*error_handler*/)
701 {
702  if(use_undo) {
704  }
705 
706  debug_cmd_notification("set_var");
707 
708  try {
709  resources::gamedata->set_variable(child["name"],child["value"]);
710  }
711  catch(const invalid_variablename_exception&) {
712  // command_failed(_("Variable not found"));
713  return false;
714  }
715  return true;
716 }
717 
718 SYNCED_COMMAND_HANDLER_FUNCTION(debug_gold, child, use_undo, /*show*/, /*error_handler*/)
719 {
720  if(use_undo) {
722  }
723 
724  debug_cmd_notification("gold");
725 
726  resources::controller->current_team().spend_gold(-child["gold"].to_int(0));
728  return true;
729 }
730 
731 
732 SYNCED_COMMAND_HANDLER_FUNCTION(debug_event, child, use_undo, /*show*/, /*error_handler*/)
733 {
734  if(use_undo) {
736  }
737 
738  debug_cmd_notification("throw");
739 
740  resources::controller->pump().fire(child["eventname"]);
742 
743  return true;
744 }
745 
746 
747 SYNCED_COMMAND_HANDLER_FUNCTION(debug_fog, /*child*/, use_undo, /*show*/, /*error_handler*/)
748 {
749  if(use_undo) {
751  }
752 
753  debug_cmd_notification("fog");
754 
755  team& current_team = resources::controller->current_team();
756  current_team.set_fog(!current_team.uses_fog());
757  actions::recalculate_fog(current_team.side());
758 
761 
762  return true;
763 }
764 
765 
766 SYNCED_COMMAND_HANDLER_FUNCTION(debug_shroud, /*child*/, use_undo, /*show*/, /*error_handler*/)
767 {
768  if(use_undo) {
770  }
771 
772  debug_cmd_notification("shroud");
773 
774  team& current_team = resources::controller->current_team();
775  current_team.set_shroud(!current_team.uses_shroud());
776  actions::clear_shroud(current_team.side());
777 
780 
781  return true;
782 }
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:1610
void redraw_minimap()
Schedule the minimap to be redrawn.
Definition: display.cpp:1631
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:3145
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:1594
void queue_rerender()
Marks everything for rendering including all tiles and sidebar.
Definition: display.cpp:2324
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: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()
static void block_undo(bool do_block=true)
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:1267
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
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:1320
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:1392
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:65
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:623
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:1486
Display units performing various actions: moving, attacking, and dying.
Various functions that implement the undoing (and redoing) of in-game commands.
#define e