The Battle for Wesnoth  1.15.0-dev
menu_events.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2018 by Joerg Hinrichs <joerg.hinrichs@alice-dsl.de>
3  wesnoth playturn Copyright (C) 2003 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 /**
17  * @file
18  * Operations activated from menus/hotkeys while playing a game.
19  * E.g. Unitlist, status_table, save_game, save_map, chat, show_help, etc.
20  */
21 
22 #include "menu_events.hpp"
23 
24 #include "actions/attack.hpp"
25 #include "actions/create.hpp"
26 #include "actions/move.hpp"
27 #include "actions/undo.hpp"
28 #include "actions/vision.hpp"
29 #include "ai/manager.hpp"
30 #include "chat_command_handler.hpp"
31 #include "color.hpp"
32 #include "display_chat_manager.hpp"
33 #include "font/standard_colors.hpp"
34 #include "formula/string_utils.hpp"
35 #include "game_board.hpp"
36 #include "game_config_manager.hpp"
37 #include "game_end_exceptions.hpp"
38 #include "game_events/pump.hpp"
39 #include "preferences/game.hpp"
40 #include "game_state.hpp"
41 #include "gettext.hpp"
42 #include "gui/dialogs/chat_log.hpp"
50 #include "gui/dialogs/message.hpp"
61 #include "gui/widgets/settings.hpp"
62 #include "gui/widgets/retval.hpp"
63 #include "help/help.hpp"
64 #include "log.hpp"
65 #include "map/label.hpp"
66 #include "map/map.hpp"
67 #include "map_command_handler.hpp"
68 #include "mouse_events.hpp"
69 #include "play_controller.hpp"
72 #include "preferences/display.hpp"
73 #include "replay.hpp"
74 #include "replay_helper.hpp"
75 #include "resources.hpp"
76 #include "save_index.hpp"
77 #include "savegame.hpp"
80 #include "synced_context.hpp"
81 #include "terrain/builder.hpp"
82 #include "units/udisplay.hpp"
83 #include "units/unit.hpp"
84 #include "whiteboard/manager.hpp"
85 
86 static lg::log_domain log_engine("engine");
87 #define ERR_NG LOG_STREAM(err, log_engine)
88 #define LOG_NG LOG_STREAM(info, log_engine)
89 
90 namespace events
91 {
93  : gui_(gui)
94  , pc_(pc)
95  , game_config_(game_config_manager::get()->game_config())
96  , last_search_()
97  , last_search_hit_()
98 {
99 }
100 
102 {
103 }
104 
106 {
107  return pc_.gamestate();
108 }
109 
111 {
112  return gamestate().gamedata_;
113 }
114 
116 {
117  return gamestate().board_;
118 }
119 
121 {
122  return gamestate().board_.units_;
123 }
124 
125 std::vector<team>& menu_handler::teams() const
126 {
127  return gamestate().board_.teams_;
128 }
129 
131 {
132  return gamestate().board_.map();
133 }
134 
136 {
137  if(!gamestate().lua_kernel_) {
138  return;
139  }
140 
141  config cfg;
142  cfg["side"] = gui_->viewing_side();
143  gamestate().lua_kernel_->run_wml_action("show_objectives", vconfig(cfg),
144  game_events::queued_event("_from_interface", "", map_location(), map_location(), config()));
146 }
147 
149 {
150  gui2::dialogs::statistics_dialog::display(board().get_team(side_num));
151 }
152 
154 {
156 }
157 
159 {
160  int selected_index;
161 
162  if(gui2::dialogs::game_stats::execute(board(), gui_->viewing_team(), selected_index)) {
163  gui_->scroll_to_leader(teams()[selected_index].side());
164  }
165 }
166 
168 {
169  const std::string& input_name
171 
173 
174  dlg.set_title(_("Save Map As"))
175  .set_save_mode(true)
176  .set_path(input_name)
177  .set_extension(".map");
178 
179  if(!dlg.show()) {
180  return;
181  }
182 
183  try {
184  filesystem::write_file(dlg.path(), map().write());
185  gui2::show_transient_message("", _("Map saved."));
186  } catch(const filesystem::io_exception& e) {
187  utils::string_map symbols;
188  symbols["msg"] = e.what();
189  const std::string msg = VGETTEXT("Could not save the map: $msg", symbols);
191  }
192 }
193 
195 {
197 }
198 
200 {
201  config c;
202  c["name"] = "prototype of chat log";
203  gui2::dialogs::chat_log::display(vconfig(c), *resources::recorder);
204  // std::string text = resources::recorder->build_chat_log();
205  // gui::show_dialog(*gui_,nullptr,_("Chat Log"),"",gui::CLOSE_ONLY,nullptr,nullptr,"",&text);
206 }
207 
209 {
210  help::show_help();
211 }
212 
214 {
215 #if 0
216  // TODO
217  const std::string check_prompt = has_friends()
218  ? board().is_observer()
219  ? _("Send to observers only")
220  : _("Send to allies only")
221  : "";
222 #endif
223 
225  std::bind(&menu_handler::do_speak, this, _1));
226 
227 #if 0
228  textbox_info_.show(gui::TEXTBOX_MESSAGE, _("Message:"), has_friends()
229  ? board().is_observer()
230  ? _("Send to observers only")
231  : _("Send to allies only")
233 #endif
234 }
235 
237 {
239  speak();
240 }
241 
243 {
245  speak();
246 }
247 
249 {
250  if(board().is_observer()) {
251  return !gui_->observers().empty();
252  }
253 
254  for(std::size_t n = 0; n != teams().size(); ++n) {
255  if(n != gui_->viewing_team() && teams()[gui_->viewing_team()].team_name() == teams()[n].team_name()
256  && teams()[n].is_network()) {
257  return true;
258  }
259  }
260 
261  return false;
262 }
263 
264 void menu_handler::recruit(int side_num, const map_location& last_hex)
265 {
266  std::vector<const unit_type*> sample_units;
267 
268  std::set<std::string> recruits = actions::get_recruits(side_num, last_hex);
269 
270  for(const auto& recruit : recruits) {
272  if(!type) {
273  ERR_NG << "could not find unit '" << recruit << "'" << std::endl;
274  return;
275  }
276 
277  sample_units.push_back(type);
278  }
279 
280  if(sample_units.empty()) {
281  gui2::show_transient_message("", _("You have no units available to recruit."));
282  return;
283  }
284 
285  gui2::dialogs::unit_recruit dlg(sample_units, board().get_team(side_num));
286 
287  if(dlg.show()) {
288  map_location recruit_hex = last_hex;
289  do_recruit(sample_units[dlg.get_selected_index()]->id(), side_num, recruit_hex);
290  }
291 }
292 
293 void menu_handler::repeat_recruit(int side_num, const map_location& last_hex)
294 {
295  const std::string& last_recruit = board().get_team(side_num).last_recruit();
296  if(last_recruit.empty() == false) {
297  map_location recruit_hex = last_hex;
298  do_recruit(last_recruit, side_num, recruit_hex);
299  }
300 }
301 
302 bool menu_handler::do_recruit(const std::string& name, int side_num, map_location& loc)
303 {
304  team& current_team = board().get_team(side_num);
305 
306  // search for the unit to be recruited in recruits
307  if(!utils::contains(actions::get_recruits(side_num, loc), name)) {
308  return false;
309  }
310 
311  const unit_type* u_type = unit_types.find(name);
312  assert(u_type);
313 
314  if(u_type->cost() > current_team.gold() - (pc_.get_whiteboard()
315  ? pc_.get_whiteboard()->get_spent_gold_for(side_num)
316  : 0))
317  {
318  gui2::show_transient_message("", _("You do not have enough gold to recruit that unit"));
319  return false;
320  }
321 
322  current_team.last_recruit(name);
323  const events::command_disabler disable_commands;
324 
325  map_location recruited_from = map_location::null_location();
326 
327  std::string msg;
328  {
329  wb::future_map_if_active future; /* start planned unit map scope if in planning mode */
330  msg = actions::find_recruit_location(side_num, loc, recruited_from, name);
331  } // end planned unit map scope
332 
333  if(!msg.empty()) {
335  return false;
336  }
337 
338  if(!pc_.get_whiteboard() || !pc_.get_whiteboard()->save_recruit(name, side_num, loc)) {
339  // MP_COUNTDOWN grant time bonus for recruiting
340  current_team.set_action_bonus_count(1 + current_team.action_bonus_count());
341 
342  // Do the recruiting.
343 
344  synced_context::run_and_throw("recruit", replay_helper::get_recruit(u_type->id(), loc, recruited_from));
345  return true;
346  }
347 
348  return false;
349 }
350 
351 void menu_handler::recall(int side_num, const map_location& last_hex)
352 {
353  if(pc_.get_disallow_recall()) {
354  gui2::show_transient_message("", _("You are separated from your soldiers and may not recall them"));
355  return;
356  }
357 
358  team& current_team = board().get_team(side_num);
359 
360  std::vector<unit_const_ptr> recall_list_team;
361  {
362  wb::future_map future; // ensures recall list has planned recalls removed
363  recall_list_team = actions::get_recalls(side_num, last_hex);
364  }
365 
366  DBG_WB << "menu_handler::recall: Contents of wb-modified recall list:\n";
367  for(const unit_const_ptr& unit : recall_list_team) {
368  DBG_WB << unit->name() << " [" << unit->id() << "]\n";
369  }
370 
371  if(current_team.recall_list().empty()) {
373  _("There are no troops available to recall\n(You must have veteran survivors from a previous scenario)"));
374  return;
375  }
376  if(recall_list_team.empty()) {
377  gui2::show_transient_message("", _("You currently can't recall at the highlighted location"));
378  return;
379  }
380 
381  gui2::dialogs::unit_recall dlg(recall_list_team, current_team);
382 
383  if(!dlg.show()) {
384  return;
385  }
386 
387  int res = dlg.get_selected_index();
388  if (res < 0) {
389  gui2::show_transient_message("", _("No unit recalled"));
390  return;
391  }
392  int unit_cost = current_team.recall_cost();
393 
394  // we need to check if unit has a specific recall cost
395  // if it does we use it elsewise we use the team.recall_cost()
396  // the magic number -1 is what it gets set to if the unit doesn't
397  // have a special recall_cost of its own.
398  if(recall_list_team[res]->recall_cost() > -1) {
399  unit_cost = recall_list_team[res]->recall_cost();
400  }
401 
402  int wb_gold = pc_.get_whiteboard() ? pc_.get_whiteboard()->get_spent_gold_for(side_num) : 0;
403  if(current_team.gold() - wb_gold < unit_cost) {
404  utils::string_map i18n_symbols;
405  i18n_symbols["cost"] = std::to_string(unit_cost);
406  std::string msg = VNGETTEXT("You must have at least 1 gold piece to recall a unit",
407  "You must have at least $cost gold pieces to recall this unit", unit_cost, i18n_symbols);
409  return;
410  }
411 
412  LOG_NG << "recall index: " << res << "\n";
413  const events::command_disabler disable_commands;
414 
415  map_location recall_location = last_hex;
417  std::string err;
418  {
420  future; // future unit map removes invisible units from map, don't do this outside of planning mode
421  err = actions::find_recall_location(side_num, recall_location, recall_from, *recall_list_team[res].get());
422  } // end planned unit map scope
423 
424  if(!err.empty()) {
426  return;
427  }
428 
429  if(!pc_.get_whiteboard()
430  || !pc_.get_whiteboard()->save_recall(*recall_list_team[res].get(), side_num, recall_location)) {
431  bool success = synced_context::run_and_throw("recall",
432  replay_helper::get_recall(recall_list_team[res]->id(), recall_location, recall_from), true, true,
434 
435  if(!success) {
436  ERR_NG << "menu_handler::recall(): Unit does not exist in the recall list." << std::endl;
437  }
438  }
439 }
440 
441 // Highlights squares that an enemy could move to on their turn, showing how many can reach each square.
442 void menu_handler::show_enemy_moves(bool ignore_units, int side_num)
443 {
444  wb::future_map future; // use unit positions as if all planned actions were executed
445 
447 
448  // Compute enemy movement positions
449  for(auto& u : units()) {
450  bool invisible = u.invisible(u.get_location());
451 
452  if(board().get_team(side_num).is_enemy(u.side()) && !gui_->fogged(u.get_location()) && !u.incapacitated()
453  && !invisible) {
454  const unit_movement_resetter move_reset(u);
455  const pathfind::paths& path
456  = pathfind::paths(u, false, true, teams()[gui_->viewing_team()], 0, false, ignore_units);
457 
459  }
460  }
461 
462  // Find possible unit (no matter whether friend or foe) under the
463  // mouse cursor.
465  const map_location& hex_under_mouse = mh.hovered_hex();
466  const bool selected_hex_has_unit = mh.hex_hosts_unit(hex_under_mouse);
467 
468  if(selected_hex_has_unit) {
469  // At this point, a single pixel move would remove the enemy
470  // [best possible] movements hex tiles highlights, so some
471  // prevention on normal unit mouseover movement highlight
472  // has to be toggled temporarily.
474  }
475 }
476 
478 {
479  team& current_team = board().get_team(side_num);
480  bool auto_shroud = current_team.auto_shroud_updates();
481  // If we're turning automatic shroud updates on, then commit all moves
482  if(!auto_shroud) {
483  update_shroud_now(side_num);
484  }
485 
486  // Toggle the setting and record this.
488 }
489 
490 void menu_handler::update_shroud_now(int /* side_num */)
491 {
493 }
494 
495 // Helpers for menu_handler::end_turn()
496 namespace
497 {
498 /** Returns true if @a side_num has at least one living unit. */
499 bool units_alive(int side_num, const unit_map& units)
500 {
501  for(auto& unit : units) {
502  if(unit.side() == side_num) {
503  return true;
504  }
505  }
506  return false;
507 }
508 
509 /** Returns true if @a side_num has at least one unit that can still move. */
510 bool partmoved_units(
511  int side_num, const unit_map& units, const game_board& board, const std::shared_ptr<wb::manager>& whiteb)
512 {
513  for(auto& unit : units) {
514  if(unit.side() == side_num) {
515  // @todo whiteboard should take into consideration units that have
516  // a planned move but can still plan more movement in the same turn
517  if(board.unit_can_move(unit) && !unit.user_end_turn() && (!whiteb || !whiteb->unit_has_actions(&unit)))
518  return true;
519  }
520  }
521  return false;
522 }
523 
524 /**
525  * Returns true if @a side_num has at least one unit that (can but) has not moved.
526  */
527 bool unmoved_units(
528  int side_num, const unit_map& units, const game_board& board, const std::shared_ptr<wb::manager>& whiteb)
529 {
530  for(auto& unit : units) {
531  if(unit.side() == side_num) {
532  if(board.unit_can_move(unit) && !unit.has_moved() && !unit.user_end_turn()
533  && (!whiteb || !whiteb->unit_has_actions(&unit))) {
534  return true;
535  }
536  }
537  }
538  return false;
539 }
540 
541 } // end anon namespace
542 
543 bool menu_handler::end_turn(int side_num)
544 {
545  if(!gamedata().allow_end_turn()) {
546  gui2::show_transient_message("", _("You cannot end your turn yet!"));
547  return false;
548  }
549 
550  std::size_t team_num = static_cast<std::size_t>(side_num - 1);
551  if(team_num < teams().size() && teams()[team_num].no_turn_confirmation()) {
552  // Skip the confirmations that follow.
553  }
554  // Ask for confirmation if the player hasn't made any moves.
556  && (!pc_.get_whiteboard() || !pc_.get_whiteboard()->current_side_has_actions())
557  && units_alive(side_num, units())) {
558  const int res = gui2::show_message("",
559  _("You have not started your turn yet. Do you really want to end your turn?"),
561  if(res == gui2::retval::CANCEL) {
562  return false;
563  }
564  }
565  // Ask for confirmation if units still have some movement left.
566  else if(preferences::yellow_confirm() && partmoved_units(side_num, units(), board(), pc_.get_whiteboard())) {
567  const int res = gui2::show_message("",
568  _("Some units have movement left. Do you really want to end your turn?"),
570  if(res == gui2::retval::CANCEL) {
571  return false;
572  }
573  }
574  // Ask for confirmation if units still have all movement left.
575  else if(preferences::green_confirm() && unmoved_units(side_num, units(), board(), pc_.get_whiteboard())) {
576  const int res = gui2::show_message("",
577  _("Some units have not moved. Do you really want to end your turn?"),
579  if(res == gui2::retval::CANCEL) {
580  return false;
581  }
582  }
583 
584  // Auto-execute remaining whiteboard planned actions
585  // Only finish turn if they all execute successfully, i.e. no ambush, etc.
586  if(pc_.get_whiteboard() && !pc_.get_whiteboard()->allow_end_turn()) {
587  return false;
588  }
589 
590  return true;
591 }
592 
593 void menu_handler::goto_leader(int side_num)
594 {
596  if(i != units().end()) {
597  gui_->scroll_to_tile(i->get_location(), game_display::WARP);
598  }
599 }
600 
602 {
604  if(un != units().end()) {
606  }
607 }
608 
610 {
611  const map_location& loc = mousehandler.get_last_hex();
612  if(map().on_board(loc) == false || gui_->shrouded(loc)) {
613  return;
614  }
615 
616  const terrain_type& type = map().get_terrain_info(loc);
617  // const terrain_type& info = board().map().get_terrain_info(terrain);
619 }
620 
622 {
623  const unit_map::iterator un = current_unit();
624  if(un == units().end() || gui_->viewing_side() != un->side()) {
625  return;
626  }
627 
628  if(un->unrenamable()) {
629  return;
630  }
631 
632  std::string name = un->name();
633  const std::string title(N_("Rename Unit"));
634  const std::string label(N_("Name:"));
635 
636  if(gui2::dialogs::edit_text::execute(title, label, name)) {
637  resources::recorder->add_rename(name, un->get_location());
638  un->rename(name);
639  }
640 }
641 
643 {
644  const mouse_handler& mousehandler = pc_.get_mouse_handler_base();
645 
647  if(res != units().end()) {
648  return res;
649  }
650 
651  return board().find_visible_unit(mousehandler.get_selected_hex(), teams()[gui_->viewing_team()]);
652 }
653 
654 // Helpers for create_unit()
655 namespace
656 {
657 /// Allows a function to return both a type and a gender.
658 typedef std::pair<const unit_type*, unit_race::GENDER> type_and_gender;
659 
660 /**
661  * Allows the user to select a type of unit, using GUI2.
662  * (Intended for use when a unit is created in debug mode via hotkey or
663  * context menu.)
664  * @returns the selected type and gender. If this is canceled, the
665  * returned type is nullptr.
666  */
667 type_and_gender choose_unit()
668 {
669  //
670  // The unit creation dialog makes sure unit types
671  // are properly cached.
672  //
673  gui2::dialogs::unit_create create_dlg;
674  create_dlg.show();
675 
676  if(create_dlg.no_choice()) {
677  return type_and_gender(nullptr, unit_race::NUM_GENDERS);
678  }
679 
680  const std::string& ut_id = create_dlg.choice();
681  const unit_type* utp = unit_types.find(ut_id);
682  if(!utp) {
683  ERR_NG << "Create unit dialog returned nonexistent or unusable unit_type id '" << ut_id << "'." << std::endl;
684  return type_and_gender(static_cast<const unit_type*>(nullptr), unit_race::NUM_GENDERS);
685  }
686  const unit_type& ut = *utp;
687 
688  unit_race::GENDER gender = create_dlg.gender();
689  // Do not try to set bad genders, may mess up l10n
690  /// @todo Is this actually necessary?
691  /// (Maybe create_dlg can enforce proper gender selection?)
692  if(ut.genders().end() == std::find(ut.genders().begin(), ut.genders().end(), gender)) {
693  gender = ut.genders().front();
694  }
695 
696  return type_and_gender(utp, gender);
697 }
698 
699 /**
700  * Creates a unit and places it on the board.
701  * (Intended for use with any units created via debug mode.)
702  */
703 void create_and_place(game_display&,
704  const gamemap&,
705  unit_map&,
706  const map_location& loc,
707  const unit_type& u_type,
709 {
710  synced_context::run_and_throw("debug_create_unit",
711  config {
712  "x", loc.wml_x(),
713  "y", loc.wml_y(),
714  "type", u_type.id(),
715  "gender", gender_string(gender),
716  }
717  );
718 }
719 
720 } // Anonymous namespace
721 
722 /**
723  * Creates a unit (in debug mode via hotkey or context menu).
724  */
726 {
727  // Save the current mouse location before popping up the choice menu (which
728  // gives time for the mouse to move, changing the location).
729  const map_location destination = mousehandler.get_last_hex();
730  assert(gui_ != nullptr);
731 
732  // Let the user select the kind of unit to create.
733  type_and_gender selection = choose_unit();
734  if(selection.first != nullptr) {
735  // Make it so.
736  create_and_place(*gui_, map(), units(), destination, *selection.first, selection.second);
737  }
738 }
739 
741 {
742  const map_location& loc = mousehandler.get_last_hex();
743  const unit_map::iterator i = units().find(loc);
744  if(i == units().end()) {
745  if(!map().is_village(loc)) {
746  return;
747  }
748 
749  // village_owner returns -1 for free village, so team 0 will get it
750  int team = board().village_owner(loc) + 1;
751  // team is 0-based so team=team::nteams() is not a team
752  // but this will make get_village free it
753  if(team > static_cast<int>(teams().size())) {
754  team = 0;
755  }
756  actions::get_village(loc, team + 1);
757  } else {
758  int side = i->side();
759  ++side;
760  if(side > static_cast<int>(teams().size())) {
761  side = 1;
762  }
763  i->set_side(side);
764 
765  if(map().is_village(loc)) {
766  actions::get_village(loc, side);
767  }
768  }
769 }
770 
772 {
773  const map_location loc = mousehandler.get_last_hex();
774  synced_context::run_and_throw("debug_kill", config {"x", loc.wml_x(), "y", loc.wml_y()});
775 }
776 
777 void menu_handler::label_terrain(mouse_handler& mousehandler, bool team_only)
778 {
779  const map_location& loc = mousehandler.get_last_hex();
780  if(map().on_board(loc) == false) {
781  return;
782  }
783 
784  const terrain_label* old_label = gui_->labels().get_label(loc);
785  std::string label = old_label ? old_label->text() : "";
786 
787  if(gui2::dialogs::edit_label::execute(label, team_only)) {
788  std::string team_name;
789  color_t color = font::LABEL_COLOR;
790 
791  if(team_only) {
792  team_name = gui_->labels().team_name();
793  } else {
795  }
796  const terrain_label* res = gui_->labels().set_label(loc, label, gui_->viewing_team(), team_name, color);
797  if(res) {
799  }
800  }
801 }
802 
804 {
805  if(gui_->team_valid() && !board().is_observer()) {
806  const int res = gui2::show_message(
807  _("Clear Labels"),
808  _("Are you sure you want to clear map labels?"),
810  );
811 
812  if(res == gui2::retval::OK) {
813  gui_->labels().clear(gui_->current_team_name(), false);
815  }
816  }
817 }
818 
820 {
823  }
824 }
825 
826 void menu_handler::continue_move(mouse_handler& mousehandler, int side_num)
827 {
829  if(i == units().end() || !i->move_interrupted()) {
830  i = units().find(mousehandler.get_selected_hex());
831  if(i == units().end() || !i->move_interrupted()) {
832  return;
833  }
834  }
835  move_unit_to_loc(i, i->get_interrupted_move(), true, side_num, mousehandler);
836 }
837 
839  const map_location& target,
840  bool continue_move,
841  int side_num,
842  mouse_handler& mousehandler)
843 {
844  assert(ui != units().end());
845 
846  pathfind::marked_route route = mousehandler.get_route(&*ui, target, board().get_team(side_num));
847 
848  if(route.steps.empty()) {
849  return;
850  }
851 
852  assert(route.steps.front() == ui->get_location());
853 
854  gui_->set_route(&route);
856 
857  {
858  LOG_NG << "move_unit_to_loc " << route.steps.front() << " to " << route.steps.back() << "\n";
860  }
861 
862  gui_->set_route(nullptr);
863 }
864 
865 void menu_handler::execute_gotos(mouse_handler& mousehandler, int side)
866 {
867  // we will loop on all gotos and try to fully move a maximum of them,
868  // but we want to avoid multiple blocking of the same unit,
869  // so, if possible, it's better to first wait that the blocker move
870 
871  bool wait_blocker_move = true;
872  std::set<map_location> fully_moved;
873 
874  bool change = false;
875  bool blocked_unit = false;
876  do {
877  change = false;
878  blocked_unit = false;
879  for(auto& unit : units()) {
880  if(unit.side() != side || unit.movement_left() == 0) {
881  continue;
882  }
883 
884  const map_location& current_loc = unit.get_location();
885  const map_location& goto_loc = unit.get_goto();
886 
887  if(goto_loc == current_loc) {
889  continue;
890  }
891 
892  if(!map().on_board(goto_loc)) {
893  continue;
894  }
895 
896  // avoid pathfinding calls for finished units
897  if(fully_moved.count(current_loc)) {
898  continue;
899  }
900 
901  pathfind::marked_route route = mousehandler.get_route(&unit, goto_loc, board().get_team(side));
902 
903  if(route.steps.size() <= 1) { // invalid path
904  fully_moved.insert(current_loc);
905  continue;
906  }
907 
908  // look where we will stop this turn (turn_1 waypoint or goto)
909  map_location next_stop = goto_loc;
910  pathfind::marked_route::mark_map::const_iterator w = route.marks.begin();
911  for(; w != route.marks.end(); ++w) {
912  if(w->second.turns == 1) {
913  next_stop = w->first;
914  break;
915  }
916  }
917 
918  if(next_stop == current_loc) {
919  fully_moved.insert(current_loc);
920  continue;
921  }
922 
923  // we delay each blocked move because some other change
924  // may open a another not blocked path
925  if(units().count(next_stop)) {
926  blocked_unit = true;
927  if(wait_blocker_move)
928  continue;
929  }
930 
931  gui_->set_route(&route);
932 
933  {
934  LOG_NG << "execute goto from " << route.steps.front() << " to " << route.steps.back() << "\n";
935  int moves = actions::move_unit_and_record(route.steps, &pc_.get_undo_stack());
936  change = moves > 0;
937  }
938 
939  if(change) {
940  // something changed, resume waiting blocker (maybe one can move now)
941  wait_blocker_move = true;
942  }
943  }
944 
945  if(!change && wait_blocker_move) {
946  // no change when waiting, stop waiting and retry
947  wait_blocker_move = false;
948  change = true;
949  }
950  } while(change && blocked_unit);
951 
952  // erase the footsteps after movement
953  gui_->set_route(nullptr);
954 }
955 
957 {
959 }
960 
962 {
964 }
965 
966 void menu_handler::unit_hold_position(mouse_handler& mousehandler, int side_num)
967 {
968  const unit_map::iterator un = units().find(mousehandler.get_selected_hex());
969  if(un != units().end() && un->side() == side_num && un->movement_left() >= 0) {
970  un->toggle_hold_position();
971 
972  mousehandler.set_current_paths(pathfind::paths());
973 
974  if(un->hold_position()) {
975  mousehandler.cycle_units(false);
976  }
977  }
978 }
979 
980 void menu_handler::end_unit_turn(mouse_handler& mousehandler, int side_num)
981 {
982  const unit_map::iterator un = units().find(mousehandler.get_selected_hex());
983  if(un != units().end() && un->side() == side_num && un->movement_left() >= 0) {
984  un->toggle_user_end_turn();
985 
986  mousehandler.set_current_paths(pathfind::paths());
987 
988  if(un->user_end_turn()) {
989  mousehandler.cycle_units(false);
990  }
991  }
992 }
993 
995 {
996  std::ostringstream msg;
997  msg << _("Search");
998  if(last_search_hit_.valid()) {
999  msg << " [" << last_search_ << "]";
1000  }
1001  msg << ':';
1002 
1004 }
1005 
1006 void menu_handler::do_speak(const std::string& message)
1007 {
1008  // None of the two parameters really needs to be passed since the information belong to members of the class.
1009  // But since it makes the called method more generic, it is done anyway.
1010 
1011  // TODO: handle checkbox
1012  chat_handler::do_speak(message, false);
1013 }
1014 
1015 void menu_handler::add_chat_message(const std::time_t& time,
1016  const std::string& speaker,
1017  int side,
1018  const std::string& message,
1020 {
1021  gui_->get_chat_manager().add_chat_message(time, speaker, side, message, type, false);
1022 
1024  config {
1025  "sender", preferences::login(),
1026  "message", message,
1027  "whisper", type == events::chat_handler::MESSAGE_PRIVATE,
1028  }
1029  );
1030 }
1031 
1032 // command handler for user :commands. Also understands all chat commands
1033 // via inheritance. This complicates some things a bit.
1034 class console_handler : public map_command_handler<console_handler>, private chat_command_handler
1035 {
1036 public:
1037  // convenience typedef
1040  : chmap()
1041  , chat_command_handler(menu_handler, true)
1042  , menu_handler_(menu_handler)
1043  , team_num_(menu_handler.pc_.current_side())
1044  {
1045  }
1046 
1047  using chmap::dispatch; // disambiguate
1048  using chmap::get_commands_list;
1049  using chmap::command_failed;
1050 
1051 protected:
1052  // chat_command_handler's init_map() and handlers will end up calling these.
1053  // this makes sure the commands end up in our map
1054  virtual void register_command(const std::string& cmd,
1056  const std::string& help = "",
1057  const std::string& usage = "",
1058  const std::string& flags = "")
1059  {
1060  chmap::register_command(cmd, h, help, usage, flags + "N"); // add chat commands as network_only
1061  }
1062 
1063  virtual void register_alias(const std::string& to_cmd, const std::string& cmd)
1064  {
1065  chmap::register_alias(to_cmd, cmd);
1066  }
1067 
1068  virtual std::string get_arg(unsigned i) const
1069  {
1070  return chmap::get_arg(i);
1071  }
1072 
1073  virtual std::string get_cmd() const
1074  {
1075  return chmap::get_cmd();
1076  }
1077 
1078  virtual std::string get_data(unsigned n = 1) const
1079  {
1080  return chmap::get_data(n);
1081  }
1082 
1083  // these are needed to avoid ambiguities introduced by inheriting from console_command_handler
1084  using chmap::register_command;
1085  using chmap::register_alias;
1086  using chmap::help;
1087  using chmap::is_enabled;
1088  using chmap::command_failed_need_arg;
1089 
1090  void do_refresh();
1091  void do_droid();
1092  void do_idle();
1093  void do_theme();
1094  void do_control();
1095  void do_controller();
1096  void do_clear();
1097  void do_foreground();
1098  void do_layers();
1099  void do_fps();
1100  void do_benchmark();
1101  void do_save();
1102  void do_save_quit();
1103  void do_quit();
1104  void do_ignore_replay_errors();
1105  void do_nosaves();
1106  void do_next_level();
1107  void do_choose_level();
1108  void do_turn();
1109  void do_turn_limit();
1110  void do_debug();
1111  void do_nodebug();
1112  void do_lua();
1113  void do_unsafe_lua();
1114  void do_custom();
1115  void do_set_alias();
1116  void do_set_var();
1117  void do_show_var();
1118  void do_inspect();
1119  void do_control_dialog();
1120  void do_unit();
1121  // void do_buff();
1122  // void do_unbuff();
1123  void do_discover();
1124  void do_undiscover();
1125  void do_create();
1126  void do_fog();
1127  void do_shroud();
1128  void do_gold();
1129  void do_event();
1130  void do_toggle_draw_coordinates();
1131  void do_toggle_draw_terrain_codes();
1132  void do_toggle_draw_num_of_bitmaps();
1133  void do_toggle_whiteboard();
1134  void do_whiteboard_options();
1135 
1136  std::string get_flags_description() const
1137  {
1138  return _("(D) — debug only, (N) — network only, (A) — admin only");
1139  }
1140 
1141  using chat_command_handler::get_command_flags_description; // silence a warning
1142  std::string get_command_flags_description(const chmap::command& c) const
1143  {
1144  std::string space(" ");
1145  return (c.has_flag('D') ? space + _("(debug command)") : "")
1146  + (c.has_flag('N') ? space + _("(network only)") : "")
1147  + (c.has_flag('A') ? space + _("(admin only)") : "")
1148  + (c.has_flag('S') ? space + _("(not during other events)") : "");
1149  }
1150 
1151  using map::is_enabled;
1152  bool is_enabled(const chmap::command& c) const
1153  {
1154  return !((c.has_flag('D') && !game_config::debug)
1155  || (c.has_flag('N') && !menu_handler_.pc_.is_networked_mp())
1156  || (c.has_flag('A') && !preferences::is_authenticated())
1157  || (c.has_flag('S') && (synced_context::get_synced_state() != synced_context::UNSYNCED || !menu_handler_.pc_.current_team().is_local())));
1158  }
1159 
1160  void print(const std::string& title, const std::string& message)
1161  {
1162  menu_handler_.add_chat_message(std::time(nullptr), title, 0, message);
1163  }
1164 
1165  void init_map()
1166  {
1167  chat_command_handler::init_map(); // grab chat_ /command handlers
1168 
1169  chmap::get_command("log")->flags = ""; // clear network-only flag from log
1170  chmap::get_command("version")->flags = ""; // clear network-only flag
1171  chmap::get_command("ignore")->flags = ""; // clear network-only flag
1172  chmap::get_command("friend")->flags = ""; // clear network-only flag
1173  chmap::get_command("remove")->flags = ""; // clear network-only flag
1174 
1175  chmap::set_cmd_prefix(":");
1176 
1177  register_command("refresh", &console_handler::do_refresh, _("Refresh gui."));
1178  register_command("droid", &console_handler::do_droid, _("Switch a side to/from AI control."),
1179  _("do not translate the on/off^[<side> [on/off]]"));
1180  register_command("idle", &console_handler::do_idle, _("Switch a side to/from idle state."),
1181  _("do not translate the on/off^[<side> [on/off]]"));
1182  register_command("theme", &console_handler::do_theme);
1183  register_command("control", &console_handler::do_control,
1184  _("Assign control of a side to a different player or observer."), _("<side> <nickname>"), "N");
1185  register_command("controller", &console_handler::do_controller, _("Query the controller status of a side."),
1186  _("<side>"));
1187  register_command("clear", &console_handler::do_clear, _("Clear chat history."));
1188  register_command("foreground", &console_handler::do_foreground, _("Debug foreground terrain."), "", "D");
1189  register_command(
1190  "layers", &console_handler::do_layers, _("Debug layers from terrain under the mouse."), "", "D");
1191  register_command("fps", &console_handler::do_fps, _("Show fps."));
1192  register_command("benchmark", &console_handler::do_benchmark);
1193  register_command("save", &console_handler::do_save, _("Save game."));
1194  register_alias("save", "w");
1195  register_command("quit", &console_handler::do_quit, _("Quit game."));
1196  // Note the next value is used hardcoded in the init tests.
1197  register_alias("quit", "q!");
1198  register_command("save_quit", &console_handler::do_save_quit, _("Save and quit."));
1199  register_alias("save_quit", "wq");
1200  register_command("ignore_replay_errors", &console_handler::do_ignore_replay_errors, _("Ignore replay errors."));
1201  register_command("nosaves", &console_handler::do_nosaves, _("Disable autosaves."));
1202  register_command("next_level", &console_handler::do_next_level,
1203  _("Advance to the next scenario, or scenario identified by 'id'"), _("<id>"), "DS");
1204  register_alias("next_level", "n");
1205  register_command("choose_level", &console_handler::do_choose_level, _("Choose next scenario"), "", "DS");
1206  register_alias("choose_level", "cl");
1207  register_command("turn", &console_handler::do_turn,
1208  _("Change turn number (and time of day), or increase by one if no number is specified."), _("[turn]"),
1209  "DS");
1210  register_command("turn_limit", &console_handler::do_turn_limit,
1211  _("Change turn limit, or turn the turn limit off if no number is specified or it’s −1."), _("[limit]"),
1212  "DS");
1213  register_command("debug", &console_handler::do_debug, _("Turn debug mode on."));
1214  register_command("nodebug", &console_handler::do_nodebug, _("Turn debug mode off."), "", "D");
1215  register_command(
1216  "lua", &console_handler::do_lua, _("Execute a Lua statement."), _("<command>[;<command>...]"), "DS");
1217  register_command(
1218  "unsafe_lua", &console_handler::do_unsafe_lua, _("Grant higher privileges to Lua scripts."), "", "D");
1219  register_command("custom", &console_handler::do_custom, _("Set the command used by the custom command hotkey"),
1220  _("<command>[;<command>...]"));
1221  register_command("give_control", &console_handler::do_control_dialog,
1222  _("Invoke a dialog allowing changing control of MP sides."), "", "N");
1223  register_command("inspect", &console_handler::do_inspect, _("Launch the gamestate inspector"), "", "D");
1224  register_command(
1225  "alias", &console_handler::do_set_alias, _("Set or show alias to a command"), _("<name>[=<command>]"));
1226  register_command(
1227  "set_var", &console_handler::do_set_var, _("Set a scenario variable."), _("<var>=<value>"), "DS");
1228  register_command("show_var", &console_handler::do_show_var, _("Show a scenario variable."), _("<var>"), "D");
1229  register_command("unit", &console_handler::do_unit,
1230  _("Modify a unit variable. (Only top level keys are supported.)"), "", "DS");
1231 
1232  // register_command("buff", &console_handler::do_buff,
1233  // _("Add a trait to a unit."), "", "D");
1234  // register_command("unbuff", &console_handler::do_unbuff,
1235  // _("Remove a trait from a unit. (Does not work yet.)"), "", "D");
1236  register_command("discover", &console_handler::do_discover, _("Discover all units in help."), "");
1237  register_command("undiscover", &console_handler::do_undiscover, _("'Undiscover' all units in help."), "");
1238  register_command("create", &console_handler::do_create, _("Create a unit."), "", "DS");
1239  register_command("fog", &console_handler::do_fog, _("Toggle fog for the current player."), "", "DS");
1240  register_command("shroud", &console_handler::do_shroud, _("Toggle shroud for the current player."), "", "DS");
1241  register_command("gold", &console_handler::do_gold, _("Give gold to the current player."), "", "DS");
1242  register_command("throw", &console_handler::do_event, _("Fire a game event."), "", "DS");
1243  register_alias("throw", "fire");
1244  register_command("show_coordinates", &console_handler::do_toggle_draw_coordinates,
1245  _("Toggle overlaying of x,y coordinates on hexes."));
1246  register_alias("show_coordinates", "sc");
1247  register_command("show_terrain_codes", &console_handler::do_toggle_draw_terrain_codes,
1248  _("Toggle overlaying of terrain codes on hexes."));
1249  register_alias("show_terrain_codes", "tc");
1250  register_command("show_num_of_bitmaps", &console_handler::do_toggle_draw_num_of_bitmaps,
1251  _("Toggle overlaying of number of bitmaps on hexes."));
1252  register_alias("show_num_of_bitmaps", "bn");
1253  register_command("whiteboard", &console_handler::do_toggle_whiteboard, _("Toggle planning mode."));
1254  register_alias("whiteboard", "wb");
1255  register_command(
1256  "whiteboard_options", &console_handler::do_whiteboard_options, _("Access whiteboard options dialog."));
1257  register_alias("whiteboard_options", "wbo");
1258 
1259  if(const config& alias_list = preferences::get_alias()) {
1260  for(const config::attribute& a : alias_list.attribute_range()) {
1261  register_alias(a.second, a.first);
1262  }
1263  }
1264  }
1265 
1266 private:
1268  const unsigned int team_num_;
1269 };
1270 
1271 void menu_handler::send_chat_message(const std::string& message, bool allies_only)
1272 {
1273  config cfg;
1274  cfg["id"] = preferences::login();
1275  cfg["message"] = message;
1276  const std::time_t time = ::std::time(nullptr);
1277  std::stringstream ss;
1278  ss << time;
1279  cfg["time"] = ss.str();
1280 
1281  const int side = board().is_observer() ? 0 : gui_->viewing_side();
1282  if(!board().is_observer()) {
1283  cfg["side"] = side;
1284  }
1285 
1286  bool private_message = has_friends() && allies_only;
1287 
1288  if(private_message) {
1289  if(board().is_observer()) {
1290  cfg["to_sides"] = game_config::observer_team_name;
1291  } else {
1292  cfg["to_sides"] = teams()[gui_->viewing_team()].allied_human_teams();
1293  }
1294  }
1295 
1296  resources::recorder->speak(cfg);
1297 
1298  add_chat_message(time, cfg["id"], side, message,
1300 }
1301 
1302 void menu_handler::do_search(const std::string& new_search)
1303 {
1304  if(new_search.empty() == false && new_search != last_search_)
1305  last_search_ = new_search;
1306 
1307  if(last_search_.empty())
1308  return;
1309 
1310  bool found = false;
1312  // If this is a location search, just center on that location.
1313  std::vector<std::string> args = utils::split(last_search_, ',');
1314  if(args.size() == 2) {
1315  int x, y;
1316  x = lexical_cast_default<int>(args[0], 0) - 1;
1317  y = lexical_cast_default<int>(args[1], 0) - 1;
1318  if(x >= 0 && x < map().w() && y >= 0 && y < map().h()) {
1319  loc = map_location(x, y);
1320  found = true;
1321  }
1322  }
1323  // Start scanning the game map
1324  if(loc.valid() == false) {
1325  loc = map_location(map().w() - 1, map().h() - 1);
1326  }
1327 
1328  map_location start = loc;
1329  while(!found) {
1330  // Move to the next location
1331  loc.x = (loc.x + 1) % map().w();
1332  if(loc.x == 0)
1333  loc.y = (loc.y + 1) % map().h();
1334 
1335  // Search label
1336  if(!gui_->shrouded(loc)) {
1337  const terrain_label* label = gui_->labels().get_label(loc);
1338  if(label) {
1339  std::string label_text = label->text().str();
1340  if(std::search(label_text.begin(), label_text.end(), last_search_.begin(), last_search_.end(),
1342  != label_text.end()) {
1343  found = true;
1344  }
1345  }
1346  }
1347  // Search unit name
1348  if(!gui_->fogged(loc)) {
1349  unit_map::const_iterator ui = units().find(loc);
1350  if(ui != units().end()) {
1351  const std::string name = ui->name();
1352  if(std::search(
1353  name.begin(), name.end(), last_search_.begin(), last_search_.end(), chars_equal_insensitive)
1354  != name.end()) {
1355  if(!teams()[gui_->viewing_team()].is_enemy(ui->side())
1356  || !ui->invisible(ui->get_location())) {
1357  found = true;
1358  }
1359  }
1360  }
1361  }
1362 
1363  if(loc == start)
1364  break;
1365  }
1366 
1367  if(found) {
1368  last_search_hit_ = loc;
1370  gui_->highlight_hex(loc);
1371  } else {
1373  // Not found, inform the player
1374  utils::string_map symbols;
1375  symbols["search"] = last_search_;
1376  const std::string msg = VGETTEXT("Could not find label or unit "
1377  "containing the string ‘$search’.",
1378  symbols);
1380  }
1381 }
1382 
1383 void menu_handler::do_command(const std::string& str)
1384 {
1385  console_handler ch(*this);
1386  ch.dispatch(str);
1387 }
1388 
1389 std::vector<std::string> menu_handler::get_commands_list()
1390 {
1391  console_handler ch(*this);
1392  // HACK: we need to call dispatch() at least once to get the
1393  // command list populated *at all*. Terrible design.
1394  // An empty command is silently ignored and has negligible
1395  // overhead, so we use that for this purpose here.
1396  ch.dispatch("");
1397  return ch.get_commands_list();
1398 }
1399 
1401 {
1403 }
1404 
1406 {
1407  // :droid [<side> [on/off]]
1408  const std::string side_s = get_arg(1);
1409  const std::string action = get_arg(2);
1410  // default to the current side if empty
1411  const unsigned int side = side_s.empty() ? team_num_ : lexical_cast_default<unsigned int>(side_s);
1412 
1413  if(side < 1 || side > menu_handler_.teams().size()) {
1414  utils::string_map symbols;
1415  symbols["side"] = side_s;
1416  command_failed(VGETTEXT("Can't droid invalid side: '$side'.", symbols));
1417  return;
1418  } else if(menu_handler_.board().get_team(side).is_network()) {
1419  utils::string_map symbols;
1420  symbols["side"] = std::to_string(side);
1421  command_failed(VGETTEXT("Can't droid networked side: '$side'.", symbols));
1422  return;
1423  } else if(menu_handler_.board().get_team(side).is_local_human()) {
1424  utils::string_map symbols;
1425  symbols["side"] = std::to_string(side);
1426  if(menu_handler_.board().get_team(side).is_droid() ? action == "on" : action == "off") {
1427  print(get_cmd(), VGETTEXT("Side '$side' is already droided.", symbols));
1428  return;
1429  }
1430  menu_handler_.board().get_team(side).toggle_droid();
1431  if(team_num_ == side) {
1432  if(playsingle_controller* psc = dynamic_cast<playsingle_controller*>(&menu_handler_.pc_)) {
1433  psc->set_player_type_changed();
1434  }
1435  }
1436  if (menu_handler_.board().get_team(side).is_droid()) {
1437  print(get_cmd(), VGETTEXT("Side '$side' controller is now controlled by: AI.", symbols));
1438  } else {
1439  print(get_cmd(), VGETTEXT("Side '$side' controller is now controlled by: human.", symbols));
1440  }
1441  } else if(menu_handler_.board().get_team(side).is_local_ai()) {
1442  // menu_handler_.board().get_team(side).make_human();
1443  // menu_handler_.change_controller(std::to_string(side),"human");
1444 
1445  utils::string_map symbols;
1446  symbols["side"] = side_s;
1447  command_failed(VGETTEXT("Can't droid a local ai side: '$side'.", symbols));
1448  }
1449 }
1450 
1452 {
1453  // :idle [<side> [on/off]]
1454  const std::string side_s = get_arg(1);
1455  const std::string action = get_arg(2);
1456  // default to the current side if empty
1457  const unsigned int side = side_s.empty() ? team_num_ : lexical_cast_default<unsigned int>(side_s);
1458 
1459  if(side < 1 || side > menu_handler_.teams().size()) {
1460  utils::string_map symbols;
1461  symbols["side"] = side_s;
1462  command_failed(VGETTEXT("Can't idle invalid side: '$side'.", symbols));
1463  return;
1464  } else if(menu_handler_.board().get_team(side).is_network()) {
1465  utils::string_map symbols;
1466  symbols["side"] = std::to_string(side);
1467  command_failed(VGETTEXT("Can't idle networked side: '$side'.", symbols));
1468  return;
1469  } else if(menu_handler_.board().get_team(side).is_local_ai()) {
1470  utils::string_map symbols;
1471  symbols["side"] = std::to_string(side);
1472  command_failed(VGETTEXT("Can't idle local ai side: '$side'.", symbols));
1473  return;
1474  } else if(menu_handler_.board().get_team(side).is_local_human()) {
1475  if(menu_handler_.board().get_team(side).is_idle() ? action == " on" : action == " off") {
1476  return;
1477  }
1478  // toggle the proxy controller between idle / non idle
1479  menu_handler_.board().get_team(side).toggle_idle();
1480  if(team_num_ == side) {
1481  if(playsingle_controller* psc = dynamic_cast<playsingle_controller*>(&menu_handler_.pc_)) {
1482  psc->set_player_type_changed();
1483  }
1484  }
1485  }
1486 }
1487 
1489 {
1491 }
1492 
1494 {
1495  save_id_matches(const std::string& save_id)
1496  : save_id_(save_id)
1497  {
1498  }
1499 
1500  bool operator()(const team& t) const
1501  {
1502  return t.save_id() == save_id_;
1503  }
1504 
1505  std::string save_id_;
1506 };
1507 
1509 {
1510  // :control <side> <nick>
1511  if(!menu_handler_.pc_.is_networked_mp()) {
1512  return;
1513  }
1514 
1515  const std::string side = get_arg(1);
1516  const std::string player = get_arg(2);
1517  if(player.empty()) {
1518  command_failed_need_arg(2);
1519  return;
1520  }
1521 
1522  unsigned int side_num;
1523  try {
1524  side_num = lexical_cast<unsigned int>(side);
1525  } catch(const bad_lexical_cast&) {
1526  const auto it_t = std::find_if(
1528  if(it_t == resources::gameboard->teams().end()) {
1529  utils::string_map symbols;
1530  symbols["side"] = side;
1531  command_failed(VGETTEXT("Can't change control of invalid side: '$side'.", symbols));
1532  return;
1533  } else {
1534  side_num = it_t->side();
1535  }
1536  }
1537 
1538  if(side_num < 1 || side_num > menu_handler_.teams().size()) {
1539  utils::string_map symbols;
1540  symbols["side"] = side;
1541  command_failed(VGETTEXT("Can't change control of out-of-bounds side: '$side'.", symbols));
1542  return;
1543  }
1544 
1545  menu_handler_.request_control_change(side_num, player);
1546 }
1547 
1549 {
1550  const std::string side = get_arg(1);
1551  unsigned int side_num;
1552  try {
1553  side_num = lexical_cast<unsigned int>(side);
1554  } catch(const bad_lexical_cast&) {
1555  utils::string_map symbols;
1556  symbols["side"] = side;
1557  command_failed(VGETTEXT("Can't query control of invalid side: '$side'.", symbols));
1558  return;
1559  }
1560 
1561  if(side_num < 1 || side_num > menu_handler_.teams().size()) {
1562  utils::string_map symbols;
1563  symbols["side"] = side;
1564  command_failed(VGETTEXT("Can't query control of out-of-bounds side: '$side'.", symbols));
1565  return;
1566  }
1567 
1568  std::string report = menu_handler_.board().get_team(side_num).controller().to_string();
1569  if(!menu_handler_.board().get_team(side_num).is_proxy_human()) {
1570  report += " (" + menu_handler_.board().get_team(side_num).proxy_controller().to_string() + ")";
1571  }
1572 
1573  if(menu_handler_.board().get_team(side_num).is_network()) {
1574  report += " (networked)";
1575  }
1576 
1577  print(get_cmd(), report);
1578 }
1579 
1581 {
1582  menu_handler_.gui_->get_chat_manager().clear_chat_messages();
1583 }
1584 
1586 {
1587  menu_handler_.gui_->toggle_debug_foreground();
1588 }
1589 
1591 {
1592  display& disp = *(menu_handler_.gui_);
1593 
1594  const mouse_handler& mousehandler = menu_handler_.pc_.get_mouse_handler_base();
1595  const map_location& loc = mousehandler.get_last_hex();
1596 
1597  //
1598  // It's possible to invoke this dialog even if loc isn't a valid hex. I'm not sure
1599  // exactly how that happens, but it does seem to occur when moving the mouse outside
1600  // the window to the menu bar. Not sure if there's a bug when the set-last-hex code
1601  // in that case, but this check at least ensures the dialog is only ever shown for a
1602  // valid, on-map location. Otherwise, an assertion gets thrown.
1603  //
1604  // -- vultraz, 2017-09-21
1605  //
1606  if(disp.get_map().on_board_with_border(loc)) {
1607  gui2::dialogs::terrain_layers::display(disp, loc);
1608  }
1609 }
1610 
1612 {
1614 }
1615 
1617 {
1618  menu_handler_.gui_->toggle_benchmark();
1619 }
1620 
1622 {
1623  menu_handler_.pc_.do_consolesave(get_data());
1624 }
1625 
1627 {
1628  do_save();
1629  do_quit();
1630 }
1631 
1633 {
1635 }
1636 
1638 {
1639  game_config::ignore_replay_errors = (get_data() != "off") ? true : false;
1640 }
1641 
1643 {
1644  game_config::disable_autosave = (get_data() != "off") ? true : false;
1645 }
1646 
1648 {
1649  synced_context::run_and_throw("debug_next_level", config {"next_level", get_data()});
1650 }
1651 
1653 {
1654  std::string tag = menu_handler_.pc_.get_classification().get_tagname();
1655  std::vector<std::string> options;
1656  std::string next;
1657  if(tag != "multiplayer") {
1658  for(const config& sc : menu_handler_.game_config_.child_range(tag)) {
1659  const std::string& id = sc["id"];
1660  options.push_back(id);
1661  if(id == menu_handler_.gamedata().next_scenario()) {
1662  next = id;
1663  }
1664  }
1665  } else {
1666  // find scenarios of multiplayer campaigns
1667  // (assumes that scenarios are ordered properly in the game_config)
1668  std::string scenario = menu_handler_.pc_.get_mp_settings().mp_scenario;
1669  for(const config& mp : menu_handler_.game_config_.child_range("multiplayer")) {
1670  if(mp["id"] == scenario) {
1671  const std::string& id = mp["id"];
1672  options.push_back(id);
1673  if(id == menu_handler_.gamedata().next_scenario())
1674  next = id;
1675  scenario = mp["next_scenario"].str();
1676  }
1677  }
1678  }
1679  std::sort(options.begin(), options.end());
1680  int choice = std::distance(options.begin(), std::lower_bound(options.begin(), options.end(), next));
1681  {
1682  gui2::dialogs::simple_item_selector dlg(_("Choose Scenario (Debug!)"), "", options);
1683  dlg.set_selected_index(choice);
1684  dlg.show();
1685  choice = dlg.selected_index();
1686  }
1687 
1688  if(choice == -1) {
1689  return;
1690  }
1691 
1692  if(std::size_t(choice) < options.size()) {
1693  synced_context::run_and_throw("debug_next_level", config {"next_level", options[choice]});
1694  }
1695 }
1696 
1698 {
1699  tod_manager& tod_man = menu_handler_.gamestate().tod_manager_;
1700 
1701  int turn = tod_man.turn() + 1;
1702  const std::string& data = get_data();
1703  if(!data.empty()) {
1704  turn = lexical_cast_default<int>(data, 1);
1705  }
1706  synced_context::run_and_throw("debug_turn", config {"turn", turn});
1707 }
1708 
1710 {
1711  int limit = get_data().empty() ? -1 : lexical_cast_default<int>(get_data(), 1);
1712  synced_context::run_and_throw("debug_turn_limit", config {"turn_limit", limit});
1713 }
1714 
1716 {
1717  if(!menu_handler_.pc_.is_networked_mp() || game_config::mp_debug) {
1718  print(get_cmd(), _("Debug mode activated!"));
1719  game_config::set_debug(true);
1720  } else {
1721  command_failed(_("Debug mode not available in network games"));
1722  }
1723 }
1724 
1726 {
1727  if(game_config::debug) {
1728  print(get_cmd(), _("Debug mode deactivated!"));
1729  game_config::set_debug(false);
1730  }
1731 }
1732 
1734 {
1735  if(!menu_handler_.gamestate().lua_kernel_) {
1736  return;
1737  }
1738 
1739  synced_context::run_and_throw("debug_lua", config {"code", get_data()});
1740 }
1741 
1743 {
1744  if(!menu_handler_.gamestate().lua_kernel_) {
1745  return;
1746  }
1747 
1748  const int retval = gui2::show_message(_("WARNING! Unsafe Lua Mode"),
1749  _("Executing Lua code in in this manner opens your computer to potential security breaches from any "
1750  "malicious add-ons or other programs you may have installed.\n\n"
1751  "Do not continue unless you really know what you are doing."), gui2::dialogs::message::ok_cancel_buttons);
1752 
1753  if(retval == gui2::retval::OK) {
1754  print(get_cmd(), _("Unsafe mode enabled!"));
1755  menu_handler_.gamestate().lua_kernel_->load_package();
1756  }
1757 }
1758 
1760 {
1761  preferences::set_custom_command(get_data());
1762 }
1763 
1765 {
1766  const std::string data = get_data();
1767  const std::string::const_iterator j = std::find(data.begin(), data.end(), '=');
1768  const std::string alias(data.begin(), j);
1769  if(j != data.end()) {
1770  const std::string command(j + 1, data.end());
1771  if(!command.empty()) {
1772  register_alias(command, alias);
1773  } else {
1774  // "alias something=" deactivate this alias. We just set it
1775  // equal to itself here. Later preferences will filter empty alias.
1776  register_alias(alias, alias);
1777  }
1778  preferences::add_alias(alias, command);
1779  // directly save it for the moment, but will slow commands sequence
1781  } else {
1782  // "alias something" display its value
1783  // if no alias, will be "'something' = 'something'"
1784  const std::string command = chmap::get_actual_cmd(alias);
1785  print(get_cmd(), "'" + alias + "'" + " = " + "'" + command + "'");
1786  }
1787 }
1788 
1790 {
1791  const std::string data = get_data();
1792  if(data.empty()) {
1793  command_failed_need_arg(1);
1794  return;
1795  }
1796 
1797  const std::string::const_iterator j = std::find(data.begin(), data.end(), '=');
1798  if(j != data.end()) {
1799  const std::string name(data.begin(), j);
1800  const std::string value(j + 1, data.end());
1801  synced_context::run_and_throw("debug_set_var", config {"name", name, "value", value});
1802  } else {
1803  command_failed(_("Variable not found"));
1804  }
1805 }
1806 
1808 {
1809  gui2::show_transient_message("", menu_handler_.gamedata().get_variable_const(get_data()));
1810 }
1811 
1813 {
1815  gui2::dialogs::gamestate_inspector::display(
1817 }
1818 
1820 {
1821  gui2::dialogs::mp_change_control::display(menu_handler_);
1822 }
1823 
1825 {
1826  // prevent SIGSEGV due to attempt to set HP during a fight
1827  if(events::commands_disabled > 0) {
1828  return;
1829  }
1830 
1831  unit_map::iterator i = menu_handler_.current_unit();
1832  if(i == menu_handler_.units().end()) {
1833  return;
1834  }
1835 
1836  const map_location loc = i->get_location();
1837  const std::string data = get_data(1);
1838  std::vector<std::string> parameters = utils::split(data, '=', utils::STRIP_SPACES);
1839  if(parameters.size() < 2) {
1840  return;
1841  }
1842 
1843  if(parameters[0] == "alignment") {
1844  unit_type::ALIGNMENT alignment;
1845  if(!alignment.parse(parameters[1])) {
1846  utils::string_map symbols;
1847  symbols["alignment"] = get_arg(1);
1848  command_failed(VGETTEXT(
1849  "Invalid alignment: '$alignment', needs to be one of lawful, neutral, chaotic, or liminal.",
1850  symbols));
1851  return;
1852  }
1853  }
1854 
1855  synced_context::run_and_throw("debug_unit",
1856  config {
1857  "x", loc.wml_x(),
1858  "y", loc.wml_y(),
1859  "name", parameters[0],
1860  "value", parameters[1],
1861  }
1862  );
1863 }
1864 
1866 {
1867  for(const unit_type_data::unit_type_map::value_type& i : unit_types.types()) {
1868  preferences::encountered_units().insert(i.second.id());
1869  }
1870 }
1871 
1873 {
1874  const int res = gui2::show_message("Undiscover",
1875  _("Do you wish to clear all of your discovered units from help?"), gui2::dialogs::message::yes_no_buttons);
1876  if(res != gui2::retval::CANCEL) {
1878  }
1879 }
1880 
1881 /** Implements the (debug mode) console command that creates a unit. */
1883 {
1884  const mouse_handler& mousehandler = menu_handler_.pc_.get_mouse_handler_base();
1885  const map_location& loc = mousehandler.get_last_hex();
1886  if(menu_handler_.map().on_board(loc)) {
1887  const unit_type* ut = unit_types.find(get_data());
1888  if(!ut) {
1889  command_failed(_("Invalid unit type"));
1890  return;
1891  }
1892 
1893  // Create the unit.
1894  create_and_place(*menu_handler_.gui_, menu_handler_.map(), menu_handler_.units(), loc, *ut);
1895  } else {
1896  command_failed(_("Invalid location"));
1897  }
1898 }
1899 
1901 {
1902  synced_context::run_and_throw("debug_fog", config());
1903 }
1904 
1906 {
1907  synced_context::run_and_throw("debug_shroud", config());
1908 }
1909 
1911 {
1912  synced_context::run_and_throw("debug_gold", config {"gold", lexical_cast_default<int>(get_data(), 1000)});
1913 }
1914 
1916 {
1917  synced_context::run_and_throw("debug_event", config {"eventname", get_data()});
1918 }
1919 
1921 {
1922  menu_handler_.gui_->set_draw_coordinates(!menu_handler_.gui_->get_draw_coordinates());
1923 }
1925 {
1926  menu_handler_.gui_->set_draw_terrain_codes(!menu_handler_.gui_->get_draw_terrain_codes());
1927 }
1928 
1930 {
1931  menu_handler_.gui_->set_draw_num_of_bitmaps(!menu_handler_.gui_->get_draw_num_of_bitmaps());
1932 }
1933 
1935 {
1936  if(const std::shared_ptr<wb::manager>& whiteb = menu_handler_.pc_.get_whiteboard()) {
1937  whiteb->set_active(!whiteb->is_active());
1938  if(whiteb->is_active()) {
1939  print(get_cmd(), _("Planning mode activated!"));
1940  whiteb->print_help_once();
1941  } else {
1942  print(get_cmd(), _("Planning mode deactivated!"));
1943  }
1944  }
1945 }
1946 
1948 {
1949  if(menu_handler_.pc_.get_whiteboard()) {
1950  menu_handler_.pc_.get_whiteboard()->options_dlg();
1951  }
1952 }
1953 
1954 void menu_handler::do_ai_formula(const std::string& str, int side_num)
1955 {
1956  try {
1957  add_chat_message(std::time(nullptr), "wfl", 0, ai::manager::get_singleton().evaluate_command(side_num, str));
1958  } catch(const wfl::formula_error&) {
1959  } catch(...) {
1960  add_chat_message(std::time(nullptr), "wfl", 0, "UNKNOWN ERROR IN FORMULA");
1961  }
1962 }
1963 
1965 {
1967  std::bind(&menu_handler::do_command, this, _1));
1968 }
1969 
1970 void menu_handler::request_control_change(int side_num, const std::string& player)
1971 {
1972  std::string side = std::to_string(side_num);
1973  if(board().get_team(side_num).is_local_human() && player == preferences::login()) {
1974  // this is already our side.
1975  return;
1976  } else {
1977  // The server will (or won't because we aren't allowed to change the controller)
1978  // send us a [change_controller] back, which we then handle in playturn.cpp
1979  pc_.send_to_wesnothd(config {"change_controller", config {"side", side, "player", player}});
1980  }
1981 }
1982 
1984 {
1985  for(const std::string& command : utils::split(preferences::custom_command(), ';')) {
1986  do_command(command);
1987  }
1988 }
1989 
1991 {
1992  if(!pc_.is_networked_mp()) {
1994  std::bind(&menu_handler::do_ai_formula, this, _1, pc_.current_side()));
1995  }
1996 }
1997 
1999 {
2000  gui_->get_chat_manager().clear_chat_messages(); // also clear debug-messages and WML-error-messages
2001 }
2002 
2004 {
2005  pc_.send_to_wesnothd(cfg);
2006 }
2007 
2008 } // end namespace events
bool show_theme_dialog()
Definition: display.cpp:116
void label_terrain(mouse_handler &mousehandler, bool team_only)
pathfind::marked_route get_route(const unit *un, map_location go_to, team &team) const
int dispatch(lua_State *L)
boost::intrusive_ptr< const unit > unit_const_ptr
Definition: ptr.hpp:30
int village_owner(const map_location &loc) const
Given the location of a village, will return the 0-based index of the team that currently owns it...
Dialog was closed with the CANCEL button.
Definition: retval.hpp:37
menu_handler & menu_handler_
bool empty() const
Is it empty?
void do_search(const std::string &new_search)
void set_current_paths(const pathfind::paths &new_paths)
Game board class.
Definition: game_board.hpp:50
game_data & gamedata()
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.
Definition: message.cpp:149
void set_grid(bool ison)
Definition: display.cpp:70
void add_chat_message(const std::time_t &time, const std::string &speaker, int side, const std::string &message, events::chat_handler::MESSAGE_TYPE type=events::chat_handler::MESSAGE_PRIVATE) override
void goto_leader(int side_num)
int h() const
Effective map height.
Definition: map.hpp:116
unit_iterator end()
Definition: map.hpp:415
static bool execute(const display_context &board, const int viewing_team, int &selected_index)
Definition: game_stats.hpp:39
bool show_fps()
Definition: general.cpp:827
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
bool message_private()
Definition: game.cpp:848
std::map< std::string, t_string > string_map
void write_preferences()
Definition: general.cpp:156
std::unique_ptr< game_lua_kernel > lua_kernel_
Definition: game_state.hpp:50
map_location last_search_hit_
file_dialog & set_extension(const std::string &value)
Sets the default file extension for file names in save mode.
This class represents a single unit of a specific type.
Definition: unit.hpp:99
void show_terrain_description(const terrain_type &t)
Definition: help.cpp:89
Various functions implementing vision (through fog of war and shroud).
void send_chat_message(const std::string &message, bool allies_only=false) override
file_dialog & set_path(const std::string &value)
Sets the initial file selection.
bool is_authenticated()
Definition: game.cpp:182
void speak(const config &cfg)
Definition: replay.cpp:347
static manager & get_singleton()
Definition: manager.hpp:152
Various functions that implement attacks and attack calculations.
map_command_handler< console_handler > chmap
unit_iterator find_leader(int side)
Definition: map.cpp:329
static config get_recall(const std::string &unit_id, const map_location &loc, const map_location &from)
std::vector< std::string > get_commands_list() const
#define a
unit_race::GENDER gender()
Gender choice from the user.
Definition: unit_create.hpp:53
const map_location hovered_hex() const
Uses SDL and game_display::hex_clicked_on to fetch the hex the mouse is hovering, if applicable...
Shows an ok and cancel button.
Definition: message.hpp:75
std::string private_message
const t_string & text() const
Definition: label.hpp:136
menu_handler(game_display *gui, play_controller &pc)
Definition: menu_events.cpp:92
child_itors child_range(config_key_type key)
Definition: config.cpp:366
void show_unit_list(display &gui)
Definition: unit_list.cpp:189
void do_command(const std::string &str)
const std::string & choice() const
Unit type choice from the user.
Definition: unit_create.hpp:41
attribute_map::value_type attribute
Definition: config.hpp:226
General purpose widgets.
void request_control_change(int side_num, const std::string &player)
virtual std::string get_cmd() const
virtual const gamemap & map() const override
Definition: game_board.hpp:109
int wml_x() const
Definition: location.hpp:157
static config get_auto_shroud(bool turned_on)
Records that the player has toggled automatic shroud updates.
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
Definition: map.cpp:96
int viewing_side() const
Definition: display.hpp:133
unit_type_data unit_types
Definition: types.cpp:1442
void print(const std::string &title, const std::string &message)
std::size_t move_unit_and_record(const std::vector< map_location > &steps, undo_list *undo_stack, bool continued_move, bool show_move, bool *interrupted, move_unit_spectator *move_spectator)
Moves a unit across the board.
Definition: move.cpp:1233
const std::string & save_id() const
Definition: team.hpp:231
const color_t LABEL_COLOR
file_dialog & set_save_mode(bool value)
Sets the dialog&#39;s behavior on non-existent file name inputs.
void update_shroud_now(int side_num)
#define VNGETTEXT(msgid, msgid_plural, count,...)
Replay control code.
#define h
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:108
bool do_recruit(const std::string &name, int side_num, map_location &target_hex)
bool chars_equal_insensitive(char a, char b)
Definition: general.hpp:21
Contains the exception interfaces used to signal completion of a scenario, campaign or turn...
bool unit_can_move(const unit &u) const
Will return true iff the unit u has any possible moves it can do (including attacking etc)...
To lexical_cast(From value)
Lexical cast converts one type to another.
bool show(const unsigned auto_close_time=0)
Shows the window.
void create_unit(mouse_handler &mousehandler)
Creates a unit (in debug mode via hotkey or context menu).
const unit_type_map & types() const
Definition: types.hpp:359
save_id_matches(const std::string &save_id)
std::vector< std::string > split(const std::string &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
bool yellow_confirm()
Definition: game.cpp:962
bool ellipses()
Definition: general.cpp:497
static synced_state get_synced_state()
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&#39;s leaders&#39; personal abilities to recall...
Definition: create.cpp:150
static config get_update_shroud()
Records that the player has manually updated fog/shroud.
void show_statistics(int side_num)
A single unit type that the player may recruit.
Definition: types.hpp:42
game_data * gamedata
Definition: resources.cpp:22
void add_chat_message(const std::time_t &time, const std::string &speaker, int side, const std::string &msg, events::chat_handler::MESSAGE_TYPE type, bool bell)
void flush_cache()
Definition: picture.cpp:244
bool get_disallow_recall() const
bool team_valid() const
Definition: display.cpp:604
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
Definition: general.hpp:78
int gold() const
Definition: team.hpp:189
std::string path() const
Gets the current file selection.
Pubic entry points for the MP workflow.
Definition: lobby_data.cpp:49
map_location get_selected_hex() const
game_board & board() const
int action_bonus_count() const
Definition: team.hpp:213
bool confirm_no_moves()
Definition: game.cpp:967
const map_location & get_last_hex() const
std::vector< team > & teams() const
unit_map units_
Definition: game_board.hpp:58
const config & options()
Definition: game.cpp:566
std::string write() const
Definition: map.cpp:204
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
bool end_turn(int side_num)
game_display * gui_
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:89
console_handler(menu_handler &menu_handler)
virtual void register_alias(const std::string &to_cmd, const std::string &cmd)
void toggle_shroud_updates(int side_num)
team & get_team(int i)
Definition: game_board.hpp:104
void set_custom_command(const std::string &command)
Definition: game.cpp:939
virtual std::string get_arg(unsigned i) const
void throw_quit_game_exception()
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
const std::vector< unit_race::GENDER > & genders() const
The returned vector will not be empty, provided this has been built to the HELP_INDEXED status...
Definition: types.hpp:239
const std::string & id() const
Gets this unit&#39;s id.
Definition: unit.hpp:305
void scroll_to_leader(int side, SCROLL_TYPE scroll_type=ONSCREEN, bool force=true)
Scrolls to the leader of a certain side.
bool hex_hosts_unit(const map_location &hex) const
Unit exists on the hex, no matter if friend or foe.
int cost() const
Definition: types.hpp:158
const t_string id
void disable_units_highlight()
Use this to disable hovering an unit from highlighting its movement range.
std::vector< team > teams_
Definition: game_board.hpp:53
const t_string name
bool is_enabled(const chmap::command &c) const
const std::set< std::string > get_recruits(int side, const map_location &recruit_loc)
Gets the recruitable units from a side&#39;s leaders&#39; personal recruit lists who can recruit on or from a...
Definition: create.cpp:58
This file contains the settings handling of the widget library.
const terrain_label * set_label(const map_location &loc, const t_string &text, const int creator=-1, const std::string &team="", const color_t color=font::NORMAL_COLOR, const bool visible_in_fog=true, const bool visible_in_shroud=false, const bool immutable=false, const std::string &category="", const t_string &tooltip="")
Definition: label.cpp:146
bool on_board_with_border(const map_location &loc) const
Definition: map.cpp:365
void do_create()
Implements the (debug mode) console command that creates a unit.
Applies the planned unit map for the duration of the struct&#39;s life.
Definition: manager.hpp:251
std::string get_user_data_dir()
Definition: filesystem.cpp:749
void clear(const std::string &, bool force)
Definition: label.cpp:210
int wml_y() const
Definition: location.hpp:158
bool disable_autosave
void write_file(const std::string &fname, const std::string &data)
Throws io_exception if an error occurs.
Definition: filesystem.cpp:955
static void ignore_error_function(const std::string &message, bool heavy)
a function to be passed to run_in_synced_context to ignore the error.
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.
bool valid() const
Definition: location.hpp:93
bool ignore_replay_errors
void recall(int side_num, const map_location &last_hex)
game_board * gameboard
Definition: resources.cpp:20
const config & game_config_
static void display(const std::string &prompt, callback_t callback=nullptr)
Shows the command console.
void end_unit_turn(mouse_handler &mousehandler, int side_num)
void set_show_fps(bool value)
Definition: general.cpp:832
Encapsulates the map of the game.
Definition: map.hpp:36
const t_string & name() const
Gets this unit&#39;s translatable display name.
Definition: unit.hpp:328
virtual const std::set< std::string > & observers() const override
void recruit(int side_num, const map_location &last_hex)
const std::string & last_recruit() const
Definition: team.hpp:228
bool has_friends() const
void do_speak(const std::string &message, bool allies_only=false)
bool is_enemy(int n) const
Definition: team.hpp:243
const map_location & get_goto() const
The map location to which this unit is moving over multiple turns, if any.
Definition: unit.hpp:1205
Object which temporarily resets a unit&#39;s movement.
Definition: unit.hpp:1756
void add_rename(const std::string &name, const map_location &loc)
Definition: replay.cpp:290
Shows a yes and no button.
Definition: message.hpp:79
void highlight_another_reach(const pathfind::paths &paths_list)
Add more paths to highlight.
const std::string & id() const
The id for this unit_type.
Definition: types.hpp:139
Managing the AIs lifecycle - headers.
replay * recorder
Definition: resources.cpp:28
Structure which holds a single route and marks for special events.
Definition: pathfind.hpp:140
bool no_choice() const
Whether the user actually chose a unit type or not.
Definition: unit_create.hpp:47
std::shared_ptr< wb::manager > get_whiteboard() const
const terrain_label * get_label(const map_location &loc, const std::string &team_name) const
Definition: label.hpp:47
const char * what() const noexcept
Definition: exceptions.hpp:37
void set_message_private(bool value)
Definition: game.cpp:853
game_events::manager * game_events
Definition: resources.cpp:24
void show_unit_description(const unit &u)
Definition: help.cpp:46
bool fogged(const map_location &loc) const
Returns true if location (x,y) is covered in fog.
Definition: display.cpp:614
const std::string & gender_string(unit_race::GENDER gender)
Definition: race.cpp:138
int recall_cost() const
Definition: team.hpp:193
Encapsulates the map of the game.
Definition: location.hpp:42
bool auto_shroud_updates() const
Definition: team.hpp:336
bool shrouded(const map_location &loc) const
Returns true if location (x,y) is covered in shroud.
Definition: display.cpp:609
Various functions related to moving units.
std::string login()
bool user_end_turn() const
Check whether the user ended their turn.
Definition: unit.hpp:673
unit_iterator find(std::size_t id)
Definition: map.cpp:311
game_state & gamestate() const
Various functions related to the creation of units (recruits, recalls, and placed units)...
actions::undo_list & get_undo_stack()
bool has_moved() const
Checks if this unit has moved.
Definition: unit.hpp:1130
std::string current_team_name() const
void recalculate_labels()
Definition: label.cpp:244
int w() const
Effective map width.
Definition: map.hpp:113
static void display(const config &game_cfg, const preferences::PREFERENCE_VIEW initial_view=preferences::VIEW_DEFAULT)
The display function – see modal_dialog for more information.
static bool execute(display_context &dc)
The execute function.
const gamemap & map() const
virtual bool is_networked_mp() const
void show_help(const std::string &show_topic)
Open the help browser, show topic with id show_topic.
Definition: help.cpp:36
static fs::path get_dir(const fs::path &dirpath)
Definition: filesystem.cpp:311
void continue_move(mouse_handler &mousehandler, int side_num)
static void print(std::stringstream &sstr, const std::string &queue, const std::string &id)
Definition: fire_event.cpp:29
void add_alias(const std::string &alias, const std::string &command)
Definition: general.cpp:873
std::size_t i
Definition: function.cpp:933
logger & err()
Definition: log.cpp:78
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.
Definition: display.cpp:1192
bool is_observer() const
Check if we are an observer in this game.
int selected_index() const
Returns the selected item index after displaying.
void execute_gotos(mouse_handler &mousehandler, int side_num)
virtual void highlight_hex(map_location hex) override
Function to highlight a location.
std::string last_search_
Game configuration data as global variables.
Definition: build_info.cpp:46
std::string get_command_flags_description(const chmap::command &c) const
An exception object used when an IO error occurs.
Definition: filesystem.hpp:48
void do_ai_formula(const std::string &str, int side_num)
void terrain_description(mouse_handler &mousehandler)
Define the game&#39;s event mechanism.
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.
Definition: create.cpp:321
ONLY IF whiteboard is currently active, applies the planned unit map for the duration of the struct&#39;s...
Definition: manager.hpp:272
CURSOR_TYPE get()
Definition: cursor.cpp:213
void unit_hold_position(mouse_handler &mousehandler, int side_num)
const std::string & team_name() const
Definition: label.cpp:128
void change_side(mouse_handler &mousehandler)
game_data gamedata_
Definition: game_state.hpp:45
int w
std::set< std::string > & encountered_units()
Definition: game.cpp:927
const bool & debug
#define N_(String)
Definition: gettext.hpp:97
Definitions for the terrain builder.
static int sort(lua_State *L)
Definition: ltablib.cpp:411
void set_goto(const map_location &new_goto)
Sets this unit&#39;s long term destination.
Definition: unit.hpp:1211
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
void set_ellipses(bool ison)
Definition: general.cpp:502
void cycle_units(const bool browse, const bool reverse=false)
void kill_unit(mouse_handler &mousehandler)
play_controller & pc_
Handling of system events.
Definition: manager.hpp:41
bool grid()
Definition: general.cpp:507
#define next(ls)
Definition: llex.cpp:32
bool operator()(const team &t) const
display_chat_manager & get_chat_manager()
static bool run_and_throw(const std::string &commandname, const config &data, bool use_undo=true, bool show=true, synced_command::error_handler_function error_handler=default_error_function)
virtual std::string get_data(unsigned n=1) const
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.
bool green_confirm()
Definition: game.cpp:953
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:139
const gamemap & get_map() const
Definition: display.hpp:109
To store label data Class implements logic for rendering.
Definition: label.hpp:107
events::mouse_handler & get_mouse_handler_base() override
Get a reference to a mouse handler member a derived class uses.
unit_map::iterator current_unit()
game_state & gamestate()
double t
Definition: astarsearch.cpp:63
bool unhighlight_reach()
Reset highlighting of paths.
void show_enemy_moves(bool ignore_units, int side_num)
const map_location & get_location() const
The current map location this unit is at.
Definition: unit.hpp:1174
static color_t get_side_color(int side)
Definition: team.cpp:940
static UNUSEDNOWARN std::string sgettext(const char *str)
Definition: gettext.hpp:68
void set_selected_index(int index)
Sets the initially selected item index (-1 by default).
game_board board_
Definition: game_state.hpp:46
std::size_t viewing_team() const
The viewing team is the team currently viewing the game.
Definition: display.hpp:128
#define DBG_WB
Definition: typedefs.hpp:27
A variable-expanding proxy for the config class.
Definition: variable.hpp:42
Various functions that implement the undoing (and redoing) of in-game commands.
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:465
void set_action_bonus_count(const int count)
Definition: team.hpp:214
Standard logging facilities (interface).
int current_side() const
Returns the number of the side whose turn it is.
REMOVE_EMPTY: remove empty elements.
Object which contains all the possible locations a unit can move to, with associated best routes to t...
Definition: pathfind.hpp:70
recall_list_manager & recall_list()
Definition: team.hpp:215
static const map_location & null_location()
Definition: location.hpp:85
Container associating units to locations.
Definition: map.hpp:99
std::string get_command_flags_description(const map_command_handler< chat_command_handler >::command &c) const
EXIT_STATUS start(const std::string &filename, bool take_screenshot, const std::string &screenshot_filename)
Main interface for launching the editor from the title screen.
Definition: editor_main.cpp:28
std::string get_flags_description() const
static vconfig empty_vconfig()
Definition: variable.cpp:105
static config get_recruit(const std::string &type_id, const map_location &loc, const map_location &from)
map_labels & labels()
Definition: display.cpp:1402
int turn() const
#define e
retval
Default window/dialog return values.
Definition: retval.hpp:28
int side() const
The side this unit belongs to.
Definition: unit.hpp:265
void do_speak(const std::string &message)
bool player_acted() const
Returns true if the player has performed any actions this turn.
Definition: undo.hpp:84
Dialog was closed with the OK button.
Definition: retval.hpp:34
void send_to_server(const config &cfg) override
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
void notify_event(const std::string &name, const config &data)
Definition: manager.cpp:144
mock_char c
const std::string & str() const
Definition: tstring.hpp:186
const config & get_alias()
Definition: general.cpp:880
void set_route(const pathfind::marked_route *route)
Sets the route along which footsteps are drawn to show movement of a unit.
Enables auto close.
Definition: message.hpp:69
std::string custom_command()
Definition: game.cpp:935
std::vector< std::string > get_commands_list()
static map_location::DIRECTION n
void repeat_recruit(int side_num, const map_location &last_hex)
void move_unit_to_loc(const unit_map::iterator &ui, const map_location &target, bool continue_move, int side_num, mouse_handler &mousehandler)
Thrown when a lexical_cast fails.
void clear_labels(const std::string &, bool)
Definition: replay.cpp:280
std::string path
File path.
const unsigned int team_num_
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
Definition: unit.hpp:1100
unit_map::iterator find_visible_unit(const map_location &loc, const team &current_team, bool see_all=false)
Definition: game_board.cpp:168
virtual void send_to_wesnothd(const config &, const std::string &="unknown") const
Display units performing various actions: moving, attacking, and dying.
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="")
play_controller & pc_
std::vector< map_location > & steps
Definition: pathfind.hpp:186
void set_debug(bool new_debug)
static plugins_manager * get()
Definition: manager.cpp:58
void show_objectives() const
void add_label(const terrain_label *)
Definition: replay.cpp:269
const std::string observer_team_name
observer team name used for observer team chat
Definition: game_config.cpp:89
file_dialog & set_title(const std::string &value)
Sets the current dialog title text.
Definition: file_dialog.hpp:56