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()) {
537  gui2::show_transient_message("", _("You cannot end your turn yet!"));
538  return false;
539  }
540 
541  std::size_t team_num = static_cast<std::size_t>(side_num - 1);
542  if(team_num < teams().size() && teams()[team_num].no_turn_confirmation()) {
543  // Skip the confirmations that follow.
544  }
545  // Ask for confirmation if the player hasn't made any moves.
547  && (!pc_.get_whiteboard() || !pc_.get_whiteboard()->current_side_has_actions())
548  && units_alive(side_num, units())) {
549  const int res = gui2::show_message("",
550  _("You have not started your turn yet. Do you really want to end your turn?"),
552  if(res == gui2::retval::CANCEL) {
553  return false;
554  }
555  }
556  // Ask for confirmation if units still have some movement left.
557  else if(preferences::yellow_confirm() && partmoved_units(side_num, units(), board(), pc_.get_whiteboard())) {
558  const int res = gui2::show_message("",
559  _("Some units have movement left. 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 all movement left.
566  else if(preferences::green_confirm() && unmoved_units(side_num, units(), board(), pc_.get_whiteboard())) {
567  const int res = gui2::show_message("",
568  _("Some units have not moved. Do you really want to end your turn?"),
570  if(res == gui2::retval::CANCEL) {
571  return false;
572  }
573  }
574 
575  // Auto-execute remaining whiteboard planned actions
576  // Only finish turn if they all execute successfully, i.e. no ambush, etc.
577  if(pc_.get_whiteboard() && !pc_.get_whiteboard()->allow_end_turn()) {
578  return false;
579  }
580 
581  return true;
582 }
583 
584 void menu_handler::goto_leader(int side_num)
585 {
587  const display_context& dc = gui_->get_disp_context();
588  if(i != units().end() && i->is_visible_to_team(dc.get_team(gui_->viewing_side()), false)) {
589  gui_->scroll_to_tile(i->get_location(), game_display::WARP);
590  }
591 }
592 
594 {
596  if(un != units().end()) {
598  }
599 }
600 
602 {
603  const map_location& loc = mousehandler.get_last_hex();
604  if(map().on_board(loc) == false || gui_->shrouded(loc)) {
605  return;
606  }
607 
608  const terrain_type& type = map().get_terrain_info(loc);
609  // const terrain_type& info = board().map().get_terrain_info(terrain);
611 }
612 
614 {
615  const unit_map::iterator un = current_unit();
616  if(un == units().end() || gui_->viewing_side() != un->side()) {
617  return;
618  }
619 
620  if(un->unrenamable()) {
621  return;
622  }
623 
624  std::string name = un->name();
625  const std::string title(N_("Rename Unit"));
626  const std::string label(N_("Name:"));
627 
628  if(gui2::dialogs::edit_text::execute(title, label, name)) {
629  resources::recorder->add_rename(name, un->get_location());
630  un->rename(name);
632  }
633 }
634 
636 {
637  const mouse_handler& mousehandler = pc_.get_mouse_handler_base();
638 
640  if(res != units().end()) {
641  return res;
642  }
643 
644  return board().find_visible_unit(mousehandler.get_selected_hex(), teams()[gui_->viewing_team()]);
645 }
646 
647 // Helpers for create_unit()
648 namespace
649 {
650 /// Allows a function to return both a type and a gender.
651 typedef std::pair<const unit_type*, unit_race::GENDER> type_and_gender;
652 
653 /**
654  * Allows the user to select a type of unit, using GUI2.
655  * (Intended for use when a unit is created in debug mode via hotkey or
656  * context menu.)
657  * @returns the selected type and gender. If this is canceled, the
658  * returned type is nullptr.
659  */
660 type_and_gender choose_unit()
661 {
662  //
663  // The unit creation dialog makes sure unit types
664  // are properly cached.
665  //
666  gui2::dialogs::unit_create create_dlg;
667  create_dlg.show();
668 
669  if(create_dlg.no_choice()) {
670  return type_and_gender(nullptr, unit_race::NUM_GENDERS);
671  }
672 
673  const std::string& ut_id = create_dlg.choice();
674  const unit_type* utp = unit_types.find(ut_id);
675  if(!utp) {
676  ERR_NG << "Create unit dialog returned nonexistent or unusable unit_type id '" << ut_id << "'." << std::endl;
677  return type_and_gender(static_cast<const unit_type*>(nullptr), unit_race::NUM_GENDERS);
678  }
679  const unit_type& ut = *utp;
680 
681  unit_race::GENDER gender = create_dlg.gender();
682  // Do not try to set bad genders, may mess up l10n
683  /// @todo Is this actually necessary?
684  /// (Maybe create_dlg can enforce proper gender selection?)
685  if(ut.genders().end() == std::find(ut.genders().begin(), ut.genders().end(), gender)) {
686  gender = ut.genders().front();
687  }
688 
689  return type_and_gender(utp, gender);
690 }
691 
692 /**
693  * Creates a unit and places it on the board.
694  * (Intended for use with any units created via debug mode.)
695  */
696 void create_and_place(game_display&,
697  const gamemap&,
698  unit_map&,
699  const map_location& loc,
700  const unit_type& u_type,
702 {
703  synced_context::run_and_throw("debug_create_unit",
704  config {
705  "x", loc.wml_x(),
706  "y", loc.wml_y(),
707  "type", u_type.id(),
708  "gender", gender_string(gender),
709  }
710  );
711 }
712 
713 } // Anonymous namespace
714 
715 /**
716  * Creates a unit (in debug mode via hotkey or context menu).
717  */
719 {
720  // Save the current mouse location before popping up the choice menu (which
721  // gives time for the mouse to move, changing the location).
722  const map_location destination = mousehandler.get_last_hex();
723  assert(gui_ != nullptr);
724 
725  // Let the user select the kind of unit to create.
726  type_and_gender selection = choose_unit();
727  if(selection.first != nullptr) {
728  // Make it so.
729  create_and_place(*gui_, map(), units(), destination, *selection.first, selection.second);
730  }
731 }
732 
734 {
735  const map_location& loc = mousehandler.get_last_hex();
736  const unit_map::iterator i = units().find(loc);
737  if(i == units().end()) {
738  if(!map().is_village(loc)) {
739  return;
740  }
741 
742  // village_owner returns -1 for free village, so team 0 will get it
743  int team = board().village_owner(loc) + 1;
744  // team is 0-based so team=team::nteams() is not a team
745  // but this will make get_village free it
746  if(team > static_cast<int>(teams().size())) {
747  team = 0;
748  }
749  actions::get_village(loc, team + 1);
750  } else {
751  int side = i->side();
752  ++side;
753  if(side > static_cast<int>(teams().size())) {
754  side = 1;
755  }
756  i->set_side(side);
757 
758  if(map().is_village(loc)) {
759  actions::get_village(loc, side);
760  }
761  }
762 }
763 
765 {
766  const map_location loc = mousehandler.get_last_hex();
767  synced_context::run_and_throw("debug_kill", config {"x", loc.wml_x(), "y", loc.wml_y()});
768 }
769 
770 void menu_handler::label_terrain(mouse_handler& mousehandler, bool team_only)
771 {
772  const map_location& loc = mousehandler.get_last_hex();
773  if(map().on_board(loc) == false) {
774  return;
775  }
776 
777  const terrain_label* old_label = gui_->labels().get_label(loc);
778  std::string label = old_label ? old_label->text() : "";
779 
780  if(gui2::dialogs::edit_label::execute(label, team_only)) {
781  std::string team_name;
782  color_t color = font::LABEL_COLOR;
783 
784  if(team_only) {
785  team_name = gui_->labels().team_name();
786  } else {
788  }
789  const terrain_label* res = gui_->labels().set_label(loc, label, gui_->viewing_team(), team_name, color);
790  if(res) {
792  }
793  }
794 }
795 
797 {
798  if(gui_->team_valid() && !board().is_observer()) {
799  const int res = gui2::show_message(
800  _("Clear Labels"),
801  _("Are you sure you want to clear map labels?"),
803  );
804 
805  if(res == gui2::retval::OK) {
806  gui_->labels().clear(gui_->current_team_name(), false);
808  }
809  }
810 }
811 
813 {
816  }
817 }
818 
819 void menu_handler::continue_move(mouse_handler& mousehandler, int side_num)
820 {
822  if(i == units().end() || !i->move_interrupted()) {
823  i = units().find(mousehandler.get_selected_hex());
824  if(i == units().end() || !i->move_interrupted()) {
825  return;
826  }
827  }
828  move_unit_to_loc(i, i->get_interrupted_move(), true, side_num, mousehandler);
829 }
830 
832  const map_location& target,
833  bool continue_move,
834  int side_num,
835  mouse_handler& mousehandler)
836 {
837  assert(ui != units().end());
838 
839  pathfind::marked_route route = mousehandler.get_route(&*ui, target, board().get_team(side_num));
840 
841  if(route.steps.empty()) {
842  return;
843  }
844 
845  assert(route.steps.front() == ui->get_location());
846 
847  gui_->set_route(&route);
849 
850  {
851  LOG_NG << "move_unit_to_loc " << route.steps.front() << " to " << route.steps.back() << "\n";
853  }
854 
855  gui_->set_route(nullptr);
857 }
858 
859 void menu_handler::execute_gotos(mouse_handler& mousehandler, int side)
860 {
861  // we will loop on all gotos and try to fully move a maximum of them,
862  // but we want to avoid multiple blocking of the same unit,
863  // so, if possible, it's better to first wait that the blocker move
864 
865  bool wait_blocker_move = true;
866  std::set<map_location> fully_moved;
867 
868  bool change = false;
869  bool blocked_unit = false;
870  do {
871  change = false;
872  blocked_unit = false;
873  for(auto& unit : units()) {
874  if(unit.side() != side || unit.movement_left() == 0) {
875  continue;
876  }
877 
878  const map_location& current_loc = unit.get_location();
879  const map_location& goto_loc = unit.get_goto();
880 
881  if(goto_loc == current_loc) {
883  continue;
884  }
885 
886  if(!map().on_board(goto_loc)) {
887  continue;
888  }
889 
890  // avoid pathfinding calls for finished units
891  if(fully_moved.count(current_loc)) {
892  continue;
893  }
894 
895  pathfind::marked_route route = mousehandler.get_route(&unit, goto_loc, board().get_team(side));
896 
897  if(route.steps.size() <= 1) { // invalid path
898  fully_moved.insert(current_loc);
899  continue;
900  }
901 
902  // look where we will stop this turn (turn_1 waypoint or goto)
903  map_location next_stop = goto_loc;
904  pathfind::marked_route::mark_map::const_iterator w = route.marks.begin();
905  for(; w != route.marks.end(); ++w) {
906  if(w->second.turns == 1) {
907  next_stop = w->first;
908  break;
909  }
910  }
911 
912  if(next_stop == current_loc) {
913  fully_moved.insert(current_loc);
914  continue;
915  }
916 
917  // we delay each blocked move because some other change
918  // may open a another not blocked path
919  if(units().count(next_stop)) {
920  blocked_unit = true;
921  if(wait_blocker_move)
922  continue;
923  }
924 
925  gui_->set_route(&route);
926 
927  {
928  LOG_NG << "execute goto from " << route.steps.front() << " to " << route.steps.back() << "\n";
929  int moves = actions::move_unit_and_record(route.steps, &pc_.get_undo_stack());
930  change = moves > 0;
931  }
932 
933  if(change) {
934  // something changed, resume waiting blocker (maybe one can move now)
935  wait_blocker_move = true;
936  }
937  }
938 
939  if(!change && wait_blocker_move) {
940  // no change when waiting, stop waiting and retry
941  wait_blocker_move = false;
942  change = true;
943  }
944  } while(change && blocked_unit);
945 
946  // erase the footsteps after movement
947  gui_->set_route(nullptr);
949 }
950 
952 {
954  gui_->invalidate_all();
955 }
956 
958 {
960  gui_->invalidate_all();
961 }
962 
963 void menu_handler::unit_hold_position(mouse_handler& mousehandler, int side_num)
964 {
965  const unit_map::iterator un = units().find(mousehandler.get_selected_hex());
966  if(un != units().end() && un->side() == side_num && un->movement_left() >= 0) {
967  un->toggle_hold_position();
968  gui_->invalidate(mousehandler.get_selected_hex());
969 
970  mousehandler.set_current_paths(pathfind::paths());
971 
972  if(un->hold_position()) {
973  mousehandler.cycle_units(false);
974  }
975  }
976 }
977 
978 void menu_handler::end_unit_turn(mouse_handler& mousehandler, int side_num)
979 {
980  const unit_map::iterator un = units().find(mousehandler.get_selected_hex());
981  if(un != units().end() && un->side() == side_num && un->movement_left() >= 0) {
982  un->toggle_user_end_turn();
983  gui_->invalidate(mousehandler.get_selected_hex());
984 
985  mousehandler.set_current_paths(pathfind::paths());
986 
987  if(un->user_end_turn()) {
988  mousehandler.cycle_units(false);
989  }
990  }
991 }
992 
994 {
995  std::ostringstream msg;
996  msg << _("Search");
997  if(last_search_hit_.valid()) {
998  msg << " [" << last_search_ << "]";
999  }
1000  msg << ':';
1001  textbox_info_.show(gui::TEXTBOX_SEARCH, msg.str(), "", false, *gui_);
1002 }
1003 
1005 {
1006  // None of the two parameters really needs to be passed since the information belong to members of the class.
1007  // But since it makes the called method more generic, it is done anyway.
1009  textbox_info_.box()->text(), textbox_info_.check() != nullptr ? textbox_info_.check()->checked() : false);
1010 }
1011 
1012 void menu_handler::add_chat_message(const std::time_t& time,
1013  const std::string& speaker,
1014  int side,
1015  const std::string& message,
1017 {
1018  gui_->get_chat_manager().add_chat_message(time, speaker, side, message, type, false);
1019 
1021  config {
1022  "sender", preferences::login(),
1023  "message", message,
1024  "whisper", type == events::chat_handler::MESSAGE_PRIVATE,
1025  }
1026  );
1027 }
1028 
1029 // command handler for user :commands. Also understands all chat commands
1030 // via inheritance. This complicates some things a bit.
1031 class console_handler : public map_command_handler<console_handler>, private chat_command_handler
1032 {
1033 public:
1034  // convenience typedef
1037  : chmap()
1038  , chat_command_handler(menu_handler, true)
1039  , menu_handler_(menu_handler)
1040  , team_num_(menu_handler.pc_.current_side())
1041  {
1042  }
1043 
1044  using chmap::dispatch; // disambiguate
1045  using chmap::get_commands_list;
1046  using chmap::command_failed;
1047 
1048 protected:
1049  // chat_command_handler's init_map() and handlers will end up calling these.
1050  // this makes sure the commands end up in our map
1051  virtual void register_command(const std::string& cmd,
1053  const std::string& help = "",
1054  const std::string& usage = "",
1055  const std::string& flags = "")
1056  {
1057  chmap::register_command(cmd, h, help, usage, flags + "N"); // add chat commands as network_only
1058  }
1059 
1060  virtual void register_alias(const std::string& to_cmd, const std::string& cmd)
1061  {
1062  chmap::register_alias(to_cmd, cmd);
1063  }
1064 
1065  virtual std::string get_arg(unsigned i) const
1066  {
1067  return chmap::get_arg(i);
1068  }
1069 
1070  virtual std::string get_cmd() const
1071  {
1072  return chmap::get_cmd();
1073  }
1074 
1075  virtual std::string get_data(unsigned n = 1) const
1076  {
1077  return chmap::get_data(n);
1078  }
1079 
1080  // these are needed to avoid ambiguities introduced by inheriting from console_command_handler
1081  using chmap::register_command;
1082  using chmap::register_alias;
1083  using chmap::help;
1084  using chmap::is_enabled;
1085  using chmap::command_failed_need_arg;
1086 
1087  void do_refresh();
1088  void do_droid();
1089  void do_idle();
1090  void do_theme();
1091  void do_control();
1092  void do_controller();
1093  void do_clear();
1094  void do_foreground();
1095  void do_layers();
1096  void do_fps();
1097  void do_benchmark();
1098  void do_save();
1099  void do_save_quit();
1100  void do_quit();
1101  void do_ignore_replay_errors();
1102  void do_nosaves();
1103  void do_next_level();
1104  void do_choose_level();
1105  void do_turn();
1106  void do_turn_limit();
1107  void do_debug();
1108  void do_nodebug();
1109  void do_lua();
1110  void do_unsafe_lua();
1111  void do_custom();
1112  void do_set_alias();
1113  void do_set_var();
1114  void do_show_var();
1115  void do_inspect();
1116  void do_control_dialog();
1117  void do_unit();
1118  // void do_buff();
1119  // void do_unbuff();
1120  void do_discover();
1121  void do_undiscover();
1122  void do_create();
1123  void do_fog();
1124  void do_shroud();
1125  void do_gold();
1126  void do_event();
1127  void do_toggle_draw_coordinates();
1128  void do_toggle_draw_terrain_codes();
1129  void do_toggle_draw_num_of_bitmaps();
1130  void do_toggle_whiteboard();
1131  void do_whiteboard_options();
1132 
1133  std::string get_flags_description() const
1134  {
1135  return _("(D) — debug only, (N) — network only, (A) — admin only");
1136  }
1137 
1138  using chat_command_handler::get_command_flags_description; // silence a warning
1139  std::string get_command_flags_description(const chmap::command& c) const
1140  {
1141  std::string space(" ");
1142  return (c.has_flag('D') ? space + _("(debug command)") : "")
1143  + (c.has_flag('N') ? space + _("(network only)") : "")
1144  + (c.has_flag('A') ? space + _("(admin only)") : "")
1145  + (c.has_flag('S') ? space + _("(not during other events)") : "");
1146  }
1147 
1148  using map::is_enabled;
1149  bool is_enabled(const chmap::command& c) const
1150  {
1151  return !((c.has_flag('D') && !game_config::debug)
1152  || (c.has_flag('N') && !menu_handler_.pc_.is_networked_mp())
1153  || (c.has_flag('A') && !preferences::is_authenticated())
1154  || (c.has_flag('S') && (synced_context::get_synced_state() != synced_context::UNSYNCED || !menu_handler_.pc_.current_team().is_local())));
1155  }
1156 
1157  void print(const std::string& title, const std::string& message)
1158  {
1159  menu_handler_.add_chat_message(std::time(nullptr), title, 0, message);
1160  }
1161 
1162  void init_map()
1163  {
1164  chat_command_handler::init_map(); // grab chat_ /command handlers
1165 
1166  chmap::get_command("log")->flags = ""; // clear network-only flag from log
1167  chmap::get_command("version")->flags = ""; // clear network-only flag
1168  chmap::get_command("ignore")->flags = ""; // clear network-only flag
1169  chmap::get_command("friend")->flags = ""; // clear network-only flag
1170  chmap::get_command("remove")->flags = ""; // clear network-only flag
1171 
1172  chmap::set_cmd_prefix(":");
1173 
1174  register_command("refresh", &console_handler::do_refresh, _("Refresh gui."));
1175  register_command("droid", &console_handler::do_droid, _("Switch a side to/from AI control."),
1176  _("do not translate the on/off^[<side> [on/off]]"));
1177  register_command("idle", &console_handler::do_idle, _("Switch a side to/from idle state."),
1178  _("do not translate the on/off^[<side> [on/off]]"));
1179  register_command("theme", &console_handler::do_theme);
1180  register_command("control", &console_handler::do_control,
1181  _("Assign control of a side to a different player or observer."), _("<side> <nickname>"), "N");
1182  register_command("controller", &console_handler::do_controller, _("Query the controller status of a side."),
1183  _("<side>"));
1184  register_command("clear", &console_handler::do_clear, _("Clear chat history."));
1185  register_command("foreground", &console_handler::do_foreground, _("Debug foreground terrain."), "", "D");
1186  register_command(
1187  "layers", &console_handler::do_layers, _("Debug layers from terrain under the mouse."), "", "D");
1188  register_command("fps", &console_handler::do_fps, _("Show fps."));
1189  register_command("benchmark", &console_handler::do_benchmark);
1190  register_command("save", &console_handler::do_save, _("Save game."));
1191  register_alias("save", "w");
1192  register_command("quit", &console_handler::do_quit, _("Quit game."));
1193  // Note the next value is used hardcoded in the init tests.
1194  register_alias("quit", "q!");
1195  register_command("save_quit", &console_handler::do_save_quit, _("Save and quit."));
1196  register_alias("save_quit", "wq");
1197  register_command("ignore_replay_errors", &console_handler::do_ignore_replay_errors, _("Ignore replay errors."));
1198  register_command("nosaves", &console_handler::do_nosaves, _("Disable autosaves."));
1199  register_command("next_level", &console_handler::do_next_level,
1200  _("Advance to the next scenario, or scenario identified by 'id'"), _("<id>"), "DS");
1201  register_alias("next_level", "n");
1202  register_command("choose_level", &console_handler::do_choose_level, _("Choose next scenario"), "", "DS");
1203  register_alias("choose_level", "cl");
1204  register_command("turn", &console_handler::do_turn,
1205  _("Change turn number (and time of day), or increase by one if no number is specified."), _("[turn]"),
1206  "DS");
1207  register_command("turn_limit", &console_handler::do_turn_limit,
1208  _("Change turn limit, or turn the turn limit off if no number is specified or it’s −1."), _("[limit]"),
1209  "DS");
1210  register_command("debug", &console_handler::do_debug, _("Turn debug mode on."));
1211  register_command("nodebug", &console_handler::do_nodebug, _("Turn debug mode off."), "", "D");
1212  register_command(
1213  "lua", &console_handler::do_lua, _("Execute a Lua statement."), _("<command>[;<command>...]"), "DS");
1214  register_command(
1215  "unsafe_lua", &console_handler::do_unsafe_lua, _("Grant higher privileges to Lua scripts."), "", "D");
1216  register_command("custom", &console_handler::do_custom, _("Set the command used by the custom command hotkey"),
1217  _("<command>[;<command>...]"));
1218  register_command("give_control", &console_handler::do_control_dialog,
1219  _("Invoke a dialog allowing changing control of MP sides."), "", "N");
1220  register_command("inspect", &console_handler::do_inspect, _("Launch the gamestate inspector"), "", "D");
1221  register_command(
1222  "alias", &console_handler::do_set_alias, _("Set or show alias to a command"), _("<name>[=<command>]"));
1223  register_command(
1224  "set_var", &console_handler::do_set_var, _("Set a scenario variable."), _("<var>=<value>"), "DS");
1225  register_command("show_var", &console_handler::do_show_var, _("Show a scenario variable."), _("<var>"), "D");
1226  register_command("unit", &console_handler::do_unit,
1227  _("Modify a unit variable. (Only top level keys are supported.)"), "", "DS");
1228 
1229  // register_command("buff", &console_handler::do_buff,
1230  // _("Add a trait to a unit."), "", "D");
1231  // register_command("unbuff", &console_handler::do_unbuff,
1232  // _("Remove a trait from a unit. (Does not work yet.)"), "", "D");
1233  register_command("discover", &console_handler::do_discover, _("Discover all units in help."), "");
1234  register_command("undiscover", &console_handler::do_undiscover, _("'Undiscover' all units in help."), "");
1235  register_command("create", &console_handler::do_create, _("Create a unit."), "", "DS");
1236  register_command("fog", &console_handler::do_fog, _("Toggle fog for the current player."), "", "DS");
1237  register_command("shroud", &console_handler::do_shroud, _("Toggle shroud for the current player."), "", "DS");
1238  register_command("gold", &console_handler::do_gold, _("Give gold to the current player."), "", "DS");
1239  register_command("throw", &console_handler::do_event, _("Fire a game event."), "", "DS");
1240  register_alias("throw", "fire");
1241  register_command("show_coordinates", &console_handler::do_toggle_draw_coordinates,
1242  _("Toggle overlaying of x,y coordinates on hexes."));
1243  register_alias("show_coordinates", "sc");
1244  register_command("show_terrain_codes", &console_handler::do_toggle_draw_terrain_codes,
1245  _("Toggle overlaying of terrain codes on hexes."));
1246  register_alias("show_terrain_codes", "tc");
1247  register_command("show_num_of_bitmaps", &console_handler::do_toggle_draw_num_of_bitmaps,
1248  _("Toggle overlaying of number of bitmaps on hexes."));
1249  register_alias("show_num_of_bitmaps", "bn");
1250  register_command("whiteboard", &console_handler::do_toggle_whiteboard, _("Toggle planning mode."));
1251  register_alias("whiteboard", "wb");
1252  register_command(
1253  "whiteboard_options", &console_handler::do_whiteboard_options, _("Access whiteboard options dialog."));
1254  register_alias("whiteboard_options", "wbo");
1255 
1256  if(const config& alias_list = preferences::get_alias()) {
1257  for(const config::attribute& a : alias_list.attribute_range()) {
1258  register_alias(a.second, a.first);
1259  }
1260  }
1261  }
1262 
1263 private:
1265  const unsigned int team_num_;
1266 };
1267 
1268 void menu_handler::send_chat_message(const std::string& message, bool allies_only)
1269 {
1270  config cfg;
1271  cfg["id"] = preferences::login();
1272  cfg["message"] = message;
1273  const std::time_t time = ::std::time(nullptr);
1274  std::stringstream ss;
1275  ss << time;
1276  cfg["time"] = ss.str();
1277 
1278  const int side = board().is_observer() ? 0 : gui_->viewing_side();
1279  if(!board().is_observer()) {
1280  cfg["side"] = side;
1281  }
1282 
1283  bool private_message = has_friends() && allies_only;
1284 
1285  if(private_message) {
1286  if(board().is_observer()) {
1287  cfg["to_sides"] = game_config::observer_team_name;
1288  } else {
1289  cfg["to_sides"] = teams()[gui_->viewing_team()].allied_human_teams();
1290  }
1291  }
1292 
1293  resources::recorder->speak(cfg);
1294 
1295  add_chat_message(time, cfg["id"], side, message,
1297 }
1298 
1299 void menu_handler::do_search(const std::string& new_search)
1300 {
1301  if(new_search.empty() == false && new_search != last_search_)
1302  last_search_ = new_search;
1303 
1304  if(last_search_.empty())
1305  return;
1306 
1307  bool found = false;
1309  // If this is a location search, just center on that location.
1310  std::vector<std::string> args = utils::split(last_search_, ',');
1311  if(args.size() == 2) {
1312  int x, y;
1313  x = lexical_cast_default<int>(args[0], 0) - 1;
1314  y = lexical_cast_default<int>(args[1], 0) - 1;
1315  if(x >= 0 && x < map().w() && y >= 0 && y < map().h()) {
1316  loc = map_location(x, y);
1317  found = true;
1318  }
1319  }
1320  // Start scanning the game map
1321  if(loc.valid() == false) {
1322  loc = map_location(map().w() - 1, map().h() - 1);
1323  }
1324 
1325  map_location start = loc;
1326  while(!found) {
1327  // Move to the next location
1328  loc.x = (loc.x + 1) % map().w();
1329  if(loc.x == 0)
1330  loc.y = (loc.y + 1) % map().h();
1331 
1332  // Search label
1333  if(!gui_->shrouded(loc)) {
1334  const terrain_label* label = gui_->labels().get_label(loc);
1335  if(label) {
1336  std::string label_text = label->text().str();
1337  if(std::search(label_text.begin(), label_text.end(), last_search_.begin(), last_search_.end(),
1339  != label_text.end()) {
1340  found = true;
1341  }
1342  }
1343  }
1344  // Search unit name
1345  if(!gui_->fogged(loc)) {
1346  unit_map::const_iterator ui = units().find(loc);
1347  if(ui != units().end()) {
1348  const std::string name = ui->name();
1349  if(std::search(
1350  name.begin(), name.end(), last_search_.begin(), last_search_.end(), chars_equal_insensitive)
1351  != name.end()) {
1352  if(!teams()[gui_->viewing_team()].is_enemy(ui->side())
1353  || !ui->invisible(ui->get_location())) {
1354  found = true;
1355  }
1356  }
1357  }
1358  }
1359 
1360  if(loc == start)
1361  break;
1362  }
1363 
1364  if(found) {
1365  last_search_hit_ = loc;
1367  gui_->highlight_hex(loc);
1368  } else {
1370  // Not found, inform the player
1371  utils::string_map symbols;
1372  symbols["search"] = last_search_;
1373  const std::string msg = VGETTEXT("Could not find label or unit "
1374  "containing the string ‘$search’.",
1375  symbols);
1377  }
1378 }
1379 
1380 void menu_handler::do_command(const std::string& str)
1381 {
1382  console_handler ch(*this);
1383  ch.dispatch(str);
1384 }
1385 
1386 std::vector<std::string> menu_handler::get_commands_list()
1387 {
1388  console_handler ch(*this);
1389  // HACK: we need to call dispatch() at least once to get the
1390  // command list populated *at all*. Terrible design.
1391  // An empty command is silently ignored and has negligible
1392  // overhead, so we use that for this purpose here.
1393  ch.dispatch("");
1394  return ch.get_commands_list();
1395 }
1396 
1398 {
1400 
1401  menu_handler_.gui_->create_buttons();
1402  menu_handler_.gui_->redraw_everything();
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  menu_handler_.textbox_info_.close(*menu_handler_.gui_);
1450 }
1451 
1453 {
1454  // :idle [<side> [on/off]]
1455  const std::string side_s = get_arg(1);
1456  const std::string action = get_arg(2);
1457  // default to the current side if empty
1458  const unsigned int side = side_s.empty() ? team_num_ : lexical_cast_default<unsigned int>(side_s);
1459 
1460  if(side < 1 || side > menu_handler_.teams().size()) {
1461  utils::string_map symbols;
1462  symbols["side"] = side_s;
1463  command_failed(VGETTEXT("Can't idle invalid side: '$side'.", symbols));
1464  return;
1465  } else if(menu_handler_.board().get_team(side).is_network()) {
1466  utils::string_map symbols;
1467  symbols["side"] = std::to_string(side);
1468  command_failed(VGETTEXT("Can't idle networked side: '$side'.", symbols));
1469  return;
1470  } else if(menu_handler_.board().get_team(side).is_local_ai()) {
1471  utils::string_map symbols;
1472  symbols["side"] = std::to_string(side);
1473  command_failed(VGETTEXT("Can't idle local ai side: '$side'.", symbols));
1474  return;
1475  } else if(menu_handler_.board().get_team(side).is_local_human()) {
1476  if(menu_handler_.board().get_team(side).is_idle() ? action == " on" : action == " off") {
1477  return;
1478  }
1479  // toggle the proxy controller between idle / non idle
1480  menu_handler_.board().get_team(side).toggle_idle();
1481  if(team_num_ == side) {
1482  if(playsingle_controller* psc = dynamic_cast<playsingle_controller*>(&menu_handler_.pc_)) {
1483  psc->set_player_type_changed();
1484  }
1485  }
1486  }
1487  menu_handler_.textbox_info_.close(*menu_handler_.gui_);
1488 }
1489 
1491 {
1493 }
1494 
1496 {
1497  save_id_matches(const std::string& save_id)
1498  : save_id_(save_id)
1499  {
1500  }
1501 
1502  bool operator()(const team& t) const
1503  {
1504  return t.save_id() == save_id_;
1505  }
1506 
1507  std::string save_id_;
1508 };
1509 
1511 {
1512  // :control <side> <nick>
1513  if(!menu_handler_.pc_.is_networked_mp()) {
1514  return;
1515  }
1516 
1517  const std::string side = get_arg(1);
1518  const std::string player = get_arg(2);
1519  if(player.empty()) {
1520  command_failed_need_arg(2);
1521  return;
1522  }
1523 
1524  unsigned int side_num;
1525  try {
1526  side_num = lexical_cast<unsigned int>(side);
1527  } catch(const bad_lexical_cast&) {
1528  const auto it_t = std::find_if(
1530  if(it_t == resources::gameboard->teams().end()) {
1531  utils::string_map symbols;
1532  symbols["side"] = side;
1533  command_failed(VGETTEXT("Can't change control of invalid side: '$side'.", symbols));
1534  return;
1535  } else {
1536  side_num = it_t->side();
1537  }
1538  }
1539 
1540  if(side_num < 1 || side_num > menu_handler_.teams().size()) {
1541  utils::string_map symbols;
1542  symbols["side"] = side;
1543  command_failed(VGETTEXT("Can't change control of out-of-bounds side: '$side'.", symbols));
1544  return;
1545  }
1546 
1547  menu_handler_.request_control_change(side_num, player);
1548  menu_handler_.textbox_info_.close(*(menu_handler_.gui_));
1549 }
1550 
1552 {
1553  const std::string side = get_arg(1);
1554  unsigned int side_num;
1555  try {
1556  side_num = lexical_cast<unsigned int>(side);
1557  } catch(const bad_lexical_cast&) {
1558  utils::string_map symbols;
1559  symbols["side"] = side;
1560  command_failed(VGETTEXT("Can't query control of invalid side: '$side'.", symbols));
1561  return;
1562  }
1563 
1564  if(side_num < 1 || side_num > menu_handler_.teams().size()) {
1565  utils::string_map symbols;
1566  symbols["side"] = side;
1567  command_failed(VGETTEXT("Can't query control of out-of-bounds side: '$side'.", symbols));
1568  return;
1569  }
1570 
1571  std::string report = menu_handler_.board().get_team(side_num).controller().to_string();
1572  if(!menu_handler_.board().get_team(side_num).is_proxy_human()) {
1573  report += " (" + menu_handler_.board().get_team(side_num).proxy_controller().to_string() + ")";
1574  }
1575 
1576  if(menu_handler_.board().get_team(side_num).is_network()) {
1577  report += " (networked)";
1578  }
1579 
1580  print(get_cmd(), report);
1581 }
1582 
1584 {
1585  menu_handler_.gui_->get_chat_manager().clear_chat_messages();
1586 }
1587 
1589 {
1590  menu_handler_.gui_->toggle_debug_foreground();
1591 }
1592 
1594 {
1595  display& disp = *(menu_handler_.gui_);
1596 
1597  const mouse_handler& mousehandler = menu_handler_.pc_.get_mouse_handler_base();
1598  const map_location& loc = mousehandler.get_last_hex();
1599 
1600  //
1601  // It's possible to invoke this dialog even if loc isn't a valid hex. I'm not sure
1602  // exactly how that happens, but it does seem to occur when moving the mouse outside
1603  // the window to the menu bar. Not sure if there's a bug when the set-last-hex code
1604  // in that case, but this check at least ensures the dialog is only ever shown for a
1605  // valid, on-map location. Otherwise, an assertion gets thrown.
1606  //
1607  // -- vultraz, 2017-09-21
1608  //
1609  if(disp.get_map().on_board_with_border(loc)) {
1610  gui2::dialogs::terrain_layers::display(disp, loc);
1611  }
1612 }
1613 
1615 {
1617 }
1618 
1620 {
1621  menu_handler_.gui_->toggle_benchmark();
1622 }
1623 
1625 {
1626  menu_handler_.pc_.do_consolesave(get_data());
1627 }
1628 
1630 {
1631  do_save();
1632  do_quit();
1633 }
1634 
1636 {
1638 }
1639 
1641 {
1642  game_config::ignore_replay_errors = (get_data() != "off") ? true : false;
1643 }
1644 
1646 {
1647  game_config::disable_autosave = (get_data() != "off") ? true : false;
1648 }
1649 
1651 {
1652  synced_context::run_and_throw("debug_next_level", config {"next_level", get_data()});
1653 }
1654 
1656 {
1657  std::string tag = menu_handler_.pc_.get_classification().get_tagname();
1658  std::vector<std::string> options;
1659  std::string next;
1660  if(tag != "multiplayer") {
1661  for(const config& sc : menu_handler_.game_config_.child_range(tag)) {
1662  const std::string& id = sc["id"];
1663  options.push_back(id);
1664  if(id == menu_handler_.gamedata().next_scenario()) {
1665  next = id;
1666  }
1667  }
1668  } else {
1669  // find scenarios of multiplayer campaigns
1670  // (assumes that scenarios are ordered properly in the game_config)
1671  std::string scenario_id = menu_handler_.pc_.get_mp_settings().mp_scenario;
1672  if(const config& this_scenario = menu_handler_.game_config_.find_child(tag, "id", scenario_id)) {
1673  std::string addon_id = this_scenario["addon_id"].str();
1674  for(const config& sc : menu_handler_.game_config_.child_range(tag)) {
1675  if(sc["addon_id"] == addon_id) {
1676  std::string id = sc["id"];
1677  options.push_back(id);
1678  if(id == menu_handler_.gamedata().next_scenario()) {
1679  next = id;
1680  }
1681  }
1682  }
1683  }
1684  }
1685  std::sort(options.begin(), options.end());
1686  int choice = std::distance(options.begin(), std::lower_bound(options.begin(), options.end(), next));
1687  {
1688  gui2::dialogs::simple_item_selector dlg(_("Choose Scenario (Debug!)"), "", options);
1689  dlg.set_selected_index(choice);
1690  dlg.show();
1691  choice = dlg.selected_index();
1692  }
1693 
1694  if(choice == -1) {
1695  return;
1696  }
1697 
1698  if(std::size_t(choice) < options.size()) {
1699  synced_context::run_and_throw("debug_next_level", config {"next_level", options[choice]});
1700  }
1701 }
1702 
1704 {
1705  tod_manager& tod_man = menu_handler_.gamestate().tod_manager_;
1706 
1707  int turn = tod_man.turn() + 1;
1708  const std::string& data = get_data();
1709  if(!data.empty()) {
1710  turn = lexical_cast_default<int>(data, 1);
1711  }
1712  synced_context::run_and_throw("debug_turn", config {"turn", turn});
1713 }
1714 
1716 {
1717  int limit = get_data().empty() ? -1 : lexical_cast_default<int>(get_data(), 1);
1718  synced_context::run_and_throw("debug_turn_limit", config {"turn_limit", limit});
1719 }
1720 
1722 {
1723  if(!menu_handler_.pc_.is_networked_mp() || game_config::mp_debug) {
1724  print(get_cmd(), _("Debug mode activated!"));
1725  game_config::set_debug(true);
1726  } else {
1727  command_failed(_("Debug mode not available in network games"));
1728  }
1729 }
1730 
1732 {
1733  if(game_config::debug) {
1734  print(get_cmd(), _("Debug mode deactivated!"));
1735  game_config::set_debug(false);
1736  }
1737 }
1738 
1740 {
1741  if(!menu_handler_.gamestate().lua_kernel_) {
1742  return;
1743  }
1744 
1745  synced_context::run_and_throw("debug_lua", config {"code", get_data()});
1746 }
1747 
1749 {
1750  if(!menu_handler_.gamestate().lua_kernel_) {
1751  return;
1752  }
1753 
1754  const int retval = gui2::show_message(_("WARNING! Unsafe Lua Mode"),
1755  _("Executing Lua code in in this manner opens your computer to potential security breaches from any "
1756  "malicious add-ons or other programs you may have installed.\n\n"
1757  "Do not continue unless you really know what you are doing."), gui2::dialogs::message::ok_cancel_buttons);
1758 
1759  if(retval == gui2::retval::OK) {
1760  print(get_cmd(), _("Unsafe mode enabled!"));
1761  menu_handler_.gamestate().lua_kernel_->load_package();
1762  }
1763 }
1764 
1766 {
1767  preferences::set_custom_command(get_data());
1768 }
1769 
1771 {
1772  const std::string data = get_data();
1773  const std::string::const_iterator j = std::find(data.begin(), data.end(), '=');
1774  const std::string alias(data.begin(), j);
1775  if(j != data.end()) {
1776  const std::string command(j + 1, data.end());
1777  if(!command.empty()) {
1778  register_alias(command, alias);
1779  } else {
1780  // "alias something=" deactivate this alias. We just set it
1781  // equal to itself here. Later preferences will filter empty alias.
1782  register_alias(alias, alias);
1783  }
1784  preferences::add_alias(alias, command);
1785  // directly save it for the moment, but will slow commands sequence
1787  } else {
1788  // "alias something" display its value
1789  // if no alias, will be "'something' = 'something'"
1790  const std::string command = chmap::get_actual_cmd(alias);
1791  print(get_cmd(), "'" + alias + "'" + " = " + "'" + command + "'");
1792  }
1793 }
1794 
1796 {
1797  const std::string data = get_data();
1798  if(data.empty()) {
1799  command_failed_need_arg(1);
1800  return;
1801  }
1802 
1803  const std::string::const_iterator j = std::find(data.begin(), data.end(), '=');
1804  if(j != data.end()) {
1805  const std::string name(data.begin(), j);
1806  const std::string value(j + 1, data.end());
1807  synced_context::run_and_throw("debug_set_var", config {"name", name, "value", value});
1808  } else {
1809  command_failed(_("Variable not found"));
1810  }
1811 }
1812 
1814 {
1815  gui2::show_transient_message("", menu_handler_.gamedata().get_variable_const(get_data()));
1816 }
1817 
1819 {
1821  gui2::dialogs::gamestate_inspector inspect_dialog(
1823  inspect_dialog.show();
1824 }
1825 
1827 {
1828  gui2::dialogs::mp_change_control mp_change_control(menu_handler_);
1829  mp_change_control.show();
1830 }
1831 
1833 {
1834  // prevent SIGSEGV due to attempt to set HP during a fight
1835  if(events::commands_disabled > 0) {
1836  return;
1837  }
1838 
1839  unit_map::iterator i = menu_handler_.current_unit();
1840  if(i == menu_handler_.units().end()) {
1841  return;
1842  }
1843 
1844  const map_location loc = i->get_location();
1845  const std::string data = get_data(1);
1846  std::vector<std::string> parameters = utils::split(data, '=', utils::STRIP_SPACES);
1847  if(parameters.size() < 2) {
1848  return;
1849  }
1850 
1851  if(parameters[0] == "alignment") {
1852  unit_type::ALIGNMENT alignment;
1853  if(!alignment.parse(parameters[1])) {
1854  utils::string_map symbols;
1855  symbols["alignment"] = get_arg(1);
1856  command_failed(VGETTEXT(
1857  "Invalid alignment: '$alignment', needs to be one of lawful, neutral, chaotic, or liminal.",
1858  symbols));
1859  return;
1860  }
1861  }
1862 
1863  synced_context::run_and_throw("debug_unit",
1864  config {
1865  "x", loc.wml_x(),
1866  "y", loc.wml_y(),
1867  "name", parameters[0],
1868  "value", parameters[1],
1869  }
1870  );
1871 }
1872 
1874 {
1875  for(const unit_type_data::unit_type_map::value_type& i : unit_types.types()) {
1876  preferences::encountered_units().insert(i.second.id());
1877  }
1878 }
1879 
1881 {
1882  const int res = gui2::show_message("Undiscover",
1883  _("Do you wish to clear all of your discovered units from help?"), gui2::dialogs::message::yes_no_buttons);
1884  if(res != gui2::retval::CANCEL) {
1886  }
1887 }
1888 
1889 /** Implements the (debug mode) console command that creates a unit. */
1891 {
1892  const mouse_handler& mousehandler = menu_handler_.pc_.get_mouse_handler_base();
1893  const map_location& loc = mousehandler.get_last_hex();
1894  if(menu_handler_.map().on_board(loc)) {
1895  const unit_type* ut = unit_types.find(get_data());
1896  if(!ut) {
1897  command_failed(_("Invalid unit type"));
1898  return;
1899  }
1900 
1901  // Create the unit.
1902  create_and_place(*menu_handler_.gui_, menu_handler_.map(), menu_handler_.units(), loc, *ut);
1903  } else {
1904  command_failed(_("Invalid location"));
1905  }
1906 }
1907 
1909 {
1910  synced_context::run_and_throw("debug_fog", config());
1911 }
1912 
1914 {
1915  synced_context::run_and_throw("debug_shroud", config());
1916 }
1917 
1919 {
1920  synced_context::run_and_throw("debug_gold", config {"gold", lexical_cast_default<int>(get_data(), 1000)});
1921 }
1922 
1924 {
1925  synced_context::run_and_throw("debug_event", config {"eventname", get_data()});
1926 }
1927 
1929 {
1930  menu_handler_.gui_->set_draw_coordinates(!menu_handler_.gui_->get_draw_coordinates());
1931  menu_handler_.gui_->invalidate_all();
1932 }
1934 {
1935  menu_handler_.gui_->set_draw_terrain_codes(!menu_handler_.gui_->get_draw_terrain_codes());
1936  menu_handler_.gui_->invalidate_all();
1937 }
1938 
1940 {
1941  menu_handler_.gui_->set_draw_num_of_bitmaps(!menu_handler_.gui_->get_draw_num_of_bitmaps());
1942  menu_handler_.gui_->invalidate_all();
1943 }
1944 
1946 {
1947  if(const std::shared_ptr<wb::manager>& whiteb = menu_handler_.pc_.get_whiteboard()) {
1948  whiteb->set_active(!whiteb->is_active());
1949  if(whiteb->is_active()) {
1950  print(get_cmd(), _("Planning mode activated!"));
1951  whiteb->print_help_once();
1952  } else {
1953  print(get_cmd(), _("Planning mode deactivated!"));
1954  }
1955  }
1956 }
1957 
1959 {
1960  if(menu_handler_.pc_.get_whiteboard()) {
1961  menu_handler_.pc_.get_whiteboard()->options_dlg();
1962  }
1963 }
1964 
1965 void menu_handler::do_ai_formula(const std::string& str, int side_num, mouse_handler& /*mousehandler*/)
1966 {
1967  try {
1968  add_chat_message(std::time(nullptr), "wfl", 0, ai::manager::get_singleton().evaluate_command(side_num, str));
1969  } catch(const wfl::formula_error&) {
1970  } catch(...) {
1971  add_chat_message(std::time(nullptr), "wfl", 0, "UNKNOWN ERROR IN FORMULA");
1972  }
1973 }
1974 
1976 {
1977  textbox_info_.show(gui::TEXTBOX_COMMAND, translation::sgettext("prompt^Command:"), "", false, *gui_);
1978 }
1979 
1980 void menu_handler::request_control_change(int side_num, const std::string& player)
1981 {
1982  std::string side = std::to_string(side_num);
1983  if(board().get_team(side_num).is_local_human() && player == preferences::login()) {
1984  // this is already our side.
1985  return;
1986  } else {
1987  // The server will (or won't because we aren't allowed to change the controller)
1988  // send us a [change_controller] back, which we then handle in playturn.cpp
1989  pc_.send_to_wesnothd(config {"change_controller", config {"side", side, "player", player}});
1990  }
1991 }
1992 
1994 {
1995  for(const std::string& command : utils::split(preferences::custom_command(), ';')) {
1996  do_command(command);
1997  }
1998 }
1999 
2001 {
2002  if(!pc_.is_networked_mp()) {
2003  textbox_info_.show(gui::TEXTBOX_AI, translation::sgettext("prompt^Command:"), "", false, *gui_);
2004  }
2005 }
2006 
2008 {
2009  gui_->get_chat_manager().clear_chat_messages(); // also clear debug-messages and WML-error-messages
2010 }
2011 
2013 {
2014  pc_.send_to_wesnothd(cfg);
2015 }
2016 
2017 } // 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:2979
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:151
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:838
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:366
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:2376
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: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: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.
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:737
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:943
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:1845
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.
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:2969
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:2160
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:97
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
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:2495
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