84 #define ERR_NG LOG_STREAM(err, log_engine)
85 #define LOG_NG LOG_STREAM(info, log_engine)
92 std::string last_created_unit =
"";
93 std::string last_recruit =
"";
94 std::string last_variation =
"";
161 const auto& unit_dlg = units_dialog::build_unit_list_dialog(
unit_list);
163 if (unit_dlg->show() && unit_dlg->is_selected()) {
199 symbols[
"msg"] =
e.what();
200 const std::string
msg =
VGETTEXT(
"Could not save the map: $msg", symbols);
208 gui2::dialogs::preferences_dialog::display();
216 c[
"name"] =
"prototype of chat log";
228 ?
board().is_observer()
229 ?
_(
"Send to observers only")
230 :
_(
"Send to allies only")
248 if(
board().is_observer()) {
267 std::map<const unit_type*, t_string> err_msgs_map;
268 std::vector<const unit_type*> recruit_list;
269 std::vector<t_string> unknown_units;
275 int selected_index = -1,
i = 0;
280 recruit_list.push_back(
type);
283 unknown_units.emplace_back(
recruit);
291 if(
type->id() == last_recruit) {
298 if(!unknown_units.empty()) {
303 "Error: there’s an unknown unit type on your recruit list: $unknown_ids",
304 "Error: there are several unknown unit types on your recruit list: $unknown_ids",
305 unknown_units.size(),
306 {{
"unknown_ids", utils::format_conjunct_list(
"", unknown_units) }}
310 if(recruit_list.empty()) {
315 auto dlg = units_dialog::build_recruit_dialog(recruit_list, err_msgs_map, current_team);
316 dlg->set_selected_index(selected_index);
317 if (!dlg->show() && !dlg->is_selected()) {
321 const unit_type*
type = recruit_list[dlg->get_selected_index()];
322 last_recruit =
type->id();
325 if(err_msgs_map[
type].empty()) {
326 do_recruit(
type->id(), side_num, last_hex);
333 void menu_handler::repeat_recruit(
int side_num,
const map_location& last_hex)
335 team& current_team = board().get_team(side_num);
336 const std::string& last_recruit = current_team.
last_recruit();
337 if(last_recruit.empty())
return;
339 const auto validation = std::array
350 for(
const std::string&
err : validation) {
357 do_recruit(last_recruit, side_num, last_hex);
360 bool menu_handler::do_recruit(
const std::string&
type,
int side_num,
const map_location& target_hex)
373 if(
auto wb = pc_.get_whiteboard()) {
374 if(
wb->save_recruit(
type, side_num,
dst)) {
380 team& current_team = board().get_team(side_num);
391 if(pc_.get_disallow_recall()) {
396 team& current_team = board().get_team(side_num);
398 std::vector<unit_const_ptr> recall_list_team;
404 DBG_WB <<
"menu_handler::recall: Contents of wb-modified recall list:";
411 _(
"There are no troops available to recall.\n(You must have veteran survivors from a previous scenario.)"));
415 if(recall_list_team.empty()) {
420 const auto& dlg = units_dialog::build_recall_dialog(recall_list_team, current_team);
423 dlg->set_show_dismiss(pc_.current_side() == side_num);
425 if(!dlg->show() || !dlg->is_selected()) {
429 int res = dlg->get_selected_index();
438 if(sel_unit->recall_cost() > -1) {
439 unit_cost = sel_unit->recall_cost();
442 int wb_gold = pc_.get_whiteboard() ? pc_.get_whiteboard()->get_spent_gold_for(side_num) : 0;
444 if(current_team.
gold() - wb_gold < unit_cost) {
446 i18n_symbols[
"cost"] = std::to_string(unit_cost);
447 std::string
msg =
VNGETTEXT(
"You must have at least 1 gold piece to recall a unit.",
448 "You must have at least $cost gold pieces to recall this unit.", unit_cost, i18n_symbols);
453 LOG_NG <<
"recall index: " << res;
470 if(!pc_.get_whiteboard()
471 || !pc_.get_whiteboard()->save_recall(*sel_unit, side_num, recall_location)) {
476 ERR_NG <<
"menu_handler::recall(): Unit does not exist in the recall list.";
482 void menu_handler::show_enemy_moves(
bool ignore_units,
int side_num)
489 gui_->unhighlight_reach();
492 for(
auto& u : pc_.get_units()) {
493 bool invisible = u.invisible(u.get_location());
495 if(board().get_team(side_num).
is_enemy(u.side()) && !gui_->fogged(u.get_location()) && !u.incapacitated()
499 =
pathfind::paths(u,
false,
true, gui_->viewing_team(), 0,
false, ignore_units);
501 gui_->highlight_another_reach(
path, hex_under_mouse);
505 gui_->invalidate(u.get_location());
510 const bool selected_hex_has_unit = mh.
hex_hosts_unit(hex_under_mouse);
512 if(selected_hex_has_unit) {
521 void menu_handler::toggle_shroud_updates(
int side_num)
523 team& current_team = board().get_team(side_num);
527 update_shroud_now(side_num);
534 void menu_handler::update_shroud_now(
int )
543 bool units_alive(
int side_num,
const unit_map& units)
545 for(
auto&
unit : units) {
554 bool partmoved_units(
555 int side_num,
const unit_map& units,
const game_board& board,
const std::shared_ptr<wb::manager>& whiteb)
557 for(
auto&
unit : units) {
572 int side_num,
const unit_map& units,
const game_board& board,
const std::shared_ptr<wb::manager>& whiteb)
574 for(
auto&
unit : units) {
577 && (!whiteb || !whiteb->unit_has_actions(&
unit))) {
587 bool menu_handler::end_turn(
int side_num)
592 reason =
_(
"You cannot end your turn yet!");
598 std::size_t team_num =
static_cast<std::size_t
>(side_num - 1);
599 if(team_num < pc_.get_teams().size() && pc_.get_teams()[team_num].no_turn_confirmation()) {
604 && (!pc_.get_whiteboard() || !pc_.get_whiteboard()->current_side_has_actions())
605 && units_alive(side_num, pc_.get_units())) {
607 _(
"You have not started your turn yet. Do you really want to end your turn?"),
608 message::yes_no_buttons);
614 else if(
prefs::get().yellow_confirm() && partmoved_units(side_num, pc_.get_units(), board(), pc_.get_whiteboard())) {
616 _(
"Some units have movement left. Do you really want to end your turn?"),
617 message::yes_no_buttons);
623 else if(
prefs::get().green_confirm() && unmoved_units(side_num, pc_.get_units(), board(), pc_.get_whiteboard())) {
625 _(
"Some units have not moved. Do you really want to end your turn?"),
626 message::yes_no_buttons);
634 if(pc_.get_whiteboard() && !pc_.get_whiteboard()->allow_end_turn()) {
641 void menu_handler::goto_leader(
int side_num)
644 if(
i != pc_.get_units().end() &&
i->is_visible_to_team(gui_->viewing_team(),
false)) {
649 void menu_handler::unit_description()
652 if(un != pc_.get_units().end()) {
660 if(pc_.get_map().on_board(
loc) ==
false || gui_->shrouded(
loc)) {
669 void menu_handler::rename_unit()
672 if(un == pc_.get_units().end() || gui_->viewing_team().side() != un->side()) {
676 if(un->unrenamable()) {
680 std::string name = un->name();
681 const std::string title(
_(
"Rename Unit"));
682 const std::string
label(
_(
"Name:"));
684 if(edit_text::execute(title,
label, name)) {
687 gui_->invalidate_unit();
693 const mouse_handler& mousehandler = pc_.get_mouse_handler_base();
694 const bool see_all = gui_->show_everything() || (pc_.is_replay() && pc_.get_replay_controller()->see_all());
697 if(res != pc_.get_units().end()) {
708 typedef std::tuple<const unit_type*, unit_race::GENDER, std::string> type_gender_variation;
717 type_gender_variation choose_unit()
721 const auto& create_dlg = units_dialog::build_create_dialog(types_list);
723 for (std::size_t
i = 0;
i < types_list.size();
i++) {
724 if (types_list[
i]->
id() == last_created_unit) {
725 create_dlg->set_selected_index(
i);
726 create_dlg->set_gender(last_gender);
727 create_dlg->set_variation(last_variation);
733 if(!create_dlg->show()) {
737 if(!create_dlg->is_selected()) {
741 const unit_type* ut = types_list[create_dlg->get_selected_index()];
742 last_created_unit = ut->
id();
743 last_gender = create_dlg->gender();
744 last_variation = create_dlg->variation();
747 if (create_dlg->is_selected()) {
748 info = type_gender_variation(ut, last_gender, last_variation);
750 ERR_NG <<
"Create unit dialog returned nonexistent or unusable unit_type id.";
761 void create_and_place(
765 const std::string& variation =
"")
773 "variation", variation,
790 if(
const auto& [
type, gender, variation] = choose_unit();
type !=
nullptr) {
791 create_and_place(destination, *
type, gender, variation);
799 if(
i == pc_.get_units().end()) {
800 if(!pc_.get_map().is_village(
loc)) {
808 if(
team >
static_cast<int>(pc_.get_teams().size())) {
813 int side =
i->side();
815 if(side >
static_cast<int>(pc_.get_teams().size())) {
820 if(pc_.get_map().is_village(
loc)) {
832 void menu_handler::label_terrain(
mouse_handler& mousehandler,
bool team_only)
835 if(pc_.get_map().on_board(
loc) ==
false) {
840 std::string
label = old_label ? old_label->
text() :
"";
842 if(edit_label::execute(
label, team_only)) {
843 std::string team_name;
847 team_name = gui_->labels().team_name();
851 const terrain_label* res = gui_->labels().set_label(
loc,
label, gui_->viewing_team_index(), team_name, color);
858 void menu_handler::clear_labels()
860 if(!board().is_observer()) {
863 _(
"Are you sure you want to clear map labels?"),
864 message::yes_no_buttons
868 std::string viewing_team = gui_->viewing_team().team_name();
869 gui_->labels().clear(viewing_team,
false);
875 void menu_handler::label_settings()
877 if(label_settings::execute(board())) {
878 gui_->labels().recalculate_labels();
885 if(
i == pc_.get_units().end() || !
i->move_interrupted()) {
887 if(
i == pc_.get_units().end() || !
i->move_interrupted()) {
891 move_unit_to_loc(
i,
i->get_interrupted_move(),
true, side_num, mousehandler);
894 void menu_handler::move_unit_to_loc(
901 assert(ui != pc_.get_units().end());
905 if(route.
steps.empty()) {
909 assert(route.
steps.front() == ui->get_location());
911 gui_->set_route(&route);
912 gui_->unhighlight_reach();
915 LOG_NG <<
"move_unit_to_loc " << route.
steps.front() <<
" to " << route.
steps.back();
920 gui_->set_route(
nullptr);
921 gui_->invalidate_game_status();
930 bool wait_blocker_move =
true;
931 std::set<map_location> fully_moved;
934 bool blocked_unit =
false;
937 blocked_unit =
false;
938 for(
auto&
unit : pc_.get_units()) {
946 if(goto_loc == current_loc) {
951 if(!pc_.get_map().on_board(goto_loc)) {
956 if(fully_moved.count(current_loc)) {
962 if(route.
steps.size() <= 1) {
963 fully_moved.insert(current_loc);
969 pathfind::marked_route::mark_map::const_iterator
w = route.
marks.begin();
970 for(;
w != route.
marks.end(); ++
w) {
971 if(
w->second.turns == 1) {
972 next_stop =
w->first;
977 if(next_stop == current_loc) {
978 fully_moved.insert(current_loc);
984 if(pc_.get_units().count(next_stop)) {
986 if(wait_blocker_move)
990 gui_->set_route(&route);
993 LOG_NG <<
"execute goto from " << route.
steps.front() <<
" to " << route.
steps.back();
1000 wait_blocker_move =
true;
1004 if(!change && wait_blocker_move) {
1006 wait_blocker_move =
false;
1009 }
while(change && blocked_unit);
1012 gui_->set_route(
nullptr);
1013 gui_->invalidate_game_status();
1016 void menu_handler::toggle_ellipses()
1019 gui_->invalidate_all();
1022 void menu_handler::toggle_grid()
1025 gui_->invalidate_all();
1028 void menu_handler::unit_hold_position(
mouse_handler& mousehandler,
int side_num)
1031 if(un != pc_.get_units().end() && un->side() == side_num && un->movement_left() >= 0) {
1032 un->toggle_hold_position();
1037 if(un->hold_position()) {
1046 if(un != pc_.get_units().end() && un->side() == side_num && un->movement_left() >= 0) {
1047 un->toggle_user_end_turn();
1052 if(un->user_end_turn()) {
1064 void menu_handler::search()
1066 std::ostringstream
msg;
1068 if(last_search_hit_.valid()) {
1069 msg <<
" [" << last_search_ <<
"]";
1075 bool menu_handler::do_speak()
1079 return chat_handler::do_speak(
1080 textbox_info_.box()->text(), textbox_info_.check() !=
nullptr ? textbox_info_.check()->checked() :
false);
1083 void menu_handler::add_chat_message(
const std::chrono::system_clock::time_point& time,
1084 const std::string& speaker,
1089 gui_->get_chat_manager().add_chat_message(time, speaker, side,
message,
type,
false);
1116 using chmap::get_commands_list;
1117 using chmap::command_failed;
1123 chat_command_handler::command_handler
h,
1124 const std::string&
help =
"",
1125 const std::string& usage =
"",
1126 const std::string& flags =
"")
1128 chmap::register_command(cmd,
h,
help, usage, flags +
"N");
1133 chmap::register_alias(to_cmd, cmd);
1138 return chmap::get_arg(
i);
1143 return chmap::get_cmd();
1148 return chmap::get_data(
n);
1152 using chmap::register_command;
1153 using chmap::register_alias;
1155 using chmap::is_enabled;
1156 using chmap::command_failed_need_arg;
1164 void do_controller();
1166 void do_foreground();
1169 void do_benchmark();
1171 void do_save_quit();
1173 void do_ignore_replay_errors();
1175 void do_next_level();
1176 void do_choose_level();
1178 void do_turn_limit();
1182 void do_unsafe_lua();
1184 void do_set_alias();
1188 void do_control_dialog();
1193 void do_undiscover();
1199 void do_toggle_draw_coordinates();
1200 void do_toggle_draw_terrain_codes();
1201 void do_toggle_draw_num_of_bitmaps();
1202 void do_toggle_whiteboard();
1203 void do_whiteboard_options();
1207 return _(
"(D) — debug only, (N) — network only, (A) — admin only");
1210 using chat_command_handler::get_command_flags_description;
1213 std::string space(
" ");
1214 return (
c.has_flag(
'D') ? space +
_(
"(debug command)") :
"")
1215 + (
c.has_flag(
'N') ? space +
_(
"(network only)") :
"")
1216 + (
c.has_flag(
'A') ? space +
_(
"(admin only)") :
"")
1217 + (
c.has_flag(
'S') ? space +
_(
"(not during other events)") :
"");
1220 using map::is_enabled;
1224 || (
c.has_flag(
'N') && !menu_handler_.pc_.is_networked_mp())
1231 menu_handler_.add_chat_message(std::chrono::system_clock::now(), title, 0,
message);
1236 chat_command_handler::init_map();
1238 chmap::get_command(
"log")->flags =
"";
1239 chmap::get_command(
"version")->flags =
"";
1240 chmap::get_command(
"ignore")->flags =
"";
1241 chmap::get_command(
"friend")->flags =
"";
1242 chmap::get_command(
"remove")->flags =
"";
1244 chmap::set_cmd_prefix(
":");
1245 chmap::set_cmd_flag(
true);
1247 register_command(
"refresh", &console_handler::do_refresh,
_(
"Refresh gui."));
1248 register_command(
"droid", &console_handler::do_droid,
_(
"Switch a side to/from AI control."),
1252 _(
"[<side> [on/off/full]]\n“on” = enable but retain vision, “full” = as if it’s controlled by another player"));
1253 register_command(
"terrain", &console_handler::do_terrain,
_(
"Change terrain type of current hex"),
1255 _(
"<terrain type> [both|base|overlay]"),
"DS");
1256 register_command(
"idle", &console_handler::do_idle,
_(
"Switch a side to/from idle state."),
1260 _(
"command_idle^[<side> [on/off]]"));
1261 register_command(
"theme", &console_handler::do_theme,
_(
"Change the in-game theme."));
1262 register_command(
"control", &console_handler::do_control,
1263 _(
"Assign control of a side to a different player or observer."),
_(
"<side> <nickname>"),
"N");
1264 register_command(
"controller", &console_handler::do_controller,
_(
"Query the controller status of a side."),
1266 register_command(
"clear", &console_handler::do_clear,
_(
"Clear chat history."));
1267 register_command(
"foreground", &console_handler::do_foreground,
_(
"Debug foreground terrain."),
"",
"D");
1269 "layers", &console_handler::do_layers,
_(
"Debug layers from terrain under the mouse."),
"",
"D");
1270 register_command(
"fps", &console_handler::do_fps,
_(
"Display and log fps (Frames Per Second)."));
1271 register_command(
"benchmark", &console_handler::do_benchmark,
_(
"Similar to the ‘fps’ command, but also forces everything to redraw instead of only things that have changed."));
1272 register_command(
"save", &console_handler::do_save,
_(
"Save game."));
1273 register_alias(
"save",
"w");
1274 register_command(
"quit", &console_handler::do_quit,
_(
"Quit game."));
1276 register_alias(
"quit",
"q!");
1277 register_command(
"save_quit", &console_handler::do_save_quit,
_(
"Save and quit."));
1278 register_alias(
"save_quit",
"wq");
1279 register_command(
"ignore_replay_errors", &console_handler::do_ignore_replay_errors,
_(
"Ignore replay errors."));
1280 register_command(
"nosaves", &console_handler::do_nosaves,
_(
"Disable autosaves."));
1281 register_command(
"next_level", &console_handler::do_next_level,
1282 _(
"Advance to the next scenario, or scenario identified by ‘id’"),
_(
"<id>"),
"DS");
1283 register_alias(
"next_level",
"n");
1284 register_command(
"choose_level", &console_handler::do_choose_level,
_(
"Choose next scenario"),
"",
"DS");
1285 register_alias(
"choose_level",
"cl");
1286 register_command(
"turn", &console_handler::do_turn,
1287 _(
"Change turn number (and time of day), or increase by one if no number is specified."),
_(
"[turn]"),
1289 register_command(
"turn_limit", &console_handler::do_turn_limit,
1290 _(
"Change turn limit, or turn the turn limit off if no number is specified or it’s −1."),
_(
"[limit]"),
1292 register_command(
"debug", &console_handler::do_debug,
_(
"Turn debug mode on."));
1293 register_command(
"nodebug", &console_handler::do_nodebug,
_(
"Turn debug mode off."),
"",
"D");
1295 "lua", &console_handler::do_lua,
_(
"Execute a Lua statement."),
_(
"<command>[;<command>...]"),
"DS");
1297 "unsafe_lua", &console_handler::do_unsafe_lua,
_(
"Grant higher privileges to Lua scripts."),
"",
"D");
1298 register_command(
"custom", &console_handler::do_custom,
_(
"Set the command used by the custom command hotkey"),
1299 _(
"<command>[;<command>...]"));
1300 register_command(
"give_control", &console_handler::do_control_dialog,
1301 _(
"Invoke a dialog allowing changing control of MP sides."),
"",
"N");
1302 register_command(
"inspect", &console_handler::do_inspect,
_(
"Launch the gamestate inspector"),
"",
"D");
1304 "alias", &console_handler::do_set_alias,
_(
"Set or show alias to a command"),
_(
"<name>[=<command>]"));
1306 "set_var", &console_handler::do_set_var,
_(
"Set a scenario variable."),
_(
"<var>=<value>"),
"DS");
1307 register_command(
"show_var", &console_handler::do_show_var,
_(
"Show a scenario variable."),
_(
"<var>"),
"D");
1308 register_command(
"unit", &console_handler::do_unit,
1310 _(
"Modify a unit variable. (Only top level keys are supported, and advances=<number>.)"),
1311 _(
"<var>=<value>"),
"DS");
1317 register_command(
"discover", &console_handler::do_discover,
_(
"Discover all units in help."),
"");
1318 register_command(
"undiscover", &console_handler::do_undiscover,
_(
"‘Undiscover’ all units in help."),
"");
1319 register_command(
"create", &console_handler::do_create,
_(
"Create a unit."),
_(
"<unit type id>"),
"DS");
1320 register_command(
"fog", &console_handler::do_fog,
_(
"Toggle fog for the current player."),
"",
"DS");
1321 register_command(
"shroud", &console_handler::do_shroud,
_(
"Toggle shroud for the current player."),
"",
"DS");
1322 register_command(
"gold", &console_handler::do_gold,
_(
"Give gold to the current player."),
_(
"<amount>"),
"DS");
1323 register_command(
"throw", &console_handler::do_event,
_(
"Fire a game event."),
_(
"<event name>"),
"DS");
1324 register_alias(
"throw",
"fire");
1325 register_command(
"show_coordinates", &console_handler::do_toggle_draw_coordinates,
1326 _(
"Toggle overlaying of x,y coordinates on hexes."));
1327 register_alias(
"show_coordinates",
"sc");
1328 register_command(
"show_terrain_codes", &console_handler::do_toggle_draw_terrain_codes,
1329 _(
"Toggle overlaying of terrain codes on hexes."));
1330 register_alias(
"show_terrain_codes",
"tc");
1331 register_command(
"show_num_of_bitmaps", &console_handler::do_toggle_draw_num_of_bitmaps,
1332 _(
"Toggle overlaying of number of bitmaps on hexes."));
1333 register_alias(
"show_num_of_bitmaps",
"bn");
1334 register_command(
"whiteboard", &console_handler::do_toggle_whiteboard,
_(
"Toggle planning mode."));
1335 register_alias(
"whiteboard",
"wb");
1337 "whiteboard_options", &console_handler::do_whiteboard_options,
_(
"Access whiteboard options dialog."));
1338 register_alias(
"whiteboard_options",
"wbo");
1340 if(
auto alias_list =
prefs::get().get_alias()) {
1341 for(
const auto& [key, value] : alias_list->attribute_range()) {
1342 register_alias(value, key);
1352 void menu_handler::send_chat_message(
const std::string&
message,
bool allies_only)
1357 auto now = std::chrono::system_clock::now();
1360 const int side = board().
is_observer() ? 0 : gui_->viewing_team().side();
1361 if(!board().is_observer()) {
1368 if(board().is_observer()) {
1371 cfg[
"to_sides"] = gui_->viewing_team().allied_human_teams();
1377 add_chat_message(now,
cfg[
"id"], side,
message,
1381 void menu_handler::do_search(
const std::string& new_search)
1383 if(new_search.empty() ==
false && new_search != last_search_)
1384 last_search_ = new_search;
1386 if(last_search_.empty())
1392 std::vector<std::string> args =
utils::split(last_search_,
',');
1393 if(args.size() == 2) {
1395 x = lexical_cast_default<int>(args[0], 0) - 1;
1396 y = lexical_cast_default<int>(args[1], 0) - 1;
1397 if(x >= 0 && x < pc_.get_map().w() && y >= 0 && y < pc_.get_map().h()) {
1410 loc.
x = (
loc.
x + 1) % pc_.get_map().w();
1412 loc.
y = (
loc.
y + 1) % pc_.get_map().h();
1415 if(!gui_->shrouded(
loc)) {
1418 const std::string& label_text =
label->text().str();
1424 if(!gui_->fogged(
loc)) {
1426 if(ui != pc_.get_units().end()) {
1427 const std::string&
unit_name = ui->name();
1429 if(!gui_->viewing_team().is_enemy(ui->side())
1430 || !ui->invisible(ui->get_location())) {
1442 last_search_hit_ =
loc;
1444 gui_->highlight_hex(
loc);
1449 symbols[
"search"] = last_search_;
1450 const std::string
msg =
VGETTEXT(
"Could not find label or unit "
1451 "containing the string ‘$search’.",
1457 void menu_handler::do_command(
const std::string& str)
1463 std::vector<std::string> menu_handler::get_commands_list()
1474 void console_handler::do_refresh()
1479 menu_handler_.gui_->create_buttons();
1480 menu_handler_.gui_->queue_rerender();
1483 void console_handler::do_droid()
1486 const std::string side_s = get_arg(1);
1487 std::string action = get_arg(2);
1488 std::transform(action.begin(), action.end(), action.begin(), tolower);
1490 const unsigned int side = side_s.empty() ? team_num_ : lexical_cast_default<unsigned int>(side_s);
1491 const bool is_your_turn = menu_handler_.pc_.current_side() ==
static_cast<int>(menu_handler_.gui_->viewing_team().side());
1492 team&
team = menu_handler_.board().get_team(side);
1495 symbols[
"side"] = std::to_string(side);
1497 if(side < 1 || side > menu_handler_.pc_.get_teams().size()) {
1498 command_failed(
VGETTEXT(
"Can’t droid invalid side: ‘$side’.", symbols));
1501 command_failed(
VGETTEXT(
"Can’t droid networked side: ‘$side’.", symbols));
1504 bool changed =
false;
1511 if(action ==
"on") {
1512 if(is_ai && !is_your_turn) {
1513 command_failed(
_(
"It is not allowed to change a side from AI to human control when it’s not your turn."));
1516 if(!is_human || !is_droid) {
1521 menu_handler_.pc_.send_to_wesnothd(
config {
"change_controller",
config {
"side", side,
"player",
prefs::get().
login(),
"to", side_controller::human}});
1523 print(get_cmd(),
VGETTEXT(
"Side ‘$side’ controller is now controlled by: AI.", symbols));
1525 print(get_cmd(),
VGETTEXT(
"Side ‘$side’ is already droided.", symbols));
1527 }
else if(action ==
"off") {
1528 if(is_ai && !is_your_turn) {
1529 command_failed(
_(
"It is not allowed to change a side from AI to human control when it’s not your turn."));
1532 if(!is_human || !is_proxy_human) {
1537 menu_handler_.pc_.send_to_wesnothd(
config {
"change_controller",
config {
"side", side,
"player",
prefs::get().
login(),
"to", side_controller::human}});
1539 print(get_cmd(),
VGETTEXT(
"Side ‘$side’ controller is now controlled by: human.", symbols));
1541 print(get_cmd(),
VGETTEXT(
"Side ‘$side’ is already not droided.", symbols));
1543 }
else if(action ==
"full") {
1545 command_failed(
_(
"It is not allowed to change a side from human to AI control when it’s not your turn."));
1548 if(!is_ai || !is_droid) {
1552 if(is_human || is_proxy_human) {
1553 menu_handler_.pc_.send_to_wesnothd(
config {
"change_controller",
config {
"side", side,
"player",
prefs::get().
login(),
"to", side_controller::ai}});
1555 print(get_cmd(),
VGETTEXT(
"Side ‘$side’ controller is now fully controlled by: AI.", symbols));
1557 print(get_cmd(),
VGETTEXT(
"Side ‘$side’ is already fully AI controlled.", symbols));
1559 }
else if(action ==
"") {
1560 if(is_ai && !is_your_turn) {
1561 command_failed(
_(
"It is not allowed to change a side from AI to human control when it’s not your turn."));
1564 if(is_ai || is_droid) {
1569 menu_handler_.pc_.send_to_wesnothd(
config {
"change_controller",
config {
"side", side,
"player",
prefs::get().
login(),
"to", side_controller::human}});
1571 print(get_cmd(),
VGETTEXT(
"Side ‘$side’ controller is now controlled by: human.", symbols));
1577 menu_handler_.pc_.send_to_wesnothd(
config {
"change_controller",
config {
"side", side,
"player",
prefs::get().
login(),
"to", side_controller::human}});
1579 print(get_cmd(),
VGETTEXT(
"Side ‘$side’ controller is now controlled by: AI.", symbols));
1582 print(get_cmd(),
VGETTEXT(
"Invalid action provided for side ‘$side’. Valid actions are: on, off, full.", symbols));
1585 if(team_num_ == side && changed) {
1587 psc->set_player_type_changed();
1591 command_failed(
VGETTEXT(
"Side ‘$side’ is not a human or AI player.", symbols));
1594 menu_handler_.textbox_info_.close();
1597 void console_handler::do_terrain()
1601 const std::string mode_str = get_arg(2);
1611 "mode_str", mode_str,
1616 void console_handler::do_idle()
1619 const std::string side_s = get_arg(1);
1620 const std::string action = get_arg(2);
1622 const unsigned int side = side_s.empty() ? team_num_ : lexical_cast_default<unsigned int>(side_s);
1623 team&
team = menu_handler_.board().get_team(side);
1625 if(side < 1 || side > menu_handler_.pc_.get_teams().size()) {
1627 symbols[
"side"] = side_s;
1628 command_failed(
VGETTEXT(
"Can’t idle invalid side: ‘$side’.", symbols));
1632 symbols[
"side"] = std::to_string(side);
1633 command_failed(
VGETTEXT(
"Can’t idle networked side: ‘$side’.", symbols));
1637 symbols[
"side"] = std::to_string(side);
1638 command_failed(
VGETTEXT(
"Can’t idle local ai side: ‘$side’.", symbols));
1641 if(
team.
is_idle() ? action ==
" on" : action ==
" off") {
1646 if(team_num_ == side) {
1648 psc->set_player_type_changed();
1652 menu_handler_.textbox_info_.close();
1655 void console_handler::do_theme()
1660 void console_handler::do_control()
1663 if(!menu_handler_.pc_.is_networked_mp()) {
1667 const std::string side = get_arg(1);
1668 const std::string player = get_arg(2);
1669 if(player.empty()) {
1670 command_failed_need_arg(2);
1674 unsigned int side_num;
1676 side_num = lexical_cast<unsigned int>(side);
1678 const auto& teams = menu_handler_.pc_.get_teams();
1681 if(it_t == teams.end()) {
1683 symbols[
"side"] = side;
1684 command_failed(
VGETTEXT(
"Can’t change control of invalid side: ‘$side’.", symbols));
1687 side_num = it_t->side();
1691 if(side_num < 1 || side_num > menu_handler_.pc_.get_teams().size()) {
1693 symbols[
"side"] = side;
1694 command_failed(
VGETTEXT(
"Can’t change control of out-of-bounds side: ‘$side’.", symbols));
1698 menu_handler_.request_control_change(side_num, player);
1699 menu_handler_.textbox_info_.close();
1702 void console_handler::do_controller()
1704 const std::string side = get_arg(1);
1705 unsigned int side_num;
1707 side_num = lexical_cast<unsigned int>(side);
1710 symbols[
"side"] = side;
1711 command_failed(
VGETTEXT(
"Can’t query control of invalid side: ‘$side’.", symbols));
1715 if(side_num < 1 || side_num > menu_handler_.pc_.get_teams().size()) {
1717 symbols[
"side"] = side;
1718 command_failed(
VGETTEXT(
"Can’t query control of out-of-bounds side: ‘$side’.", symbols));
1723 if(!menu_handler_.board().get_team(side_num).is_proxy_human()) {
1727 if(menu_handler_.board().get_team(side_num).is_network()) {
1728 report +=
" (networked)";
1731 print(get_cmd(), report);
1734 void console_handler::do_clear()
1736 menu_handler_.gui_->get_chat_manager().clear_chat_messages();
1739 void console_handler::do_foreground()
1742 menu_handler_.gui_->invalidate_all();
1745 void console_handler::do_layers()
1747 display& disp = *(menu_handler_.gui_);
1761 if(menu_handler_.pc_.get_map().on_board_with_border(
loc)) {
1762 terrain_layers::display(disp,
loc);
1766 void console_handler::do_fps()
1771 void console_handler::do_benchmark()
1776 void console_handler::do_save()
1778 menu_handler_.pc_.do_consolesave(get_data());
1781 void console_handler::do_save_quit()
1787 void console_handler::do_quit()
1792 void console_handler::do_ignore_replay_errors()
1797 void console_handler::do_nosaves()
1802 void console_handler::do_next_level()
1807 void console_handler::do_choose_level()
1809 std::string
tag = menu_handler_.pc_.get_classification().get_tagname();
1810 std::vector<std::string> options;
1812 if(
tag !=
"multiplayer") {
1814 const std::string&
id = sc[
"id"];
1815 options.push_back(
id);
1816 if(
id == menu_handler_.gamedata().next_scenario()) {
1823 std::string scenario_id = menu_handler_.pc_.get_mp_settings().mp_scenario;
1824 if(
auto this_scenario = menu_handler_.game_config_.find_child(
tag,
"id", scenario_id)) {
1825 std::string addon_id = this_scenario[
"addon_id"].str();
1827 if(sc[
"addon_id"] == addon_id) {
1828 std::string
id = sc[
"id"];
1829 options.push_back(
id);
1830 if(
id == menu_handler_.gamedata().next_scenario()) {
1837 std::sort(options.begin(), options.end());
1838 int choice = std::distance(options.begin(), std::lower_bound(options.begin(), options.end(), next));
1850 if(std::size_t(choice) < options.size()) {
1855 void console_handler::do_turn()
1857 tod_manager& tod_man = menu_handler_.gamestate().tod_manager_;
1859 int turn = tod_man.
turn() + 1;
1860 const std::string&
data = get_data();
1862 turn = lexical_cast_default<int>(
data, 1);
1867 void console_handler::do_turn_limit()
1869 int limit = get_data().empty() ? -1 : lexical_cast_default<int>(get_data(), 1);
1873 void console_handler::do_debug()
1876 print(get_cmd(),
_(
"Debug mode activated!"));
1879 command_failed(
_(
"Debug mode not available in network games"));
1883 void console_handler::do_nodebug()
1886 print(get_cmd(),
_(
"Debug mode deactivated!"));
1891 void console_handler::do_lua()
1893 if(!menu_handler_.gamestate().lua_kernel_) {
1900 void console_handler::do_unsafe_lua()
1902 if(!menu_handler_.gamestate().lua_kernel_) {
1907 _(
"Executing Lua code in in this manner opens your computer to potential security breaches from any "
1908 "malicious add-ons or other programs you may have installed.\n\n"
1909 "Do not continue unless you really know what you are doing."), message::ok_cancel_buttons);
1912 print(get_cmd(),
_(
"Unsafe mode enabled!"));
1913 menu_handler_.gamestate().lua_kernel_->load_package();
1917 void console_handler::do_custom()
1922 void console_handler::do_set_alias()
1924 const std::string
data = get_data();
1926 const std::string alias(
data.begin(), j);
1927 if(j !=
data.end()) {
1928 const std::string command(j + 1,
data.end());
1929 if(!command.empty()) {
1930 register_alias(command, alias);
1934 register_alias(alias, alias);
1942 const std::string command = chmap::get_actual_cmd(alias);
1943 print(get_cmd(),
"'" + alias +
"'" +
" = " +
"'" + command +
"'");
1947 void console_handler::do_set_var()
1949 const std::string
data = get_data();
1951 command_failed_need_arg(1);
1956 if(j !=
data.end()) {
1957 const std::string name(
data.begin(), j);
1958 const std::string value(j + 1,
data.end());
1961 command_failed(
_(
"Variable not found"));
1965 void console_handler::do_show_var()
1970 void console_handler::do_inspect()
1973 gamestate_inspector::display(
1977 void console_handler::do_control_dialog()
1979 mp_change_control::display(menu_handler_);
1982 void console_handler::do_unit()
1990 if(
i == menu_handler_.pc_.get_units().end()) {
1992 symbols[
"unit"] = get_arg(1);
1994 "Debug command ‘unit: $unit’ failed: no unit selected or hovered over.",
2000 const std::string
data = get_data(1);
2002 if(parameters.size() < 2) {
2006 if(parameters[0] ==
"alignment") {
2010 symbols[
"alignment"] = get_arg(1);
2012 "Invalid alignment: ‘$alignment’, needs to be one of lawful, neutral, chaotic, or liminal.",
2022 "name", parameters[0],
2023 "value", parameters[1],
2028 void console_handler::do_discover()
2030 for(
const unit_type_data::unit_type_map::value_type&
i :
unit_types.
types()) {
2035 void console_handler::do_undiscover()
2038 _(
"Do you wish to clear all of your discovered units from help?"), message::yes_no_buttons);
2045 void console_handler::do_create()
2049 if(menu_handler_.pc_.get_map().on_board(
loc)) {
2052 command_failed(
_(
"Invalid unit type"));
2057 create_and_place(
loc, *ut);
2059 command_failed(
_(
"Invalid location"));
2063 void console_handler::do_fog()
2068 void console_handler::do_shroud()
2073 void console_handler::do_gold()
2078 void console_handler::do_event()
2083 void console_handler::do_toggle_draw_coordinates()
2086 menu_handler_.gui_->invalidate_all();
2088 void console_handler::do_toggle_draw_terrain_codes()
2091 menu_handler_.gui_->invalidate_all();
2094 void console_handler::do_toggle_draw_num_of_bitmaps()
2097 menu_handler_.gui_->invalidate_all();
2100 void console_handler::do_toggle_whiteboard()
2102 if(
const std::shared_ptr<wb::manager>& whiteb = menu_handler_.pc_.get_whiteboard()) {
2103 whiteb->set_active(!whiteb->is_active());
2104 if(whiteb->is_active()) {
2105 print(get_cmd(),
_(
"Planning mode activated!"));
2106 whiteb->print_help_once();
2108 print(get_cmd(),
_(
"Planning mode deactivated!"));
2113 void console_handler::do_whiteboard_options()
2115 if(menu_handler_.pc_.get_whiteboard()) {
2116 menu_handler_.pc_.get_whiteboard()->options_dlg();
2125 add_chat_message(std::chrono::system_clock::now(),
"wfl", 0, result.
to_debug_string());
2132 void menu_handler::user_command()
2137 void menu_handler::request_control_change(
int side_num,
const std::string& player)
2139 std::string side = std::to_string(side_num);
2140 if(board().get_team(side_num).is_local_human() && player ==
prefs::get().login()) {
2146 pc_.send_to_wesnothd(
config {
"change_controller",
config {
"side", side,
"player", player}});
2150 void menu_handler::custom_command()
2153 do_command(command);
2157 void menu_handler::ai_formula()
2159 if(!pc_.is_networked_mp()) {
2164 void menu_handler::clear_messages()
2166 gui_->get_chat_manager().clear_chat_messages();
2171 pc_.send_to_wesnothd(
cfg);
static bool is_enemy(std::size_t side, std::size_t other_side)
Various functions related to moving units.
A config object defines a single node in a WML file, with access to child nodes.
child_itors child_range(std::string_view key)
int village_owner(const map_location &loc) const
Given the location of a village, will return the 1-based number of the team that currently owns it,...
bool is_observer() const
Check if we are an observer in this game.
can_move_result unit_can_move(const unit &u) const
Work out what u can do - this does not check which player's turn is currently active,...
virtual const unit_map & units() const =0
Sort-of-Singleton that many classes, both GUI and non-GUI, use to access the game data.
const team & viewing_team() const
@ DEBUG_COORDINATES
Overlays x,y coords on tiles.
@ DEBUG_BENCHMARK
Toggle to continuously redraw the whole map.
@ DEBUG_NUM_BITMAPS
Overlays number of bitmaps on tiles.
@ DEBUG_FOREGROUND
Separates background and foreground terrain layers.
@ DEBUG_TERRAIN_CODES
Overlays terrain codes on tiles.
void scroll_to_tile(const map_location &loc, SCROLL_TYPE scroll_type=ONSCREEN, bool check_fogged=true, bool force=true)
Scroll such that location loc is on-screen.
const display_context & context() const
void queue_rerender()
Marks everything for rendering including all tiles and sidebar.
virtual std::string get_arg(unsigned i) const
std::string get_flags_description() const
virtual std::string get_cmd() const
console_handler(menu_handler &menu_handler)
void print(const std::string &title, const std::string &message)
virtual void register_alias(const std::string &to_cmd, const std::string &cmd)
bool is_enabled(const chmap::command &c) const
virtual std::string get_data(unsigned n=1) const
menu_handler & menu_handler_
std::string get_command_flags_description(const chmap::command &c) const
virtual void register_command(const std::string &cmd, chat_command_handler::command_handler h, const std::string &help="", const std::string &usage="", const std::string &flags="")
map_command_handler< console_handler > chmap
const unsigned int team_num_
bool dispatch(std::string cmd)
std::vector< std::string > get_commands_list() const
game_board & board() const
gui::floating_textbox & get_textbox()
gui::floating_textbox textbox_info_
void show_statistics(int side_num)
void recruit(int side_num, const map_location &last_hex)
game_state & gamestate() const
void disable_units_highlight()
Use this to disable hovering an unit from highlighting its movement range.
void set_current_paths(const pathfind::paths &new_paths)
pathfind::marked_route get_route(const unit *un, map_location go_to, const team &team) const
map_location get_selected_hex() const
const map_location hovered_hex() const
Uses SDL and game_display::hex_clicked_on to fetch the hex the mouse is hovering, if applicable.
const map_location & get_last_hex() const
bool hex_hosts_unit(const map_location &hex) const
Unit exists on the hex, no matter if friend or foe.
void cycle_units(const bool browse, const bool reverse=false)
unit_map::iterator find_visible_unit(const map_location &loc, const team ¤t_team, bool see_all=false)
void scroll_to_leader(int side, SCROLL_TYPE scroll_type=ONSCREEN, bool force=true)
Scrolls to the leader of a certain side.
virtual const std::set< std::string > & observers() const override
virtual void select_hex(map_location hex) override
Function to display a location as selected.
std::string write() const
file_dialog & set_extension(const std::string &value)
Sets allowed file extensions for file names in save mode.
file_dialog & set_path(const std::string &value)
Sets the initial file selection.
file_dialog & set_title(const std::string &value)
Sets the current dialog title text.
file_dialog & set_save_mode(bool value)
Sets the dialog's behavior on non-existent file name inputs.
std::string path() const
Gets the current file selection.
Main class to show messages to the user.
bool show(const unsigned auto_close_time=0)
Shows the window.
int selected_index() const
Returns the selected item index after displaying.
void set_selected_index(int index)
Sets the initially selected item index (-1 by default).
void show(gui::TEXTBOX_MODE mode, const std::string &label, const std::string &check_label, bool checked, game_display &gui)
std::vector< team > & get_teams()
void show_objectives() const
statistics_t & statistics()
events::mouse_handler & get_mouse_handler_base() override
Get a reference to a mouse handler member a derived class uses.
const gamemap & get_map() const
void refresh_objectives() const
Reevaluate [show_if] conditions and build a new objectives string.
void notify_event(const std::string &name, const config &data)
static plugins_manager * get()
std::set< std::string > & encountered_units()
void add_alias(const std::string &alias, const std::string &command)
void set_message_private(bool value)
void set_show_fps(bool value)
bool empty() const
Is it empty?
static config get_recall(const std::string &unit_id, const map_location &loc, const map_location &from)
static config get_recruit(const std::string &type_id, const map_location &loc, const map_location &from)
static config get_update_shroud()
Records that the player has manually updated fog/shroud.
static config get_auto_shroud(bool turned_on, bool block_undo=true)
Records that the player has toggled automatic shroud updates.
void add_rename(const std::string &name, const map_location &loc)
void add_label(const terrain_label *)
void speak(const config &cfg)
void clear_labels(const std::string &, bool)
static synced_state get_synced_state()
static bool run_and_throw(const std::string &commandname, const config &data, action_spectator &spectator=get_default_spectator())
This class stores all the data for a single 'side' (in game nomenclature).
bool is_proxy_human() const
bool auto_shroud_updates() const
const std::string & team_name() const
bool is_local_human() const
void set_last_recruit(const std::string &u_type)
const std::string & save_id() const
static color_t get_side_color(int side)
void increment_action_bonus_count()
recall_list_manager & recall_list()
const std::string & last_recruit() const
To store label data Class implements logic for rendering.
const t_string & text() const
Container associating units to locations.
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.
const std::vector< const unit_type * > types_list() const
const unit_type_map & types() const
A single unit type that the player may recruit.
const std::string & id() const
The id for this unit_type.
This class represents a single unit of a specific type.
A variable-expanding proxy for the config class.
static vconfig empty_vconfig()
An object representing the state of the game, providing access to the map and basic information.
std::string to_debug_string(bool verbose=false, formula_seen_stack *seen=nullptr) const
Various functions related to the creation of units (recruits, recalls, and placed units).
static void print(std::stringstream &sstr, const std::string &queue, const std::string &id)
Contains the exception interfaces used to signal completion of a scenario, campaign or turn.
void throw_quit_game_exception()
int dispatch(lua_State *L)
static std::string _(const char *str)
bool user_end_turn() const
Check whether the user ended their turn.
const std::string & id() const
Gets this unit's id.
int side() const
The side this unit belongs to.
const t_string & name() const
Gets this unit's translatable display name.
const map_location & get_location() const
The current map location this unit is at.
bool has_moved() const
Checks if this unit has moved.
void set_goto(const map_location &new_goto)
Sets this unit's long term destination.
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
const map_location & get_goto() const
The map location to which this unit is moving over multiple turns, if any.
std::string label
What to show in the filter's drop-down list.
std::string id
Text to match against addon_info.tags()
Standard logging facilities (interface).
std::set< std::string > get_recruits(int side, const map_location &recruit_loc)
Gets the recruitable units from a side's leaders' personal recruit lists who can recruit on or from a...
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.
std::vector< unit_const_ptr > get_recalls(int side, const map_location &recall_loc)
Gets the recallable units for a side, restricted by that side's leaders' personal abilities to recall...
std::size_t move_unit_and_record(const std::vector< map_location > &steps, bool continued_move, bool *interrupted)
Wrapper around the other overload.
std::string find_recall_location(const int side, map_location &recall_location, map_location &recall_from, const unit &unit_recall)
Finds a location on which to recall unit_recall.
auto serialize_timestamp(const std::chrono::system_clock::time_point &time)
EXIT_STATUS start(bool clear_id, const std::string &filename, bool take_screenshot, const std::string &screenshot_filename)
Main interface for launching the editor from the title screen.
Handling of system events.
std::string get_legacy_editor_dir()
const std::string map_extension
void write_file(const std::string &fname, const std::string &data, std::ios_base::openmode mode)
Throws io_exception if an error occurs.
const color_t LABEL_COLOR
std::string private_message
Game configuration data as global variables.
bool ignore_replay_errors
const std::string observer_team_name
observer team name used for observer team chat
void set_debug(bool new_debug)
void show_transient_error_message(const std::string &message, const std::string &image, const bool message_use_markup)
Shows a transient error message to the user.
void show_transient_message(const std::string &title, const std::string &message, const std::string &image, const bool message_use_markup, const bool title_use_markup)
Shows a transient message to the user.
void show_message(const std::string &title, const std::string &msg, const std::string &button_caption, const bool auto_close, const bool message_use_markup, const bool title_use_markup)
Shows a message to the user.
retval
Default window/dialog return values.
@ OK
Dialog was closed with the OK button.
@ CANCEL
Dialog was closed with the CANCEL button.
void show_terrain_description(const terrain_type &t)
void show_unit_description(const unit &u)
void show_help(const std::string &show_topic)
Open the help browser.
void flush_cache()
Purges all image caches.
std::string tag(std::string_view tag, Args &&... data)
Wraps the given data in the specified tag.
void send_to_server(const config &data)
Attempts to send given data to server if a connection is open.
bool logged_in_as_moderator()
Gets whether the currently logged-in user is a moderator.
game_events::manager * game_events
bool ci_search(const std::string &s1, const std::string &s2)
Case-insensitive search.
static std::string sgettext(const char *str)
std::string check_recruit_list(const std::string &type, int side_number, const map_location &target_hex)
std::string check_recruit_purse(int unit_cost, int current_purse, int investments)
int planned_gold_spent(int side_number)
std::tuple< std::string, map_location, map_location > validate_recruit_target(const std::string &type, int side_number, const map_location &target_hex)
Verifies that target_hex is a valid recruit location for the given side.
auto find(Container &container, const Value &value, const Projection &projection={})
@ STRIP_SPACES
REMOVE_EMPTY: remove empty elements.
std::string get_unknown_exception_type()
Utility function for finding the type of thing caught with catch(...).
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()
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
std::shared_ptr< const unit > unit_const_ptr
const std::string & gender_string(unit_race::GENDER gender)
static config unit_name(const unit *u)
rect dst
Location on the final composed sheet.
rect src
Non-transparent portion of the surface to compose.
Thrown when a lexical_cast fails.
The basic class for representing 8-bit RGB or RGBA colour values.
An exception object used when an IO error occurs.
Encapsulates the map of the game.
static const map_location & null_location()
Structure which holds a single route and marks for special events.
std::vector< map_location > & steps
Object which contains all the possible locations a unit can move to, with associated best routes to t...
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
static constexpr utils::optional< enum_type > get_enum(const std::string_view value)
Converts a string into its enum equivalent.
Object which temporarily resets a unit's movement.
ONLY IF whiteboard is currently active, applies the planned unit map for the duration of the struct's...
Applies the planned unit map for the duration of the struct's life.
const std::string & gamedata
static map_location::direction n
unit_type_data unit_types
Various functions that implement the undoing (and redoing) of in-game commands.