The Battle for Wesnoth  1.15.1+dev
manager.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2018 by Gabriel Morin <gabrielmorin (at) gmail (dot) com>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13  */
14 
15 /**
16  * @file
17  */
18 
19 #include "whiteboard/manager.hpp"
20 
21 #include "whiteboard/action.hpp"
24 #include "whiteboard/move.hpp"
25 #include "whiteboard/attack.hpp"
26 #include "whiteboard/recall.hpp"
27 #include "whiteboard/recruit.hpp"
29 #include "whiteboard/utility.hpp"
30 
31 #include "actions/create.hpp"
32 #include "actions/undo.hpp"
33 #include "arrow.hpp"
34 #include "chat_events.hpp"
35 #include "fake_unit_manager.hpp"
36 #include "fake_unit_ptr.hpp"
37 #include "formula/string_utils.hpp"
38 #include "game_board.hpp"
39 #include "preferences/game.hpp"
40 #include "game_state.hpp"
41 #include "gettext.hpp"
43 #include "key.hpp"
44 #include "pathfind/pathfind.hpp"
45 #include "play_controller.hpp"
46 #include "replay_helper.hpp"
47 #include "resources.hpp"
48 #include "synced_context.hpp"
49 #include "team.hpp"
50 #include "units/unit.hpp"
52 #include "units/udisplay.hpp"
53 
54 #include "utils/functional.hpp"
55 
56 #include <sstream>
57 
58 namespace wb {
59 
61  active_(false),
62  inverted_behavior_(false),
63  self_activate_once_(true),
64 #if 0
65  print_help_once_(true),
66 #endif
67  wait_for_side_init_(true),
68  planned_unit_map_active_(false),
69  executing_actions_(false),
70  executing_all_actions_(false),
71  preparing_to_end_turn_(false),
72  gamestate_mutated_(false),
73  activation_state_lock_(new bool),
74  unit_map_lock_(new bool),
75  mapbuilder_(),
76  highlighter_(),
77  route_(),
78  move_arrows_(),
79  fake_units_(),
80  temp_move_unit_underlying_id_(0),
81  key_poller_(new CKey),
82  hidden_unit_hexes_(),
83  net_buffer_(resources::gameboard->teams().size()),
84  team_plans_hidden_(resources::gameboard->teams().size()),
85  units_owning_moves_()
86 {
88  team_plans_hidden_.flip();
89  }
90  LOG_WB << "Manager initialized.\n";
91 }
92 
94 {
95  LOG_WB << "Manager destroyed.\n";
96 }
97 
98 //Used for chat-spamming debug info
99 #if 0
100 static void print_to_chat(const std::string& title, const std::string& message)
101 {
102  display::get_singleton()->add_chat_message(std::time(nullptr), title, 0, message,
104 }
105 #endif
106 
108 {
109 #if 0
110  if (!print_help_once_)
111  return;
112  else
113  print_help_once_ = false;
114 
115  print_to_chat("whiteboard", std::string("Type :wb to activate/deactivate planning mode.")
116  + " Hold TAB to temporarily deactivate/activate it.");
117  std::stringstream hotkeys;
118  const hotkey::hotkey_item& hk_execute = hotkey::get_hotkey(hotkey::HOTKEY_WB_EXECUTE_ACTION);
119  if(!hk_execute.null()) {
120  //print_to_chat("[execute action]", "'" + hk_execute.get_name() + "'");
121  hotkeys << "Execute: " << hk_execute.get_name() << ", ";
122  }
123  const hotkey::hotkey_item& hk_execute_all = hotkey::get_hotkey(hotkey::HOTKEY_WB_EXECUTE_ALL_ACTIONS);
124  if(!hk_execute_all.null()) {
125  //print_to_chat("[execute action]", "'" + hk_execute_all.get_name() + "'");
126  hotkeys << "Execute all: " << hk_execute_all.get_name() << ", ";
127  }
128  const hotkey::hotkey_item& hk_delete = hotkey::get_hotkey(hotkey::HOTKEY_WB_DELETE_ACTION);
129  if(!hk_delete.null()) {
130  //print_to_chat("[delete action]", "'" + hk_delete.get_name() + "'");
131  hotkeys << "Delete: " << hk_delete.get_name() << ", ";
132  }
133  const hotkey::hotkey_item& hk_bump_up = hotkey::get_hotkey(hotkey::HOTKEY_WB_BUMP_UP_ACTION);
134  if(!hk_bump_up.null()) {
135  //print_to_chat("[move action earlier in queue]", "'" + hk_bump_up.get_name() + "'");
136  hotkeys << "Move earlier: " << hk_bump_up.get_name() << ", ";
137  }
138  const hotkey::hotkey_item& hk_bump_down = hotkey::get_hotkey(hotkey::HOTKEY_WB_BUMP_DOWN_ACTION);
139  if(!hk_bump_down.null()) {
140  //print_to_chat("[move action later in queue]", "'" + hk_bump_down.get_name() + "'");
141  hotkeys << "Move later: " << hk_bump_down.get_name() << ", ";
142  }
143  print_to_chat("HOTKEYS:", hotkeys.str() + "\n");
144 #endif
145 }
146 
148 {
150  || resources::gameboard == nullptr
152  || resources::gameboard->is_observer()
153  || resources::controller->is_linger_mode())
154  {
155  return false;
156  }
157  else
158  {
159  return true;
160  }
161 }
162 
164 {
165  //any more than one reference means a lock on whiteboard state was requested
166  if(activation_state_lock_.use_count() != 1)
167  return false;
168 
169  return can_modify_game_state();
170 }
171 
172 void manager::set_active(bool active)
173 {
174  if(!can_activate())
175  {
176  active_ = false;
177  LOG_WB << "Whiteboard can't be activated now.\n";
178  }
179  else if (active != active_)
180  {
181  active_ = active;
182  erase_temp_move();
183 
184  if (active_)
185  {
186  if(should_clear_undo()) {
187  if(!resources::controller->current_team().auto_shroud_updates()) {
190  }
192  }
194  LOG_WB << "Whiteboard activated! " << *viewer_actions() << "\n";
196  } else {
197  LOG_WB << "Whiteboard deactivated!\n";
198  }
199  }
200 }
201 
203 {
204  //any more than one reference means a lock on whiteboard state was requested
205  if(activation_state_lock_.use_count() != 1)
206  return;
207 
208  bool block_whiteboard_activation = false;
209  if(!can_activate())
210  {
211  block_whiteboard_activation = true;
212  }
213 
214  if (invert)
215  {
216  if (!inverted_behavior_)
217  {
218  if (active_)
219  {
220  DBG_WB << "Whiteboard deactivated temporarily.\n";
221  inverted_behavior_ = true;
222  set_active(false);
223  }
224  else if (!block_whiteboard_activation)
225  {
226  DBG_WB << "Whiteboard activated temporarily.\n";
227  inverted_behavior_ = true;
228  set_active(true);
229  }
230  }
231  }
232  else
233  {
234  if (inverted_behavior_)
235  {
236  if (active_)
237  {
238  DBG_WB << "Whiteboard set back to deactivated status.\n";
239  inverted_behavior_ = false;
240  set_active(false);
241  }
242  else if (!block_whiteboard_activation)
243  {
244  DBG_WB << "Whiteboard set back to activated status.\n";
245  inverted_behavior_ = false;
246  set_active(true);
247  }
248  }
249  }
250 }
251 
253 {
255  && viewer_actions()->turn_size(0) > 0;
256 }
257 
259 {
260  return can_modify_game_state() && !viewer_actions()->empty();
261 }
262 
264 {
265  return can_enable_modifier_hotkeys() && highlighter_ && highlighter_->get_bump_target();
266 }
267 
268 bool manager::allow_leader_to_move(const unit& leader) const
269 {
270  if(!has_actions())
271  return true;
272 
273  //Look for another leader on another keep in the same castle
274  { wb::future_map future; // start planned unit map scope
275 
276  // TODO: when the game executes all whiteboard moves at turn end applying the future map
277  // will fail because we are currently executing actions, and if one of those actions
278  // was a movement of the leader this function will be called, resulting the the error
279  // mesage below, we silence that message for now by adding (!executing_actions_)
280  //
281  // Also this check is generally flawed, for example it could happen that the leader found
282  // by find_backup_leader would be moved to that location _after_ the unit would be recruited
283  // It could also happen that the original leader can be moved back to that location before
284  // the unit is recruited.
286  WRN_WB << "Unable to build future map to determine whether leader's allowed to move." << std::endl;
287  }
288  if(find_backup_leader(leader))
289  return true;
290  } // end planned unit map scope
291 
292  if(viewer_actions()->empty()) {
293  return true;
294  }
295 
296  //Look for planned recruits that depend on this leader
298  {
299  recruit_const_ptr recruit = std::dynamic_pointer_cast<class recruit const>(action);
300  recall_const_ptr recall = std::dynamic_pointer_cast<class recall const>(action);
301  if(recruit || recall)
302  {
303  map_location const target_hex = recruit?recruit->get_recruit_hex():recall->get_recall_hex();
304  if (dynamic_cast<game_state&>(*resources::filter_con).can_recruit_on(leader, target_hex))
305  return false;
306  }
307  }
308  return true;
309 }
310 
312 {
313  //Turn should never start with action auto-execution already enabled!
315 
316  update_plan_hiding(); /* validates actions */
317  wait_for_side_init_ = false;
318  LOG_WB << "on_init_side()\n";
319 
321  {
322  self_activate_once_ = false;
323  set_active(true);
324  }
325 }
326 
328 {
329  preparing_to_end_turn_ = false;
330  wait_for_side_init_ = true;
331  if(side == viewer_side() && !viewer_actions()->empty()) {
332  viewer_actions()->synced_turn_shift();
333  }
334  highlighter_.reset();
335  erase_temp_move();
336  LOG_WB << "on_finish_side_turn()\n";
337 }
338 
340 {
341 }
342 
344 {
345  // The fake unit representing the destination of a chain of planned moves should have the regular animation.
346  // If the last remaining action of the unit that owned this move is a move as well,
347  // adjust its appearance accordingly.
348 
349  side_actions_ptr side_actions = resources::gameboard->teams().at(action->team_index()).get_side_actions();
350 
351  unit_ptr actor = action->get_unit();
352  if(actor) { // The unit might have died following the execution of an attack
353  side_actions::iterator action_it = side_actions->find_last_action_of(*actor);
354  if(action_it != side_actions->end()) {
355  move_ptr move = std::dynamic_pointer_cast<class move>(*action_it);
356  if(move && move->get_fake_unit()) {
357  move->get_fake_unit()->anim_comp().set_standing(true);
358  }
359  }
360  }
361 }
362 
363 static void hide_all_plans()
364 {
365  for(team& t : resources::gameboard->teams()){
366  t.get_side_actions()->hide();
367  }
368 }
369 
370 /* private */
371 void manager::update_plan_hiding(std::size_t team_index)
372 {
373  //We don't control the "viewing" side ... we're probably an observer
374  if(!resources::gameboard->teams().at(team_index).is_local_human())
375  hide_all_plans();
376  else // normal circumstance
377  {
378  for(team& t : resources::gameboard->teams())
379  {
380  //make sure only appropriate teams are hidden
381  if(!t.is_network_human())
382  team_plans_hidden_[t.side()-1] = false;
383 
384  if(t.is_enemy(team_index+1) || team_plans_hidden_[t.side()-1])
385  t.get_side_actions()->hide();
386  else
387  t.get_side_actions()->show();
388  }
389  }
391 }
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 {
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.\n";
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
599  hex_has_unit = resources::gameboard->units().find(selected_hex) != resources::gameboard->units().end();
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.\n";
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).\n";
646  }
647 }
648 
650 {
651  if(const config& wb_cfg = cfg.child("whiteboard"))
652  {
653  std::size_t count = wb_cfg.child_count("net_cmd");
654  LOG_WB << "Received wb data (" << count << ").\n";
655 
656  team& team_from = resources::gameboard->get_team(wb_cfg["side"]);
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_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() << "\n";
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() << "\n";
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_side())
882  {
883  LOG_WB <<"manager::save_recruit called for a different side than viewing side.\n";
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_side())
911  {
912  LOG_WB <<"manager::save_recall called for a different side than viewing side.\n";
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 
952  unit const* selected_unit = future_visible_unit(resources::controller->get_mouse_handler_base().get_selected_hex(), viewer_side());
953  if (selected_unit &&
954  (it = viewer_actions()->find_first_action_of(*selected_unit)) != viewer_actions()->end())
955  {
956  executing_actions_ = true;
957  viewer_actions()->execute(it);
958  }
959  else if (highlighter_ && (action = highlighter_->get_execute_target()) &&
960  (it = viewer_actions()->get_position_of(action)) != viewer_actions()->end())
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!!!" << std::endl;
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!!!" << std::endl;
1014  }
1015 
1016  //LOG_WB << "Before executing all actions, " << *sa << "\n";
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.\n";
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.\n";
1178  return;
1179  }
1181  WRN_WB << "Not building planned unit map: already set." << std::endl;
1182  return;
1183  }
1184 
1185  log_scope2("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("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.\n";
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.\n";
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.\n";
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
bool is_local_ai() const
Definition: team.hpp:268
void clear()
Clears the stack of undoable (and redoable) actions.
Definition: undo.cpp:220
bool self_activate_once_
Definition: manager.hpp:205
container::iterator iterator
bool initial_planned_unit_map_
Definition: manager.hpp:255
play_controller * controller
Definition: resources.cpp:21
#define WRN_WB
Definition: typedefs.hpp:25
void reset()
Reset the internal unit pointer, and deregister from the manager. This fake_unit_ptr is now dissassoc...
std::shared_ptr< wb::side_actions > get_side_actions() const
get the whiteboard planned actions for this team
Definition: team.hpp:385
int viewer_side()
Definition: utility.cpp:45
Move numbering for the whiteboard.
Definition: display.hpp:854
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:420
Arrows destined to be drawn on the map.
void update_plan_hiding()
Definition: manager.cpp:392
unit_iterator end()
Definition: map.hpp:415
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:88
virtual const std::vector< team > & teams() const override
Definition: game_board.hpp:92
std::map< std::string, t_string > string_map
virtual const unit_map & units() const override
Definition: game_board.hpp:114
std::shared_ptr< recruit const > recruit_const_ptr
Definition: typedefs.hpp:72
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:2998
This class represents a single unit of a specific type.
Definition: unit.hpp:99
void on_viewer_change(std::size_t team_index)
Definition: manager.cpp:395
const pathfind::marked_route & get_current_route() const
bool initial_planned_unit_map_
Definition: manager.hpp:286
bool is_network() const
Definition: team.hpp:262
std::set< std::size_t > units_owning_moves_
used to keep track of units owning planned moves for visual ghosting/unghosting
Definition: manager.hpp:246
internal_ptr get_unit_ptr()
Get a copy of the internal unit pointer.
void clear_exclusive_draws()
Cancels all the exclusive draw requests.
Definition: display.hpp:120
std::vector< int > numbers_to_draw
std::shared_ptr< highlighter > highlighter_
Definition: manager.hpp:227
std::vector< arrow_ptr > move_arrows_
Definition: manager.hpp:231
std::shared_ptr< recall const > recall_const_ptr
Definition: typedefs.hpp:74
void set_invert_behavior(bool invert)
Called by the key that temporarily toggles the activated state when held.
Definition: manager.cpp:202
unsigned child_count(config_key_type key) const
Definition: config.cpp:390
void contextual_delete()
Deletes last action in the queue for current side.
Definition: manager.cpp:1031
std::shared_ptr< side_actions > side_actions_ptr
Definition: typedefs.hpp:65
whiteboard_lock activation_state_lock_
Reference counted "lock" to allow preventing whiteboard activation state changes. ...
Definition: manager.hpp:221
child_itors child_range(config_key_type key)
Definition: config.cpp:362
unit * find_recruiter(std::size_t team_index, const map_location &hex)
Definition: utility.cpp:79
void validate_actions_if_needed()
Definition: manager.cpp:1211
std::shared_ptr< attack > attack_ptr
Definition: typedefs.hpp:69
bool has_actions()
Return whether the whiteboard has actions.
Definition: utility.cpp:170
bool hide_whiteboard()
Definition: game.cpp:449
unit_ptr clone() const
Definition: unit.hpp:174
void post_delete_action(action_ptr action)
Handles various cleanup right after removing an action from the queue.
Definition: manager.cpp:343
static config get_auto_shroud(bool turned_on)
Records that the player has toggled automatic shroud updates.
iterator queue_recruit(std::size_t turn_num, const std::string &unit_name, const map_location &recruit_hex)
Queues a recruit to be executed last.
bool is_network_ai() const
Definition: team.hpp:270
int viewing_side() const
Definition: display.hpp:103
STL namespace.
bool can_activate() const
Determine whether the whiteboard can be activated safely.
Definition: manager.cpp:163
void clear()
Definition: config.cpp:863
bool executing_all_actions_
Track whether we&#39;re in the process of executing all actions.
Definition: manager.hpp:214
-file sdl_utils.hpp
void pre_draw()
Called from the display before drawing.
Definition: manager.cpp:539
bool show(const unsigned auto_close_time=0)
Shows the window.
void contextual_bump_down_action()
Moves the action determined by the UI toward the beginning of the queue.
Definition: manager.cpp:1069
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.
static config get_update_shroud()
Records that the player has manually updated fog/shroud.
std::vector< map_location > arrow_path_t
Definition: arrow.hpp:24
void save_temp_move()
Creates a move action for the current side, and erases the temp move.
Definition: manager.cpp:783
void set_active(bool active)
Activates/Deactivates the whiteboard.
Definition: manager.cpp:172
std::vector< std::size_t > team_numbers
std::vector< fake_unit_ptr > fake_units_
Definition: manager.hpp:232
static const std::string STYLE_HIGHLIGHTED
Definition: arrow.hpp:67
void get_numbers(const map_location &hex, numbers_t &result)
Gets called when display is drawing a hex to determine which numbers to draw on it.
void unghost_owner_unit(unit *unit)
Definition: utility.cpp:164
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
bool planned_unit_map_active_
Definition: manager.hpp:210
static bool is_active(const widget *wgt)
Definition: window.cpp:1342
map_location get_selected_hex() const
void on_gamestate_change()
Definition: manager.cpp:613
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
const config & options()
Definition: game.cpp:579
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
static std::string at(const std::string &file, int line)
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:91
virtual void draw_hex(const map_location &hex)=0
Gets called by display when drawing a hex, to allow actions to draw to the screen.
team & get_team(int i)
Definition: game_board.hpp:104
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
whiteboard_lock unit_map_lock_
Reference counted "lock" to prevent the building of the unit map at certain times.
Definition: manager.hpp:223
const std::string & id() const
Gets this unit&#39;s id.
Definition: unit.hpp:344
void set_real_unit_map()
Restore the regular unit map.
Definition: manager.cpp:1192
std::shared_ptr< recruit > recruit_ptr
Definition: typedefs.hpp:71
void options_dlg()
Displays the whiteboard options dialog.
Definition: manager.cpp:1107
void process_network_data(const config &)
Called by turn_info::process_network_data() when network data needs to be processed.
Definition: manager.cpp:649
Arrows destined to be drawn on the map.
Definition: arrow.hpp:29
const hotkey_ptr get_hotkey(const SDL_Event &event)
Iterate through the list of hotkeys and return a hotkey that matches the SDL_Event and the current ke...
Applies the planned unit map for the duration of the struct&#39;s life.
Definition: manager.hpp:251
filter_context * filter_con
Definition: resources.cpp:23
friend struct future_map
Definition: manager.hpp:44
bool valid() const
Definition: location.hpp:93
void contextual_execute()
Executes first action in the queue for current side.
Definition: manager.cpp:940
void on_kill_unit()
Definition: manager.cpp:430
game_board * gameboard
Definition: resources.cpp:20
#define ERR_WB
Definition: typedefs.hpp:24
bool gamestate_mutated_
Track whether the gamestate changed and we need to validate actions.
Definition: manager.hpp:218
bool allow_end_turn()
@ return true if the whiteboard is ready to end turn.
Definition: manager.cpp:973
iterator queue_move(std::size_t turn_num, unit &mover, const pathfind::marked_route &route, arrow_ptr arrow, fake_unit_ptr fake_unit)
Queues a move to be executed last.
unit_map::iterator get_temp_move_unit() const
Definition: manager.cpp:821
Class that handles highlighting planned actions as you hover over them and determine the right target...
Definition: highlighter.hpp:37
std::shared_ptr< action > action_ptr
Definition: typedefs.hpp:61
fake_unit_manager * fake_units
Definition: resources.cpp:30
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
bool is_enemy(int n) const
Definition: team.hpp:243
std::string path
Definition: game_config.cpp:39
void draw_text_in_hex(const map_location &loc, const drawing_layer layer, const std::string &text, std::size_t font_size, color_t color, double x_in_hex=0.5, double y_in_hex=0.5)
Draw text on a hex.
Definition: display.cpp:1514
iterator queue_recall(std::size_t turn_num, const unit &unit, const map_location &recall_hex)
Queues a recall to be executed last.
#define log_scope2(domain, description)
Definition: log.hpp:187
std::unique_ptr< pathfind::marked_route > route_
Definition: manager.hpp:229
virtual fake_unit_ptr get_fake_unit()
Definition: move.hpp:58
void ghost_owner_unit(unit *unit)
Definition: utility.cpp:158
if(win_locale=="af") win_locale
iterator queue_suppose_dead(std::size_t turn_num, unit &curr_unit, const map_location &loc)
Queues a suppose_dead to be executed last.
Structure which holds a single route and marks for special events.
Definition: pathfind.hpp:140
bool preparing_to_end_turn_
true if we&#39;re in the process of executing all action and should end turn once finished.
Definition: manager.hpp:216
friend struct real_map
Definition: manager.hpp:46
bool active_
Tracks whether the whiteboard is active.
Definition: manager.hpp:203
static void hide_all_plans()
Definition: manager.cpp:363
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:185
void on_change_controller(int side, const team &t)
Definition: manager.cpp:401
void on_finish_side_turn(int side)
Definition: manager.cpp:327
bool has_planned_unit_map() const
Whether the planned unit map is currently applied.
Definition: manager.hpp:115
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
static std::string get_side_color_id(unsigned side)
Definition: team.cpp:960
Encapsulates the map of the game.
Definition: location.hpp:42
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
bool wait_for_side_init_
Definition: manager.hpp:209
void post_draw()
Called from the display after drawing.
Definition: manager.cpp:555
unit_iterator find(std::size_t id)
Definition: map.cpp:311
std::shared_ptr< wb::manager > whiteboard
Definition: resources.cpp:33
Various functions related to the creation of units (recruits, recalls, and placed units)...
std::size_t get_turn_num_of(const unit &) const
Determines the appropriate turn number for the next action planned for this unit. ...
virtual bool is_networked_mp() const
std::size_t team_index()
Returns the team index this action queue belongs to.
std::size_t i
Definition: function.cpp:933
int selected_index() const
Returns the selected item index after displaying.
net_cmd make_net_cmd_clear() const
int get_spent_gold_for(int side)
Used to track gold spending per-side when building the planned unit map Is referenced by the top bar ...
Definition: manager.cpp:1094
void erase_temp_move()
Erase the temporary arrow.
Definition: manager.cpp:770
std::vector< config > net_buffer_
net_buffer_[i] = whiteboard network data to be sent "from" teams[i].
Definition: manager.hpp:240
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:147
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:64
std::shared_ptr< suppose_dead > suppose_dead_ptr
Definition: typedefs.hpp:75
std::pair< iterator, iterator > range_t
bool hidden() const
Class that collects and applies unit_map modifications from the actions it visits and reverts all cha...
Definition: mapbuilder.hpp:39
void create_temp_move()
Creates a temporary visual arrow, that follows the cursor, for move creation purposes.
Definition: manager.cpp:668
int w
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
#define LOG_WB
Definition: typedefs.hpp:26
std::shared_ptr< move > move_ptr
Definition: typedefs.hpp:67
bool is_local() const
Definition: team.hpp:261
side_actions_ptr viewer_actions()
Definition: utility.cpp:50
bool unit_has_actions(unit const *unit) const
Checks whether the specified unit has at least one planned action.
Definition: manager.cpp:1087
void contextual_bump_up_action()
Moves the action determined by the UI toward the beginning of the queue.
Definition: manager.cpp:1057
config & add_child(config_key_type key)
Definition: config.cpp:476
bool has_actions() const
Checks whether the whiteboard has any planned action on any team.
Definition: manager.cpp:1081
std::shared_ptr< arrow > arrow_ptr
Definition: typedefs.hpp:59
void on_init_side()
The on_* methods below inform the whiteboard of specific events.
Definition: manager.cpp:311
std::size_t temp_move_unit_underlying_id_
Definition: manager.hpp:233
static bool run_and_throw(const std::string &commandname, const config &data, bool use_undo=true, bool show=true, synced_command::error_handler_function error_handler=default_error_function)
std::set< std::size_t > secondary_numbers
bool save_recall(const unit &unit, int side_num, const map_location &recall_hex)
Creates a recall action for the current side.
Definition: manager.cpp:904
bool is_local_human() const
Definition: team.hpp:267
events::mouse_handler & get_mouse_handler_base() override
Get a reference to a mouse handler member a derived class uses.
boost::intrusive_ptr< unit > unit_ptr
Definition: ptr.hpp:29
double t
Definition: astarsearch.cpp:64
void print_help_once()
Definition: manager.cpp:107
void send_network_data()
Called by replay_network_sender to add whiteboard data to the outgoing network packets.
Definition: manager.cpp:625
static color_t get_side_color(int side)
Definition: team.cpp:948
boost::dynamic_bitset team_plans_hidden_
team_plans_hidden_[i] = whether or not to hide actions from teams[i].
Definition: manager.hpp:243
#define DBG_WB
Definition: typedefs.hpp:27
bool enable_whiteboard_mode_on_start()
Definition: game.cpp:439
Various functions that implement the undoing (and redoing) of in-game commands.
Finalizer class to help with exception safety sets variable to value on destruction.
Definition: utility.hpp:85
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 current_side() const
Returns the number of the side whose turn it is.
static void draw_numbers(const map_location &hex, side_actions::numbers_t numbers)
Definition: manager.cpp:459
bool has_temp_move() const
Informs whether an arrow is being displayed for move creation purposes.
Definition: manager.hpp:136
unit * future_visible_unit(map_location hex, int viewer_side)
Applies the future unit map and.
Definition: utility.cpp:108
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:263
std::shared_ptr< recall > recall_ptr
Definition: typedefs.hpp:73
int side() const
The side this unit belongs to.
Definition: unit.hpp:304
actions::undo_list * undo_stack
Definition: resources.cpp:32
virtual void accept(visitor &v)=0
std::size_t num_turns() const
Returns the number of turns that have plans.
bool should_clear_undo() const
Determines whether or not the undo_stack should be cleared.
Definition: manager.cpp:1102
Abstract base class for all the whiteboard planned actions.
Definition: action.hpp:32
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
bool executing_actions_
Track whenever we&#39;re modifying actions, to avoid dual execution etc.
Definition: manager.hpp:212
bool valid() const
Definition: map.hpp:276
Class that keeps track of all the keys on the keyboard.
Definition: key.hpp:27
std::unique_ptr< mapbuilder > mapbuilder_
Definition: manager.hpp:226
const int font_size
Definition: button.cpp:40
bool inverted_behavior_
Definition: manager.hpp:204
bool execute_all_actions()
Executes all actions for the current turn in sequence.
Definition: manager.cpp:979
static bool valid_path(const arrow_path_t &path)
Checks that the path is not of length 0 or 1.
Definition: arrow.cpp:146
void on_mouseover_change(const map_location &hex)
Definition: manager.cpp:593
void validate_viewer_actions()
Validates all actions of the current viewing side.
Definition: manager.cpp:447
This module contains various pathfinding functions and utilities.
bool can_enable_execution_hotkeys() const
Used to ask the whiteboard if its action execution hotkeys should be available to the user...
Definition: manager.cpp:252
This internal whiteboard class holds the planned action queues for a team, and offers many utility me...
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
Holds a temporary unit that can be drawn on the map without being placed in the unit_map.
A planned move, represented on the map by an arrow and a ghosted unit in the destination hex...
Definition: move.hpp:32
std::size_t underlying_id() const
This unit&#39;s unique internal ID.
Definition: unit.hpp:356
bool empty() const
Definition: config.cpp:884
virtual void send_to_wesnothd(const config &, const std::string &="unknown") const
Display units performing various actions: moving, attacking, and dying.
void move_unit(const std::vector< map_location > &path, unit_ptr u, bool animate, map_location::DIRECTION dir, bool force_scroll)
Display a unit moving along a given path.
Definition: udisplay.cpp:510
std::vector< map_location > & steps
Definition: pathfind.hpp:186
Definition: display.hpp:48
std::size_t viewer_team()
Definition: utility.cpp:40
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:268
Abstract base class for all the visitors (cf GoF Visitor Design Pattern) the whiteboard uses...
Definition: visitor.hpp:31
static game_display * get_singleton()
void set_planned_unit_map()
Transforms the unit map so that it now reflects the future state of things, i.e.
Definition: manager.cpp:1169
const std::vector< map_location > & route_
Definition: move.cpp:292
void clear()
Empties the action queue.
void pre_delete_action(action_ptr action)
Handles various cleanup right before removing an action from the queue.
Definition: manager.cpp:339
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:258
side_actions_ptr current_side_actions()
Definition: utility.cpp:57
std::shared_ptr< action const > action_const_ptr
Definition: typedefs.hpp:62