The Battle for Wesnoth  1.17.0-dev
manager.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2021
3  by Gabriel Morin <gabrielmorin (at) gmail (dot) com>
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  */
19 
20 #include "whiteboard/manager.hpp"
21 
22 #include "whiteboard/action.hpp"
25 #include "whiteboard/move.hpp"
26 #include "whiteboard/attack.hpp"
27 #include "whiteboard/recall.hpp"
28 #include "whiteboard/recruit.hpp"
30 #include "whiteboard/utility.hpp"
31 
32 #include "actions/create.hpp"
33 #include "actions/undo.hpp"
34 #include "arrow.hpp"
35 #include "chat_events.hpp"
36 #include "fake_unit_manager.hpp"
37 #include "fake_unit_ptr.hpp"
38 #include "formula/string_utils.hpp"
39 #include "game_board.hpp"
40 #include "preferences/game.hpp"
41 #include "game_state.hpp"
42 #include "gettext.hpp"
44 #include "key.hpp"
45 #include "pathfind/pathfind.hpp"
46 #include "play_controller.hpp"
47 #include "replay_helper.hpp"
48 #include "resources.hpp"
49 #include "synced_context.hpp"
50 #include "team.hpp"
51 #include "units/unit.hpp"
53 #include "units/udisplay.hpp"
54 
55 #include <functional>
56 
57 #include <sstream>
58 
59 namespace wb {
60 
62  active_(false),
63  inverted_behavior_(false),
64  self_activate_once_(true),
65 #if 0
66  print_help_once_(true),
67 #endif
68  wait_for_side_init_(true),
69  planned_unit_map_active_(false),
70  executing_actions_(false),
71  executing_all_actions_(false),
72  preparing_to_end_turn_(false),
73  gamestate_mutated_(false),
74  activation_state_lock_(new bool),
75  unit_map_lock_(new bool),
76  mapbuilder_(),
77  highlighter_(),
78  route_(),
79  move_arrows_(),
80  fake_units_(),
81  temp_move_unit_underlying_id_(0),
82  key_poller_(new CKey),
83  hidden_unit_hexes_(),
84  net_buffer_(resources::gameboard->teams().size()),
85  team_plans_hidden_(resources::gameboard->teams().size()),
86  units_owning_moves_()
87 {
89  team_plans_hidden_.flip();
90  }
91  LOG_WB << "Manager initialized.\n";
92 }
93 
95 {
96  LOG_WB << "Manager destroyed.\n";
97 }
98 
99 //Used for chat-spamming debug info
100 #if 0
101 static void print_to_chat(const std::string& title, const std::string& message)
102 {
103  display::get_singleton()->add_chat_message(std::time(nullptr), title, 0, message,
105 }
106 #endif
107 
109 {
110 #if 0
111  if (!print_help_once_)
112  return;
113  else
114  print_help_once_ = false;
115 
116  print_to_chat("whiteboard", std::string("Type :wb to activate/deactivate planning mode.")
117  + " Hold TAB to temporarily deactivate/activate it.");
118  std::stringstream hotkeys;
119  const hotkey::hotkey_item& hk_execute = hotkey::get_hotkey(hotkey::HOTKEY_WB_EXECUTE_ACTION);
120  if(!hk_execute.null()) {
121  //print_to_chat("[execute action]", "'" + hk_execute.get_name() + "'");
122  hotkeys << "Execute: " << hk_execute.get_name() << ", ";
123  }
124  const hotkey::hotkey_item& hk_execute_all = hotkey::get_hotkey(hotkey::HOTKEY_WB_EXECUTE_ALL_ACTIONS);
125  if(!hk_execute_all.null()) {
126  //print_to_chat("[execute action]", "'" + hk_execute_all.get_name() + "'");
127  hotkeys << "Execute all: " << hk_execute_all.get_name() << ", ";
128  }
129  const hotkey::hotkey_item& hk_delete = hotkey::get_hotkey(hotkey::HOTKEY_WB_DELETE_ACTION);
130  if(!hk_delete.null()) {
131  //print_to_chat("[delete action]", "'" + hk_delete.get_name() + "'");
132  hotkeys << "Delete: " << hk_delete.get_name() << ", ";
133  }
134  const hotkey::hotkey_item& hk_bump_up = hotkey::get_hotkey(hotkey::HOTKEY_WB_BUMP_UP_ACTION);
135  if(!hk_bump_up.null()) {
136  //print_to_chat("[move action earlier in queue]", "'" + hk_bump_up.get_name() + "'");
137  hotkeys << "Move earlier: " << hk_bump_up.get_name() << ", ";
138  }
139  const hotkey::hotkey_item& hk_bump_down = hotkey::get_hotkey(hotkey::HOTKEY_WB_BUMP_DOWN_ACTION);
140  if(!hk_bump_down.null()) {
141  //print_to_chat("[move action later in queue]", "'" + hk_bump_down.get_name() + "'");
142  hotkeys << "Move later: " << hk_bump_down.get_name() << ", ";
143  }
144  print_to_chat("HOTKEYS:", hotkeys.str() + "\n");
145 #endif
146 }
147 
149 {
151  || resources::gameboard == nullptr
153  || resources::gameboard->is_observer()
154  || resources::controller->is_linger_mode())
155  {
156  return false;
157  }
158  else
159  {
160  return true;
161  }
162 }
163 
165 {
166  //any more than one reference means a lock on whiteboard state was requested
167  if(activation_state_lock_.use_count() != 1)
168  return false;
169 
170  return can_modify_game_state();
171 }
172 
173 void manager::set_active(bool active)
174 {
175  if(!can_activate())
176  {
177  active_ = false;
178  LOG_WB << "Whiteboard can't be activated now.\n";
179  }
180  else if (active != active_)
181  {
182  active_ = active;
183  erase_temp_move();
184 
185  if (active_)
186  {
187  if(should_clear_undo()) {
188  if(!resources::controller->current_team().auto_shroud_updates()) {
191  }
193  }
195  LOG_WB << "Whiteboard activated! " << *viewer_actions() << "\n";
197  } else {
198  LOG_WB << "Whiteboard deactivated!\n";
199  }
200  }
201 }
202 
204 {
205  //any more than one reference means a lock on whiteboard state was requested
206  if(activation_state_lock_.use_count() != 1)
207  return;
208 
209  bool block_whiteboard_activation = false;
210  if(!can_activate())
211  {
212  block_whiteboard_activation = true;
213  }
214 
215  if (invert)
216  {
217  if (!inverted_behavior_)
218  {
219  if (active_)
220  {
221  DBG_WB << "Whiteboard deactivated temporarily.\n";
222  inverted_behavior_ = true;
223  set_active(false);
224  }
225  else if (!block_whiteboard_activation)
226  {
227  DBG_WB << "Whiteboard activated temporarily.\n";
228  inverted_behavior_ = true;
229  set_active(true);
230  }
231  }
232  }
233  else
234  {
235  if (inverted_behavior_)
236  {
237  if (active_)
238  {
239  DBG_WB << "Whiteboard set back to deactivated status.\n";
240  inverted_behavior_ = false;
241  set_active(false);
242  }
243  else if (!block_whiteboard_activation)
244  {
245  DBG_WB << "Whiteboard set back to activated status.\n";
246  inverted_behavior_ = false;
247  set_active(true);
248  }
249  }
250  }
251 }
252 
254 {
256  && viewer_actions()->turn_size(0) > 0;
257 }
258 
260 {
261  return can_modify_game_state() && !viewer_actions()->empty();
262 }
263 
265 {
266  return can_enable_modifier_hotkeys() && highlighter_ && highlighter_->get_bump_target();
267 }
268 
269 bool manager::allow_leader_to_move(const unit& leader) const
270 {
271  if(!has_actions())
272  return true;
273 
274  //Look for another leader on another keep in the same castle
275  { wb::future_map future; // start planned unit map scope
276 
277  // TODO: when the game executes all whiteboard moves at turn end applying the future map
278  // will fail because we are currently executing actions, and if one of those actions
279  // was a movement of the leader this function will be called, resulting the the error
280  // mesage below, we silence that message for now by adding (!executing_actions_)
281  //
282  // Also this check is generally flawed, for example it could happen that the leader found
283  // by find_backup_leader would be moved to that location _after_ the unit would be recruited
284  // It could also happen that the original leader can be moved back to that location before
285  // the unit is recruited.
287  WRN_WB << "Unable to build future map to determine whether leader's allowed to move." << std::endl;
288  }
289  if(find_backup_leader(leader))
290  return true;
291  } // end planned unit map scope
292 
293  if(viewer_actions()->empty()) {
294  return true;
295  }
296 
297  //Look for planned recruits that depend on this leader
299  {
300  recruit_const_ptr recruit = std::dynamic_pointer_cast<class recruit const>(action);
301  recall_const_ptr recall = std::dynamic_pointer_cast<class recall const>(action);
302  if(recruit || recall)
303  {
304  map_location const target_hex = recruit?recruit->get_recruit_hex():recall->get_recall_hex();
305  if (dynamic_cast<game_state&>(*resources::filter_con).can_recruit_on(leader, target_hex))
306  return false;
307  }
308  }
309  return true;
310 }
311 
313 {
314  //Turn should never start with action auto-execution already enabled!
316 
317  update_plan_hiding(); /* validates actions */
318  wait_for_side_init_ = false;
319  LOG_WB << "on_init_side()\n";
320 
322  {
323  self_activate_once_ = false;
324  set_active(true);
325  }
326 }
327 
329 {
330  preparing_to_end_turn_ = false;
331  wait_for_side_init_ = true;
332  if(side == viewer_side() && !viewer_actions()->empty()) {
333  viewer_actions()->synced_turn_shift();
334  }
335  highlighter_.reset();
336  erase_temp_move();
337  LOG_WB << "on_finish_side_turn()\n";
338 }
339 
341 {
342 }
343 
345 {
346  // The fake unit representing the destination of a chain of planned moves should have the regular animation.
347  // If the last remaining action of the unit that owned this move is a move as well,
348  // adjust its appearance accordingly.
349 
350  side_actions_ptr side_actions = resources::gameboard->teams().at(action->team_index()).get_side_actions();
351 
352  unit_ptr actor = action->get_unit();
353  if(actor) { // The unit might have died following the execution of an attack
354  side_actions::iterator action_it = side_actions->find_last_action_of(*actor);
355  if(action_it != side_actions->end()) {
356  move_ptr move = std::dynamic_pointer_cast<class move>(*action_it);
357  if(move && move->get_fake_unit()) {
358  move->get_fake_unit()->anim_comp().set_standing(true);
359  }
360  }
361  }
362 }
363 
364 static void hide_all_plans()
365 {
366  for(team& t : resources::gameboard->teams()){
367  t.get_side_actions()->hide();
368  }
369 }
370 
371 /* private */
372 void manager::update_plan_hiding(std::size_t team_index)
373 {
374  //We don't control the "viewing" side ... we're probably an observer
375  if(!resources::gameboard->teams().at(team_index).is_local_human())
376  hide_all_plans();
377  else // normal circumstance
378  {
379  for(team& t : resources::gameboard->teams())
380  {
381  //make sure only appropriate teams are hidden
382  if(!t.is_network_human())
383  team_plans_hidden_[t.side()-1] = false;
384 
385  if(t.is_enemy(team_index+1) || team_plans_hidden_[t.side()-1])
386  t.get_side_actions()->hide();
387  else
388  t.get_side_actions()->show();
389  }
390  }
392 }
395 
396 void manager::on_viewer_change(std::size_t team_index)
397 {
399  update_plan_hiding(team_index);
400 }
401 
402 void manager::on_change_controller(int side, const team& t)
403 {
405  if(t.is_local_human()) // we own this side now
406  {
407  //tell everyone to clear this side's actions -- we're starting anew
409  sa.clear();
410  //refresh the hidden_ attribute of every team's side_actions
412  }
413  else if(t.is_local_ai() || t.is_network_ai()) // no one owns this side anymore
414  sa.clear(); // clear its plans away -- the ai doesn't plan ... yet
415  else if(t.is_network()) // Another client is taking control of the side
416  {
417  if(side==viewer_side()) // They're taking OUR side away!
418  hide_all_plans(); // give up knowledge of everyone's plans, in case we became an observer
419 
420  //tell them our plans -- they may not have received them up to this point
421  std::size_t num_teams = resources::gameboard->teams().size();
422  for(std::size_t i=0; i<num_teams; ++i)
423  {
424  team& local_team = resources::gameboard->teams().at(i);
425  if(local_team.is_local_human() && !local_team.is_enemy(side))
426  queue_net_cmd(i,local_team.get_side_actions()->make_net_cmd_refresh());
427  }
428  }
429 }
430 
432 {
433  if(highlighter_ != nullptr) {
434  highlighter_->set_selection_candidate(unit_ptr());
435  }
436 }
437 
439 {
440  if(current_side_actions()->empty()) {
441  return false;
442  }
443 
444  side_actions::range_t range = current_side_actions()->iter_turn(0);
445  return range.first != range.second; //non-empty range
446 }
447 
449 {
450  LOG_WB << "'gamestate_mutated_' flag dirty, validating actions.\n";
451  gamestate_mutated_ = false;
452  if(has_planned_unit_map()) {
453  real_map();
454  } else {
455  future_map();
456  }
457 }
458 
459 //helper fcn
460 static void draw_numbers(const map_location& hex, side_actions::numbers_t numbers)
461 {
462  std::vector<int>& numbers_to_draw = numbers.numbers_to_draw;
463  std::vector<std::size_t>& team_numbers = numbers.team_numbers;
464  int& main_number = numbers.main_number;
465  std::set<std::size_t>& secondary_numbers = numbers.secondary_numbers;
466 
467  const double x_offset_base = 0.0;
468  const double y_offset_base = 0.2;
469  //position 0,0 in the hex is the upper left corner
470  //0.8 = horizontal coord., close to the right side of the hex
471  const double x_origin = 0.8 - numbers_to_draw.size() * x_offset_base;
472  //0.5 = halfway in the hex vertically
473  const double y_origin = 0.5 - numbers_to_draw.size() * (y_offset_base / 2);
474  double x_offset = 0, y_offset = 0;
475 
476  std::size_t size = numbers_to_draw.size();
477  for(std::size_t i=0; i<size; ++i)
478  {
479  int number = numbers_to_draw[i];
480 
481  std::string number_text = std::to_string(number);
482  std::size_t font_size;
483  if (static_cast<int>(i) == main_number) font_size = 19;
484  else if (secondary_numbers.find(i)!=secondary_numbers.end()) font_size = 17;
485  else font_size = 15;
486 
487  color_t color = team::get_side_color(static_cast<int>(team_numbers[i]+1));
488  const double x_in_hex = x_origin + x_offset;
489  const double y_in_hex = y_origin + y_offset;
491  number_text, font_size, color, x_in_hex, y_in_hex);
492  x_offset += x_offset_base;
493  y_offset += y_offset_base;
494  }
495 }
496 
497 
498 namespace
499 {
500  //Helper struct that finds all units teams whose planned actions are currently visible
501  //Only used by manager::pre_draw().
502  //Note that this structure is used as a functor.
503  struct move_owners_finder: public visitor
504  {
505 
506  public:
507  move_owners_finder(): move_owners_() { }
508 
509  void operator()(action* action) {
510  action->accept(*this);
511  }
512 
513  const std::set<std::size_t>& get_units_owning_moves() {
514  return move_owners_;
515  }
516 
517  virtual void visit(move_ptr move) {
518  if(std::size_t id = move->get_unit_id()) {
519  move_owners_.insert(id);
520  }
521  }
522 
523  virtual void visit(attack_ptr attack) {
524  //also add attacks if they have an associated move
525  if(attack->get_route().steps.size() >= 2) {
526  if(std::size_t id = attack->get_unit_id()) {
527  move_owners_.insert(id);
528  }
529  }
530  }
531  virtual void visit(recruit_ptr){}
532  virtual void visit(recall_ptr){}
533  virtual void visit(suppose_dead_ptr){}
534 
535  private:
536  std::set<std::size_t> move_owners_;
537  };
538 }
539 
541 {
542  if (can_modify_game_state() && has_actions() && unit_map_lock_.use_count() == 1) {
543  move_owners_finder move_finder;
544  for_each_action(std::ref(move_finder));
545  units_owning_moves_ = move_finder.get_units_owning_moves();
546 
547  for (std::size_t unit_id : units_owning_moves_) {
548  unit_map::iterator unit_iter = resources::gameboard->units().find(unit_id);
549  if(unit_iter.valid()) {
550  ghost_owner_unit(&*unit_iter);
551  }
552  }
553  }
554 }
555 
557 {
558  for (std::size_t unit_id : units_owning_moves_)
559  {
560  unit_map::iterator unit_iter = resources::gameboard->units().find(unit_id);
561  if (unit_iter.valid()) {
562  unghost_owner_unit(&*unit_iter);
563  }
564  }
565  units_owning_moves_.clear();
566 }
567 
569 {
570  /**
571  * IMPORTANT: none of the code in this method can call anything which would
572  * cause a hex to be invalidated (i.e. by calling in turn any variant of display::invalidate()).
573  * Doing so messes up the iterator currently going over the list of invalidated hexes to draw.
574  */
575 
577  {
578  //call draw() for all actions
579  for_each_action(std::bind(&action::draw_hex, std::placeholders::_1, hex));
580 
581  //Info about the action numbers to be displayed on screen.
582  side_actions::numbers_t numbers;
583  for (team& t : resources::gameboard->teams())
584  {
585  side_actions& sa = *t.get_side_actions();
586  if(!sa.hidden())
587  sa.get_numbers(hex,numbers);
588  }
589  draw_numbers(hex,numbers); // helper fcn
590  }
591 
592 }
593 
595 {
596 
598  bool hex_has_unit;
599  { wb::future_map future; // start planned unit map scope
600  hex_has_unit = resources::gameboard->units().find(selected_hex) != resources::gameboard->units().end();
601  } // end planned unit map scope
602  if (!((selected_hex.valid() && hex_has_unit)
604  {
605  if (!highlighter_)
606  {
608  }
609  highlighter_->set_mouseover_hex(hex);
610  highlighter_->highlight();
611  }
612 }
613 
615 {
616  DBG_WB << "Manager received gamestate change notification.\n";
617  // if on_gamestate_change() is called while the future unit map is applied,
618  // it means that the future unit map scope is used where it shouldn't be.
619  assert(!planned_unit_map_active_);
620  // Set mutated flag so action queue gets validated on next future map build
621  gamestate_mutated_ = true;
622  //Clear exclusive draws that might not get a chance to be cleared the normal way
624 }
625 
627 {
628  std::size_t size = net_buffer_.size();
629  for(std::size_t team_index=0; team_index<size; ++team_index)
630  {
631  config& buf_cfg = net_buffer_[team_index];
632 
633  if(buf_cfg.empty())
634  continue;
635 
636  config packet;
637  config& wb_cfg = packet.add_child("whiteboard",buf_cfg);
638  wb_cfg["side"] = static_cast<int>(team_index+1);
639  wb_cfg["to_sides"] = resources::gameboard->teams().at(team_index).allied_human_teams();
640 
641  buf_cfg.clear();
642 
643  resources::controller->send_to_wesnothd(packet, "whiteboard");
644 
645  std::size_t count = wb_cfg.child_count("net_cmd");
646  LOG_WB << "Side " << (team_index+1) << " sent wb data (" << count << " cmds).\n";
647  }
648 }
649 
651 {
652  if(const config& wb_cfg = cfg.child("whiteboard"))
653  {
654  std::size_t count = wb_cfg.child_count("net_cmd");
655  LOG_WB << "Received wb data (" << count << ").\n";
656 
657  team& team_from = resources::gameboard->get_team(wb_cfg["side"]);
658  for(const side_actions::net_cmd& cmd : wb_cfg.child_range("net_cmd"))
659  team_from.get_side_actions()->execute_net_cmd(cmd);
660  }
661 }
662 
663 void manager::queue_net_cmd(std::size_t team_index, const side_actions::net_cmd& cmd)
664 {
665  assert(team_index < net_buffer_.size());
666  net_buffer_[team_index].add_child("net_cmd",cmd);
667 }
668 
670 {
671  route_.reset();
672 
673  /*
674  * CHECK PRE-CONDITIONS
675  * (This section has multiple return paths.)
676  */
677 
678  if ( !active_ || !can_modify_game_state() )
679  return;
680 
681  const pathfind::marked_route& route =
683 
684  if (route.steps.empty() || route.steps.size() < 2) return;
685 
686  unit* temp_moved_unit =
687  future_visible_unit(resources::controller->get_mouse_handler_base().get_selected_hex(), viewer_side());
688  if (!temp_moved_unit) temp_moved_unit =
689  future_visible_unit(resources::controller->get_mouse_handler_base().get_last_hex(), viewer_side());
690  if (!temp_moved_unit) return;
691  if (temp_moved_unit->side() != display::get_singleton()->viewing_side()) return;
692 
693  /*
694  * DONE CHECKING PRE-CONDITIONS, CREATE THE TEMP MOVE
695  * (This section has only one return path.)
696  */
697 
698  temp_move_unit_underlying_id_ = temp_moved_unit->underlying_id();
699 
700  //@todo: May be appropriate to replace these separate components by a temporary
701  // wb::move object
702 
703  route_.reset(new pathfind::marked_route(route));
704  //NOTE: route_->steps.back() = dst, and route_->steps.front() = src
705 
706  std::size_t turn = 0;
707  std::vector<map_location>::iterator prev_itor = route.steps.begin();
708  std::vector<map_location>::iterator curr_itor = prev_itor;
709  std::vector<map_location>::iterator end_itor = route.steps.end();
710  for(; curr_itor!=end_itor; ++curr_itor)
711  {
712  const map_location& hex = *curr_itor;
713 
714  //search for end-of-turn marks
715  pathfind::marked_route::mark_map::const_iterator w =
716  route.marks.find(hex);
717  if(w != route.marks.end() && w->second.turns > 0)
718  {
719  turn = w->second.turns-1;
720 
721  if(turn >= move_arrows_.size())
722  move_arrows_.resize(turn+1);
723  if(turn >= fake_units_.size())
724  fake_units_.resize(turn+1);
725 
726  arrow_ptr& move_arrow = move_arrows_[turn];
727  fake_unit_ptr& fake_unit = fake_units_[turn];
728 
729  if(!move_arrow)
730  {
731  // Create temp arrow
732  move_arrow.reset(new arrow());
733  move_arrow->set_color(team::get_side_color_id(
734  viewer_side()));
735  move_arrow->set_style(arrow::STYLE_HIGHLIGHTED);
736  }
737 
738  arrow_path_t path(prev_itor,curr_itor+1);
739  move_arrow->set_path(path);
740 
741  if(path.size() >= 2)
742  {
743  // Bug #20299 demonstrates a situation where an incorrect fake/ghosted unit can be used.
744  // So before assuming that a pre-existing fake_unit can be re-used, check that its ID matches the unit being moved.
745  if(!fake_unit || fake_unit.get_unit_ptr()->id() != temp_moved_unit->id())
746  {
747  // Create temp ghost unit
748  fake_unit = fake_unit_ptr(temp_moved_unit->clone(), resources::fake_units);
749  fake_unit->anim_comp().set_ghosted(true);
750  }
751 
752  unit_display::move_unit(path, fake_unit.get_unit_ptr(), false); //get facing right
753  fake_unit->anim_comp().invalidate(*game_display::get_singleton());
754  fake_unit->set_location(*curr_itor);
755  fake_unit->anim_comp().set_ghosted(true);
756  }
757  else //zero-hex path -- don't bother drawing a fake unit
758  fake_unit.reset();
759 
760  prev_itor = curr_itor;
761  }
762  }
763  //in case path shortens on next step and one ghosted unit has to be removed
764  int ind = fake_units_.size() - 1;
765  fake_units_[ind]->anim_comp().invalidate(*game_display::get_singleton());
766  //toss out old arrows and fake units
767  move_arrows_.resize(turn+1);
768  fake_units_.resize(turn+1);
769 }
770 
772 {
773  move_arrows_.clear();
774  for(const fake_unit_ptr& tmp : fake_units_) {
775  if(tmp) {
776  tmp->anim_comp().invalidate(*game_display::get_singleton());
777  }
778  }
779  fake_units_.clear();
780  route_.reset();
782 }
783 
785 {
786  if (has_temp_move() && !executing_actions_ && !resources::controller->is_linger_mode())
787  {
788  side_actions& sa = *viewer_actions();
789  unit* u = future_visible_unit(route_->steps.front());
790  assert(u);
791  std::size_t first_turn = sa.get_turn_num_of(*u);
792 
794 
795  assert(move_arrows_.size() == fake_units_.size());
796  std::size_t size = move_arrows_.size();
797  for(std::size_t i=0; i<size; ++i)
798  {
799  arrow_ptr move_arrow = move_arrows_[i];
800  if(!arrow::valid_path(move_arrow->get_path()))
801  continue;
802 
803  std::size_t turn = first_turn + i;
804 
805  //@todo Using a marked_route here is wrong, since right now it's not marked
806  //either switch over to a plain route for planned moves, or mark it correctly
808  route.steps = move_arrow->get_path();
809  // path_cost() is incomplete as it for example doesn't handle skirmisher, we let the move action generate the costs on it own.
810  // route.move_cost = path_cost(route.steps,*u);
811  route.move_cost = -1;
812 
813  sa.queue_move(turn, *u, route, move_arrow, std::move(fake_units_[i]));
814  }
815  erase_temp_move();
816 
817  LOG_WB << *viewer_actions() << "\n";
818  print_help_once();
819  }
820 }
821 
823 {
825 }
826 
827 void manager::save_temp_attack(const map_location& attacker_loc, const map_location& defender_loc, int weapon_choice)
828 {
829  if (active_ && !executing_actions_ && !resources::controller->is_linger_mode())
830  {
831  assert(weapon_choice >= 0);
832 
833  arrow_ptr move_arrow;
834  fake_unit_ptr* fake_unit = nullptr;
835  map_location source_hex;
836 
837  if (route_ && !route_->steps.empty())
838  {
839  //attack-move
840  assert(move_arrows_.size() == 1);
841  assert(fake_units_.size() == 1);
842  move_arrow = move_arrows_.front();
843  fake_unit = &fake_units_.front();
844 
845  assert(route_->steps.back() == attacker_loc);
846  source_hex = route_->steps.front();
847 
848  (**fake_unit).anim_comp().set_disabled_ghosted(true);
849  }
850  else
851  {
852  //simple attack
853  move_arrow.reset(new arrow);
854  source_hex = attacker_loc;
855  route_.reset(new pathfind::marked_route);
856  // We'll pass as parameter a one-hex route with no marks.
857  route_->steps.push_back(attacker_loc);
858  }
859 
860  unit* attacking_unit = future_visible_unit(source_hex);
861  assert(attacking_unit);
862 
864 
865  side_actions& sa = *viewer_actions();
866  sa.queue_attack(sa.get_turn_num_of(*attacking_unit), *attacking_unit, defender_loc, weapon_choice, *route_, move_arrow, fake_unit ? std::move(*fake_unit) : fake_unit_ptr());
867 
868  print_help_once();
869 
870  display::get_singleton()->invalidate(defender_loc);
871  display::get_singleton()->invalidate(attacker_loc);
872  erase_temp_move();
873  LOG_WB << *viewer_actions() << "\n";
874  }
875 }
876 
877 bool manager::save_recruit(const std::string& name, int side_num, const map_location& recruit_hex)
878 {
879  bool created_planned_recruit = false;
880 
881  if (active_ && !executing_actions_ && !resources::controller->is_linger_mode()) {
882  if (side_num != display::get_singleton()->viewing_side())
883  {
884  LOG_WB <<"manager::save_recruit called for a different side than viewing side.\n";
885  created_planned_recruit = false;
886  }
887  else
888  {
889  side_actions& sa = *viewer_actions();
890  unit* recruiter;
891  { wb::future_map raii;
892  recruiter = find_recruiter(side_num-1,recruit_hex);
893  } // end planned unit map scope
894  assert(recruiter);
895  std::size_t turn = sa.get_turn_num_of(*recruiter);
896  sa.queue_recruit(turn,name,recruit_hex);
897  created_planned_recruit = true;
898 
899  print_help_once();
900  }
901  }
902  return created_planned_recruit;
903 }
904 
905 bool manager::save_recall(const unit& unit, int side_num, const map_location& recall_hex)
906 {
907  bool created_planned_recall = false;
908 
909  if (active_ && !executing_actions_ && !resources::controller->is_linger_mode())
910  {
911  if (side_num != display::get_singleton()->viewing_side())
912  {
913  LOG_WB <<"manager::save_recall called for a different side than viewing side.\n";
914  created_planned_recall = false;
915  }
916  else
917  {
918  side_actions& sa = *viewer_actions();
919  std::size_t turn = sa.num_turns();
920  if(turn > 0)
921  --turn;
922  sa.queue_recall(turn,unit,recall_hex);
923  created_planned_recall = true;
924 
925  print_help_once();
926  }
927  }
928  return created_planned_recall;
929 }
930 
931 void manager::save_suppose_dead(unit& curr_unit, const map_location& loc)
932 {
933  if(active_ && !executing_actions_ && !resources::controller->is_linger_mode())
934  {
936  side_actions& sa = *viewer_actions();
937  sa.queue_suppose_dead(sa.get_turn_num_of(curr_unit),curr_unit,loc);
938  }
939 }
940 
942 {
945  {
946  erase_temp_move();
947 
948  //For exception-safety, this struct sets executing_actions_ to false on destruction.
950 
953  unit const* selected_unit = future_visible_unit(resources::controller->get_mouse_handler_base().get_selected_hex(), viewer_side());
954  if (selected_unit &&
955  (it = viewer_actions()->find_first_action_of(*selected_unit)) != viewer_actions()->end())
956  {
957  executing_actions_ = true;
958  viewer_actions()->execute(it);
959  }
960  else if (highlighter_ && (action = highlighter_->get_execute_target()) &&
961  (it = viewer_actions()->get_position_of(action)) != viewer_actions()->end())
962  {
963  executing_actions_ = true;
964  viewer_actions()->execute(it);
965  }
966  else //we already check above for viewer_actions()->empty()
967  {
968  executing_actions_ = true;
969  viewer_actions()->execute_next();
970  }
971  } //Finalizer struct sets executing_actions_ to false
972 }
973 
975 {
976  preparing_to_end_turn_ = true;
977  return execute_all_actions();
978 }
979 
981 {
982  if (has_planned_unit_map())
983  {
984  ERR_WB << "Modifying action queue while temp modifiers are applied1!!!" << std::endl;
985  }
986  //exception-safety: finalizers set variables to false on destruction
987  //i.e. when method exits naturally or exception is thrown
988  variable_finalizer<bool> finalize_executing_actions(executing_actions_, false);
989  variable_finalizer<bool> finalize_executing_all_actions(executing_all_actions_, false);
990 
992  if(viewer_actions()->empty() || viewer_actions()->turn_size(0) == 0)
993  {
994  //No actions to execute, job done.
995  return true;
996  }
997 
999 
1000  erase_temp_move();
1001 
1002  // Build unit map once to ensure spent gold and other calculations are refreshed
1004  assert(has_planned_unit_map());
1006 
1007  executing_actions_ = true;
1008  executing_all_actions_ = true;
1009 
1011 
1012  if (has_planned_unit_map())
1013  {
1014  ERR_WB << "Modifying action queue while temp modifiers are applied!!!" << std::endl;
1015  }
1016 
1017  //LOG_WB << "Before executing all actions, " << *sa << "\n";
1018 
1019  while (sa->turn_begin(0) != sa->turn_end(0))
1020  {
1021  bool action_successful = sa->execute(sa->begin());
1022 
1023  // Interrupt on incomplete action
1024  if (!action_successful)
1025  {
1026  return false;
1027  }
1028  }
1029  return true;
1030 }
1031 
1033 {
1036  erase_temp_move();
1037 
1039  side_actions::iterator it = viewer_actions()->end();
1040  unit const* selected_unit = future_visible_unit(resources::controller->get_mouse_handler_base().get_selected_hex(), viewer_side());
1041  if(selected_unit && (it = viewer_actions()->find_last_action_of(*selected_unit)) != viewer_actions()->end()) {
1042  viewer_actions()->remove_action(it);
1043  // TODO: Shouldn't we probably deselect the unit at this point?
1044  } else if(highlighter_ && (action = highlighter_->get_delete_target()) && (it = viewer_actions()->get_position_of(action)) != viewer_actions()->end()) {
1045  viewer_actions()->remove_action(it);
1047  highlighter_->set_mouseover_hex(highlighter_->get_mouseover_hex());
1048  highlighter_->highlight();
1049  } else { //we already check above for viewer_actions()->empty()
1050  it = (viewer_actions()->end() - 1);
1051  action = *it;
1052  viewer_actions()->remove_action(it);
1054  }
1055  }
1056 }
1057 
1059 {
1062  action_ptr action = highlighter_->get_bump_target();
1063  if(action) {
1064  viewer_actions()->bump_earlier(viewer_actions()->get_position_of(action));
1065  validate_viewer_actions(); // Redraw arrows
1066  }
1067  }
1068 }
1069 
1071 {
1074  action_ptr action = highlighter_->get_bump_target();
1075  if(action) {
1076  viewer_actions()->bump_later(viewer_actions()->get_position_of(action));
1077  validate_viewer_actions(); // Redraw arrows
1078  }
1079  }
1080 }
1081 
1083 {
1084  assert(resources::gameboard);
1085  return wb::has_actions();
1086 }
1087 
1089 {
1090  assert(unit != nullptr);
1091  assert(resources::gameboard);
1092  return viewer_actions()->unit_has_actions(*unit);
1093 }
1094 
1096 {
1098  return 0;
1099 
1100  return resources::gameboard->get_team(side).get_side_actions()->get_gold_spent();
1101 }
1102 
1104 {
1106 }
1107 
1109 {
1110  int v_side = viewer_side();
1111 
1112  int selection = 0;
1113 
1114  std::vector<team*> allies;
1115  std::vector<std::string> options;
1116  utils::string_map t_vars;
1117 
1118  options.emplace_back(_("SHOW ALL allies’ plans"));
1119  options.emplace_back(_("HIDE ALL allies’ plans"));
1120 
1121  //populate list of networked allies
1122  for(team &t : resources::gameboard->teams())
1123  {
1124  //Exclude enemies, AIs, and local players
1125  if(t.is_enemy(v_side) || !t.is_network())
1126  continue;
1127 
1128  allies.push_back(&t);
1129 
1130  t_vars["player"] = t.current_player();
1131  std::size_t t_index = t.side()-1;
1132  if(team_plans_hidden_[t_index])
1133  options.emplace_back(VGETTEXT("Show plans for $player", t_vars));
1134  else
1135  options.emplace_back(VGETTEXT("Hide plans for $player", t_vars));
1136  }
1137 
1138  gui2::dialogs::simple_item_selector dlg("", _("Whiteboard Options"), options);
1139  dlg.show();
1140  selection = dlg.selected_index();
1141 
1142  if(selection == -1)
1143  return;
1144 
1145  switch(selection)
1146  {
1147  case 0:
1148  for(team* t : allies) {
1149  team_plans_hidden_[t->side()-1]=false;
1150  }
1151  break;
1152  case 1:
1153  for(team* t : allies) {
1154  team_plans_hidden_[t->side()-1]=true;
1155  }
1156  break;
1157  default:
1158  if(selection > 1)
1159  {
1160  std::size_t t_index = allies[selection-2]->side()-1;
1161  //toggle ...
1162  bool hidden = team_plans_hidden_[t_index];
1163  team_plans_hidden_[t_index] = !hidden;
1164  }
1165  break;
1166  }
1168 }
1169 
1171 {
1172  if (!can_modify_game_state()) {
1173  LOG_WB << "Not building planned unit map: cannot modify game state now.\n";
1174  return;
1175  }
1176  //any more than one reference means a lock on unit map was requested
1177  if(unit_map_lock_.use_count() != 1) {
1178  LOG_WB << "Not building planned unit map: unit map locked.\n";
1179  return;
1180  }
1182  WRN_WB << "Not building planned unit map: already set." << std::endl;
1183  return;
1184  }
1185 
1186  log_scope2(log_whiteboard, "Building planned unit map");
1187  mapbuilder_.reset(new mapbuilder(resources::gameboard->units()));
1188  mapbuilder_->build_map();
1189 
1190  planned_unit_map_active_ = true;
1191 }
1192 
1194 {
1196  {
1197  assert(!executing_actions_);
1198  assert(!wait_for_side_init_);
1199  if(mapbuilder_)
1200  {
1201  log_scope2(log_whiteboard, "Restoring regular unit map.");
1202  mapbuilder_.reset();
1203  }
1204  planned_unit_map_active_ = false;
1205  }
1206  else
1207  {
1208  LOG_WB << "Not disabling planned unit map: already disabled.\n";
1209  }
1210 }
1211 
1213 {
1214  if (gamestate_mutated_) {
1216  }
1217 }
1218 
1220  initial_planned_unit_map_(resources::whiteboard && resources::whiteboard->has_planned_unit_map())
1221 {
1222  if (!resources::whiteboard)
1223  return;
1225  resources::whiteboard->set_planned_unit_map();
1226  // check if if unit map was successfully applied
1227  if (!resources::whiteboard->has_planned_unit_map()) {
1228  DBG_WB << "Scoped future unit map failed to apply.\n";
1229  }
1230 }
1231 
1233 {
1234  try {
1235  if (!resources::whiteboard)
1236  return;
1237  if (!initial_planned_unit_map_ && resources::whiteboard->has_planned_unit_map())
1238  resources::whiteboard->set_real_unit_map();
1239  } catch (...) {}
1240 }
1241 
1243  initial_planned_unit_map_(resources::whiteboard && resources::whiteboard->has_planned_unit_map()),
1244  whiteboard_active_(resources::whiteboard && resources::whiteboard->is_active())
1245 {
1246  if (!resources::whiteboard)
1247  return;
1248  if (!whiteboard_active_)
1249  return;
1251  resources::whiteboard->set_planned_unit_map();
1252  // check if if unit map was successfully applied
1253  if (!resources::whiteboard->has_planned_unit_map()) {
1254  DBG_WB << "Scoped future unit map failed to apply.\n";
1255  }
1256 }
1257 
1259 {
1260  try {
1261  if (!resources::whiteboard)
1262  return;
1263  if (!initial_planned_unit_map_ && resources::whiteboard->has_planned_unit_map())
1264  resources::whiteboard->set_real_unit_map();
1265  } catch (...) {}
1266 }
1267 
1268 
1270  initial_planned_unit_map_(resources::whiteboard && resources::whiteboard->has_planned_unit_map()),
1271  unit_map_lock_(resources::whiteboard ? resources::whiteboard->unit_map_lock_ : std::make_shared<bool>(false))
1272 {
1273  if (!resources::whiteboard)
1274  return;
1276  resources::whiteboard->set_real_unit_map();
1277 }
1278 
1280 {
1281  if (!resources::whiteboard)
1282  return;
1283  assert(!resources::whiteboard->has_planned_unit_map());
1285  {
1286  resources::whiteboard->set_planned_unit_map();
1287  }
1288 }
1289 
1290 } // end namespace wb
bool is_local_ai() const
Definition: team.hpp:280
void clear()
Clears the stack of undoable (and redoable) actions.
Definition: undo.cpp:221
bool self_activate_once_
Definition: manager.hpp:206
container::iterator iterator
bool initial_planned_unit_map_
Definition: manager.hpp:256
play_controller * controller
Definition: resources.cpp:22
#define WRN_WB
Definition: typedefs.hpp:26
void reset()
Reset the internal unit pointer, and deregister from the manager.
std::shared_ptr< wb::side_actions > get_side_actions() const
get the whiteboard planned actions for this team
Definition: team.hpp:398
int viewer_side()
Definition: utility.cpp:46
Move numbering for the whiteboard.
Definition: display.hpp:855
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:402
Arrows destined to be drawn on the map.
void update_plan_hiding()
Definition: manager.cpp:393
unit_iterator end()
Definition: map.hpp:429
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:92
virtual const std::vector< team > & teams() const override
Definition: game_board.hpp:85
std::map< std::string, t_string > string_map
virtual const unit_map & units() const override
Definition: game_board.hpp:112
std::shared_ptr< recruit const > recruit_const_ptr
Definition: typedefs.hpp:73
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:3026
This class represents a single unit of a specific type.
Definition: unit.hpp:121
void on_viewer_change(std::size_t team_index)
Definition: manager.cpp:396
const pathfind::marked_route & get_current_route() const
bool initial_planned_unit_map_
Definition: manager.hpp:287
bool is_network() const
Definition: team.hpp:274
std::set< std::size_t > units_owning_moves_
used to keep track of units owning planned moves for visual ghosting/unghosting
Definition: manager.hpp:247
internal_ptr get_unit_ptr()
Get a copy of the internal unit pointer.
void clear_exclusive_draws()
Cancels all the exclusive draw requests.
Definition: display.hpp:124
std::vector< int > numbers_to_draw
std::shared_ptr< highlighter > highlighter_
Definition: manager.hpp:228
std::vector< arrow_ptr > move_arrows_
Definition: manager.hpp:232
std::shared_ptr< recall const > recall_const_ptr
Definition: typedefs.hpp:75
void set_invert_behavior(bool invert)
Called by the key that temporarily toggles the activated state when held.
Definition: manager.cpp:203
unsigned child_count(config_key_type key) const
Definition: config.cpp:372
void contextual_delete()
Deletes last action in the queue for current side.
Definition: manager.cpp:1032
std::shared_ptr< side_actions > side_actions_ptr
Definition: typedefs.hpp:66
whiteboard_lock activation_state_lock_
Reference counted "lock" to allow preventing whiteboard activation state changes. ...
Definition: manager.hpp:222
child_itors child_range(config_key_type key)
Definition: config.cpp:344
unit * find_recruiter(std::size_t team_index, const map_location &hex)
Definition: utility.cpp:80
void validate_actions_if_needed()
Definition: manager.cpp:1212
std::shared_ptr< attack > attack_ptr
Definition: typedefs.hpp:70
bool has_actions()
Return whether the whiteboard has actions.
Definition: utility.cpp:171
bool hide_whiteboard()
Definition: game.cpp:450
unit_ptr clone() const
Definition: unit.hpp:210
void post_delete_action(action_ptr action)
Handles various cleanup right after removing an action from the queue.
Definition: manager.cpp:344
static config get_auto_shroud(bool turned_on)
Records that the player has toggled automatic shroud updates.
iterator queue_recruit(std::size_t turn_num, const std::string &unit_name, const map_location &recruit_hex)
Queues a recruit to be executed last.
bool is_network_ai() const
Definition: team.hpp:282
int viewing_side() const
Definition: display.hpp:107
STL namespace.
bool can_activate() const
Determine whether the whiteboard can be activated safely.
Definition: manager.cpp:164
void clear()
Definition: config.cpp:920
bool executing_all_actions_
Track whether we&#39;re in the process of executing all actions.
Definition: manager.hpp:215
static std::string _(const char *str)
Definition: gettext.hpp:93
void pre_draw()
Called from the display before drawing.
Definition: manager.cpp:540
bool show(const unsigned auto_close_time=0)
Shows the window.
void contextual_bump_down_action()
Moves the action determined by the UI toward the beginning of the queue.
Definition: manager.cpp:1070
iterator queue_attack(std::size_t turn_num, unit &mover, const map_location &target_hex, int weapon_choice, const pathfind::marked_route &route, arrow_ptr arrow, fake_unit_ptr fake_unit)
Queues an attack or attack-move to be executed last.
std::shared_ptr< unit > unit_ptr
Definition: ptr.hpp:26
static config get_update_shroud()
Records that the player has manually updated fog/shroud.
std::vector< map_location > arrow_path_t
Definition: arrow.hpp:25
void save_temp_move()
Creates a move action for the current side, and erases the temp move.
Definition: manager.cpp:784
void set_active(bool active)
Activates/Deactivates the whiteboard.
Definition: manager.cpp:173
std::vector< std::size_t > team_numbers
std::vector< fake_unit_ptr > fake_units_
Definition: manager.hpp:233
static const std::string STYLE_HIGHLIGHTED
Definition: arrow.hpp:68
void get_numbers(const map_location &hex, numbers_t &result)
Gets called when display is drawing a hex to determine which numbers to draw on it.
void unghost_owner_unit(unit *unit)
Definition: utility.cpp:165
void save_temp_attack(const map_location &attacker_loc, const map_location &defender_loc, int weapon_choice)
Creates an attack or attack-move action for the current side.
Definition: manager.cpp:827
bool planned_unit_map_active_
Definition: manager.hpp:211
static bool is_active(const widget *wgt)
Definition: window.cpp:1336
map_location get_selected_hex() const
void on_gamestate_change()
Definition: manager.cpp:614
void draw_hex(const map_location &hex)
Called from the display when drawing hexes, to allow the whiteboard to add visual elements...
Definition: manager.cpp:568
const config & options()
Definition: game.cpp:569
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:72
static std::string at(const std::string &file, int line)
virtual void draw_hex(const map_location &hex)=0
Gets called by display when drawing a hex, to allow actions to draw to the screen.
team & get_team(int i)
Definition: game_board.hpp:97
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
A simple one-column listbox with OK and Cancel buttons.
whiteboard_lock unit_map_lock_
Reference counted "lock" to prevent the building of the unit map at certain times.
Definition: manager.hpp:224
const std::string & id() const
Gets this unit&#39;s id.
Definition: unit.hpp:371
void set_real_unit_map()
Restore the regular unit map.
Definition: manager.cpp:1193
std::shared_ptr< recruit > recruit_ptr
Definition: typedefs.hpp:72
void options_dlg()
Displays the whiteboard options dialog.
Definition: manager.cpp:1108
void process_network_data(const config &)
Called by turn_info::process_network_data() when network data needs to be processed.
Definition: manager.cpp:650
Arrows destined to be drawn on the map.
Definition: arrow.hpp:30
const hotkey_ptr get_hotkey(const SDL_Event &event)
Iterate through the list of hotkeys and return a hotkey that matches the SDL_Event and the current ke...
Applies the planned unit map for the duration of the struct&#39;s life.
Definition: manager.hpp:252
filter_context * filter_con
Definition: resources.cpp:24
friend struct future_map
Definition: manager.hpp:45
bool valid() const
Definition: location.hpp:89
void contextual_execute()
Executes first action in the queue for current side.
Definition: manager.cpp:941
void on_kill_unit()
Definition: manager.cpp:431
game_board * gameboard
Definition: resources.cpp:21
#define ERR_WB
Definition: typedefs.hpp:25
bool gamestate_mutated_
Track whether the gamestate changed and we need to validate actions.
Definition: manager.hpp:219
bool allow_end_turn()
@ return true if the whiteboard is ready to end turn.
Definition: manager.cpp:974
iterator queue_move(std::size_t turn_num, unit &mover, const pathfind::marked_route &route, arrow_ptr arrow, fake_unit_ptr fake_unit)
Queues a move to be executed last.
unit_map::iterator get_temp_move_unit() const
Definition: manager.cpp:822
Class that handles highlighting planned actions as you hover over them and determine the right target...
Definition: highlighter.hpp:38
std::shared_ptr< action > action_ptr
Definition: typedefs.hpp:62
fake_unit_manager * fake_units
Definition: resources.cpp:31
static bool current_side_has_actions()
Whether the current side has actions in the first turn of its planned actions queue.
Definition: manager.cpp:438
bool is_enemy(int n) const
Definition: team.hpp:255
std::string path
Definition: game_config.cpp:39
void draw_text_in_hex(const map_location &loc, const drawing_layer layer, const std::string &text, std::size_t font_size, color_t color, double x_in_hex=0.5, double y_in_hex=0.5)
Draw text on a hex.
Definition: display.cpp:1523
iterator queue_recall(std::size_t turn_num, const unit &unit, const map_location &recall_hex)
Queues a recall to be executed last.
#define log_scope2(domain, description)
Definition: log.hpp:219
std::unique_ptr< pathfind::marked_route > route_
Definition: manager.hpp:230
virtual fake_unit_ptr get_fake_unit()
Definition: move.hpp:61
void ghost_owner_unit(unit *unit)
Definition: utility.cpp:159
iterator queue_suppose_dead(std::size_t turn_num, unit &curr_unit, const map_location &loc)
Queues a suppose_dead to be executed last.
Structure which holds a single route and marks for special events.
Definition: pathfind.hpp:141
bool preparing_to_end_turn_
true if we&#39;re in the process of executing all action and should end turn once finished.
Definition: manager.hpp:217
friend struct real_map
Definition: manager.hpp:47
bool active_
Tracks whether the whiteboard is active.
Definition: manager.hpp:204
static void hide_all_plans()
Definition: manager.cpp:364
void for_each_action(std::function< void(action *)> function, team_filter team_filter)
Apply a function to all the actions of the whiteboard.
Definition: utility.cpp:186
void on_change_controller(int side, const team &t)
Definition: manager.cpp:402
void on_finish_side_turn(int side)
Definition: manager.cpp:328
bool has_planned_unit_map() const
Whether the planned unit map is currently applied.
Definition: manager.hpp:116
void queue_net_cmd(std::size_t team_index, const side_actions::net_cmd &)
Adds a side_actions::net_cmd to net_buffer_[team_index], whereupon it will (later) be sent to all all...
Definition: manager.cpp:663
static std::string get_side_color_id(unsigned side)
Definition: team.cpp:973
Encapsulates the map of the game.
Definition: location.hpp:38
bool save_recruit(const std::string &name, int side_num, const map_location &recruit_hex)
Creates a recruit action for the current side.
Definition: manager.cpp:877
bool wait_for_side_init_
Definition: manager.hpp:210
void post_draw()
Called from the display after drawing.
Definition: manager.cpp:556
unit_iterator find(std::size_t id)
Definition: map.cpp:310
std::shared_ptr< wb::manager > whiteboard
Definition: resources.cpp:34
Various functions related to the creation of units (recruits, recalls, and placed units)...
std::size_t get_turn_num_of(const unit &) const
Determines the appropriate turn number for the next action planned for this unit. ...
virtual bool is_networked_mp() const
std::size_t team_index()
Returns the team index this action queue belongs to.
static lg::log_domain log_whiteboard("whiteboard")
std::size_t i
Definition: function.cpp:967
int selected_index() const
Returns the selected item index after displaying.
net_cmd make_net_cmd_clear() const
int get_spent_gold_for(int side)
Used to track gold spending per-side when building the planned unit map Is referenced by the top bar ...
Definition: manager.cpp:1095
void erase_temp_move()
Erase the temporary arrow.
Definition: manager.cpp:771
std::vector< config > net_buffer_
net_buffer_[i] = whiteboard network data to be sent "from" teams[i].
Definition: manager.hpp:241
bool can_modify_game_state() const
Determine whether the game is initialized and the current side has control of the game i...
Definition: manager.cpp:148
unit_const_ptr find_backup_leader(const unit &leader)
For a given leader on a keep, find another leader on another keep in the same castle.
Definition: utility.cpp:65
std::shared_ptr< suppose_dead > suppose_dead_ptr
Definition: typedefs.hpp:76
std::pair< iterator, iterator > range_t
bool hidden() const
Class that collects and applies unit_map modifications from the actions it visits and reverts all cha...
Definition: mapbuilder.hpp:39
void create_temp_move()
Creates a temporary visual arrow, that follows the cursor, for move creation purposes.
Definition: manager.cpp:669
int w
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
#define LOG_WB
Definition: typedefs.hpp:27
std::shared_ptr< move > move_ptr
Definition: typedefs.hpp:68
bool is_local() const
Definition: team.hpp:273
side_actions_ptr viewer_actions()
Definition: utility.cpp:51
bool unit_has_actions(unit const *unit) const
Checks whether the specified unit has at least one planned action.
Definition: manager.cpp:1088
void contextual_bump_up_action()
Moves the action determined by the UI toward the beginning of the queue.
Definition: manager.cpp:1058
config & add_child(config_key_type key)
Definition: config.cpp:514
bool has_actions() const
Checks whether the whiteboard has any planned action on any team.
Definition: manager.cpp:1082
std::shared_ptr< arrow > arrow_ptr
Definition: typedefs.hpp:60
void on_init_side()
The on_* methods below inform the whiteboard of specific events.
Definition: manager.cpp:312
std::size_t temp_move_unit_underlying_id_
Definition: manager.hpp:234
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)
std::set< std::size_t > secondary_numbers
bool save_recall(const unit &unit, int side_num, const map_location &recall_hex)
Creates a recall action for the current side.
Definition: manager.cpp:905
bool is_local_human() const
Definition: team.hpp:279
events::mouse_handler & get_mouse_handler_base() override
Get a reference to a mouse handler member a derived class uses.
double t
Definition: astarsearch.cpp:65
void print_help_once()
Definition: manager.cpp:108
void send_network_data()
Called by replay_network_sender to add whiteboard data to the outgoing network packets.
Definition: manager.cpp:626
static color_t get_side_color(int side)
Definition: team.cpp:961
boost::dynamic_bitset team_plans_hidden_
team_plans_hidden_[i] = whether or not to hide actions from teams[i].
Definition: manager.hpp:244
#define DBG_WB
Definition: typedefs.hpp:28
bool enable_whiteboard_mode_on_start()
Definition: game.cpp:440
Various functions that implement the undoing (and redoing) of in-game commands.
Finalizer class to help with exception safety sets variable to value on destruction.
Definition: utility.hpp:92
void save_suppose_dead(unit &curr_unit, const map_location &loc)
Creates a suppose-dead action for the current side.
Definition: manager.cpp:931
int current_side() const
Returns the number of the side whose turn it is.
static void draw_numbers(const map_location &hex, side_actions::numbers_t numbers)
Definition: manager.cpp:460
bool has_temp_move() const
Informs whether an arrow is being displayed for move creation purposes.
Definition: manager.hpp:137
unit * future_visible_unit(map_location hex, int viewer_side)
Applies the future unit map and.
Definition: utility.cpp:109
bool can_enable_reorder_hotkeys() const
Used to ask the whiteboard if its action reordering hotkeys should be available to the user...
Definition: manager.cpp:264
std::shared_ptr< recall > recall_ptr
Definition: typedefs.hpp:74
int side() const
The side this unit belongs to.
Definition: unit.hpp:334
actions::undo_list * undo_stack
Definition: resources.cpp:33
virtual void accept(visitor &v)=0
std::size_t num_turns() const
Returns the number of turns that have plans.
bool should_clear_undo() const
Determines whether or not the undo_stack should be cleared.
Definition: manager.cpp:1103
Abstract base class for all the whiteboard planned actions.
Definition: action.hpp:33
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:61
bool executing_actions_
Track whenever we&#39;re modifying actions, to avoid dual execution etc.
Definition: manager.hpp:213
bool valid() const
Definition: map.hpp:274
Class that keeps track of all the keys on the keyboard.
Definition: key.hpp:28
std::unique_ptr< mapbuilder > mapbuilder_
Definition: manager.hpp:227
bool inverted_behavior_
Definition: manager.hpp:205
bool execute_all_actions()
Executes all actions for the current turn in sequence.
Definition: manager.cpp:980
static bool valid_path(const arrow_path_t &path)
Checks that the path is not of length 0 or 1.
Definition: arrow.cpp:147
void on_mouseover_change(const map_location &hex)
Definition: manager.cpp:594
void validate_viewer_actions()
Validates all actions of the current viewing side.
Definition: manager.cpp:448
This module contains various pathfinding functions and utilities.
bool can_enable_execution_hotkeys() const
Used to ask the whiteboard if its action execution hotkeys should be available to the user...
Definition: manager.cpp:253
This internal whiteboard class holds the planned action queues for a team, and offers many utility me...
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
Holds a temporary unit that can be drawn on the map without being placed in the unit_map.
A planned move, represented on the map by an arrow and a ghosted unit in the destination hex...
Definition: move.hpp:35
std::size_t underlying_id() const
This unit&#39;s unique internal ID.
Definition: unit.hpp:383
bool empty() const
Definition: config.cpp:941
virtual void send_to_wesnothd(const config &, const std::string &="unknown") const
Display units performing various actions: moving, attacking, and dying.
void move_unit(const std::vector< map_location > &path, unit_ptr u, bool animate, map_location::DIRECTION dir, bool force_scroll)
Display a unit moving along a given path.
Definition: udisplay.cpp:510
std::vector< map_location > & steps
Definition: pathfind.hpp:187
Definition: display.hpp:49
std::size_t viewer_team()
Definition: utility.cpp:41
bool allow_leader_to_move(const unit &leader) const
Used to ask permission to the wb to move a leader, to avoid invalidating planned recruits.
Definition: manager.cpp:269
Abstract base class for all the visitors (cf GoF Visitor Design Pattern) the whiteboard uses...
Definition: visitor.hpp:32
static game_display * get_singleton()
void set_planned_unit_map()
Transforms the unit map so that it now reflects the future state of things, i.e.
Definition: manager.cpp:1170
const std::vector< map_location > & route_
Definition: move.cpp:295
void clear()
Empties the action queue.
void pre_delete_action(action_ptr action)
Handles various cleanup right before removing an action from the queue.
Definition: manager.cpp:340
bool can_enable_modifier_hotkeys() const
Used to ask the whiteboard if hotkeys affecting the action queue should be available to the user...
Definition: manager.cpp:259
side_actions_ptr current_side_actions()
Definition: utility.cpp:58
std::shared_ptr< action const > action_const_ptr
Definition: typedefs.hpp:63