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