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