The Battle for Wesnoth  1.17.21+dev
manager.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2023
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.";
92 }
93 
95 {
96  LOG_WB << "Manager destroyed.";
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()
156  {
157  return false;
158  }
159  else
160  {
161  return true;
162  }
163 }
164 
166 {
167  //any more than one reference means a lock on whiteboard state was requested
168  if(activation_state_lock_.use_count() != 1)
169  return false;
170 
171  return can_modify_game_state();
172 }
173 
174 void manager::set_active(bool active)
175 {
176  if(!can_activate())
177  {
178  active_ = false;
179  LOG_WB << "Whiteboard can't be activated now.";
180  }
181  else if (active != active_)
182  {
183  active_ = active;
184  erase_temp_move();
185 
186  if (active_)
187  {
188  if(should_clear_undo()) {
189  if(!resources::controller->current_team().auto_shroud_updates()) {
191  }
193  }
195  LOG_WB << "Whiteboard activated! " << *viewer_actions();
197  } else {
198  LOG_WB << "Whiteboard deactivated!";
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.";
222  inverted_behavior_ = true;
223  set_active(false);
224  }
225  else if (!block_whiteboard_activation)
226  {
227  DBG_WB << "Whiteboard activated temporarily.";
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.";
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.";
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.";
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  {
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()";
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()";
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 
351 
352  unit_ptr actor = action->get_unit();
353  if(actor) { // The unit might have died following the execution of an attack
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 {
404  wb::side_actions& sa = *t.get_side_actions();
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.";
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.";
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).";
647  }
648 }
649 
651 {
652  if(auto wb_cfg = cfg.optional_child("whiteboard"))
653  {
654  std::size_t count = wb_cfg->child_count("net_cmd");
655  LOG_WB << "Received wb data (" << count << ").";
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();
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();
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.";
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.";
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 
952  unit const* selected_unit = future_visible_unit(resources::controller->get_mouse_handler_base().get_selected_hex(), viewer_side());
953 
954  auto check_action = [&](side_actions::iterator i) {
955  it = i;
956  return it != viewer_actions()->end() && it < viewer_actions()->turn_end(0);
957  };
958 
959  if (selected_unit && check_action(viewer_actions()->find_first_action_of(*selected_unit)))
960  {
961  executing_actions_ = true;
962  viewer_actions()->execute(it);
963  }
964  else if (highlighter_ && check_action(viewer_actions()->get_position_of(highlighter_->get_execute_target())))
965  {
966  executing_actions_ = true;
967  viewer_actions()->execute(it);
968  }
969  else //we already check above for viewer_actions()->empty()
970  {
971  executing_actions_ = true;
972  viewer_actions()->execute_next();
973  }
974  } //Finalizer struct sets executing_actions_ to false
975 }
976 
978 {
979  preparing_to_end_turn_ = true;
980  return execute_all_actions();
981 }
982 
984 {
985  if (has_planned_unit_map())
986  {
987  ERR_WB << "Modifying action queue while temp modifiers are applied1!!!";
988  }
989  //exception-safety: finalizers set variables to false on destruction
990  //i.e. when method exits naturally or exception is thrown
991  variable_finalizer<bool> finalize_executing_actions(executing_actions_, false);
992  variable_finalizer<bool> finalize_executing_all_actions(executing_all_actions_, false);
993 
995  if(viewer_actions()->empty() || viewer_actions()->turn_size(0) == 0)
996  {
997  //No actions to execute, job done.
998  return true;
999  }
1000 
1001  assert(can_enable_execution_hotkeys());
1002 
1003  erase_temp_move();
1004 
1005  // Build unit map once to ensure spent gold and other calculations are refreshed
1007  assert(has_planned_unit_map());
1009 
1010  executing_actions_ = true;
1011  executing_all_actions_ = true;
1012 
1014 
1015  if (has_planned_unit_map())
1016  {
1017  ERR_WB << "Modifying action queue while temp modifiers are applied!!!";
1018  }
1019 
1020  //LOG_WB << "Before executing all actions, " << *sa;
1021 
1022  while (sa->turn_begin(0) != sa->turn_end(0))
1023  {
1024  bool action_successful = sa->execute(sa->begin());
1025 
1026  // Interrupt on incomplete action
1027  if (!action_successful)
1028  {
1029  return false;
1030  }
1031  }
1032  return true;
1033 }
1034 
1036 {
1039  erase_temp_move();
1040 
1042  side_actions::iterator it = viewer_actions()->end();
1043  unit const* selected_unit = future_visible_unit(resources::controller->get_mouse_handler_base().get_selected_hex(), viewer_side());
1044  if(selected_unit && (it = viewer_actions()->find_last_action_of(*selected_unit)) != viewer_actions()->end()) {
1045  viewer_actions()->remove_action(it);
1046  // TODO: Shouldn't we probably deselect the unit at this point?
1047  } else if(highlighter_ && (action = highlighter_->get_delete_target()) && (it = viewer_actions()->get_position_of(action)) != viewer_actions()->end()) {
1048  viewer_actions()->remove_action(it);
1050  highlighter_->set_mouseover_hex(highlighter_->get_mouseover_hex());
1051  highlighter_->highlight();
1052  } else { //we already check above for viewer_actions()->empty()
1053  it = (viewer_actions()->end() - 1);
1054  action = *it;
1055  viewer_actions()->remove_action(it);
1057  }
1058  }
1059 }
1060 
1062 {
1065  action_ptr action = highlighter_->get_bump_target();
1066  if(action) {
1067  viewer_actions()->bump_earlier(viewer_actions()->get_position_of(action));
1068  validate_viewer_actions(); // Redraw arrows
1069  }
1070  }
1071 }
1072 
1074 {
1077  action_ptr action = highlighter_->get_bump_target();
1078  if(action) {
1079  viewer_actions()->bump_later(viewer_actions()->get_position_of(action));
1080  validate_viewer_actions(); // Redraw arrows
1081  }
1082  }
1083 }
1084 
1086 {
1087  assert(resources::gameboard);
1088  return wb::has_actions();
1089 }
1090 
1092 {
1093  assert(unit != nullptr);
1094  assert(resources::gameboard);
1095  return viewer_actions()->unit_has_actions(*unit);
1096 }
1097 
1099 {
1101  return 0;
1102 
1103  return resources::gameboard->get_team(side).get_side_actions()->get_gold_spent();
1104 }
1105 
1107 {
1109 }
1110 
1112 {
1113  int v_side = viewer_side();
1114 
1115  int selection = 0;
1116 
1117  std::vector<team*> allies;
1118  std::vector<std::string> options;
1119  utils::string_map t_vars;
1120 
1121  options.emplace_back(_("SHOW ALL allies’ plans"));
1122  options.emplace_back(_("HIDE ALL allies’ plans"));
1123 
1124  //populate list of networked allies
1125  for(team &t : resources::gameboard->teams())
1126  {
1127  //Exclude enemies, AIs, and local players
1128  if(t.is_enemy(v_side) || !t.is_network())
1129  continue;
1130 
1131  allies.push_back(&t);
1132 
1133  t_vars["player"] = t.current_player();
1134  std::size_t t_index = t.side()-1;
1135  if(team_plans_hidden_[t_index])
1136  options.emplace_back(VGETTEXT("Show plans for $player", t_vars));
1137  else
1138  options.emplace_back(VGETTEXT("Hide plans for $player", t_vars));
1139  }
1140 
1141  gui2::dialogs::simple_item_selector dlg("", _("Whiteboard Options"), options);
1142  dlg.show();
1143  selection = dlg.selected_index();
1144 
1145  if(selection == -1)
1146  return;
1147 
1148  switch(selection)
1149  {
1150  case 0:
1151  for(team* t : allies) {
1152  team_plans_hidden_[t->side()-1]=false;
1153  }
1154  break;
1155  case 1:
1156  for(team* t : allies) {
1157  team_plans_hidden_[t->side()-1]=true;
1158  }
1159  break;
1160  default:
1161  if(selection > 1)
1162  {
1163  std::size_t t_index = allies[selection-2]->side()-1;
1164  //toggle ...
1165  bool hidden = team_plans_hidden_[t_index];
1166  team_plans_hidden_[t_index] = !hidden;
1167  }
1168  break;
1169  }
1171 }
1172 
1174 {
1175  if (!can_modify_game_state()) {
1176  LOG_WB << "Not building planned unit map: cannot modify game state now.";
1177  return;
1178  }
1179  //any more than one reference means a lock on unit map was requested
1180  if(unit_map_lock_.use_count() != 1) {
1181  LOG_WB << "Not building planned unit map: unit map locked.";
1182  return;
1183  }
1185  WRN_WB << "Not building planned unit map: already set.";
1186  return;
1187  }
1188 
1189  log_scope2(log_whiteboard, "Building planned unit map");
1190  mapbuilder_.reset(new mapbuilder(resources::gameboard->units()));
1191  mapbuilder_->build_map();
1192 
1193  planned_unit_map_active_ = true;
1194 }
1195 
1197 {
1199  {
1200  assert(!executing_actions_);
1201  assert(!wait_for_side_init_);
1202  if(mapbuilder_)
1203  {
1204  log_scope2(log_whiteboard, "Restoring regular unit map.");
1205  mapbuilder_.reset();
1206  }
1207  planned_unit_map_active_ = false;
1208  }
1209  else
1210  {
1211  LOG_WB << "Not disabling planned unit map: already disabled.";
1212  }
1213 }
1214 
1216 {
1217  if (gamestate_mutated_) {
1219  }
1220 }
1221 
1223  initial_planned_unit_map_(resources::whiteboard && resources::whiteboard->has_planned_unit_map())
1224 {
1225  if (!resources::whiteboard)
1226  return;
1228  resources::whiteboard->set_planned_unit_map();
1229  // check if if unit map was successfully applied
1230  if (!resources::whiteboard->has_planned_unit_map()) {
1231  DBG_WB << "Scoped future unit map failed to apply.";
1232  }
1233 }
1234 
1236 {
1237  try {
1238  if (!resources::whiteboard)
1239  return;
1240  if (!initial_planned_unit_map_ && resources::whiteboard->has_planned_unit_map())
1241  resources::whiteboard->set_real_unit_map();
1242  } catch (...) {}
1243 }
1244 
1246  initial_planned_unit_map_(resources::whiteboard && resources::whiteboard->has_planned_unit_map()),
1247  whiteboard_active_(resources::whiteboard && resources::whiteboard->is_active())
1248 {
1249  if (!resources::whiteboard)
1250  return;
1251  if (!whiteboard_active_)
1252  return;
1254  resources::whiteboard->set_planned_unit_map();
1255  // check if if unit map was successfully applied
1256  if (!resources::whiteboard->has_planned_unit_map()) {
1257  DBG_WB << "Scoped future unit map failed to apply.";
1258  }
1259 }
1260 
1262 {
1263  try {
1264  if (!resources::whiteboard)
1265  return;
1266  if (!initial_planned_unit_map_ && resources::whiteboard->has_planned_unit_map())
1267  resources::whiteboard->set_real_unit_map();
1268  } catch (...) {}
1269 }
1270 
1271 
1273  initial_planned_unit_map_(resources::whiteboard && resources::whiteboard->has_planned_unit_map()),
1274  unit_map_lock_(resources::whiteboard ? resources::whiteboard->unit_map_lock_ : std::make_shared<bool>(false))
1275 {
1276  if (!resources::whiteboard)
1277  return;
1279  resources::whiteboard->set_real_unit_map();
1280 }
1281 
1283 {
1284  if (!resources::whiteboard)
1285  return;
1286  assert(!resources::whiteboard->has_planned_unit_map());
1288  {
1289  resources::whiteboard->set_planned_unit_map();
1290  }
1291 }
1292 
1293 } // end namespace wb
const std::vector< map_location > & route_
Definition: move.cpp:295
Arrows destined to be drawn on the map.
std::vector< map_location > arrow_path_t
Definition: arrow.hpp:25
double t
Definition: astarsearch.cpp:65
Class that keeps track of all the keys on the keyboard.
Definition: key.hpp:29
void clear()
Clears the stack of undoable (and redoable) actions.
Definition: undo.cpp:212
Arrows destined to be drawn on the map.
Definition: arrow.hpp:30
static const std::string STYLE_HIGHLIGHTED
Definition: arrow.hpp:68
static bool valid_path(const arrow_path_t &path)
Checks that the path is not of length 0 or 1.
Definition: arrow.cpp:149
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:161
std::size_t child_count(config_key_type key) const
Definition: config.cpp:301
child_itors child_range(config_key_type key)
Definition: config.cpp:277
bool empty() const
Definition: config.cpp:856
void clear()
Definition: config.cpp:835
optional_config_impl< config > optional_child(config_key_type key, int n=0)
Euivalent to mandatory_child, but returns an empty optional if the nth child was not found.
Definition: config.cpp:389
config & add_child(config_key_type key)
Definition: config.cpp:445
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:1445
int viewing_side() const
The 1-based equivalent of the 0-based viewing_team() function.
Definition: display.hpp:130
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:3094
@ LAYER_ACTIONS_NUMBERING
Move numbering for the whiteboard.
Definition: display.hpp:834
void clear_exclusive_draws()
Cancels all the exclusive draw requests.
Definition: display.hpp:147
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:101
map_location get_selected_hex() const
const pathfind::marked_route & get_current_route() const
Holds a temporary unit that can be drawn on the map without being placed in the unit_map.
internal_ptr get_unit_ptr()
Get a copy of the internal unit pointer.
void reset()
Reset the internal unit pointer, and deregister from the manager.
virtual const std::vector< team > & teams() const override
Definition: game_board.hpp:86
team & get_team(int i)
Definition: game_board.hpp:98
virtual const unit_map & units() const override
Definition: game_board.hpp:113
static game_display * get_singleton()
bool show(const unsigned auto_close_time=0)
Shows the window.
A simple one-column listbox with OK and Cancel buttons.
int selected_index() const
Returns the selected item index after displaying.
events::mouse_handler & get_mouse_handler_base() override
Get a reference to a mouse handler member a derived class uses.
virtual void send_to_wesnothd(const config &, const std::string &="unknown") const
int current_side() const
Returns the number of the side whose turn it is.
virtual bool is_networked_mp() const
static config get_auto_shroud(bool turned_on)
Records that the player has toggled automatic shroud updates.
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)
static bool is_unsynced()
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:76
bool is_local() const
Definition: team.hpp:249
bool is_local_human() const
Definition: team.hpp:255
bool is_enemy(int n) const
Definition: team.hpp:231
static std::string get_side_color_id(unsigned side)
Definition: team.cpp:972
std::shared_ptr< wb::side_actions > get_side_actions() const
get the whiteboard planned actions for this team
Definition: team.hpp:373
static color_t get_side_color(int side)
Definition: team.cpp:960
unit_iterator end()
Definition: map.hpp:429
unit_iterator find(std::size_t id)
Definition: map.cpp:301
This class represents a single unit of a specific type.
Definition: unit.hpp:134
unit_ptr clone() const
Definition: unit.hpp:222
Abstract base class for all the whiteboard planned actions.
Definition: action.hpp:34
virtual unit_ptr get_unit() const =0
Return the unit targeted by this action.
std::size_t team_index() const
Returns the index of the team that owns this action.
Definition: action.hpp:84
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.
Class that handles highlighting planned actions as you hover over them and determine the right target...
Definition: highlighter.hpp:39
bool executing_all_actions_
Track whether we're in the process of executing all actions.
Definition: manager.hpp:215
void on_finish_side_turn(int side)
Definition: manager.cpp:328
void contextual_bump_down_action()
Moves the action determined by the UI toward the beginning of the queue
Definition: manager.cpp:1073
void on_viewer_change(std::size_t team_index)
Definition: manager.cpp:396
bool can_activate() const
Determine whether the whiteboard can be activated safely.
Definition: manager.cpp:165
bool active_
Tracks whether the whiteboard is active.
Definition: manager.hpp:204
bool executing_actions_
Track whenever we're modifying actions, to avoid dual execution etc.
Definition: manager.hpp:213
std::unique_ptr< mapbuilder > mapbuilder_
Definition: manager.hpp:227
whiteboard_lock activation_state_lock_
Reference counted "lock" to allow preventing whiteboard activation state changes.
Definition: manager.hpp:222
std::vector< fake_unit_ptr > fake_units_
Definition: manager.hpp:233
bool has_temp_move() const
Informs whether an arrow is being displayed for move creation purposes.
Definition: manager.hpp:137
bool allow_end_turn()
@ return true if the whiteboard is ready to end turn.
Definition: manager.cpp:977
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
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
void on_kill_unit()
Definition: manager.cpp:431
void post_delete_action(action_ptr action)
Handles various cleanup right after removing an action from the queue.
Definition: manager.cpp:344
bool wait_for_side_init_
Definition: manager.hpp:210
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
void contextual_bump_up_action()
Moves the action determined by the UI toward the beginning of the queue
Definition: manager.cpp:1061
void set_active(bool active)
Activates/Deactivates the whiteboard.
Definition: manager.cpp:174
void set_planned_unit_map()
Transforms the unit map so that it now reflects the future state of things, i.e.
Definition: manager.cpp:1173
friend struct future_map
Definition: manager.hpp:45
bool gamestate_mutated_
Track whether the gamestate changed and we need to validate actions.
Definition: manager.hpp:219
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 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:1098
whiteboard_lock unit_map_lock_
Reference counted "lock" to prevent the building of the unit map at certain times.
Definition: manager.hpp:224
void set_real_unit_map()
Restore the regular unit map.
Definition: manager.cpp:1196
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
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
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
std::size_t temp_move_unit_underlying_id_
Definition: manager.hpp:234
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
std::shared_ptr< highlighter > highlighter_
Definition: manager.hpp:228
void process_network_data(const config &)
Called by turn_info::process_network_data() when network data needs to be processed.
Definition: manager.cpp:650
void validate_actions_if_needed()
Definition: manager.cpp:1215
void options_dlg()
Displays the whiteboard options dialog.
Definition: manager.cpp:1111
void set_invert_behavior(bool invert)
Called by the key that temporarily toggles the activated state when held.
Definition: manager.cpp:203
void on_change_controller(int side, const team &t)
Definition: manager.cpp:402
void print_help_once()
Definition: manager.cpp:108
bool planned_unit_map_active_
Definition: manager.hpp:211
friend struct real_map
Definition: manager.hpp:47
bool preparing_to_end_turn_
true if we're in the process of executing all action and should end turn once finished.
Definition: manager.hpp:217
void pre_delete_action(action_ptr action)
Handles various cleanup right before removing an action from the queue.
Definition: manager.cpp:340
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
void post_draw()
Called from the display after drawing.
Definition: manager.cpp:556
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
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
void update_plan_hiding()
Definition: manager.cpp:393
std::vector< config > net_buffer_
net_buffer_[i] = whiteboard network data to be sent "from" teams[i].
Definition: manager.hpp:241
void contextual_delete()
Deletes last action in the queue for current side.
Definition: manager.cpp:1035
void create_temp_move()
Creates a temporary visual arrow, that follows the cursor, for move creation purposes.
Definition: manager.cpp:669
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
void send_network_data()
Called by replay_network_sender to add whiteboard data to the outgoing network packets.
Definition: manager.cpp:626
void save_temp_move()
Creates a move action for the current side, and erases the temp move.
Definition: manager.cpp:784
bool should_clear_undo() const
Determines whether or not the undo_stack should be cleared.
Definition: manager.cpp:1106
void validate_viewer_actions()
Validates all actions of the current viewing side.
Definition: manager.cpp:448
bool unit_has_actions(unit const *unit) const
Checks whether the specified unit has at least one planned action.
Definition: manager.cpp:1091
void on_init_side()
The on_* methods below inform the whiteboard of specific events.
Definition: manager.cpp:312
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
void on_gamestate_change()
Definition: manager.cpp:614
bool inverted_behavior_
Definition: manager.hpp:205
void on_mouseover_change(const map_location &hex)
Definition: manager.cpp:594
void erase_temp_move()
Erase the temporary arrow.
Definition: manager.cpp:771
boost::dynamic_bitset team_plans_hidden_
team_plans_hidden_[i] = whether or not to hide actions from teams[i].
Definition: manager.hpp:244
bool self_activate_once_
Definition: manager.hpp:206
bool execute_all_actions()
Executes all actions for the current turn in sequence.
Definition: manager.cpp:983
void pre_draw()
Called from the display before drawing.
Definition: manager.cpp:540
void contextual_execute()
Executes first action in the queue for current side.
Definition: manager.cpp:941
unit_map::iterator get_temp_move_unit() const
Definition: manager.cpp:822
std::unique_ptr< pathfind::marked_route > route_
Definition: manager.hpp:230
bool has_actions() const
Checks whether the whiteboard has any planned action on any team.
Definition: manager.cpp:1085
std::vector< arrow_ptr > move_arrows_
Definition: manager.hpp:232
Class that collects and applies unit_map modifications from the actions it visits and reverts all cha...
Definition: mapbuilder.hpp:40
A planned move, represented on the map by an arrow and a ghosted unit in the destination hex.
Definition: move.hpp:36
virtual fake_unit_ptr get_fake_unit()
Definition: move.hpp:61
map_location const get_recall_hex() const
Definition: recall.hpp:70
map_location const get_recruit_hex() const
Definition: recruit.hpp:75
This internal whiteboard class holds the planned action queues for a team, and offers many utility me...
std::size_t team_index()
Returns the team index this action queue belongs to.
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.
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.
iterator queue_recall(std::size_t turn_num, const unit &unit, const map_location &recall_hex)
Queues a recall to be executed last.
std::size_t num_turns() const
Returns the number of turns that have plans.
iterator find_last_action_of(const unit &unit, iterator start_position)
Finds the last action that belongs to this unit, starting the search backwards from the specified pos...
iterator queue_suppose_dead(std::size_t turn_num, unit &curr_unit, const map_location &loc)
Queues a suppose_dead to be executed last.
std::size_t get_turn_num_of(const unit &) const
Determines the appropriate turn number for the next action planned for this unit.
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.
net_cmd make_net_cmd_clear() const
container::iterator iterator
bool hidden() const
void clear()
Empties the action queue.
iterator end()
Returns the iterator for the position after the last executed action within the actions queue.
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::pair< iterator, iterator > range_t
Finalizer class to help with exception safety sets variable to value on destruction.
Definition: utility.hpp:93
Various functions related to the creation of units (recruits, recalls, and placed units).
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
std::size_t i
Definition: function.cpp:968
int w
static std::string _(const char *str)
Definition: gettext.hpp:93
const std::string & id() const
Gets this unit's id.
Definition: unit.hpp:381
int side() const
The side this unit belongs to.
Definition: unit.hpp:344
std::size_t underlying_id() const
This unit's unique internal ID.
Definition: unit.hpp:393
#define log_scope2(domain, description)
Definition: log.hpp:242
std::string path
Definition: filesystem.cpp:86
static bool is_active(const widget *wgt)
Definition: window.cpp:1190
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...
@ HOTKEY_WB_EXECUTE_ALL_ACTIONS
@ HOTKEY_WB_EXECUTE_ACTION
@ HOTKEY_WB_BUMP_UP_ACTION
@ HOTKEY_WB_BUMP_DOWN_ACTION
@ HOTKEY_WB_DELETE_ACTION
bool hide_whiteboard()
Definition: game.cpp:436
bool enable_whiteboard_mode_on_start()
Definition: game.cpp:426
const config & options()
Definition: game.cpp:555
game_board * gameboard
Definition: resources.cpp:21
fake_unit_manager * fake_units
Definition: resources.cpp:31
actions::undo_list * undo_stack
Definition: resources.cpp:33
play_controller * controller
Definition: resources.cpp:22
filter_context * filter_con
Definition: resources.cpp:24
std::shared_ptr< wb::manager > whiteboard
Definition: resources.cpp:34
static std::string at(const std::string &file, int line)
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:509
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
std::map< std::string, t_string > string_map
Definition: display.hpp:49
side_actions_ptr current_side_actions()
Definition: utility.cpp:58
static void hide_all_plans()
Definition: manager.cpp:364
std::shared_ptr< recruit > recruit_ptr
Definition: typedefs.hpp:72
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 ghost_owner_unit(unit *unit)
Definition: utility.cpp:159
std::shared_ptr< suppose_dead > suppose_dead_ptr
Definition: typedefs.hpp:76
std::shared_ptr< recall const > recall_const_ptr
Definition: typedefs.hpp:75
std::shared_ptr< move > move_ptr
Definition: typedefs.hpp:68
unit * find_recruiter(std::size_t team_index, const map_location &hex)
Definition: utility.cpp:80
std::size_t viewer_team()
Definition: utility.cpp:41
int viewer_side()
Definition: utility.cpp:46
std::shared_ptr< action > action_ptr
Definition: typedefs.hpp:62
unit * future_visible_unit(map_location hex, int viewer_side)
Applies the future unit map and.
Definition: utility.cpp:109
std::shared_ptr< side_actions > side_actions_ptr
Definition: typedefs.hpp:66
std::shared_ptr< recruit const > recruit_const_ptr
Definition: typedefs.hpp:73
std::shared_ptr< arrow > arrow_ptr
Definition: typedefs.hpp:60
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
side_actions_ptr viewer_actions()
Definition: utility.cpp:51
bool has_actions()
Return whether the whiteboard has actions.
Definition: utility.cpp:171
static void draw_numbers(const map_location &hex, side_actions::numbers_t numbers)
Definition: manager.cpp:460
std::shared_ptr< action const > action_const_ptr
Definition: typedefs.hpp:63
void unghost_owner_unit(unit *unit)
Definition: utility.cpp:165
std::shared_ptr< recall > recall_ptr
Definition: typedefs.hpp:74
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
This module contains various pathfinding functions and utilities.
std::shared_ptr< attack_type > attack_ptr
Definition: ptr.hpp:33
std::shared_ptr< unit > unit_ptr
Definition: ptr.hpp:26
This file contains object "key", which is used to store information about keys while annotation parsi...
The basic class for representing 8-bit RGB or RGBA colour values.
Definition: color.hpp:59
Encapsulates the map of the game.
Definition: location.hpp:38
bool valid() const
Definition: location.hpp:89
Structure which holds a single route and marks for special events.
Definition: pathfind.hpp:142
std::vector< map_location > & steps
Definition: pathfind.hpp:187
bool valid() const
Definition: map.hpp:274
Applies the planned unit map for the duration of the struct's life.
Definition: manager.hpp:253
bool initial_planned_unit_map_
Definition: manager.hpp:256
bool initial_planned_unit_map_
Definition: manager.hpp:287
std::set< std::size_t > secondary_numbers
std::vector< int > numbers_to_draw
std::vector< std::size_t > team_numbers
#define WRN_WB
Definition: typedefs.hpp:26
static lg::log_domain log_whiteboard("whiteboard")
#define ERR_WB
Definition: typedefs.hpp:25
#define DBG_WB
Definition: typedefs.hpp:28
#define LOG_WB
Definition: typedefs.hpp:27
Display units performing various actions: moving, attacking, and dying.
Various functions that implement the undoing (and redoing) of in-game commands.