The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
side_actions.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2016 by Gabriel Morin <gabrielmorin (at) gmail (dot) com>
3  Part of the Battle for Wesnoth Project http://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 <set>
20 #include <sstream>
21 #include <iterator>
22 
23 #include "side_actions.hpp"
24 
25 #include "action.hpp"
26 #include "attack.hpp"
27 #include "manager.hpp"
28 #include "mapbuilder.hpp"
29 #include "move.hpp"
30 #include "recall.hpp"
31 #include "recruit.hpp"
32 #include "suppose_dead.hpp"
33 #include "highlighter.hpp"
34 #include "utility.hpp"
35 
36 #include "actions/create.hpp"
37 #include "actions/undo.hpp"
38 #include "game_display.hpp"
39 #include "game_end_exceptions.hpp"
40 #include "game_state.hpp"
41 #include "map/map.hpp"
42 #include "resources.hpp"
43 #include "units/unit.hpp"
44 
45 namespace wb
46 {
47 
48 /** Dumps side_actions on a stream, for debug purposes. */
49 std::ostream &operator<<(std::ostream &out, wb::side_actions const& side_actions)
50 {
51  out << "Content of side_actions:";
52  for(size_t turn = 0; turn < side_actions.num_turns(); ++turn) {
53  out << "\n Turn " << turn;
54 
55  int count = 1;
56  for(wb::side_actions::const_iterator it = side_actions.turn_begin(turn); it != side_actions.turn_end(turn); ++it) {
57  out << "\n (" << count++ << ") " << *it;
58  }
59 
60  if(side_actions.turn_size(turn) == 0) {
61  out << "\n (empty)";
62  }
63  }
64 
65  if(side_actions.empty()) {
66  out << " (empty)";
67  }
68 
69  return out;
70 }
71 
73  : actions_()
74  , turn_beginnings_()
75 {
76 }
77 
78 size_t side_actions_container::get_turn_impl(size_t begin, size_t end, const_iterator it) const
79 {
80  if(begin+1 >= end) {
81  return begin;
82  }
83  size_t mid = (begin+end) / 2;
84  if(it < turn_beginnings_[mid]) {
85  return get_turn_impl(begin, mid, it);
86  } else if(it > turn_beginnings_[mid]) {
87  return get_turn_impl(mid, end, it);
88  } else {
89  return mid;
90  }
91 }
92 
94 {
95  return get_turn_impl(0, num_turns(), it);
96 }
97 
99 {
100  return it - turn_begin( get_turn(it) );
101 }
102 
104  if(turn_num >= num_turns()) {
105  return end();
106  } else {
107  return turn_beginnings_[turn_num];
108  }
109 }
110 
112 {
113  if(turn_num >= num_turns()) {
114  return end();
115  } else {
116  return turn_beginnings_[turn_num];
117  }
118 }
119 
121  if(turn_size(turn) == 0) {
122  return queue(turn, action);
123  }
124 
125  iterator res = insert(turn_begin(turn), action);
126  if(res != end()) {
127  bool current_turn_unplanned = turn_size(0) == 0;
128  turn_beginnings_[turn] = res;
129 
130  if(current_turn_unplanned && turn == 1) {
131  turn_beginnings_.front() = res;
132  }
133  }
134  return res;
135 }
136 
138 {
139  assert(position <= end());
140 
141  bool first = position == begin();
142 
143  std::pair<iterator,bool> res = actions_.insert(position, action);
144  if(!res.second) {
145  return end();
146  }
147  if(first) {
148  // If we are inserting before the first action, then the inserted action should became the first of turn 0.
149  turn_beginnings_.front() = begin();
150  }
151  return res.first;
152 }
153 
155 {
156  // Are we inserting an action in the future while the current turn is empty?
157  // That is, are we in the sole case where an empty turn can be followed by a non-empty one.
158  bool future_only = turn_num == 1 && num_turns() == 0;
159 
160  bool current_turn_unplanned = turn_size(0) == 0;
161 
162  //for a little extra safety, since we should never resize by much at a time
163  assert(turn_num <= num_turns() || future_only);
164 
165  std::pair<iterator,bool> res = actions_.insert(turn_end(turn_num), action);
166  if(!res.second) {
167  return end();
168  }
169 
170  if(future_only) {
171  // No action are planned for the current turn but we are planning an action for turn 1 (the next turn).
172  turn_beginnings_.push_back(res.first);
173  }
174  if(turn_num >= num_turns()) {
175  turn_beginnings_.push_back(res.first);
176  } else if(current_turn_unplanned && turn_num == 0) {
177  // We are planning the first action of the current turn while others actions are planned in the future.
178  turn_beginnings_.front() = res.first;
179  }
180 
181  return res.first;
182 }
183 
185 {
186  assert(position > begin());
187  assert(position < end());
188 
189  action_ptr rhs = *position;
190  action_ptr lhs = position[-1];
191 
192  actions_.replace(position, lhs);
193  actions_.replace(position-1, rhs);
194  return position-1;
195 }
196 
198 {
199  return bump_earlier(position + 1);
200 }
201 
203 {
204  //precondition
205  assert(position < end());
206 
207  //prepare
208  iterator next = position + 1;
209  bool deleting_last_element = next == end();
210 
211  // pre-processing (check if position is at the beginning of a turn)
212  action_limits::iterator beginning = std::find(turn_beginnings_.begin(), turn_beginnings_.end(), position);
213  if(beginning != turn_beginnings_.end()) {
214  if(deleting_last_element) {
215  if(size() == 1) {
216  // If we are deleting our sole action, we can clear turn_beginnings_ (and we have to if this last action is in turn 1)
217  turn_beginnings_.clear();
218  } else {
219  // Otherwise, we just delete the last turn
220  turn_beginnings_.pop_back();
221  }
222  } else {
223  size_t turn_of_position = beginning - turn_beginnings_.begin();
224  // If we still have action this turn
225  if(get_turn(next) == turn_of_position) {
226  *beginning = next; // We modify the beginning of the turn
227  } else {
228  assert(turn_of_position == 0);
229  *beginning = turn_end(0); // Otherwise, we are emptying the current turn.
230  }
231  }
232  }
233 
234  //erase!
235  return actions_.erase(position);
236 }
237 
239  // @todo rewrite using boost::multi_index::erase(iterator,iterator) for efficiency.
240  if(first>=last) {
241  return last;
242  }
243  for(iterator it = last-1; it>first; --it) {
244  it = erase(it);
245  }
246  return erase(first);
247 }
248 
249 
251  : actions_()
252  , team_index_(0)
253  , team_index_defined_(false)
254  , gold_spent_(0)
255  , hidden_(false)
256 {
257 }
258 
259 void side_actions::set_team_index(size_t team_index)
260 {
261  assert(!team_index_defined_);
263  team_index_defined_ = true;
264 }
265 
267 {
268  if(empty()) {
269  return;
270  }
271 
272  std::vector<int>& numbers_to_draw = result.numbers_to_draw;
273  std::vector<size_t>& team_numbers = result.team_numbers;
274  int& main_number = result.main_number;
275  std::set<size_t>& secondary_numbers = result.secondary_numbers;
276  boost::shared_ptr<highlighter> hlighter = resources::whiteboard->get_highlighter().lock();
277 
278  for(const_iterator it = begin(); it != end(); ++it) {
279  if((*it)->is_numbering_hex(hex)) {
280  //store number corresponding to iterator's position + 1
281  size_t number = (it - begin()) + 1;
282  size_t index = numbers_to_draw.size();
283  numbers_to_draw.push_back(number);
284  team_numbers.push_back(team_index());
285 
286  if(hlighter) {
287  if(hlighter->get_main_highlight().lock() == *it) {
288  main_number = index;
289  }
290 
291  for(weak_action_ptr action : hlighter->get_secondary_highlights()) {
292  if(action.lock() == *it) {
293  secondary_numbers.insert(index);
294  }
295  }
296  }
297  }
298  }
299 }
300 
302 {
303  if(!empty()) {
304  return execute(begin());
305  } else { //nothing is executable right now
306  return false;
307  }
308 }
309 
311 {
312  if(resources::whiteboard->has_planned_unit_map()) {
313  ERR_WB << "Modifying action queue while temp modifiers are applied!!!" << std::endl;
314  }
315 
316  if(actions_.empty() || position == actions_.end()) {
317  return false;
318  }
319 
320  assert(position < turn_end(0)); //can't execute actions from future turns
321 
322  LOG_WB << "Before execution, " << *this << "\n";
323 
324  action_ptr action = *position;
325 
326  if(!action->valid()) {
327  LOG_WB << "Invalid action sent to execution, deleting.\n";
328  synced_erase(position);
329  return true;
330  }
331 
332  bool action_successful;
333  // Determines whether action should be deleted. Interrupted moves return action_complete == false.
334  bool action_complete;
335  try {
336  action->execute(action_successful, action_complete);
337  } catch (return_to_play_side_exception&) {
338  synced_erase(position);
339  LOG_WB << "End turn exception caught during execution, deleting action. " << *this << "\n";
340  //validate actions at next map rebuild
341  resources::whiteboard->on_gamestate_change();
342  throw;
343  }
344 
345  if(resources::whiteboard->should_clear_undo()) {
347  }
348 
349  std::stringstream ss;
350  ss << "After " << (action_successful? "successful": "failed") << " execution ";
351  if(action_complete) {
352  ss << "with deletion, ";
353  synced_erase(position);
354  }
355  else { //action may have revised itself; let's tell our allies.
356  ss << "without deletion, ";
357  resources::whiteboard->queue_net_cmd(team_index_,make_net_cmd_replace(position,*position));
358 
359  //Idea that needs refining: move action at the end of the queue if it failed executing:
360  //actions_.erase(position);
361  //actions_.insert(end(), action);
362  }
363  ss << *this << "\n";
364  LOG_WB << ss.str();
365 
366  resources::whiteboard->validate_viewer_actions();
367  return action_successful;
368 }
369 
371 {
372  if(hidden_) {
373  return;
374  }
375 
376  hidden_ = true;
377 
378  for(action_ptr act : *this) {
379  act->hide();
380  }
381 }
383 {
384  if(!hidden_) {
385  return;
386  }
387 
388  hidden_ = false;
389 
390  for(action_ptr act : *this) {
391  act->show();
392  }
393 }
394 
396 {
397  if(resources::whiteboard->has_planned_unit_map()) {
398  ERR_WB << "Modifying action queue while temp modifiers are applied!!!" << std::endl;
399  }
400  iterator valid_position = synced_insert(position, action);
401  LOG_WB << "Inserted into turn #" << get_turn(valid_position) << " at position #"
402  << actions_.position_in_turn(valid_position) << " : " << action <<"\n";
403  resources::whiteboard->validate_viewer_actions();
404  return valid_position;
405 }
406 
408 {
409  if(resources::whiteboard->has_planned_unit_map()) {
410  ERR_WB << "Modifying action queue while temp modifiers are applied!!!" << std::endl;
411  }
412  iterator result = synced_enqueue(turn_num, action);
413  LOG_WB << "Queue into turn #" << turn_num << " : " << action <<"\n";
414  resources::whiteboard->validate_viewer_actions();
415  return result;
416 }
417 
418 namespace
419 {
420  /**
421  * Check whether a move is swapable with a given action.
422  */
423  struct swapable_with_move: public visitor
424  {
425  public:
426  swapable_with_move(side_actions &sa, side_actions::iterator position, move_ptr second): sa_(sa), valid_(false), position_(position), second_(second) {}
427  bool valid() const { return valid_; }
428 
429  void visit(move_ptr first) {
430  valid_ = second_->get_dest_hex() != first->get_source_hex();
431  }
432 
433  void visit(attack_ptr first) {
434  visit(boost::static_pointer_cast<move>(first));
435  }
436 
437  void visit(recruit_ptr first) {
438  check_recruit_recall(first->get_recruit_hex());
439  }
440 
441  void visit(recall_ptr first) {
442  check_recruit_recall(first->get_recall_hex());
443  }
444 
445  void visit(suppose_dead_ptr) {
446  valid_ = true;
447  }
448 
449  private:
450  side_actions &sa_;
451  bool valid_;
452  side_actions::iterator position_;
453  move_ptr second_;
454 
455  void check_recruit_recall(const map_location &loc) {
456  const unit_const_ptr leader = second_->get_unit();
457  if(leader->can_recruit() && dynamic_cast<game_state*>(resources::filter_con)->can_recruit_on(*leader, loc)) {
458  if(const unit_const_ptr backup_leader = find_backup_leader(*leader)) {
459  side_actions::iterator it = sa_.find_first_action_of(*backup_leader);
460  if(!(it == sa_.end() || position_ < it)) {
461  return; //backup leader but he moves before us, refuse bump
462  }
463  } else {
464  return; //no backup leader, refuse bump
465  }
466  }
467  valid_ = true;
468  }
469  };
470 }
471 
472 //move action toward front of queue
474 {
475  if(resources::whiteboard->has_planned_unit_map()) {
476  ERR_WB << "Modifying action queue while temp modifiers are applied!!!" << std::endl;
477  }
478 
479  assert(position <= end());
480 
481  //Don't allow bumping the very first action any earlier, of course.
482  //Also, don't allow bumping an action into a previous turn queue
483  if(actions_.position_in_turn(position) == 0) {
484  return end();
485  }
486 
487  side_actions::iterator previous = position - 1;
488 
489  //Verify we're not moving an action out-of-order compared to other action of the same unit
490  const unit_const_ptr previous_ptr = (*previous)->get_unit();
491  const unit_const_ptr current_ptr = (*position)->get_unit();
492  if(previous_ptr && current_ptr && previous_ptr.get() == current_ptr.get()) {
493  return end();
494  }
495 
496  if(move_ptr second = boost::dynamic_pointer_cast<move>(*position)) {
497  swapable_with_move check(*this, position, second);
498  (*previous)->accept(check);
499  if(!check.valid()) {
500  return end();
501  }
502  }
503 
504  LOG_WB << "Before bumping earlier, " << *this << "\n";
505 
506  int turn_number = get_turn(position);
507  int action_number = actions_.position_in_turn(position);
508  int last_position = turn_size(turn_number) - 1;
509  LOG_WB << "In turn #" << turn_number
510  << ", bumping action #" << action_number << "/" << last_position
511  << " to position #" << action_number - 1 << "/" << last_position << ".\n";
512 
513  resources::whiteboard->queue_net_cmd(team_index_, make_net_cmd_bump_later(position - 1));
514 
515  actions_.bump_earlier(position);
516 
517  LOG_WB << "After bumping earlier, " << *this << "\n";
518  return position - 1;
519 }
520 
521 //move action toward back of queue
523 {
524  assert(position < end());
525 
526  ++position;
527  if(position == end()) {
528  return end();
529  }
530  position = bump_earlier(position);
531  if(position == end()) {
532  return end();
533  }
534  return position + 1;
535 }
536 
538 {
539  if(resources::whiteboard->has_planned_unit_map()) {
540  ERR_WB << "Modifying action queue while temp modifiers are applied!!!" << std::endl;
541  }
542 
543  assert(position < end());
544 
545  LOG_WB << "Erasing action at turn #" << get_turn(position) << " position #" << actions_.position_in_turn(position) << "\n";
546 
547  position = synced_erase(position);
548 
549  if(validate_after_delete) {
550  resources::whiteboard->validate_viewer_actions();
551  }
552 
553  return position;
554 }
555 
557 {
558  return find_first_action_of(actions_.get<container::by_hex>().equal_range(hex), begin(), std::less<iterator>());
559 }
560 
562 {
563  return find_first_action_of(actions_.get<container::by_unit>().equal_range(unit.underlying_id()), start_position, std::less<iterator>());
564 }
565 
567  return find_first_action_of(actions_.get<container::by_unit>().equal_range(unit.underlying_id()), start_position, std::greater<iterator>());
568 }
569 
571 {
572  return find_first_action_of(actions_.get<container::by_unit>().equal_range(unit.underlying_id()), start_position, std::greater<iterator>());
573 }
574 
576 {
577  return find_last_action_of(unit, end() - 1);
578 }
579 
581 {
582  return find_last_action_of(unit, end() - 1);
583 }
584 
586 {
588 }
589 
591 {
593 }
594 
595 std::deque<action_ptr> side_actions::actions_of(unit const &target)
596 {
598  std::pair<unit_iterator, unit_iterator> action_its = actions_.get<container::by_unit>().equal_range(target.underlying_id());
599 
600  std::deque<action_ptr> actions (action_its.first, action_its.second);
601  return actions;
602 }
603 
604 size_t side_actions::get_turn_num_of(unit const& u) const
605 {
607  if(itor == end()) {
608  return 0;
609  }
610  return get_turn(itor);
611 }
612 
614 {
615  DBG_WB << "Changing gold spent for side " << (team_index() + 1) << "; old value: "
616  << gold_spent_ << "; new value: " << (gold_spent_ + difference) << "\n";
617  gold_spent_ += difference; assert(gold_spent_ >= 0);
618 }
619 
621 {
622  DBG_WB << "Resetting gold spent for side " << (team_index() + 1) << " to 0.\n";
623  gold_spent_ = 0;
624 }
625 
627 {
628  assert(act);
629  if(pos == 0) {
630  return actions_.push_front(turn, act);
631  } else {
632  return actions_.insert(turn_begin(turn) + pos, act);
633  }
634 }
635 
637 {
639  return safe_erase(itor);
640 }
641 
643 {
644  resources::whiteboard->queue_net_cmd(team_index_, make_net_cmd_insert(itor, act));
645  return actions_.insert(itor, act);
646 }
647 
649 {
650  //raw_enqueue() creates actions_[turn_num] if it doesn't exist already, so we
651  //have to do it first -- before subsequently calling actions_[turn_num].size().
652  iterator result = actions_.queue(turn_num, act);
653  if(result != end()) {
654  resources::whiteboard->queue_net_cmd(team_index_, make_net_cmd_insert(turn_num, turn_size(turn_num) - 1, act));
655  // The insert position is turn_size(turn_num)-1 since we already inserted the action.
656  }
657  return result;
658 }
659 
661 {
663  resources::whiteboard->pre_delete_action(action); //misc cleanup
664  iterator return_itor = actions_.erase(itor);
665  resources::whiteboard->post_delete_action(action);
666  return return_itor;
667 }
669 {
670  move_ptr new_move(boost::make_shared<move>(team_index(), hidden_, std::ref(mover), route, arrow, fake_unit));
671  return queue_action(turn, new_move);
672 }
673 
674 side_actions::iterator side_actions::queue_attack(size_t turn, unit& mover, const map_location& target_hex, int weapon_choice, const pathfind::marked_route& route, arrow_ptr arrow, fake_unit_ptr fake_unit)
675 {
676  attack_ptr new_attack(boost::make_shared<attack>(team_index(), hidden_, std::ref(mover), target_hex, weapon_choice, route, arrow, fake_unit));
677  return queue_action(turn, new_attack);
678 }
679 
681 {
682  recruit_ptr new_recruit(boost::make_shared<recruit>(team_index(), hidden_, unit_name, recruit_hex));
683  return queue_action(turn, new_recruit);
684 }
685 
687 {
688  recall_ptr new_recall(boost::make_shared<recall>(team_index(), hidden_, unit, recall_hex));
689  return queue_action(turn, new_recall);
690 }
691 
693 {
694  suppose_dead_ptr new_suppose_dead(boost::make_shared<suppose_dead>(team_index(), hidden_, std::ref(curr_unit), loc));
695  return queue_action(turn, new_suppose_dead);
696 }
697 
699 {
700  std::string type = cmd["type"];
701 
702  if(type=="insert") {
703  size_t turn = cmd["turn"].to_int();
704  size_t pos = cmd["pos"].to_int();
705  action_ptr act = action::from_config(cmd.child("action"), hidden_);
706  if(!act) {
707  ERR_WB << "side_actions::execute_network_command(): received invalid action data!" << std::endl;
708  return;
709  }
710 
711  iterator itor = safe_insert(turn, pos, act);
712  if(itor >= end()) {
713  ERR_WB << "side_actions::execute_network_command(): received invalid insertion position!" << std::endl;
714  return;
715  }
716 
717  LOG_WB << "Command received: action inserted on turn #" << turn << ", position #" << pos << ": " << act << "\n";
718 
719  //update numbering hexes as necessary
720  ++itor;
721  for(iterator end_itor = end(); itor != end_itor; ++itor) {
722  resources::screen->invalidate((*itor)->get_numbering_hex());
723  }
724  } else if(type=="replace") {
725  size_t turn = cmd["turn"].to_int();
726  size_t pos = cmd["pos"].to_int();
727  action_ptr act = action::from_config(cmd.child("action"), hidden_);
728  if(!act) {
729  ERR_WB << "side_actions::execute_network_command(): received invalid action data!" << std::endl;
730  return;
731  }
732 
733  iterator itor = turn_begin(turn) + pos;
734  if(itor >= end() || get_turn(itor) != turn) {
735  ERR_WB << "side_actions::execute_network_command(): received invalid pos!" << std::endl;
736  return;
737  }
738 
739  if(!actions_.replace(itor, act)){
740  ERR_WB << "side_actions::execute_network_command(): replace failed!" << std::endl;
741  return;
742  }
743 
744  LOG_WB << "Command received: action replaced on turn #" << turn << ", position #" << pos << ": " << act << "\n";
745  } else if(type=="remove") {
746  size_t turn = cmd["turn"].to_int();
747  size_t pos = cmd["pos"].to_int();
748 
749  iterator itor = turn_begin(turn) + pos;
750  if(itor >= end() || get_turn(itor) != turn) {
751  ERR_WB << "side_actions::execute_network_command(): received invalid pos!" << std::endl;
752  return;
753  }
754 
755  itor = safe_erase(itor);
756 
757  LOG_WB << "Command received: action removed on turn #" << turn << ", position #" << pos << "\n";
758 
759  //update numbering hexes as necessary
760  for(iterator end_itor = end(); itor != end_itor; ++itor) {
761  resources::screen->invalidate((*itor)->get_numbering_hex());
762  }
763  } else if(type=="bump_later") {
764  size_t turn = cmd["turn"].to_int();
765  size_t pos = cmd["pos"].to_int();
766 
767  iterator itor = turn_begin(turn) + pos;
768  if(itor+1 >= end() || get_turn(itor) != turn) {
769  ERR_WB << "side_actions::execute_network_command(): received invalid pos!" << std::endl;
770  return;
771  }
772 
773  action_ptr first_action = *itor;
774  action_ptr second_action = itor[1];
775  bump_later(itor);
776 
777  LOG_WB << "Command received: action bumped later from turn #" << turn << ", position #" << pos << "\n";
778 
779  //update numbering hexes as necessary
780  resources::screen->invalidate(first_action->get_numbering_hex());
781  resources::screen->invalidate(second_action->get_numbering_hex());
782  } else if(type=="clear") {
783  LOG_WB << "Command received: clear\n";
784  clear();
785  } else if(type=="refresh") {
786  LOG_WB << "Command received: refresh\n";
787  clear();
788  for(net_cmd const& sub_cmd : cmd.child_range("net_cmd"))
789  execute_net_cmd(sub_cmd);
790  } else {
791  ERR_WB << "side_actions::execute_network_command(): received invalid type!" << std::endl;
792  return;
793  }
794 
795  resources::whiteboard->validate_viewer_actions();
796 }
797 
799 {
800  net_cmd result;
801  result["type"] = "insert";
802  result["turn"] = static_cast<int>(turn_num);
803  result["pos"] = static_cast<int>(pos);
804  result.add_child("action", act->to_config());
805  return result;
806 }
808 {
809  if(pos == begin()) {
810  return make_net_cmd_insert(0,0,act);
811  } else {
812  const_iterator prec = pos - 1;
813  return make_net_cmd_insert(get_turn(prec), actions_.position_in_turn(prec)+1, act);
814  }
815 }
817 {
818  net_cmd result;
819  result["type"] = "replace";
820  result["turn"] = static_cast<int>(get_turn(pos));
821  result["pos"] = static_cast<int>(actions_.position_in_turn(pos));
822  result.add_child("action", act->to_config());
823  return result;
824 }
826 {
827  net_cmd result;
828  result["type"] = "remove";
829  result["turn"] = static_cast<int>(get_turn(pos));
830  result["pos"] = static_cast<int>(actions_.position_in_turn(pos));
831  return result;
832 }
834 {
835  net_cmd result;
836  result["type"] = "bump_later";
837  result["turn"] = static_cast<int>(get_turn(pos));
838  result["pos"] = static_cast<int>(actions_.position_in_turn(pos));
839  return result;
840 }
842 {
843  net_cmd result;
844  result["type"] = "clear";
845  return result;
846 }
848 {
849  net_cmd result;
850  result["type"] = "refresh";
851 
852  for(const_iterator itor = begin(), end_itor = end(); itor != end_itor; ++itor) {
854  }
855 
856  return result;
857 }
858 
860 {
861  //find units who still have plans for turn 0 (i.e. were too lazy to finish their jobs)
862  std::set<unit_const_ptr> lazy_units;
863  for(action_ptr const& act : iter_turn(0)) {
864  unit_const_ptr u = act->get_unit();
865  if(u) {
866  lazy_units.insert(u);
867  }
868  }
869 
870  //push their plans back one turn
871  std::set<unit_const_ptr>::iterator lazy_end = lazy_units.end();
872  iterator itor = end();
873  while(itor != begin()) {
874  --itor;
875  action_ptr act = *itor;
876 
877  if(lazy_units.find(act->get_unit()) != lazy_end) {
878  safe_insert(get_turn(itor)+1, 0, act);
879  itor = actions_.erase(itor);
880  }
881  }
882 
883  //push any remaining first-turn plans into the second turn
884  for(iterator act=turn_begin(0), end=turn_end(0); act!=end; ++act) {
885  safe_insert(1, 0, *act);
886  }
887 
888  //shift everything forward one turn
891 }
892 
894 {
895  raw_turn_shift();
897 }
898 
899 } //end namespace wb
void clear()
Clears the stack of undoable (and redoable) actions.
Definition: undo.cpp:226
container::iterator iterator
child_itors child_range(const std::string &key)
Definition: config.cpp:613
iterator end()
Returns the iterator for the position after the last executed action within the actions queue...
net_cmd make_net_cmd_insert(size_t turn_num, size_t pos, action_const_ptr) const
net_cmd make_net_cmd_replace(const_iterator const &pos, action_const_ptr) const
static void check(LexState *ls, int c)
Definition: lparser.cpp:109
size_t position_in_turn(const_iterator it) const
Returns the position of a given iterator in its turn.
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:3536
Definition: unit.hpp:95
net_cmd make_net_cmd_refresh() const
size_t underlying_id() const
The unique internal ID of the unit.
Definition: unit.hpp:150
boost::shared_ptr< attack > attack_ptr
Definition: typedefs.hpp:78
action_limits turn_beginnings_
Contains a list of iterator to the beginning of each turn.
int pos
Definition: formula.cpp:800
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1221
iterator push_front(size_t turn, action_ptr action)
Pushes an action in front of a given turn.
std::vector< int > numbers_to_draw
game_display * screen
Definition: resources.cpp:27
iterator turn_begin(size_t turn_num)
size_t get_turn(const_iterator it) const
Returns the turn of a given iterator planned execution.
size_t turn_size(size_t turn_num) const
Returns the number of actions planned for turn turn_num.
size_t num_turns() const
Returns the number of turns that have plans.
void turn_shift()
Shift turn.
size_t get_turn(const_iterator it) const
Returns the turn of a given iterator planned execution.
action_set::index< chronological >::type::iterator iterator
bool replace(iterator it, action_ptr act)
Replaces the action at a given position with another action.
iterator synced_erase(iterator itor)
Contains the exception interfaces used to signal completion of a scenario, campaign or turn...
static config unit_name(const unit *u)
Definition: reports.cpp:133
const std::string number
template to number regex
iterator bump_earlier(iterator position)
Moves an action earlier in the execution order.
iterator bump_earlier(iterator position)
Moves an action earlier in the execution order.
iterator queue_suppose_dead(size_t turn_num, unit &curr_unit, map_location const &loc)
Queues a suppose_dead to be executed last.
std::set< size_t > secondary_numbers
boost::weak_ptr< action > weak_action_ptr
Definition: typedefs.hpp:72
int gold_spent_
Used to store gold "spent" in planned recruits/recalls when the future unit map is applied...
iterator find_last_action_of(unit const &unit, iterator start_position)
Finds the last action that belongs to this unit, starting the search backwards from the specified pos...
net_cmd make_net_cmd_remove(const_iterator const &pos) const
iterator remove_action(iterator position, bool validate_after_delete=true)
Deletes the action at the specified position.
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.
boost::shared_ptr< suppose_dead > suppose_dead_ptr
Definition: typedefs.hpp:84
iterator queue_recruit(size_t turn_num, const std::string &unit_name, const map_location &recruit_hex)
Queues a recruit to be executed last.
iterator find_first_action_at(map_location hex)
Find the first action occurring at a given hex.
size_t get_turn_impl(size_t begin, size_t end, const_iterator it) const
Binary search to find the occuring turn of the action pointed by an iterator.
std::deque< action_ptr > actions_of(unit const &unit)
size_t count_actions_of(unit const &unit)
std::vector< size_t > team_numbers
GLuint GLuint end
Definition: glew.h:1221
iterator queue_move(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.
GLuint64EXT * result
Definition: glew.h:10727
iterator erase(iterator position)
Deletes the action at the specified position.
size_t num_turns() const
Returns the number of turns that have plans.
Arrows destined to be drawn on the map.
Definition: arrow.hpp:30
filter_context * filter_con
Definition: resources.cpp:23
iterator queue_action(size_t turn_num, action_ptr action)
Queues an action to be executed last.
bool execute(iterator position)
Executes the specified action, if it exists in the queue.
iterator queue_recall(size_t turn_num, const unit &unit, const map_location &recall_hex)
Queues a recall to be executed last.
#define ERR_WB
Definition: typedefs.hpp:26
range_t iter_turn(size_t turn_num)
Returns an iterator range corresponding to the requested turn.
config & add_child(const std::string &key)
Definition: config.cpp:743
iterator insert_action(iterator position, action_ptr action)
Inserts an action at the specified position.
iterator queue_attack(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.
net_cmd make_net_cmd_bump_later(const_iterator const &pos) const
Structure which holds a single route and marks for special events.
Definition: pathfind.hpp:141
GLuint GLuint GLsizei count
Definition: glew.h:1221
size_t get_turn_num_of(unit const &) const
Determines the appropriate turn number for the next action planned for this unit. ...
bool empty() const
Indicates whether the action queue is empty.
Encapsulates the map of the game.
Definition: location.hpp:38
Various functions related to the creation of units (recruits, recalls, and placed units)...
size_t team_index()
Returns the team index this action queue belongs to.
GLuint res
Definition: glew.h:9258
Tag for action_set's hashed_non_unique index.
void execute_net_cmd(net_cmd const &)
static action_ptr from_config(config const &, bool hidden)
Constructs an object of a subclass of wb::action using a config.
Definition: action.cpp:59
iterator bump_later(iterator position)
Moves an action later in the execution order.
std::map< std::string, tfilter >::iterator itor
Definition: filter.cpp:199
iterator synced_enqueue(size_t turn_num, action_ptr to_insert)
iterator synced_insert(iterator itor, action_ptr to_insert)
GLuint index
Definition: glew.h:1782
iterator begin()
Returns the iterator for the first (executed earlier) action within the actions queue.
void hide()
Sets whether or not the contents should be drawn on the screen.
iterator turn_begin(size_t turn_num)
Returns the iterator for the first (executed earlier) action of a given turn within the actions queue...
#define LOG_WB
Definition: typedefs.hpp:28
iterator turn_end(size_t turn_num)
net_cmd make_net_cmd_clear() const
iterator begin()
Returns the iterator for the first (executed earlier) action within the actions queue.
iterator turn_end(size_t turn_num)
#define next(ls)
Definition: llex.cpp:27
action_set::index< T >::type & get()
Returns a given index.
void reset_gold_spent()
Set gold spent back to zero.
GLenum GLint ref
Definition: glew.h:1813
bool empty() const
Indicates whether the action queue is empty.
iterator safe_insert(size_t turn_num, size_t pos, action_ptr to_insert)
void change_gold_spent_by(int difference)
Used to track gold spending by recruits/recalls when building the future unit map.
bool find(E event, F functor)
Tests whether an event handler is available.
boost::shared_ptr< move > move_ptr
Definition: typedefs.hpp:76
config & child(const std::string &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:658
container::const_iterator const_iterator
#define DBG_WB
Definition: typedefs.hpp:29
Various functions that implement the undoing (and redoing) of in-game commands.
iterator insert(iterator position, action_ptr action)
Inserts an action at the specified position.
Tag for action_set's hashed_non_unique index.
GLint * first
Definition: glew.h:1496
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:63
std::ostream & operator<<(std::ostream &s, action_ptr action)
Definition: action.cpp:33
iterator end()
Returns the iterator for the position after the last executed action within the actions queue...
iterator find_first_action_of(std::pair< T, T > between, iterator limit, Compare comp)
Find the (chronologically) first action between the iterators between.first and between.second but after or equals to limit with respect to the predicate comp.
boost::shared_ptr< wb::manager > whiteboard
Definition: resources.cpp:36
actions::undo_list * undo_stack
Definition: resources.cpp:34
iterator safe_erase(iterator const &itor)
size_t size() const
Returns the number of actions in the action queue.
void set_team_index(size_t team_index)
Must be called only once, right after the team that owns this side_actions is added to the teams vect...
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
boost::shared_ptr< recall > recall_ptr
Definition: typedefs.hpp:82
Abstract base class for all the whiteboard planned actions.
Definition: action.hpp:33
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
iterator queue(size_t turn_num, action_ptr action)
Queues an action to be executed last.
GLsizei const GLcharARB ** string
Definition: glew.h:4503
This internal whiteboard class holds the planned action queues for a team, and offers many utility me...
bool execute_next()
Executes the first action in the queue, and then deletes it.
Holds a temporary unit that can be drawn on the map without being placed in the unit_map.
action_set::index< chronological >::type::const_iterator const_iterator
size_t turn_size(size_t turn_num) const
Returns the number of actions planned for turn turn_num.
boost::shared_ptr< recruit > recruit_ptr
Definition: typedefs.hpp:80
Definition: display.hpp:47
GLenum target
Definition: glew.h:5190
bool unit_has_actions(unit const &unit)
Abstract base class for all the visitors (cf GoF Visitor Design Pattern) the whiteboard uses...
Definition: visitor.hpp:32
void clear()
Empties the action queue.
iterator bump_later(iterator position)
Moves an action later in the execution order.
const std::string valid
Little parts of regex templates used to parse Wml annoations.