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