The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
synced_commands.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2014 - 2025
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#include <stdexcept>
19
20#include "log.hpp"
21#include "map/location.hpp"
22#include "game_data.hpp"
23#include "units/unit.hpp"
24#include "team.hpp"
25#include "play_controller.hpp"
26#include "actions/create.hpp"
28#include "actions/attack.hpp"
29#include "actions/move.hpp"
30#include "actions/undo.hpp"
32#include "game_events/pump.hpp"
33#include "map/map.hpp"
35#include "resources.hpp"
36#include "savegame.hpp"
39#include "units/types.hpp"
40#include "units/udisplay.hpp"
43
44static lg::log_domain log_replay("replay");
45#define DBG_REPLAY LOG_STREAM(debug, log_replay)
46#define LOG_REPLAY LOG_STREAM(info, log_replay)
47#define WRN_REPLAY LOG_STREAM(warn, log_replay)
48#define ERR_REPLAY LOG_STREAM(err, log_replay)
49
50
51/**
52 * @param[in] tag The replay tag for this action.
53 * @param[in] function The callback for this action.
54 */
55synced_command::synced_command(const std::string & tag, handler function)
56{
57 assert(registry().find( tag ) == registry().end());
58 registry()[tag] = function;
59}
60
62{
63 //Use a pointer to ensure that this object is not destructed when the program ends.
64 static map* instance = new map();
65 return *instance;
66}
67
68
69SYNCED_COMMAND_HANDLER_FUNCTION(recruit, child, spectator)
70{
71 int current_team_num = resources::controller->current_side();
72 team &current_team = resources::gameboard->get_team(current_team_num);
73
75 map_location from(child.child_or_empty("from"), resources::gamedata);
76 // Validate "from".
77 if ( !from.valid() ) {
78 // This will be the case for AI recruits in replays saved
79 // before 1.11.2, so it is not more severe than a warning.
80 // EDIT: we broke compatibility with 1.11.2 anyway so we should give an error.
81 spectator.error("Missing leader location for recruitment.\n");
82 }
83 else if ( resources::gameboard->units().find(from) == resources::gameboard->units().end() ) {
84 // Sync problem?
85 std::stringstream errbuf;
86 errbuf << "Recruiting leader not found at " << from << ".\n";
87 spectator.error(errbuf.str());
88 }
89
90 // Get the unit_type ID.
91 std::string type_id = child["type"];
92 if ( type_id.empty() ) {
93 spectator.error("Recruitment is missing a unit type.");
94 return false;
95 }
96
97 const unit_type *u_type = unit_types.find(type_id);
98 if (!u_type) {
99 std::stringstream errbuf;
100 errbuf << "Recruiting illegal unit: '" << type_id << "'.\n";
101 spectator.error(errbuf.str());
102 return false;
103 }
104
105 const std::string res = actions::find_recruit_location(current_team_num, loc, from, type_id);
106 if(!res.empty())
107 {
108 std::stringstream errbuf;
109 errbuf << "cannot recruit unit: " << res << "\n";
110 spectator.error(errbuf.str());
111 return false;
112 //we are already oos because the unit wasn't created, no need to keep the bookkeeping right...
113 }
114 const int beginning_gold = current_team.gold();
115
116
117
118 if ( u_type->cost() > beginning_gold ) {
119 std::stringstream errbuf;
120 errbuf << "unit '" << type_id << "' is too expensive to recruit: "
121 << u_type->cost() << "/" << beginning_gold << "\n";
122 spectator.error(errbuf.str());
123 }
124
125 actions::recruit_unit(*u_type, current_team_num, loc, from);
126
127 LOG_REPLAY << "recruit: team=" << current_team_num << " '" << type_id << "' at (" << loc
128 << ") cost=" << u_type->cost() << " from gold=" << beginning_gold << ' '
129 << "-> " << current_team.gold();
130 return true;
131}
132
133SYNCED_COMMAND_HANDLER_FUNCTION(recall, child, spectator)
134{
135 int current_team_num = resources::controller->current_side();
136 team &current_team = resources::gameboard->get_team(current_team_num);
137
138 const std::string& unit_id = child["value"];
140 map_location from(child.child_or_empty("from"), resources::gamedata);
141
142 if(!actions::recall_unit(unit_id, current_team, loc, from, map_location::direction::indeterminate)) {
143 spectator.error("illegal recall: unit_id '" + unit_id + "' could not be found within the recall list.\n");
144 //when recall_unit returned false nothing happened so we can safety return false;
145 return false;
146 }
147 return true;
148}
149
150SYNCED_COMMAND_HANDLER_FUNCTION(attack, child, spectator)
151{
152 const auto destination = child.optional_child("destination");
153 const auto source = child.optional_child("source");
154 //check_checksums(*cfg);
155
156 if (!destination) {
157 spectator.error("no destination found in attack\n");
158 return false;
159 }
160
161 if (!source) {
162 spectator.error("no source found in attack \n");
163 return false;
164 }
165
166 //we must get locations by value instead of by references, because the iterators
167 //may become invalidated later
168 const map_location src(source.value(), resources::gamedata);
169 const map_location dst(destination.value(), resources::gamedata);
170
171 int weapon_num = child["weapon"].to_int();
172 // having defender_weapon in the replay fixes a bug (OOS) where one player (or observer) chooses a different defensive weapon.
173 // Xan pointed out this was a possibility: we calculate defense weapon
174 // now based on attack_prediction code, but this uses floating point
175 // calculations, which means that in the case where results are close,
176 // rounding differences can mean that both ends choose different weapons.
177 int def_weapon_num = child["defender_weapon"].to_int(-2);
178 if (def_weapon_num == -2) {
179 // Let's not gratuitously destroy backwards compatibility.
180 LOG_REPLAY << "Old data, having to guess weapon";
181 def_weapon_num = -1;
182 }
183
185 if (!u.valid()) {
186 spectator.error("unfound location for source of attack\n");
187 return false;
188 }
189
190 if (child.has_attribute("attacker_type")) {
191 const std::string &att_type_id = child["attacker_type"];
192 if (u->type_id() != att_type_id) {
193 WRN_REPLAY << "unexpected attacker type: " << att_type_id << "(game state gives: " << u->type_id() << ")";
194 }
195 }
196
197 if (static_cast<unsigned>(weapon_num) >= u->attacks().size()) {
198 spectator.error("illegal weapon type in attack\n");
199 return false;
200 }
201
203
204 if (!tgt.valid()) {
205 std::stringstream errbuf;
206 errbuf << "unfound defender for attack: " << src << " -> " << dst << '\n';
207 spectator.error(errbuf.str());
208 return false;
209 }
210
211 if (child.has_attribute("defender_type")) {
212 const std::string &def_type_id = child["defender_type"];
213 if (tgt->type_id() != def_type_id) {
214 WRN_REPLAY << "unexpected defender type: " << def_type_id << "(game state gives: " << tgt->type_id() << ")";
215 }
216 }
217
218 if (def_weapon_num >= static_cast<int>(tgt->attacks().size())) {
219
220 spectator.error("illegal defender weapon type in attack\n");
221 return false;
222 }
223
224 DBG_REPLAY << "Attacker XP (before attack): " << u->experience();
225
228 attack_unit_and_advance(src, dst, weapon_num, def_weapon_num, show);
229 return true;
230}
231
232SYNCED_COMMAND_HANDLER_FUNCTION(disband, child, spectator)
233{
234
235 team& current_team = resources::controller->current_team();
236
237 const std::string& unit_id = child["value"];
238 std::size_t old_size = current_team.recall_list().size();
239
240 // Find the unit in the recall list.
241 unit_ptr dismissed_unit = current_team.recall_list().find_if_matches_id(unit_id);
242 if (!dismissed_unit) {
243 spectator.error("illegal disband\n");
244 return false;
245 }
246 //add dismissal to the undo stack
247 resources::undo_stack->add_dismissal(dismissed_unit);
248
249 current_team.recall_list().erase_if_matches_id(unit_id);
250
251 assert(old_size != current_team.recall_list().size());
252 return true;
253}
254
255SYNCED_COMMAND_HANDLER_FUNCTION(move, child, spectator)
256{
257 team& current_team = resources::controller->current_team();
258
259 std::vector<map_location> steps;
260
261 try {
262 steps = read_locations(child);
263 } catch (const std::invalid_argument&) {
264 WRN_REPLAY << "Warning: Path data contained something which could not be parsed to a sequence of locations:" << "\n config = " << child.debug();
265 return false;
266 } catch (const std::out_of_range&) {
267 WRN_REPLAY << "Warning: Path data contained something which could not be parsed to a sequence of locations:" << "\n config = " << child.debug();
268 return false;
269 }
270
271 if(steps.empty())
272 {
273 WRN_REPLAY << "Warning: Missing path data found in [move]";
274 return false;
275 }
276
277 for(const map_location& step : steps) {
278 if(!resources::gameboard->map().on_board(step)) {
279 WRN_REPLAY << "Warning: Movement path contained an off-map location";
280 return false;
281 }
282 }
283
284 const map_location& src = steps.front();
285 const map_location& dst = steps.back();
286
287 if (src == dst) {
288 WRN_REPLAY << "Warning: Move with identical source and destination. Skipping...";
289 return false;
290 }
291
292 // The nominal destination should appear to be unoccupied.
294 if ( u.valid() ) {
295 WRN_REPLAY << "Warning: Move destination " << dst << " appears occupied.";
296 // We'll still proceed with this movement, though, since
297 // an event might intervene.
298 // 'event' doesn't mean wml event but rather it means 'hidden' units form the movers point of view.
299 }
300
302 if (!u.valid()) {
303 std::stringstream errbuf;
304 errbuf << "unfound location for source of movement: "
305 << src << " -> " << dst << '\n';
306 spectator.error(errbuf.str());
307 return false;
308 }
309
310 bool skip_sighted = child["skip_sighted"] == "all";
311 bool skip_ally_sighted = child["skip_sighted"] == "only_ally";
312
313 actions::execute_move_unit(steps, skip_sighted, skip_ally_sighted, dynamic_cast<actions::move_unit_spectator*>(&spectator));
314
315 return true;
316}
317
318SYNCED_COMMAND_HANDLER_FUNCTION(fire_event, child, /*spectator*/)
319{
320 if(const auto last_select = child.optional_child("last_select"))
321 {
322 //the select event cannot clear the undo stack.
323 resources::game_events->pump().fire("select", map_location(last_select.value(), resources::gamedata));
324 }
325 const std::string &event_name = child["raise"];
326 if (const auto source = child.optional_child("source")) {
327 synced_context::block_undo(std::get<0>(resources::game_events->pump().fire(event_name, map_location(source.value(), resources::gamedata))));
328 } else {
329 synced_context::block_undo(std::get<0>(resources::game_events->pump().fire(event_name)));
330 }
331
332 return true;
333}
334
335SYNCED_COMMAND_HANDLER_FUNCTION(custom_command, child, /*spectator*/)
336{
337 assert(resources::lua_kernel);
338 resources::lua_kernel->custom_command(child["name"], child.child_or_empty("data"));
339
340 return true;
341}
342
343SYNCED_COMMAND_HANDLER_FUNCTION(auto_shroud, child, /*spectator*/)
344{
345 team &current_team = resources::controller->current_team();
346
347 bool active = child["active"].to_bool();
348 bool block_undo = child["block_undo"].to_bool();
349 if(active && !current_team.auto_shroud_updates()) {
350 block_undo |= resources::undo_stack->commit_vision();
351 }
352 current_team.set_auto_shroud_updates(active);
354 if(block_undo) {
356 }
357 return true;
358}
359
360SYNCED_COMMAND_HANDLER_FUNCTION(update_shroud, /*child*/, spectator)
361{
362 // When "updating shroud now" is used.
363 // Updates fog/shroud based on the undo stack, then updates stack as needed.
364 // This may fire events and change the game state.
365
366 team &current_team = resources::controller->current_team();
367 if(current_team.auto_shroud_updates()) {
368 spectator.error("Team has DSU disabled but we found an explicit shroud update");
369 }
371 if(res) {
373 }
374 return true;
375}
376
377namespace
378{
379 void debug_notification(const std::string& text, bool message_is_command = false)
380 {
382 auto& current_team = controller.current_team();
383 static bool ignore = false;
384 bool show_long_message = controller.is_replay() || !current_team.is_local();
385
386 std::string message;
387 utils::string_map i18n_vars = {{ "player", current_team.current_player() }};
388
389 if(i18n_vars["player"].empty()) {
390 i18n_vars["player"] = _("(unknown player)");
391 }
392
393 if(message_is_command) {
394 i18n_vars["command"] = text;
395 message = VGETTEXT("The :$command debug command was used during $player’s turn", i18n_vars);
396 } else {
397 message = VGETTEXT(text.c_str(), i18n_vars);
398 }
399
400 if(show_long_message && !ignore) {
402 std::stringstream sbuilder;
403 sbuilder << _("A player used a debug command during the game. If this is unexpected, it is possible the player in question is cheating.")
404 << "\n\n"
405 << _("Details:") << "\n"
406 << message
407 << "\n\n"
408 << _("Do you wish to save the game before continuing?");
409 savegame::oos_savegame save(controller.get_saved_game(), ignore);
410 save.set_title(_("Debug Command Used"));
411 save.save_game_interactive(sbuilder.str(), savegame::savegame::YES_NO); // can throw quit_game_exception
412 }
413 else {
414 display::announce_options announce_options;
415 display::get_singleton()->announce(message, font::NORMAL_COLOR, announce_options);
416 }
417 }
418
419 void debug_cmd_notification(const std::string& command)
420 {
421 debug_notification(command, true);
422 }
423}
424
425SYNCED_COMMAND_HANDLER_FUNCTION(debug_terrain, child, /*spectator*/)
426{
428 debug_cmd_notification("terrain");
429
430 map_location loc(child);
431 const std::string& terrain_type = child["terrain_type"];
432 const std::string& mode_str = child["mode_str"];
433
434 bool result = resources::gameboard->change_terrain(loc, terrain_type, mode_str, false);
435 if(result) {
439 }
440 return true;
441}
442
443SYNCED_COMMAND_HANDLER_FUNCTION(debug_unit, child, /*spectator*/)
444{
446 debug_cmd_notification("unit");
447 map_location loc(child);
448 const std::string name = child["name"];
449 const std::string value = child["value"];
450
452 if (i == resources::gameboard->units().end()) {
453 return false;
454 }
455 if (name == "advances" ) {
456 int int_value = 0;
457 try {
458 int_value = std::stoi(value);
459 } catch (const std::invalid_argument&) {
460 WRN_REPLAY << "Warning: Invalid unit advancement argument: " << value;
461 return false;
462 }
463 for (int levels=0; levels<int_value; levels++) {
464 i->set_experience(i->max_experience());
465
466 advance_unit_at(advance_unit_params(loc).force_dialog(true));
468 if (!i.valid()) {
469 break;
470 }
471 }
472 } else if (name == "status" ) {
473 for (std::string status : utils::split(value)) {
474 bool add = true;
475 if (status.length() >= 1 && status[0] == '-') {
476 add = false;
477 status = status.substr(1);
478 }
479 if (status.empty()) {
480 continue;
481 }
482 i->set_state(status, add);
483 }
484 } else {
485 config cfg;
486 i->write(cfg);
487 cfg[name] = value;
488
489 // Attempt to create a new unit. If there are error (such an invalid type key), exit.
490 try{
491 unit_ptr new_u = unit::create(cfg, true);
492 new_u->set_location(loc);
493 // Don't remove the unit until after we've verified there are no errors in creating the new one,
494 // or else the unit would simply be removed from the map with no replacement.
496 resources::whiteboard->on_kill_unit();
498 } catch(const unit_type::error& e) {
499 ERR_REPLAY << e.what(); // TODO: more appropriate error message log
500 return false;
501 }
502 }
503 if (name == "fail") { //testcase for bug #18488
504 assert(i.valid());
505 }
508
509 return true;
510}
511
512SYNCED_COMMAND_HANDLER_FUNCTION(debug_create_unit, child, spectator)
513{
515
516 debug_notification(N_("A unit was created using debug mode during $player’s turn"));
517 map_location loc(child);
518 resources::whiteboard->on_kill_unit();
519 const std::string& variation = child["variation"].str();
520 const unit_race::GENDER gender = string_gender(child["gender"], unit_race::NUM_GENDERS);
521 const unit_type *u_type = unit_types.find(child["type"]);
522 if (!u_type) {
523 spectator.error("Invalid unit type");
524 return false;
525 }
526
527 const int side_num = resources::controller
529
530 // Create the unit.
531 unit_ptr created = unit::create(*u_type, side_num, true, gender, variation);
532 created->new_turn();
533
535
536 // Add the unit to the board.
537 std::tie(unit_it, std::ignore) = resources::gameboard->units().replace(loc, created);
538
540 resources::game_events->pump().fire("unit_placed", loc);
542
543 // Village capture?
544 if ( resources::gameboard->map().is_village(loc) )
545 actions::get_village(loc, created->side());
546
547 // Update fog/shroud.
548 // Not checking auto_shroud_updates() here since :create is not undoable. (#2196)
550 clearer.clear_unit(loc, *created);
551 clearer.fire_events();
552 if (unit_it.valid() ) // In case sighted events messed with the unit.
553 actions::actor_sighted(*unit_it);
554
555 return true;
556}
557
558SYNCED_COMMAND_HANDLER_FUNCTION(debug_lua, child, /*spectator*/)
559{
561 debug_cmd_notification("lua");
562 resources::lua_kernel->run(child["code"].str().c_str(), "debug command");
564
565 return true;
566}
567
568SYNCED_COMMAND_HANDLER_FUNCTION(debug_teleport, child, /*spectator*/)
569{
571 debug_cmd_notification("teleport");
572
573 const map_location teleport_from(child["teleport_from_x"].to_int(), child["teleport_from_y"].to_int(), wml_loc());
574 const map_location teleport_to(child["teleport_to_x"].to_int(), child["teleport_to_y"].to_int(), wml_loc());
575
576 const unit_map::iterator unit_iter = resources::gameboard->units().find(teleport_from);
577 if(unit_iter != resources::gameboard->units().end()) {
578 if(unit_iter.valid()) {
579 actions::teleport_unit_from_replay({teleport_from, teleport_to}, false, false, false);
580 }
582 }
583
584 return true;
585}
586
587SYNCED_COMMAND_HANDLER_FUNCTION(debug_kill, child, /*spectator*/)
588{
590 debug_cmd_notification("kill");
591
592 const map_location loc(child["x"].to_int(), child["y"].to_int(), wml_loc());
594 if (i != resources::gameboard->units().end()) {
595 const int dying_side = i->side();
596 resources::controller->pump().fire("last_breath", loc, loc);
597 if (i.valid()) {
599 }
601 if (i.valid()) {
602 i->set_hitpoints(0);
603 }
605 if (i.valid()) {
607 }
608 resources::whiteboard->on_kill_unit();
609 actions::recalculate_fog(dying_side);
610 }
611 return true;
612}
613
614SYNCED_COMMAND_HANDLER_FUNCTION(debug_next_level, child, /*spectator*/)
615{
617
618 debug_cmd_notification("next_level");
619
620 std::string next_level = child["next_level"];
621 if (!next_level.empty())
625 e.prescenario_save = true;
626 e.transient.linger_mode = false;
627 e.proceed_to_next_level = true;
628 e.is_victory = true;
629
632
633 return true;
634}
635
636SYNCED_COMMAND_HANDLER_FUNCTION(debug_turn_limit, child, /*spectator*/)
637{
639
640 debug_cmd_notification("turn_limit");
641
642 resources::tod_manager->set_number_of_turns(child["turn_limit"].to_int(-1));
644 return true;
645}
646
647SYNCED_COMMAND_HANDLER_FUNCTION(debug_turn, child, /*spectator*/)
648{
650
651 debug_cmd_notification("turn");
652
653 resources::tod_manager->set_turn(child["turn"].to_int(1), resources::gamedata);
654
657
658 return true;
659}
660
661SYNCED_COMMAND_HANDLER_FUNCTION(debug_set_var, child, /*spectator*/)
662{
664
665 debug_cmd_notification("set_var");
666
667 try {
668 resources::gamedata->set_variable(child["name"],child["value"]);
669 }
670 catch(const invalid_variablename_exception&) {
671 // command_failed(_("Variable not found"));
672 return false;
673 }
674 return true;
675}
676
677SYNCED_COMMAND_HANDLER_FUNCTION(debug_gold, child, /*spectator*/)
678{
680
681 debug_cmd_notification("gold");
682
683 resources::controller->current_team().spend_gold(-child["gold"].to_int(0));
685 return true;
686}
687
688
689SYNCED_COMMAND_HANDLER_FUNCTION(debug_event, child, /*spectator*/)
690{
692
693 debug_cmd_notification("throw");
694
695 resources::controller->pump().fire(child["eventname"]);
697
698 return true;
699}
700
701
702SYNCED_COMMAND_HANDLER_FUNCTION(debug_fog, /*child*/, /*spectator*/)
703{
705
706 debug_cmd_notification("fog");
707
708 team& current_team = resources::controller->current_team();
709 current_team.set_fog(!current_team.uses_fog());
710 actions::recalculate_fog(current_team.side());
711
714
715 return true;
716}
717
718
719SYNCED_COMMAND_HANDLER_FUNCTION(debug_shroud, /*child*/, /*spectator*/)
720{
722
723 debug_cmd_notification("shroud");
724
725 team& current_team = resources::controller->current_team();
726 current_team.set_shroud(!current_team.uses_shroud());
727 actions::clear_shroud(current_team.side());
728
731
732 return true;
733}
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:1485
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:157
void recalculate_minimap()
Schedule the minimap for recalculation.
Definition display.cpp:1465
void redraw_minimap()
Schedule the minimap to be redrawn.
Definition display.cpp:1486
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition display.cpp:2927
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:1449
void queue_rerender()
Marks everything for rendering including all tiles and sidebar.
Definition display.cpp:2105
static display * get_singleton()
Returns the display object if a display object exists.
Definition display.hpp:102
bool change_terrain(const map_location &loc, const std::string &t, const std::string &mode, bool replace_if_failed)
unit_map::iterator find_visible_unit(const map_location &loc, const team &current_team, bool see_all=false)
team & get_team(int i)
virtual const unit_map & units() const override
void set_next_scenario(const std::string &next_scenario)
void set_variable(const std::string &varname, const config::attribute_value &value)
does nothing if varname is no valid variable name.
Definition game_data.cpp:88
static game_display * get_singleton()
void invalidate_unit()
Function to invalidate that unit status displayed on the sidebar.
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:257
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:74
bool uses_shroud() const
Definition team.hpp:344
int side() const
Definition team.hpp:182
void set_shroud(bool shroud)
Definition team.hpp:352
bool auto_shroud_updates() const
Definition team.hpp:366
void set_auto_shroud_updates(bool value)
Definition team.hpp:367
int gold() const
Definition team.hpp:183
recall_list_manager & recall_list()
Definition team.hpp:242
void set_fog(bool fog)
Definition team.hpp:353
void spend_gold(const int amount)
Definition team.hpp:221
bool uses_fog() const
Definition team.hpp:345
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:1253
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:176
static unit_ptr create(const config &cfg, bool use_traits=false, const vconfig *vcfg=nullptr)
Initializes a unit from a config.
Definition unit.hpp:107
Various functions related to the creation of units (recruits, recalls, and placed units).
const config * cfg
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
#define N_(String)
Definition gettext.hpp:108
static std::string _(const char *str)
Definition gettext.hpp:100
std::vector< map_location > read_locations(const config &cfg)
Parse x,y keys of a config into a vector of locations.
Definition location.cpp:475
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:1412
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:221
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:1388
const color_t NORMAL_COLOR
::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:571
void unit_recruited(const map_location &loc, const map_location &leader_loc)
Definition udisplay.cpp:798
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
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
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.
Holds options for calls to function 'announce' (announce).
Definition display.hpp:602
Additional information on the game outcome which can be provided by WML.
transient_end_level transient
Encapsulates the map of the game.
Definition location.hpp:46
bool valid() const
Definition location.hpp:111
bool carryover_report
Should a summary of the scenario outcome be displayed?
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
#define SYNCED_COMMAND_HANDLER_FUNCTION(pname, pcfg, spectator)
unit_type_data unit_types
Definition types.cpp:1499
Display units performing various actions: moving, attacking, and dying.
Various functions that implement the undoing (and redoing) of in-game commands.
#define i
#define e