The Battle for Wesnoth  1.19.7+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"
31 #include "game_events/pump.hpp"
32 #include "map/map.hpp"
33 #include "recall_list_manager.hpp"
34 #include "resources.hpp"
35 #include "savegame.hpp"
37 #include "formula/string_utils.hpp"
38 #include "units/types.hpp"
39 #include "units/udisplay.hpp"
40 #include "whiteboard/manager.hpp"
41 #include "font/standard_colors.hpp"
42 
43 static lg::log_domain log_replay("replay");
44 #define DBG_REPLAY LOG_STREAM(debug, log_replay)
45 #define LOG_REPLAY LOG_STREAM(info, log_replay)
46 #define WRN_REPLAY LOG_STREAM(warn, log_replay)
47 #define ERR_REPLAY LOG_STREAM(err, log_replay)
48 
49 
50 /**
51  * @param[in] tag The replay tag for this action.
52  * @param[in] function The callback for this action.
53  */
54 synced_command::synced_command(const std::string & tag, handler function)
55 {
56  assert(registry().find( tag ) == registry().end());
57  registry()[tag] = function;
58 }
59 
61 {
62  //Use a pointer to ensure that this object is not destructed when the program ends.
63  static map* instance = new map();
64  return *instance;
65 }
66 
67 
68 SYNCED_COMMAND_HANDLER_FUNCTION(recruit, child, spectator)
69 {
70  int current_team_num = resources::controller->current_side();
71  team &current_team = resources::gameboard->get_team(current_team_num);
72 
74  map_location from(child.child_or_empty("from"), resources::gamedata);
75  // Validate "from".
76  if ( !from.valid() ) {
77  // This will be the case for AI recruits in replays saved
78  // before 1.11.2, so it is not more severe than a warning.
79  // EDIT: we broke compatibility with 1.11.2 anyway so we should give an error.
80  spectator.error("Missing leader location for recruitment.\n");
81  }
82  else if ( resources::gameboard->units().find(from) == resources::gameboard->units().end() ) {
83  // Sync problem?
84  std::stringstream errbuf;
85  errbuf << "Recruiting leader not found at " << from << ".\n";
86  spectator.error(errbuf.str());
87  }
88 
89  // Get the unit_type ID.
90  std::string type_id = child["type"];
91  if ( type_id.empty() ) {
92  spectator.error("Recruitment is missing a unit type.");
93  return false;
94  }
95 
96  const unit_type *u_type = unit_types.find(type_id);
97  if (!u_type) {
98  std::stringstream errbuf;
99  errbuf << "Recruiting illegal unit: '" << type_id << "'.\n";
100  spectator.error(errbuf.str());
101  return false;
102  }
103 
104  const std::string res = actions::find_recruit_location(current_team_num, loc, from, type_id);
105  if(!res.empty())
106  {
107  std::stringstream errbuf;
108  errbuf << "cannot recruit unit: " << res << "\n";
109  spectator.error(errbuf.str());
110  return false;
111  //we are already oos because the unit wasn't created, no need to keep the bookkeeping right...
112  }
113  const int beginning_gold = current_team.gold();
114 
115 
116 
117  if ( u_type->cost() > beginning_gold ) {
118  std::stringstream errbuf;
119  errbuf << "unit '" << type_id << "' is too expensive to recruit: "
120  << u_type->cost() << "/" << beginning_gold << "\n";
121  spectator.error(errbuf.str());
122  }
123 
124  actions::recruit_unit(*u_type, current_team_num, loc, from);
125 
126  LOG_REPLAY << "recruit: team=" << current_team_num << " '" << type_id << "' at (" << loc
127  << ") cost=" << u_type->cost() << " from gold=" << beginning_gold << ' '
128  << "-> " << current_team.gold();
129  return true;
130 }
131 
132 SYNCED_COMMAND_HANDLER_FUNCTION(recall, child, spectator)
133 {
134  int current_team_num = resources::controller->current_side();
135  team &current_team = resources::gameboard->get_team(current_team_num);
136 
137  const std::string& unit_id = child["value"];
139  map_location from(child.child_or_empty("from"), resources::gamedata);
140 
141  if(!actions::recall_unit(unit_id, current_team, loc, from, map_location::direction::indeterminate)) {
142  spectator.error("illegal recall: unit_id '" + unit_id + "' could not be found within the recall list.\n");
143  //when recall_unit returned false nothing happened so we can safety return false;
144  return false;
145  }
146  return true;
147 }
148 
149 SYNCED_COMMAND_HANDLER_FUNCTION(attack, child, spectator)
150 {
151  const auto destination = child.optional_child("destination");
152  const auto source = child.optional_child("source");
153  //check_checksums(*cfg);
154 
155  if (!destination) {
156  spectator.error("no destination found in attack\n");
157  return false;
158  }
159 
160  if (!source) {
161  spectator.error("no source found in attack \n");
162  return false;
163  }
164 
165  //we must get locations by value instead of by references, because the iterators
166  //may become invalidated later
167  const map_location src(source.value(), resources::gamedata);
168  const map_location dst(destination.value(), resources::gamedata);
169 
170  int weapon_num = child["weapon"].to_int();
171  // having defender_weapon in the replay fixes a bug (OOS) where one player (or observer) chooses a different defensive weapon.
172  // Xan pointed out this was a possibility: we calculate defense weapon
173  // now based on attack_prediction code, but this uses floating point
174  // calculations, which means that in the case where results are close,
175  // rounding differences can mean that both ends choose different weapons.
176  int def_weapon_num = child["defender_weapon"].to_int(-2);
177  if (def_weapon_num == -2) {
178  // Let's not gratuitously destroy backwards compatibility.
179  LOG_REPLAY << "Old data, having to guess weapon";
180  def_weapon_num = -1;
181  }
182 
184  if (!u.valid()) {
185  spectator.error("unfound location for source of attack\n");
186  return false;
187  }
188 
189  if (child.has_attribute("attacker_type")) {
190  const std::string &att_type_id = child["attacker_type"];
191  if (u->type_id() != att_type_id) {
192  WRN_REPLAY << "unexpected attacker type: " << att_type_id << "(game state gives: " << u->type_id() << ")";
193  }
194  }
195 
196  if (static_cast<unsigned>(weapon_num) >= u->attacks().size()) {
197  spectator.error("illegal weapon type in attack\n");
198  return false;
199  }
200 
202 
203  if (!tgt.valid()) {
204  std::stringstream errbuf;
205  errbuf << "unfound defender for attack: " << src << " -> " << dst << '\n';
206  spectator.error(errbuf.str());
207  return false;
208  }
209 
210  if (child.has_attribute("defender_type")) {
211  const std::string &def_type_id = child["defender_type"];
212  if (tgt->type_id() != def_type_id) {
213  WRN_REPLAY << "unexpected defender type: " << def_type_id << "(game state gives: " << tgt->type_id() << ")";
214  }
215  }
216 
217  if (def_weapon_num >= static_cast<int>(tgt->attacks().size())) {
218 
219  spectator.error("illegal defender weapon type in attack\n");
220  return false;
221  }
222 
223  DBG_REPLAY << "Attacker XP (before attack): " << u->experience();
224 
227  attack_unit_and_advance(src, dst, weapon_num, def_weapon_num, show);
228  return true;
229 }
230 
231 SYNCED_COMMAND_HANDLER_FUNCTION(disband, child, spectator)
232 {
233 
234  team& current_team = resources::controller->current_team();
235 
236  const std::string& unit_id = child["value"];
237  std::size_t old_size = current_team.recall_list().size();
238 
239  // Find the unit in the recall list.
240  unit_ptr dismissed_unit = current_team.recall_list().find_if_matches_id(unit_id);
241  if (!dismissed_unit) {
242  spectator.error("illegal disband\n");
243  return false;
244  }
245  //add dismissal to the undo stack
246  resources::undo_stack->add_dismissal(dismissed_unit);
247 
248  current_team.recall_list().erase_if_matches_id(unit_id);
249 
250  if (old_size == current_team.recall_list().size()) {
251  spectator.error("illegal disband\n");
252  return false;
253  }
254  return true;
255 }
256 
257 SYNCED_COMMAND_HANDLER_FUNCTION(move, child, spectator)
258 {
259  team& current_team = resources::controller->current_team();
260 
261  std::vector<map_location> steps;
262 
263  try {
264  read_locations(child,steps);
265  } catch (const std::invalid_argument&) {
266  WRN_REPLAY << "Warning: Path data contained something which could not be parsed to a sequence of locations:" << "\n config = " << child.debug();
267  return false;
268  }
269 
270  if(steps.empty())
271  {
272  WRN_REPLAY << "Warning: Missing path data found in [move]";
273  return false;
274  }
275 
276  const map_location& src = steps.front();
277  const map_location& dst = steps.back();
278 
279  if (src == dst) {
280  WRN_REPLAY << "Warning: Move with identical source and destination. Skipping...";
281  return false;
282  }
283 
284  // The nominal destination should appear to be unoccupied.
286  if ( u.valid() ) {
287  WRN_REPLAY << "Warning: Move destination " << dst << " appears occupied.";
288  // We'll still proceed with this movement, though, since
289  // an event might intervene.
290  // 'event' doesn't mean wml event but rather it means 'hidden' units form the movers point of view.
291  }
292 
294  if (!u.valid()) {
295  std::stringstream errbuf;
296  errbuf << "unfound location for source of movement: "
297  << src << " -> " << dst << '\n';
298  spectator.error(errbuf.str());
299  return false;
300  }
301 
302  bool skip_sighted = child["skip_sighted"] == "all";
303  bool skip_ally_sighted = child["skip_sighted"] == "only_ally";
304 
305  actions::execute_move_unit(steps, skip_sighted, skip_ally_sighted, dynamic_cast<actions::move_unit_spectator*>(&spectator));
306 
307  return true;
308 }
309 
311 {
312  if(const auto last_select = child.optional_child("last_select"))
313  {
314  //the select event cannot clear the undo stack.
315  resources::game_events->pump().fire("select", map_location(last_select.value(), resources::gamedata));
316  }
317  const std::string &event_name = child["raise"];
318  if (const auto source = child.optional_child("source")) {
319  synced_context::block_undo(std::get<0>(resources::game_events->pump().fire(event_name, map_location(source.value(), resources::gamedata))));
320  } else {
321  synced_context::block_undo(std::get<0>(resources::game_events->pump().fire(event_name)));
322  }
323 
324  return true;
325 }
326 
327 SYNCED_COMMAND_HANDLER_FUNCTION(custom_command, child, /*spectator*/)
328 {
329  assert(resources::lua_kernel);
330  resources::lua_kernel->custom_command(child["name"], child.child_or_empty("data"));
331 
332  return true;
333 }
334 
335 SYNCED_COMMAND_HANDLER_FUNCTION(auto_shroud, child, /*spectator*/)
336 {
337  team &current_team = resources::controller->current_team();
338 
339  bool active = child["active"].to_bool();
340  if(active && !current_team.auto_shroud_updates()) {
342  }
343  current_team.set_auto_shroud_updates(active);
344  if(resources::undo_stack->can_undo()) {
346  }
347  return true;
348 }
349 
350 SYNCED_COMMAND_HANDLER_FUNCTION(update_shroud, /*child*/, spectator)
351 {
352  // When "updating shroud now" is used.
353  // Updates fog/shroud based on the undo stack, then updates stack as needed.
354  // This may fire events and change the game state.
355 
356  team &current_team = resources::controller->current_team();
357  if(current_team.auto_shroud_updates()) {
358  spectator.error("Team has DSU disabled but we found an explicit shroud update");
359  }
360  bool res = resources::undo_stack->commit_vision();
361  if(res) {
363  }
364  return true;
365 }
366 
367 namespace
368 {
369  void debug_notification(const std::string& text, bool message_is_command = false)
370  {
372  auto& current_team = controller.current_team();
373  static bool ignore = false;
374  bool show_long_message = controller.is_replay() || !current_team.is_local();
375 
376  std::string message;
377  utils::string_map i18n_vars = {{ "player", current_team.current_player() }};
378 
379  if(i18n_vars["player"].empty()) {
380  i18n_vars["player"] = _("(unknown player)");
381  }
382 
383  if(message_is_command) {
384  i18n_vars["command"] = text;
385  message = VGETTEXT("The :$command debug command was used during $player’s turn", i18n_vars);
386  } else {
387  message = VGETTEXT(text.c_str(), i18n_vars);
388  }
389 
390  if(show_long_message && !ignore) {
392  std::stringstream sbuilder;
393  sbuilder << _("A player used a debug command during the game. If this is unexpected, it is possible the player in question is cheating.")
394  << "\n\n"
395  << _("Details:") << "\n"
396  << message
397  << "\n\n"
398  << _("Do you wish to save the game before continuing?");
399  savegame::oos_savegame save(controller.get_saved_game(), ignore);
400  save.set_title(_("Debug Command Used"));
401  save.save_game_interactive(sbuilder.str(), savegame::savegame::YES_NO); // can throw quit_game_exception
402  }
403  else {
404  display::announce_options announce_options;
405  display::get_singleton()->announce(message, font::NORMAL_COLOR, announce_options);
406  }
407  }
408 
409  void debug_cmd_notification(const std::string& command)
410  {
411  debug_notification(command, true);
412  }
413 }
414 
415 SYNCED_COMMAND_HANDLER_FUNCTION(debug_terrain, child, /*spectator*/)
416 {
418  debug_cmd_notification("terrain");
419 
420  map_location loc(child);
421  const std::string& terrain_type = child["terrain_type"];
422  const std::string& mode_str = child["mode_str"];
423 
424  bool result = resources::gameboard->change_terrain(loc, terrain_type, mode_str, false);
425  if(result) {
429  }
430  return true;
431 }
432 
433 SYNCED_COMMAND_HANDLER_FUNCTION(debug_unit, child, /*spectator*/)
434 {
436  debug_cmd_notification("unit");
437  map_location loc(child);
438  const std::string name = child["name"];
439  const std::string value = child["value"];
440 
442  if (i == resources::gameboard->units().end()) {
443  return false;
444  }
445  if (name == "advances" ) {
446  int int_value = 0;
447  try {
448  int_value = std::stoi(value);
449  } catch (const std::invalid_argument&) {
450  WRN_REPLAY << "Warning: Invalid unit advancement argument: " << value;
451  return false;
452  }
453  for (int levels=0; levels<int_value; levels++) {
454  i->set_experience(i->max_experience());
455 
456  advance_unit_at(advance_unit_params(loc).force_dialog(true));
458  if (!i.valid()) {
459  break;
460  }
461  }
462  } else if (name == "status" ) {
463  for (std::string status : utils::split(value)) {
464  bool add = true;
465  if (status.length() >= 1 && status[0] == '-') {
466  add = false;
467  status = status.substr(1);
468  }
469  if (status.empty()) {
470  continue;
471  }
472  i->set_state(status, add);
473  }
474  } else {
475  config cfg;
476  i->write(cfg);
477  cfg[name] = value;
478 
479  // Attempt to create a new unit. If there are error (such an invalid type key), exit.
480  try{
481  unit_ptr new_u = unit::create(cfg, true);
482  new_u->set_location(loc);
483  // Don't remove the unit until after we've verified there are no errors in creating the new one,
484  // or else the unit would simply be removed from the map with no replacement.
486  resources::whiteboard->on_kill_unit();
488  } catch(const unit_type::error& e) {
489  ERR_REPLAY << e.what(); // TODO: more appropriate error message log
490  return false;
491  }
492  }
493  if (name == "fail") { //testcase for bug #18488
494  assert(i.valid());
495  }
498 
499  return true;
500 }
501 
502 SYNCED_COMMAND_HANDLER_FUNCTION(debug_create_unit, child, spectator)
503 {
505 
506  debug_notification(N_("A unit was created using debug mode during $player’s turn"));
507  map_location loc(child);
508  resources::whiteboard->on_kill_unit();
509  const std::string& variation = child["variation"].str();
510  const unit_race::GENDER gender = string_gender(child["gender"], unit_race::NUM_GENDERS);
511  const unit_type *u_type = unit_types.find(child["type"]);
512  if (!u_type) {
513  spectator.error("Invalid unit type");
514  return false;
515  }
516 
517  const int side_num = resources::controller
519 
520  // Create the unit.
521  unit_ptr created = unit::create(*u_type, side_num, true, gender, variation);
522  created->new_turn();
523 
524  unit_map::unit_iterator unit_it;
525 
526  // Add the unit to the board.
527  std::tie(unit_it, std::ignore) = resources::gameboard->units().replace(loc, created);
528 
530  resources::game_events->pump().fire("unit_placed", loc);
532 
533  // Village capture?
534  if ( resources::gameboard->map().is_village(loc) )
535  actions::get_village(loc, created->side());
536 
537  // Update fog/shroud.
538  // Not checking auto_shroud_updates() here since :create is not undoable. (#2196)
539  actions::shroud_clearer clearer;
540  clearer.clear_unit(loc, *created);
541  clearer.fire_events();
542  if (unit_it.valid() ) // In case sighted events messed with the unit.
543  actions::actor_sighted(*unit_it);
544 
545  return true;
546 }
547 
549 {
551  debug_cmd_notification("lua");
552  resources::lua_kernel->run(child["code"].str().c_str(), "debug command");
554 
555  return true;
556 }
557 
558 SYNCED_COMMAND_HANDLER_FUNCTION(debug_teleport, child, /*spectator*/)
559 {
561  debug_cmd_notification("teleport");
562 
563  const map_location teleport_from(child["teleport_from_x"].to_int(), child["teleport_from_y"].to_int(), wml_loc());
564  const map_location teleport_to(child["teleport_to_x"].to_int(), child["teleport_to_y"].to_int(), wml_loc());
565 
566  const unit_map::iterator unit_iter = resources::gameboard->units().find(teleport_from);
567  if(unit_iter != resources::gameboard->units().end()) {
568  if(unit_iter.valid()) {
569  actions::teleport_unit_from_replay({teleport_from, teleport_to}, false, false, false);
570  }
572  }
573 
574  return true;
575 }
576 
577 SYNCED_COMMAND_HANDLER_FUNCTION(debug_kill, child, /*spectator*/)
578 {
580  debug_cmd_notification("kill");
581 
582  const map_location loc(child["x"].to_int(), child["y"].to_int(), wml_loc());
584  if (i != resources::gameboard->units().end()) {
585  const int dying_side = i->side();
586  resources::controller->pump().fire("last_breath", loc, loc);
587  if (i.valid()) {
589  }
591  if (i.valid()) {
592  i->set_hitpoints(0);
593  }
594  resources::controller->pump().fire("die", loc, loc);
595  if (i.valid()) {
597  }
598  resources::whiteboard->on_kill_unit();
599  actions::recalculate_fog(dying_side);
600  }
601  return true;
602 }
603 
604 SYNCED_COMMAND_HANDLER_FUNCTION(debug_next_level, child, /*spectator*/)
605 {
607 
608  debug_cmd_notification("next_level");
609 
610  std::string next_level = child["next_level"];
611  if (!next_level.empty())
614  e.transient.carryover_report = false;
615  e.prescenario_save = true;
616  e.transient.linger_mode = false;
617  e.proceed_to_next_level = true;
618  e.is_victory = true;
619 
622 
623  return true;
624 }
625 
626 SYNCED_COMMAND_HANDLER_FUNCTION(debug_turn_limit, child, /*spectator*/)
627 {
629 
630  debug_cmd_notification("turn_limit");
631 
632  resources::tod_manager->set_number_of_turns(child["turn_limit"].to_int(-1));
634  return true;
635 }
636 
637 SYNCED_COMMAND_HANDLER_FUNCTION(debug_turn, child, /*spectator*/)
638 {
640 
641  debug_cmd_notification("turn");
642 
643  resources::tod_manager->set_turn(child["turn"].to_int(1), resources::gamedata);
644 
647 
648  return true;
649 }
650 
651 SYNCED_COMMAND_HANDLER_FUNCTION(debug_set_var, child, /*spectator*/)
652 {
654 
655  debug_cmd_notification("set_var");
656 
657  try {
658  resources::gamedata->set_variable(child["name"],child["value"]);
659  }
660  catch(const invalid_variablename_exception&) {
661  // command_failed(_("Variable not found"));
662  return false;
663  }
664  return true;
665 }
666 
667 SYNCED_COMMAND_HANDLER_FUNCTION(debug_gold, child, /*spectator*/)
668 {
670 
671  debug_cmd_notification("gold");
672 
673  resources::controller->current_team().spend_gold(-child["gold"].to_int(0));
675  return true;
676 }
677 
678 
679 SYNCED_COMMAND_HANDLER_FUNCTION(debug_event, child, /*spectator*/)
680 {
682 
683  debug_cmd_notification("throw");
684 
685  resources::controller->pump().fire(child["eventname"]);
687 
688  return true;
689 }
690 
691 
692 SYNCED_COMMAND_HANDLER_FUNCTION(debug_fog, /*child*/, /*spectator*/)
693 {
695 
696  debug_cmd_notification("fog");
697 
698  team& current_team = resources::controller->current_team();
699  current_team.set_fog(!current_team.uses_fog());
700  actions::recalculate_fog(current_team.side());
701 
704 
705  return true;
706 }
707 
708 
709 SYNCED_COMMAND_HANDLER_FUNCTION(debug_shroud, /*child*/, /*spectator*/)
710 {
712 
713  debug_cmd_notification("shroud");
714 
715  team& current_team = resources::controller->current_team();
716  current_team.set_shroud(!current_team.uses_shroud());
717  actions::clear_shroud(current_team.side());
718 
721 
722  return true;
723 }
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:1574
Various functions that implement attacks and attack calculations.
map_location loc
Definition: move.cpp:172
Various functions related to moving units.
void advance_unit_at(const advance_unit_params &params)
Various functions that implement advancements of units.
Class to encapsulate fog/shroud clearing and the resultant sighted events.
Definition: vision.hpp:72
game_events::pump_result_t fire_events()
Fires the sighted events that were earlier recorded by fog/shroud clearing.
Definition: vision.cpp:541
bool clear_unit(const map_location &view_loc, team &view_team, std::size_t viewer_id, int sight_range, bool slowed, const movetype::terrain_costs &costs, const map_location &real_loc, const std::set< map_location > *known_units=nullptr, std::size_t *enemy_count=nullptr, std::size_t *friend_count=nullptr, move_unit_spectator *spectator=nullptr, bool instant=true)
Clears shroud (and fog) around the provided location for view_team based on sight_range,...
Definition: vision.cpp:330
void add_dismissal(const unit_const_ptr &u)
Adds a dismissal to the undo stack.
Definition: undo.cpp:88
bool commit_vision()
Updates fog/shroud based on the undo stack, then updates stack as needed.
Definition: undo.cpp:153
void add_auto_shroud(bool turned_on)
Adds an auto-shroud toggle to the undo stack.
Definition: undo.cpp:79
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:158
void recalculate_minimap()
Schedule the minimap for recalculation.
Definition: display.cpp:1576
void redraw_minimap()
Schedule the minimap to be redrawn.
Definition: display.cpp:1597
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:3087
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:1560
void queue_rerender()
Marks everything for rendering including all tiles and sidebar.
Definition: display.cpp:2261
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:111
bool change_terrain(const map_location &loc, const std::string &t, const std::string &mode, bool replace_if_failed)
Definition: game_board.cpp:317
team & get_team(int i)
Definition: game_board.hpp:92
unit_map::iterator find_visible_unit(const map_location &loc, const team &current_team, bool see_all=false)
Definition: game_board.cpp:185
virtual const unit_map & units() const override
Definition: game_board.hpp:107
void set_next_scenario(const std::string &next_scenario)
Definition: game_data.hpp:131
void set_variable(const std::string &varname, const 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.
bool is_skipping_replay() const
virtual void force_end_turn()=0
game_events::wml_event_pump & pump()
std::size_t size() const
Get the number of units on the list.
unit_ptr find_if_matches_id(const std::string &unit_id)
Find a unit by id.
void erase_if_matches_id(const std::string &unit_id)
Erase any unit with this id.
synced_command(const std::string &tag, handler function)
static map & registry()
using static function variable instead of static member variable to prevent static initialization fia...
std::map< std::string, handler > map
static void block_undo(bool do_block=true, bool clear_undo=true)
set this to false to prevent clearing the undo stack, this is important when we cannot change the gam...
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:75
bool uses_shroud() const
Definition: team.hpp:308
int side() const
Definition: team.hpp:180
void set_shroud(bool shroud)
Definition: team.hpp:316
bool auto_shroud_updates() const
Definition: team.hpp:329
void set_auto_shroud_updates(bool value)
Definition: team.hpp:330
int gold() const
Definition: team.hpp:181
void set_fog(bool fog)
Definition: team.hpp:317
void spend_gold(const int amount)
Definition: team.hpp:200
bool uses_fog() const
Definition: team.hpp:309
recall_list_manager & recall_list()
Definition: team.hpp:206
void set_turn(const int num, game_data *vars=nullptr, const bool increase_limit_if_needed=true)
Dynamically change the current turn number.
void set_number_of_turns(int num)
unit_iterator find(std::size_t id)
Definition: map.cpp:302
umap_retval_pair_t replace(const map_location &l, const unit_ptr &p)
Works like unit_map::add; but l is emptied first, if needed.
Definition: map.cpp:216
std::size_t erase(const map_location &l)
Erases the unit at location l, if any.
Definition: map.cpp:289
umap_retval_pair_t insert(const unit_ptr &p)
Inserts the unit pointed to by p into the map.
Definition: map.cpp:135
@ NUM_GENDERS
Definition: race.hpp:28
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
Definition: types.cpp:1265
A single unit type that the player may recruit.
Definition: types.hpp:43
unit_type_error error
Definition: types.hpp:49
int cost() const
Definition: types.hpp: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:1029
#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:447
Standard logging facilities (interface).
std::string find_recruit_location(const int side, map_location &recruit_location, map_location &recruited_from, const std::string &unit_type)
Finds a location on which to place a unit.
Definition: create.cpp:466
void teleport_unit_from_replay(const std::vector< map_location > &steps, bool continued_move, bool skip_ally_sighted, bool show_move)
Teleports a unit across the board.
Definition: move.cpp:1406
bool clear_shroud(int side, bool reset_fog, bool fire_events)
Function that will clear shroud (and fog) based on current unit positions.
Definition: vision.cpp:746
bool recall_unit(const std::string &id, team &current_team, const map_location &loc, const map_location &from, map_location::direction facing)
Recalls the unit with the indicated ID for the provided team.
Definition: create.cpp:740
game_events::pump_result_t actor_sighted(const unit &target, const std::vector< int > *cache)
Fires sighted events for the sides that can see target.
Definition: vision.cpp:614
void recruit_unit(const unit_type &u_type, int side_num, const map_location &loc, const map_location &from)
Recruits a unit of the given type for the given side.
Definition: create.cpp:717
game_events::pump_result_t get_village(const map_location &loc, int side, bool *action_timebonus, bool fire_event)
Makes it so the village at the given location is owned by the given side.
Definition: move.cpp:219
void recalculate_fog(int side)
Function that recalculates the fog of war.
Definition: vision.cpp:697
void execute_move_unit(const std::vector< map_location > &steps, bool continued_move, bool skip_ally_sighted, move_unit_spectator *move_spectator)
Moves a unit across the board.
Definition: move.cpp:1382
void pump()
Process all events currently in the queue.
Definition: events.cpp:479
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:64
bool fire_event(const ui_event event, const std::vector< std::pair< widget *, ui_event >> &event_chain, widget *dispatcher, widget *w, F &&... params)
Helper function for fire_event.
std::string tag(const std::string &tag_name, Args &&... contents)
Definition: markup.hpp:45
::tod_manager * tod_manager
Definition: resources.cpp:29
game_board * gameboard
Definition: resources.cpp:20
game_data * gamedata
Definition: resources.cpp:22
game_events::manager * game_events
Definition: resources.cpp:24
actions::undo_list * undo_stack
Definition: resources.cpp:32
game_lua_kernel * lua_kernel
Definition: resources.cpp:25
play_controller * controller
Definition: resources.cpp:21
std::shared_ptr< wb::manager > whiteboard
Definition: resources.cpp:33
void unit_die(const map_location &loc, unit &loser, const const_attack_ptr &attack, const const_attack_ptr &secondary_attack, const map_location &winner_loc, const unit_ptr &winner)
Show a unit fading out.
Definition: udisplay.cpp:569
void unit_recruited(const map_location &loc, const map_location &leader_loc)
Definition: udisplay.cpp:799
int stoi(std::string_view str)
Same interface as std::stoi and meant as a drop in replacement, except:
Definition: charconv.hpp:154
std::map< std::string, t_string > string_map
std::vector< std::string > split(const config_attribute_value &val)
auto * find(Container &container, const Value &value)
Convenience wrapper for using find on a container without needing to comare to end()
Definition: general.hpp:140
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:149
rect dst
Location on the final composed sheet.
rect src
Non-transparent portion of the surface to compose.
advances the unit at loc if it has enough experience, maximum 20 times.
Definition: advancement.hpp:39
Holds options for calls to function 'announce' (announce).
Definition: display.hpp:616
Additional information on the game outcome which can be provided by WML.
Encapsulates the map of the game.
Definition: location.hpp:45
bool valid() const
Definition: location.hpp:110
bool valid() const
Definition: map.hpp:273
#define WRN_REPLAY
#define DBG_REPLAY
static lg::log_domain log_replay("replay")
#define LOG_REPLAY
#define ERR_REPLAY
SYNCED_COMMAND_HANDLER_FUNCTION(recruit, child, spectator)
unit_type_data unit_types
Definition: types.cpp:1504
Display units performing various actions: moving, attacking, and dying.
Various functions that implement the undoing (and redoing) of in-game commands.
#define e