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