The Battle for Wesnoth  1.19.5+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"];
138  map_location loc(child, resources::gamedata);
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  // Not clearing the undo stack here causes OOS because we added an entry to the replay but no entry to the undo stack.
327  } else {
329  }
330  return true;
331 }
332 
333 SYNCED_COMMAND_HANDLER_FUNCTION(custom_command, child, /*spectator*/)
334 {
335  assert(resources::lua_kernel);
336  resources::lua_kernel->custom_command(child["name"], child.child_or_empty("data"));
337 
340  } else {
342  }
343  return true;
344 }
345 
346 SYNCED_COMMAND_HANDLER_FUNCTION(auto_shroud, child, /*spectator*/)
347 {
348  team &current_team = resources::controller->current_team();
349 
350  bool active = child["active"].to_bool();
351  if(active && !current_team.auto_shroud_updates()) {
353  }
354  current_team.set_auto_shroud_updates(active);
355  if(resources::undo_stack->can_undo()) {
357  }
358  return true;
359 }
360 
361 SYNCED_COMMAND_HANDLER_FUNCTION(update_shroud, /*child*/, spectator)
362 {
363  // When "updating shroud now" is used.
364  // Updates fog/shroud based on the undo stack, then updates stack as needed.
365  // This may fire events and change the game state.
366 
367  team &current_team = resources::controller->current_team();
368  if(current_team.auto_shroud_updates()) {
369  spectator.error("Team has DSU disabled but we found an explicit shroud update");
370  }
371  bool res = resources::undo_stack->commit_vision();
373  if(res) {
375  }
376  return true;
377 }
378 
379 namespace
380 {
381  void debug_notification(const std::string& text, bool message_is_command = false)
382  {
384  auto& current_team = controller.current_team();
385  static bool ignore = false;
386  bool show_long_message = controller.is_replay() || !current_team.is_local();
387 
388  std::string message;
389  utils::string_map i18n_vars = {{ "player", current_team.current_player() }};
390 
391  if(i18n_vars["player"].empty()) {
392  i18n_vars["player"] = _("(unknown player)");
393  }
394 
395  if(message_is_command) {
396  i18n_vars["command"] = text;
397  message = VGETTEXT("The :$command debug command was used during $player’s turn", i18n_vars);
398  } else {
399  message = VGETTEXT(text.c_str(), i18n_vars);
400  }
401 
402  if(show_long_message && !ignore) {
404  std::stringstream sbuilder;
405  sbuilder << _("A player used a debug command during the game. If this is unexpected, it is possible the player in question is cheating.")
406  << "\n\n"
407  << _("Details:") << "\n"
408  << message
409  << "\n\n"
410  << _("Do you wish to save the game before continuing?");
411  savegame::oos_savegame save(controller.get_saved_game(), ignore);
412  save.set_title(_("Debug Command Used"));
413  save.save_game_interactive(sbuilder.str(), savegame::savegame::YES_NO); // can throw quit_game_exception
414  }
415  else {
416  display::announce_options announce_options;
417  display::get_singleton()->announce(message, font::NORMAL_COLOR, announce_options);
418  }
419  }
420 
421  void debug_cmd_notification(const std::string& command)
422  {
423  debug_notification(command, true);
424  }
425 }
426 
427 SYNCED_COMMAND_HANDLER_FUNCTION(debug_terrain, child, /*spectator*/)
428 {
430  debug_cmd_notification("terrain");
431 
432  map_location loc(child);
433  const std::string& terrain_type = child["terrain_type"];
434  const std::string& mode_str = child["mode_str"];
435 
436  bool result = resources::gameboard->change_terrain(loc, terrain_type, mode_str, false);
437  if(result) {
441  }
442  return true;
443 }
444 
445 SYNCED_COMMAND_HANDLER_FUNCTION(debug_unit, child, /*spectator*/)
446 {
448  debug_cmd_notification("unit");
449  map_location loc(child);
450  const std::string name = child["name"];
451  const std::string value = child["value"];
452 
454  if (i == resources::gameboard->units().end()) {
455  return false;
456  }
457  if (name == "advances" ) {
458  int int_value = 0;
459  try {
460  int_value = std::stoi(value);
461  } catch (const std::invalid_argument&) {
462  WRN_REPLAY << "Warning: Invalid unit advancement argument: " << value;
463  return false;
464  }
465  for (int levels=0; levels<int_value; levels++) {
466  i->set_experience(i->max_experience());
467 
468  advance_unit_at(advance_unit_params(loc).force_dialog(true));
469  i = resources::gameboard->units().find(loc);
470  if (!i.valid()) {
471  break;
472  }
473  }
474  } else if (name == "status" ) {
475  for (std::string status : utils::split(value)) {
476  bool add = true;
477  if (status.length() >= 1 && status[0] == '-') {
478  add = false;
479  status = status.substr(1);
480  }
481  if (status.empty()) {
482  continue;
483  }
484  i->set_state(status, add);
485  }
486  } else {
487  config cfg;
488  i->write(cfg);
489  cfg[name] = value;
490 
491  // Attempt to create a new unit. If there are error (such an invalid type key), exit.
492  try{
493  unit_ptr new_u = unit::create(cfg, true);
494  new_u->set_location(loc);
495  // Don't remove the unit until after we've verified there are no errors in creating the new one,
496  // or else the unit would simply be removed from the map with no replacement.
498  resources::whiteboard->on_kill_unit();
500  } catch(const unit_type::error& e) {
501  ERR_REPLAY << e.what(); // TODO: more appropriate error message log
502  return false;
503  }
504  }
505  if (name == "fail") { //testcase for bug #18488
506  assert(i.valid());
507  }
510 
511  return true;
512 }
513 
514 SYNCED_COMMAND_HANDLER_FUNCTION(debug_create_unit, child, spectator)
515 {
517 
518  debug_notification(N_("A unit was created using debug mode during $player’s turn"));
519  map_location loc(child);
520  resources::whiteboard->on_kill_unit();
521  const std::string& variation = child["variation"].str();
522  const unit_race::GENDER gender = string_gender(child["gender"], unit_race::NUM_GENDERS);
523  const unit_type *u_type = unit_types.find(child["type"]);
524  if (!u_type) {
525  spectator.error("Invalid unit type");
526  return false;
527  }
528 
529  const int side_num = resources::controller
531 
532  // Create the unit.
533  unit_ptr created = unit::create(*u_type, side_num, true, gender, variation);
534  created->new_turn();
535 
536  unit_map::unit_iterator unit_it;
537 
538  // Add the unit to the board.
539  std::tie(unit_it, std::ignore) = resources::gameboard->units().replace(loc, created);
540 
542  resources::game_events->pump().fire("unit_placed", loc);
544 
545  // Village capture?
546  if ( resources::gameboard->map().is_village(loc) )
547  actions::get_village(loc, created->side());
548 
549  // Update fog/shroud.
550  // Not checking auto_shroud_updates() here since :create is not undoable. (#2196)
551  actions::shroud_clearer clearer;
552  clearer.clear_unit(loc, *created);
553  clearer.fire_events();
554  if (unit_it.valid() ) // In case sighted events messed with the unit.
555  actions::actor_sighted(*unit_it);
556 
557  return true;
558 }
559 
561 {
563  debug_cmd_notification("lua");
564  resources::lua_kernel->run(child["code"].str().c_str(), "debug command");
566 
567  return true;
568 }
569 
570 SYNCED_COMMAND_HANDLER_FUNCTION(debug_teleport, child, /*spectator*/)
571 {
573  debug_cmd_notification("teleport");
574 
575  const map_location teleport_from(child["teleport_from_x"].to_int(), child["teleport_from_y"].to_int(), wml_loc());
576  const map_location teleport_to(child["teleport_to_x"].to_int(), child["teleport_to_y"].to_int(), wml_loc());
577 
578  const unit_map::iterator unit_iter = resources::gameboard->units().find(teleport_from);
579  if(unit_iter != resources::gameboard->units().end()) {
580  if(unit_iter.valid()) {
581  actions::teleport_unit_from_replay({teleport_from, teleport_to}, false, false, false);
582  }
584  }
585 
586  return true;
587 }
588 
589 SYNCED_COMMAND_HANDLER_FUNCTION(debug_kill, child, /*spectator*/)
590 {
592  debug_cmd_notification("kill");
593 
594  const map_location loc(child["x"].to_int(), child["y"].to_int(), wml_loc());
596  if (i != resources::gameboard->units().end()) {
597  const int dying_side = i->side();
598  resources::controller->pump().fire("last_breath", loc, loc);
599  if (i.valid()) {
600  unit_display::unit_die(loc, *i);
601  }
603  if (i.valid()) {
604  i->set_hitpoints(0);
605  }
606  resources::controller->pump().fire("die", loc, loc);
607  if (i.valid()) {
609  }
610  resources::whiteboard->on_kill_unit();
611  actions::recalculate_fog(dying_side);
612  }
613  return true;
614 }
615 
616 SYNCED_COMMAND_HANDLER_FUNCTION(debug_next_level, child, /*spectator*/)
617 {
619 
620  debug_cmd_notification("next_level");
621 
622  std::string next_level = child["next_level"];
623  if (!next_level.empty())
626  e.transient.carryover_report = false;
627  e.prescenario_save = true;
628  e.transient.linger_mode = false;
629  e.proceed_to_next_level = true;
630  e.is_victory = true;
631 
634 
635  return true;
636 }
637 
638 SYNCED_COMMAND_HANDLER_FUNCTION(debug_turn_limit, child, /*spectator*/)
639 {
641 
642  debug_cmd_notification("turn_limit");
643 
644  resources::tod_manager->set_number_of_turns(child["turn_limit"].to_int(-1));
646  return true;
647 }
648 
649 SYNCED_COMMAND_HANDLER_FUNCTION(debug_turn, child, /*spectator*/)
650 {
652 
653  debug_cmd_notification("turn");
654 
655  resources::tod_manager->set_turn(child["turn"].to_int(1), resources::gamedata);
656 
659 
660  return true;
661 }
662 
663 SYNCED_COMMAND_HANDLER_FUNCTION(debug_set_var, child, /*spectator*/)
664 {
666 
667  debug_cmd_notification("set_var");
668 
669  try {
670  resources::gamedata->set_variable(child["name"],child["value"]);
671  }
672  catch(const invalid_variablename_exception&) {
673  // command_failed(_("Variable not found"));
674  return false;
675  }
676  return true;
677 }
678 
679 SYNCED_COMMAND_HANDLER_FUNCTION(debug_gold, child, /*spectator*/)
680 {
682 
683  debug_cmd_notification("gold");
684 
685  resources::controller->current_team().spend_gold(-child["gold"].to_int(0));
687  return true;
688 }
689 
690 
691 SYNCED_COMMAND_HANDLER_FUNCTION(debug_event, child, /*spectator*/)
692 {
694 
695  debug_cmd_notification("throw");
696 
697  resources::controller->pump().fire(child["eventname"]);
699 
700  return true;
701 }
702 
703 
704 SYNCED_COMMAND_HANDLER_FUNCTION(debug_fog, /*child*/, /*spectator*/)
705 {
707 
708  debug_cmd_notification("fog");
709 
710  team& current_team = resources::controller->current_team();
711  current_team.set_fog(!current_team.uses_fog());
712  actions::recalculate_fog(current_team.side());
713 
716 
717  return true;
718 }
719 
720 
721 SYNCED_COMMAND_HANDLER_FUNCTION(debug_shroud, /*child*/, /*spectator*/)
722 {
724 
725  debug_cmd_notification("shroud");
726 
727  team& current_team = resources::controller->current_team();
728  current_team.set_shroud(!current_team.uses_shroud());
729  actions::clear_shroud(current_team.side());
730 
733 
734  return true;
735 }
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:1572
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:146
bool commit_vision()
Updates fog/shroud based on the undo stack, then updates stack as needed.
Definition: undo.cpp:221
void add_dummy()
Adds an auto-shroud toggle to the undo stack.
Definition: undo.cpp:138
void add_auto_shroud(bool turned_on)
Adds an auto-shroud toggle to the undo stack.
Definition: undo.cpp:133
void add_update_shroud()
Adds a shroud update to the undo stack.
Definition: undo.cpp:186
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:172
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:327
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 bool undo_blocked()
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:303
int side() const
Definition: team.hpp:175
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:176
void set_fog(bool fog)
Definition: team.hpp:312
void spend_gold(const int amount)
Definition: team.hpp:195
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: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:1028
#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:1351
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:738
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:716
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:163
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:1327
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_recruited(const map_location &loc, const map_location &leader_loc)
Definition: udisplay.cpp:799
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:569
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: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:1500
Display units performing various actions: moving, attacking, and dying.
Various functions that implement the undoing (and redoing) of in-game commands.
#define e