The Battle for Wesnoth  1.19.0-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"
37 #include "preferences/game.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 {
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 
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 }
391 
392 void manager::on_viewer_change(std::size_t team_index)
393 {
395  update_plan_hiding(team_index);
396 }
397 
398 void manager::on_change_controller(int side, const team& t)
399 {
400  wb::side_actions& sa = *t.get_side_actions();
401  if(t.is_local_human()) // we own this side now
402  {
403  //tell everyone to clear this side's actions -- we're starting anew
405  sa.clear();
406  //refresh the hidden_ attribute of every team's side_actions
408  }
409  else if(t.is_local_ai() || t.is_network_ai()) // no one owns this side anymore
410  sa.clear(); // clear its plans away -- the ai doesn't plan ... yet
411  else if(t.is_network()) // Another client is taking control of the side
412  {
413  if(side==viewer_side()) // They're taking OUR side away!
414  hide_all_plans(); // give up knowledge of everyone's plans, in case we became an observer
415 
416  //tell them our plans -- they may not have received them up to this point
417  std::size_t num_teams = resources::gameboard->teams().size();
418  for(std::size_t i=0; i<num_teams; ++i)
419  {
420  team& local_team = resources::gameboard->teams().at(i);
421  if(local_team.is_local_human() && !local_team.is_enemy(side))
422  queue_net_cmd(i,local_team.get_side_actions()->make_net_cmd_refresh());
423  }
424  }
425 }
426 
428 {
429  if(highlighter_ != nullptr) {
430  highlighter_->set_selection_candidate(unit_ptr());
431  }
432 }
433 
435 {
436  if(current_side_actions()->empty()) {
437  return false;
438  }
439 
440  side_actions::range_t range = current_side_actions()->iter_turn(0);
441  return range.first != range.second; //non-empty range
442 }
443 
445 {
446  LOG_WB << "'gamestate_mutated_' flag dirty, validating actions.";
447  gamestate_mutated_ = false;
448  if(has_planned_unit_map()) {
449  real_map();
450  } else {
451  future_map();
452  }
453 }
454 
455 //helper fcn
456 static void draw_numbers(const map_location& hex, side_actions::numbers_t numbers)
457 {
458  std::vector<int>& numbers_to_draw = numbers.numbers_to_draw;
459  std::vector<std::size_t>& team_numbers = numbers.team_numbers;
460  int& main_number = numbers.main_number;
461  std::set<std::size_t>& secondary_numbers = numbers.secondary_numbers;
462 
463  const double x_offset_base = 0.0;
464  const double y_offset_base = 0.2;
465  //position 0,0 in the hex is the upper left corner
466  //0.8 = horizontal coord., close to the right side of the hex
467  const double x_origin = 0.8 - numbers_to_draw.size() * x_offset_base;
468  //0.5 = halfway in the hex vertically
469  const double y_origin = 0.5 - numbers_to_draw.size() * (y_offset_base / 2);
470  double x_offset = 0, y_offset = 0;
471 
472  std::size_t size = numbers_to_draw.size();
473  for(std::size_t i=0; i<size; ++i)
474  {
475  int number = numbers_to_draw[i];
476 
477  std::string number_text = std::to_string(number);
478  std::size_t font_size;
479  if (static_cast<int>(i) == main_number) font_size = 19;
480  else if (secondary_numbers.find(i)!=secondary_numbers.end()) font_size = 17;
481  else font_size = 15;
482 
483  color_t color = team::get_side_color(static_cast<int>(team_numbers[i]+1));
484  const double x_in_hex = x_origin + x_offset;
485  const double y_in_hex = y_origin + y_offset;
487  number_text, font_size, color, x_in_hex, y_in_hex);
488  x_offset += x_offset_base;
489  y_offset += y_offset_base;
490  }
491 }
492 
493 
494 namespace
495 {
496  //Helper struct that finds all units teams whose planned actions are currently visible
497  //Only used by manager::pre_draw().
498  //Note that this structure is used as a functor.
499  struct move_owners_finder: public visitor
500  {
501 
502  public:
503  move_owners_finder(): move_owners_() { }
504 
505  void operator()(action* action) {
506  action->accept(*this);
507  }
508 
509  const std::set<std::size_t>& get_units_owning_moves() {
510  return move_owners_;
511  }
512 
513  virtual void visit(move_ptr move) {
514  if(std::size_t id = move->get_unit_id()) {
515  move_owners_.insert(id);
516  }
517  }
518 
519  virtual void visit(attack_ptr attack) {
520  //also add attacks if they have an associated move
521  if(attack->get_route().steps.size() >= 2) {
522  if(std::size_t id = attack->get_unit_id()) {
523  move_owners_.insert(id);
524  }
525  }
526  }
527  virtual void visit(recruit_ptr){}
528  virtual void visit(recall_ptr){}
529  virtual void visit(suppose_dead_ptr){}
530 
531  private:
532  std::set<std::size_t> move_owners_;
533  };
534 }
535 
537 {
538  if (can_modify_game_state() && has_actions() && unit_map_lock_.use_count() == 1) {
539  move_owners_finder move_finder;
540  for_each_action(std::ref(move_finder));
541  units_owning_moves_ = move_finder.get_units_owning_moves();
542 
543  for (std::size_t unit_id : units_owning_moves_) {
544  unit_map::iterator unit_iter = resources::gameboard->units().find(unit_id);
545  if(unit_iter.valid()) {
546  ghost_owner_unit(&*unit_iter);
547  }
548  }
549  }
550 }
551 
553 {
554  for (std::size_t unit_id : units_owning_moves_)
555  {
556  unit_map::iterator unit_iter = resources::gameboard->units().find(unit_id);
557  if (unit_iter.valid()) {
558  unghost_owner_unit(&*unit_iter);
559  }
560  }
561  units_owning_moves_.clear();
562 }
563 
565 {
566  /**
567  * IMPORTANT: none of the code in this method can call anything which would
568  * cause a hex to be invalidated (i.e. by calling in turn any variant of display::invalidate()).
569  * Doing so messes up the iterator currently going over the list of invalidated hexes to draw.
570  */
571 
573  {
574  //call draw() for all actions
575  for_each_action(std::bind(&action::draw_hex, std::placeholders::_1, hex));
576 
577  //Info about the action numbers to be displayed on screen.
578  side_actions::numbers_t numbers;
579  for (team& t : resources::gameboard->teams())
580  {
581  side_actions& sa = *t.get_side_actions();
582  if(!sa.hidden())
583  sa.get_numbers(hex,numbers);
584  }
585  draw_numbers(hex,numbers); // helper fcn
586  }
587 
588 }
589 
591 {
592 
594  bool hex_has_unit;
595  { wb::future_map future; // start planned unit map scope
596  hex_has_unit = resources::gameboard->units().find(selected_hex) != resources::gameboard->units().end();
597  } // end planned unit map scope
598  if (!((selected_hex.valid() && hex_has_unit)
600  {
601  if (!highlighter_)
602  {
604  }
605  highlighter_->set_mouseover_hex(hex);
606  highlighter_->highlight();
607  }
608 }
609 
611 {
612  DBG_WB << "Manager received gamestate change notification.";
613  // if on_gamestate_change() is called while the future unit map is applied,
614  // it means that the future unit map scope is used where it shouldn't be.
615  assert(!planned_unit_map_active_);
616  // Set mutated flag so action queue gets validated on next future map build
617  gamestate_mutated_ = true;
618  //Clear exclusive draws that might not get a chance to be cleared the normal way
620 }
621 
623 {
624  std::size_t size = net_buffer_.size();
625  for(std::size_t team_index=0; team_index<size; ++team_index)
626  {
627  config& buf_cfg = net_buffer_[team_index];
628 
629  if(buf_cfg.empty())
630  continue;
631 
632  config packet;
633  config& wb_cfg = packet.add_child("whiteboard",buf_cfg);
634  wb_cfg["side"] = static_cast<int>(team_index+1);
635  wb_cfg["to_sides"] = resources::gameboard->teams().at(team_index).allied_human_teams();
636 
637  buf_cfg.clear();
638 
639  resources::controller->send_to_wesnothd(packet, "whiteboard");
640 
641  std::size_t count = wb_cfg.child_count("net_cmd");
642  LOG_WB << "Side " << (team_index+1) << " sent wb data (" << count << " cmds).";
643  }
644 }
645 
647 {
648  if(auto wb_cfg = cfg.optional_child("whiteboard"))
649  {
650  std::size_t count = wb_cfg->child_count("net_cmd");
651  LOG_WB << "Received wb data (" << count << ").";
652 
653  team& team_from = resources::gameboard->get_team(wb_cfg["side"]);
654  for(const side_actions::net_cmd& cmd : wb_cfg->child_range("net_cmd"))
655  team_from.get_side_actions()->execute_net_cmd(cmd);
656  }
657 }
658 
659 void manager::queue_net_cmd(std::size_t team_index, const side_actions::net_cmd& cmd)
660 {
661  assert(team_index < net_buffer_.size());
662  net_buffer_[team_index].add_child("net_cmd",cmd);
663 }
664 
666 {
667  route_.reset();
668 
669  /*
670  * CHECK PRE-CONDITIONS
671  * (This section has multiple return paths.)
672  */
673 
674  if ( !active_ || !can_modify_game_state() )
675  return;
676 
677  const pathfind::marked_route& route =
679 
680  if (route.steps.empty() || route.steps.size() < 2) return;
681 
682  unit* temp_moved_unit =
683  future_visible_unit(resources::controller->get_mouse_handler_base().get_selected_hex(), viewer_side());
684  if (!temp_moved_unit) temp_moved_unit =
685  future_visible_unit(resources::controller->get_mouse_handler_base().get_last_hex(), viewer_side());
686  if (!temp_moved_unit) return;
687  if (temp_moved_unit->side() != display::get_singleton()->viewing_side()) return;
688 
689  /*
690  * DONE CHECKING PRE-CONDITIONS, CREATE THE TEMP MOVE
691  * (This section has only one return path.)
692  */
693 
694  temp_move_unit_underlying_id_ = temp_moved_unit->underlying_id();
695 
696  //@todo: May be appropriate to replace these separate components by a temporary
697  // wb::move object
698 
699  route_.reset(new pathfind::marked_route(route));
700  //NOTE: route_->steps.back() = dst, and route_->steps.front() = src
701 
702  std::size_t turn = 0;
703  std::vector<map_location>::iterator prev_itor = route.steps.begin();
704  std::vector<map_location>::iterator curr_itor = prev_itor;
705  std::vector<map_location>::iterator end_itor = route.steps.end();
706  for(; curr_itor!=end_itor; ++curr_itor)
707  {
708  const map_location& hex = *curr_itor;
709 
710  //search for end-of-turn marks
711  pathfind::marked_route::mark_map::const_iterator w =
712  route.marks.find(hex);
713  if(w != route.marks.end() && w->second.turns > 0)
714  {
715  turn = w->second.turns-1;
716 
717  if(turn >= move_arrows_.size())
718  move_arrows_.resize(turn+1);
719  if(turn >= fake_units_.size())
720  fake_units_.resize(turn+1);
721 
722  arrow_ptr& move_arrow = move_arrows_[turn];
723  fake_unit_ptr& fake_unit = fake_units_[turn];
724 
725  if(!move_arrow)
726  {
727  // Create temp arrow
728  move_arrow.reset(new arrow());
729  move_arrow->set_color(team::get_side_color_id(
730  viewer_side()));
731  move_arrow->set_style(arrow::STYLE_HIGHLIGHTED);
732  }
733 
734  arrow_path_t path(prev_itor,curr_itor+1);
735  move_arrow->set_path(path);
736 
737  if(path.size() >= 2)
738  {
739  // Bug #20299 demonstrates a situation where an incorrect fake/ghosted unit can be used.
740  // So before assuming that a pre-existing fake_unit can be re-used, check that its ID matches the unit being moved.
741  if(!fake_unit || fake_unit.get_unit_ptr()->id() != temp_moved_unit->id())
742  {
743  // Create temp ghost unit
744  fake_unit = fake_unit_ptr(temp_moved_unit->clone(), resources::fake_units);
745  fake_unit->anim_comp().set_ghosted(true);
746  }
747 
748  unit_display::move_unit(path, fake_unit.get_unit_ptr(), false); //get facing right
749  fake_unit->anim_comp().invalidate(*game_display::get_singleton());
750  fake_unit->set_location(*curr_itor);
751  fake_unit->anim_comp().set_ghosted(true);
752  }
753  else //zero-hex path -- don't bother drawing a fake unit
754  fake_unit.reset();
755 
756  prev_itor = curr_itor;
757  }
758  }
759  //in case path shortens on next step and one ghosted unit has to be removed
760  int ind = fake_units_.size() - 1;
761  fake_units_[ind]->anim_comp().invalidate(*game_display::get_singleton());
762  //toss out old arrows and fake units
763  move_arrows_.resize(turn+1);
764  fake_units_.resize(turn+1);
765 }
766 
768 {
769  move_arrows_.clear();
770  for(const fake_unit_ptr& tmp : fake_units_) {
771  if(tmp) {
772  tmp->anim_comp().invalidate(*game_display::get_singleton());
773  }
774  }
775  fake_units_.clear();
776  route_.reset();
778 }
779 
781 {
782  if (has_temp_move() && !executing_actions_ && !resources::controller->is_linger_mode())
783  {
784  side_actions& sa = *viewer_actions();
785  unit* u = future_visible_unit(route_->steps.front());
786  assert(u);
787  std::size_t first_turn = sa.get_turn_num_of(*u);
788 
790 
791  assert(move_arrows_.size() == fake_units_.size());
792  std::size_t size = move_arrows_.size();
793  for(std::size_t i=0; i<size; ++i)
794  {
795  arrow_ptr move_arrow = move_arrows_[i];
796  if(!arrow::valid_path(move_arrow->get_path()))
797  continue;
798 
799  std::size_t turn = first_turn + i;
800 
801  //@todo Using a marked_route here is wrong, since right now it's not marked
802  //either switch over to a plain route for planned moves, or mark it correctly
804  route.steps = move_arrow->get_path();
805  // path_cost() is incomplete as it for example doesn't handle skirmisher, we let the move action generate the costs on it own.
806  // route.move_cost = path_cost(route.steps,*u);
807  route.move_cost = -1;
808 
809  sa.queue_move(turn, *u, route, move_arrow, std::move(fake_units_[i]));
810  }
811  erase_temp_move();
812 
813  LOG_WB << *viewer_actions();
814  print_help_once();
815  }
816 }
817 
819 {
821 }
822 
823 void manager::save_temp_attack(const map_location& attacker_loc, const map_location& defender_loc, int weapon_choice)
824 {
825  if (active_ && !executing_actions_ && !resources::controller->is_linger_mode())
826  {
827  assert(weapon_choice >= 0);
828 
829  arrow_ptr move_arrow;
830  fake_unit_ptr* fake_unit = nullptr;
831  map_location source_hex;
832 
833  if (route_ && !route_->steps.empty())
834  {
835  //attack-move
836  assert(move_arrows_.size() == 1);
837  assert(fake_units_.size() == 1);
838  move_arrow = move_arrows_.front();
839  fake_unit = &fake_units_.front();
840 
841  assert(route_->steps.back() == attacker_loc);
842  source_hex = route_->steps.front();
843 
844  (**fake_unit).anim_comp().set_disabled_ghosted(true);
845  }
846  else
847  {
848  //simple attack
849  move_arrow.reset(new arrow);
850  source_hex = attacker_loc;
851  route_.reset(new pathfind::marked_route);
852  // We'll pass as parameter a one-hex route with no marks.
853  route_->steps.push_back(attacker_loc);
854  }
855 
856  unit* attacking_unit = future_visible_unit(source_hex);
857  assert(attacking_unit);
858 
860 
861  side_actions& sa = *viewer_actions();
862  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());
863 
864  print_help_once();
865 
866  display::get_singleton()->invalidate(defender_loc);
867  display::get_singleton()->invalidate(attacker_loc);
868  erase_temp_move();
869  LOG_WB << *viewer_actions();
870  }
871 }
872 
873 bool manager::save_recruit(const std::string& name, int side_num, const map_location& recruit_hex)
874 {
875  bool created_planned_recruit = false;
876 
877  if (active_ && !executing_actions_ && !resources::controller->is_linger_mode()) {
878  if (side_num != display::get_singleton()->viewing_side())
879  {
880  LOG_WB <<"manager::save_recruit called for a different side than viewing side.";
881  created_planned_recruit = false;
882  }
883  else
884  {
885  side_actions& sa = *viewer_actions();
886  unit* recruiter;
887  { wb::future_map raii;
888  recruiter = find_recruiter(side_num-1,recruit_hex);
889  } // end planned unit map scope
890  assert(recruiter);
891  std::size_t turn = sa.get_turn_num_of(*recruiter);
892  sa.queue_recruit(turn,name,recruit_hex);
893  created_planned_recruit = true;
894 
895  print_help_once();
896  }
897  }
898  return created_planned_recruit;
899 }
900 
901 bool manager::save_recall(const unit& unit, int side_num, const map_location& recall_hex)
902 {
903  bool created_planned_recall = false;
904 
905  if (active_ && !executing_actions_ && !resources::controller->is_linger_mode())
906  {
907  if (side_num != display::get_singleton()->viewing_side())
908  {
909  LOG_WB <<"manager::save_recall called for a different side than viewing side.";
910  created_planned_recall = false;
911  }
912  else
913  {
914  side_actions& sa = *viewer_actions();
915  std::size_t turn = sa.num_turns();
916  if(turn > 0)
917  --turn;
918  sa.queue_recall(turn,unit,recall_hex);
919  created_planned_recall = true;
920 
921  print_help_once();
922  }
923  }
924  return created_planned_recall;
925 }
926 
927 void manager::save_suppose_dead(unit& curr_unit, const map_location& loc)
928 {
929  if(active_ && !executing_actions_ && !resources::controller->is_linger_mode())
930  {
932  side_actions& sa = *viewer_actions();
933  sa.queue_suppose_dead(sa.get_turn_num_of(curr_unit),curr_unit,loc);
934  }
935 }
936 
938 {
941  {
942  erase_temp_move();
943 
944  //For exception-safety, this struct sets executing_actions_ to false on destruction.
946 
948  unit const* selected_unit = future_visible_unit(resources::controller->get_mouse_handler_base().get_selected_hex(), viewer_side());
949 
950  auto check_action = [&](side_actions::iterator i) {
951  it = i;
952  return it != viewer_actions()->end() && it < viewer_actions()->turn_end(0);
953  };
954 
955  if (selected_unit && check_action(viewer_actions()->find_first_action_of(*selected_unit)))
956  {
957  executing_actions_ = true;
958  viewer_actions()->execute(it);
959  }
960  else if (highlighter_ && check_action(viewer_actions()->get_position_of(highlighter_->get_execute_target())))
961  {
962  executing_actions_ = true;
963  viewer_actions()->execute(it);
964  }
965  else //we already check above for viewer_actions()->empty()
966  {
967  executing_actions_ = true;
968  viewer_actions()->execute_next();
969  }
970  } //Finalizer struct sets executing_actions_ to false
971 }
972 
974 {
975  preparing_to_end_turn_ = true;
976  return execute_all_actions();
977 }
978 
980 {
981  if (has_planned_unit_map())
982  {
983  ERR_WB << "Modifying action queue while temp modifiers are applied1!!!";
984  }
985  //exception-safety: finalizers set variables to false on destruction
986  //i.e. when method exits naturally or exception is thrown
987  variable_finalizer<bool> finalize_executing_actions(executing_actions_, false);
988  variable_finalizer<bool> finalize_executing_all_actions(executing_all_actions_, false);
989 
991  if(viewer_actions()->empty() || viewer_actions()->turn_size(0) == 0)
992  {
993  //No actions to execute, job done.
994  return true;
995  }
996 
998 
999  erase_temp_move();
1000 
1001  // Build unit map once to ensure spent gold and other calculations are refreshed
1003  assert(has_planned_unit_map());
1005 
1006  executing_actions_ = true;
1007  executing_all_actions_ = true;
1008 
1010 
1011  if (has_planned_unit_map())
1012  {
1013  ERR_WB << "Modifying action queue while temp modifiers are applied!!!";
1014  }
1015 
1016  //LOG_WB << "Before executing all actions, " << *sa;
1017 
1018  while (sa->turn_begin(0) != sa->turn_end(0))
1019  {
1020  bool action_successful = sa->execute(sa->begin());
1021 
1022  // Interrupt on incomplete action
1023  if (!action_successful)
1024  {
1025  return false;
1026  }
1027  }
1028  return true;
1029 }
1030 
1032 {
1035  erase_temp_move();
1036 
1038  side_actions::iterator it = viewer_actions()->end();
1039  unit const* selected_unit = future_visible_unit(resources::controller->get_mouse_handler_base().get_selected_hex(), viewer_side());
1040  if(selected_unit && (it = viewer_actions()->find_last_action_of(*selected_unit)) != viewer_actions()->end()) {
1041  viewer_actions()->remove_action(it);
1042  // TODO: Shouldn't we probably deselect the unit at this point?
1043  } else if(highlighter_ && (action = highlighter_->get_delete_target()) && (it = viewer_actions()->get_position_of(action)) != viewer_actions()->end()) {
1044  viewer_actions()->remove_action(it);
1046  highlighter_->set_mouseover_hex(highlighter_->get_mouseover_hex());
1047  highlighter_->highlight();
1048  } else { //we already check above for viewer_actions()->empty()
1049  it = (viewer_actions()->end() - 1);
1050  action = *it;
1051  viewer_actions()->remove_action(it);
1053  }
1054  }
1055 }
1056 
1058 {
1061  action_ptr action = highlighter_->get_bump_target();
1062  if(action) {
1063  viewer_actions()->bump_earlier(viewer_actions()->get_position_of(action));
1064  validate_viewer_actions(); // Redraw arrows
1065  }
1066  }
1067 }
1068 
1070 {
1073  action_ptr action = highlighter_->get_bump_target();
1074  if(action) {
1075  viewer_actions()->bump_later(viewer_actions()->get_position_of(action));
1076  validate_viewer_actions(); // Redraw arrows
1077  }
1078  }
1079 }
1080 
1082 {
1083  assert(resources::gameboard);
1084  return wb::has_actions();
1085 }
1086 
1088 {
1089  assert(unit != nullptr);
1090  assert(resources::gameboard);
1091  return viewer_actions()->unit_has_actions(*unit);
1092 }
1093 
1095 {
1097  return 0;
1098 
1099  return resources::gameboard->get_team(side).get_side_actions()->get_gold_spent();
1100 }
1101 
1103 {
1105 }
1106 
1108 {
1109  int v_side = viewer_side();
1110 
1111  int selection = 0;
1112 
1113  std::vector<team*> allies;
1114  std::vector<std::string> options;
1115  utils::string_map t_vars;
1116 
1117  options.emplace_back(_("SHOW ALL allies’ plans"));
1118  options.emplace_back(_("HIDE ALL allies’ plans"));
1119 
1120  //populate list of networked allies
1121  for(team &t : resources::gameboard->teams())
1122  {
1123  //Exclude enemies, AIs, and local players
1124  if(t.is_enemy(v_side) || !t.is_network())
1125  continue;
1126 
1127  allies.push_back(&t);
1128 
1129  t_vars["player"] = t.current_player();
1130  std::size_t t_index = t.side()-1;
1131  if(team_plans_hidden_[t_index])
1132  options.emplace_back(VGETTEXT("Show plans for $player", t_vars));
1133  else
1134  options.emplace_back(VGETTEXT("Hide plans for $player", t_vars));
1135  }
1136 
1137  gui2::dialogs::simple_item_selector dlg("", _("Whiteboard Options"), options);
1138  dlg.show();
1139  selection = dlg.selected_index();
1140 
1141  if(selection == -1)
1142  return;
1143 
1144  switch(selection)
1145  {
1146  case 0:
1147  for(team* t : allies) {
1148  team_plans_hidden_[t->side()-1]=false;
1149  }
1150  break;
1151  case 1:
1152  for(team* t : allies) {
1153  team_plans_hidden_[t->side()-1]=true;
1154  }
1155  break;
1156  default:
1157  if(selection > 1)
1158  {
1159  std::size_t t_index = allies[selection-2]->side()-1;
1160  //toggle ...
1161  bool hidden = team_plans_hidden_[t_index];
1162  team_plans_hidden_[t_index] = !hidden;
1163  }
1164  break;
1165  }
1167 }
1168 
1170 {
1171  if (!can_modify_game_state()) {
1172  LOG_WB << "Not building planned unit map: cannot modify game state now.";
1173  return;
1174  }
1175  //any more than one reference means a lock on unit map was requested
1176  if(unit_map_lock_.use_count() != 1) {
1177  LOG_WB << "Not building planned unit map: unit map locked.";
1178  return;
1179  }
1181  WRN_WB << "Not building planned unit map: already set.";
1182  return;
1183  }
1184 
1185  log_scope2(log_whiteboard, "Building planned unit map");
1186  mapbuilder_.reset(new mapbuilder(resources::gameboard->units()));
1187  mapbuilder_->build_map();
1188 
1189  planned_unit_map_active_ = true;
1190 }
1191 
1193 {
1195  {
1196  assert(!executing_actions_);
1197  assert(!wait_for_side_init_);
1198  if(mapbuilder_)
1199  {
1200  log_scope2(log_whiteboard, "Restoring regular unit map.");
1201  mapbuilder_.reset();
1202  }
1203  planned_unit_map_active_ = false;
1204  }
1205  else
1206  {
1207  LOG_WB << "Not disabling planned unit map: already disabled.";
1208  }
1209 }
1210 
1212 {
1213  if (gamestate_mutated_) {
1215  }
1216 }
1217 
1219  initial_planned_unit_map_(resources::whiteboard && resources::whiteboard->has_planned_unit_map())
1220 {
1221  if (!resources::whiteboard)
1222  return;
1224  resources::whiteboard->set_planned_unit_map();
1225  // check if if unit map was successfully applied
1226  if (!resources::whiteboard->has_planned_unit_map()) {
1227  DBG_WB << "Scoped future unit map failed to apply.";
1228  }
1229 }
1230 
1232 {
1233  try {
1234  if (!resources::whiteboard)
1235  return;
1236  if (!initial_planned_unit_map_ && resources::whiteboard->has_planned_unit_map())
1237  resources::whiteboard->set_real_unit_map();
1238  } catch (...) {}
1239 }
1240 
1242  initial_planned_unit_map_(resources::whiteboard && resources::whiteboard->has_planned_unit_map()),
1243  whiteboard_active_(resources::whiteboard && resources::whiteboard->is_active())
1244 {
1245  if (!resources::whiteboard)
1246  return;
1247  if (!whiteboard_active_)
1248  return;
1250  resources::whiteboard->set_planned_unit_map();
1251  // check if if unit map was successfully applied
1252  if (!resources::whiteboard->has_planned_unit_map()) {
1253  DBG_WB << "Scoped future unit map failed to apply.";
1254  }
1255 }
1256 
1258 {
1259  try {
1260  if (!resources::whiteboard)
1261  return;
1262  if (!initial_planned_unit_map_ && resources::whiteboard->has_planned_unit_map())
1263  resources::whiteboard->set_real_unit_map();
1264  } catch (...) {}
1265 }
1266 
1267 
1269  initial_planned_unit_map_(resources::whiteboard && resources::whiteboard->has_planned_unit_map()),
1270  unit_map_lock_(resources::whiteboard ? resources::whiteboard->unit_map_lock_ : std::make_shared<bool>(false))
1271 {
1272  if (!resources::whiteboard)
1273  return;
1275  resources::whiteboard->set_real_unit_map();
1276 }
1277 
1279 {
1280  if (!resources::whiteboard)
1281  return;
1282  assert(!resources::whiteboard->has_planned_unit_map());
1284  {
1285  resources::whiteboard->set_planned_unit_map();
1286  }
1287 }
1288 
1289 } // end namespace wb
const std::vector< map_location > & route_
Definition: move.cpp:294
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:201
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:148
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
std::size_t child_count(config_key_type key) const
Definition: config.cpp:297
child_itors child_range(config_key_type key)
Definition: config.cpp:273
bool empty() const
Definition: config.cpp:852
void clear()
Definition: config.cpp:831
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:385
config & add_child(config_key_type key)
Definition: config.cpp:441
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:1476
int viewing_side() const
The 1-based equivalent of the 0-based viewing_team() function.
Definition: display.hpp:131
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:3145
@ LAYER_ACTIONS_NUMBERING
Move numbering for the whiteboard.
Definition: display.hpp:851
void clear_exclusive_draws()
Cancels all the exclusive draw requests.
Definition: display.hpp:148
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:102
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:79
team & get_team(int i)
Definition: game_board.hpp:91
virtual const unit_map & units() const override
Definition: game_board.hpp:106
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:74
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:1069
void on_viewer_change(std::size_t team_index)
Definition: manager.cpp:392
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:973
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:427
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:659
void contextual_bump_up_action()
Moves the action determined by the UI toward the beginning of the queue
Definition: manager.cpp:1057
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:1169
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:927
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:1094
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:1192
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:434
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:564
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:823
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:646
void validate_actions_if_needed()
Definition: manager.cpp:1211
void options_dlg()
Displays the whiteboard options dialog.
Definition: manager.cpp:1107
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:398
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:552
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:901
void update_plan_hiding()
Definition: manager.cpp:389
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:1031
void create_temp_move()
Creates a temporary visual arrow, that follows the cursor, for move creation purposes.
Definition: manager.cpp:665
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:622
void save_temp_move()
Creates a move action for the current side, and erases the temp move.
Definition: manager.cpp:780
bool should_clear_undo() const
Determines whether or not the undo_stack should be cleared.
Definition: manager.cpp:1102
void validate_viewer_actions()
Validates all actions of the current viewing side.
Definition: manager.cpp:444
bool unit_has_actions(unit const *unit) const
Checks whether the specified unit has at least one planned action.
Definition: manager.cpp:1087
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:873
void on_gamestate_change()
Definition: manager.cpp:610
bool inverted_behavior_
Definition: manager.hpp:205
void on_mouseover_change(const map_location &hex)
Definition: manager.cpp:590
void erase_temp_move()
Erase the temporary arrow.
Definition: manager.cpp:767
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:979
void pre_draw()
Called from the display before drawing.
Definition: manager.cpp:536
void contextual_execute()
Executes first action in the queue for current side.
Definition: manager.cpp:937
unit_map::iterator get_temp_move_unit() const
Definition: manager.cpp:818
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:1081
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:93
#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: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:275
std::string path
Definition: filesystem.cpp:83
static bool is_active(const widget *wgt)
Definition: window.cpp:1281
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:433
bool enable_whiteboard_mode_on_start()
Definition: game.cpp:423
const config & options()
Definition: game.cpp:552
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:506
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:55
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:183
void ghost_owner_unit(unit *unit)
Definition: utility.cpp:156
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:77
std::size_t viewer_team()
Definition: utility.cpp:38
int viewer_side()
Definition: utility.cpp:43
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:106
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:62
side_actions_ptr viewer_actions()
Definition: utility.cpp:48
bool has_actions()
Return whether the whiteboard has actions.
Definition: utility.cpp:168
static void draw_numbers(const map_location &hex, side_actions::numbers_t numbers)
Definition: manager.cpp:456
std::shared_ptr< action const > action_const_ptr
Definition: typedefs.hpp:63
void unghost_owner_unit(unit *unit)
Definition: utility.cpp:162
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: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.