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 #pragma once
20 
21 #include <deque>
22 
23 #include <boost/multi_index/hashed_index.hpp>
24 #include <boost/multi_index/mem_fun.hpp>
25 #include <boost/multi_index/random_access_index.hpp>
26 #include <boost/multi_index_container.hpp>
27 
28 #include "action.hpp"
29 #include "typedefs.hpp"
30 
31 namespace wb
32 {
33 
34 class move;
35 
36 /**
37  * Datastructure holding the actions of a side on multiple turns.
38  *
39  * @invariant forall(t>0) if turn_size(t)==0 then turn_size(t+1)==0
40  */
41 class side_actions_container
42 {
43 public:
44 
45 	side_actions_container();
46 
47 	//! Tag for action_set's random_access index.
48 	struct chronological{};
49 
50 	//! Tag for action_set's hashed_non_unique index.
51 	struct by_unit{};
52 
53 	//! Tag for action_set's hashed_non_unique index.
54 	struct by_hex{};
55 
56 	//! Underlying container
57 	typedef boost::multi_index::multi_index_container <
58 		action_ptr,
59 		boost::multi_index::indexed_by<
60 			boost::multi_index::random_access<
61 				boost::multi_index::tag< chronological >>,
62 			boost::multi_index::hashed_non_unique<
63 				boost::multi_index::tag< by_unit >,
64 				boost::multi_index::const_mem_fun< action, size_t, &action::get_unit_id >>,
65 			boost::multi_index::hashed_non_unique<
66 				boost::multi_index::tag< by_hex >,
67 				boost::multi_index::const_mem_fun< action, map_location, &action::get_numbering_hex >>
68 			>
69 		> action_set;
70 
71 	typedef action_set::index<chronological>::type::iterator iterator;
72 	typedef action_set::index<chronological>::type::const_iterator const_iterator;
73 	typedef action_set::index<chronological>::type::reverse_iterator reverse_iterator;
74 	typedef action_set::index<chronological>::type::const_reverse_iterator const_reverse_iterator;
75 
76 	typedef std::pair<iterator,iterator> range_t;
77 	typedef std::pair<reverse_iterator,reverse_iterator> rrange_t;
78 	typedef std::pair<const_iterator,const_iterator> crange_t;
79 	typedef std::pair<const_reverse_iterator,const_reverse_iterator> crrange_t;
80 
81 	typedef std::deque<iterator> action_limits;
82 
83 
84 	/**
85 	 * Inserts an action at the specified position.
86 	 *
87 	 * The planned turn of the inserted action is the same as the planned turn of position-1 before the insertion.
88 	 * If position == begin(), the new action will became the first action of the current turn.
89 	 *
90 	 * @param position   The iterator before which action will be inserted.
91 	 * @param action     The action to insert.
92 	 *
93 	 * @return           The inserted action's position.
94 	 * @retval end()     When the action can't be inserted.
95 	 */
96 	iterator insert(iterator position, action_ptr action);
97 
98 	/**
99 	 * Queues an action to be executed last
100 	 * @return The queued action's position
101 	 * @retval end() when the action can't be inserted
102 	 */
103 	iterator queue(size_t turn_num, action_ptr action);
104 
105 	/**
106 	 * Pushes an action in front of a given turn.
107 	 * @return The inserted action's position
108 	 */
109 	iterator push_front(size_t turn, action_ptr action);
110 
111 	/**
112 	 * Moves an action earlier in the execution order.
113 	 * i.e. at the front of the queue by one position.
114 	 * @return The action's new position.
115 	 */
116 	iterator bump_earlier(iterator position);
117 
118 	/**
119 	 * Moves an action later in the execution order.
120 	 * i.e. at the back of the queue by one position.
121 	 * @return The action's new position.
122 	 */
123 	iterator bump_later(iterator position);
124 
125 	/**
126 	 * Deletes the action at the specified position.
127 	 * @return The position of the element after the one deleted, or end() if the queue is empty.
128 	 */
129 	iterator erase(iterator position);
130 
131 	/**
132 	 * Deletes the action at the specified position.
133 	 * @return last
134 	 */
135 	iterator erase(iterator first, iterator last);
136 
137 	/**
138 	 * Empties the action queue.
139 	 */
clear()140 	void clear() { actions_.clear(); turn_beginnings_.clear(); }
141 
142 	/**
143 	 * Shift turn.
144 	 *
145 	 * The turn 0 is deleted, the actions of turn n are moved to turn n-1.
146 	 * @pre turn_size(0)==0
147 	 */
turn_shift()148 	void turn_shift() { assert(turn_size(0)==0); turn_beginnings_.pop_front(); }
149 
150 	/**
151 	 * Replaces the action at a given position with another action.
152 	 */
replace(iterator it,action_ptr act)153 	bool replace(iterator it, action_ptr act){ return actions_.replace(it, act); }
154 
155 
156 	/**
157 	 * Returns a given index.
158 	 */
159 	template <typename T>
get()160 	typename action_set::index<T>::type& get(){ return actions_.get<T>(); }
161 	template <typename T>
get() const162 	typename action_set::index<T>::type const& get() const { return actions_.get<T>(); }
163 
164 	/**
165 	 * Projects an iterator on a given index.
166 	 */
167 	template <typename T, typename U>
project(U it)168 	typename action_set::index<T>::type::iterator project(U it){ return actions_.project<T>(it); }
169 	template <typename T, typename U>
project(U it) const170 	typename action_set::index<T>::type::const_iterator project(U it) const { return actions_.project<T>(it); }
171 
172 	/**
173 	 * Returns the iterator for the first (executed earlier) action within the actions queue.
174 	 */
begin()175 	iterator begin(){ return actions_.get<chronological>().begin(); }
176 	/** reverse version of the above */
rbegin()177 	reverse_iterator rbegin(){ return actions_.get<chronological>().rbegin(); }
178 	/** const versions of the above */
begin() const179 	const_iterator begin() const { return actions_.get<chronological>().cbegin(); }
180 	/** const reverse versions of the above */
rbegin() const181 	const_reverse_iterator rbegin() const { return actions_.get<chronological>().crbegin(); }
182 
183 	/**
184 	 * Returns the iterator for the position *after* the last executed action within the actions queue.
185 	 */
end()186 	iterator end(){ return actions_.get<chronological>().end(); }
187 	/** reverse version of the above */
rend()188 	reverse_iterator rend(){ return actions_.get<chronological>().rend(); }
189 	/** const versions of the above */
end() const190 	const_iterator end() const { return actions_.get<chronological>().cend(); }
191 	/** const reverse versions of the above */
rend() const192 	const_reverse_iterator rend() const { return actions_.get<chronological>().crend(); }
193 
194 	/**
195 	 * Indicates whether the action queue is empty.
196 	 */
empty() const197 	bool empty() const { return actions_.empty(); }
198 
199 	/**
200 	 * Returns the number of actions in the action queue.
201 	 */
size() const202 	size_t size() const { return actions_.size(); }
203 
204 	/**
205 	 * Returns the number of turns that have plans.
206 	 * If the container holds only one action on turn 1 (that is turn 0 is empty),
207 	 * this function will still returns 2. Indeed, turn 0 has an "empty" plan.
208 	 *
209 	 * @note The current turn is counted. That is if num_turns()==0 then empty()==true.
210 	 */
num_turns() const211 	size_t num_turns() const { return turn_beginnings_.size(); }
212 
213 	/**
214 	 * Returns the turn of a given iterator planned execution.
215 	 *
216 	 * The value returned is the difference between the planned turn and the current turn.
217 	 *
218 	 * @retval 0 If the action is planned for the current turn.
219 	 */
220 	size_t get_turn(const_iterator it) const;
221 
222 	/**
223 	 * Returns the position of a given iterator in its turn.
224 	 */
225 	size_t position_in_turn(const_iterator it) const;
226 
227 	/**
228 	 * Returns the iterator for the first (executed earlier) action of a given turn within the actions queue.
229 	 */
230 	iterator turn_begin(size_t turn_num);
231 	const_iterator turn_begin(size_t turn_num) const;
turn_rbegin(size_t turn_num)232 	reverse_iterator turn_rbegin(size_t turn_num){ return reverse_iterator(turn_end(turn_num)); }
turn_rbegin(size_t turn_num) const233 	const_reverse_iterator turn_rbegin(size_t turn_num) const { return reverse_iterator(turn_end(turn_num)); }
234 
235 	/*
236 	 * Returns the iterator for the position *after* the last executed action of a given turn within the actions queue.
237 	 */
turn_end(size_t turn_num)238 	iterator turn_end(size_t turn_num){ return turn_begin(turn_num+1); }
turn_end(size_t turn_num) const239 	const_iterator turn_end(size_t turn_num) const { return turn_begin(turn_num+1); }
turn_rend(size_t turn_num)240 	reverse_iterator turn_rend(size_t turn_num){ return reverse_iterator(turn_begin(turn_num)); }
turn_rend(size_t turn_num) const241 	const_reverse_iterator turn_rend(size_t turn_num) const { return reverse_iterator(turn_begin(turn_num)); }
242 
243 	/**
244 	 * Returns an iterator range corresponding to the requested turn.
245 	 */
iter_turn(size_t turn_num)246 	range_t iter_turn(size_t turn_num){ return range_t(turn_begin(turn_num),turn_end(turn_num)); }
riter_turn(size_t turn_num)247 	rrange_t riter_turn(size_t turn_num){ return rrange_t(turn_rbegin(turn_num),turn_rend(turn_num)); }
iter_turn(size_t turn_num) const248 	crange_t iter_turn(size_t turn_num) const { return crange_t(turn_begin(turn_num),turn_end(turn_num)); }
riter_turn(size_t turn_num) const249 	crrange_t riter_turn(size_t turn_num) const { return crrange_t(turn_rbegin(turn_num),turn_rend(turn_num)); }
250 
251 	/** Returns the number of actions planned for turn turn_num */
turn_size(size_t turn_num) const252 	size_t turn_size(size_t turn_num) const { return turn_end(turn_num) - turn_begin(turn_num); }
253 
254 	/** Get the underlying action container */
actions() const255 	const action_set& actions() const { return actions_; }
256 
257 	template<typename Modifier>
modify(iterator position,Modifier mod)258 	bool modify(iterator position, Modifier mod) { return actions_.modify(position, mod); }
259 private:
260 	/**
261 	 * Binary search to find the occurring turn of the action pointed by an iterator.
262 	 */
263 	size_t get_turn_impl(size_t begin, size_t end, const_iterator it) const;
264 
265 	action_set actions_;
266 
267 	/**
268 	 * Contains a list of iterator to the beginning of each turn.
269 	 *
270 	 * @invariant turn_beginnings_.front()==actions_.begin() || actions_.empty()
271 	 */
272 	action_limits turn_beginnings_;
273 };
274 
275 
276 /**
277  * This internal whiteboard class holds the planned action queues for a team, and offers many
278  * utility methods to create and manipulate them.
279  * It also provides an interface to the underlying side_actions_container.
280  */
281 class side_actions: public std::enable_shared_from_this<side_actions>
282 {
283 public:
284 	typedef side_actions_container container;
285 
286 	typedef container::iterator iterator;
287 	typedef container::const_iterator const_iterator;
288 	typedef container::reverse_iterator reverse_iterator;
289 	typedef container::const_reverse_iterator const_reverse_iterator;
290 
291 	typedef std::pair<iterator,iterator> range_t;
292 	typedef std::pair<reverse_iterator,reverse_iterator> rrange_t;
293 	typedef std::pair<const_iterator,const_iterator> crange_t;
294 	typedef std::pair<const_reverse_iterator,const_reverse_iterator> crrange_t;
295 
296 
297 	side_actions();
298 
299 	/** Must be called only once, right after the team that owns this side_actions is added to the teams vector */
300 	void set_team_index(size_t team_index);
301 
302 	/** Returns the team index this action queue belongs to */
team_index()303 	size_t team_index() { assert(team_index_defined_); return team_index_; }
304 
305 	struct numbers_t;
306 	/** Gets called when display is drawing a hex to determine which numbers to draw on it */
307 	void get_numbers(const map_location& hex, numbers_t& result);
308 
309 	/**
310 	 * Executes the first action in the queue, and then deletes it.
311 	 * @return true if the action was completed successfully
312 	 */
313 	bool execute_next();
314 
315 	/**
316 	 * Executes the specified action, if it exists in the queue.
317 	 * If the action is not finished, it's moved at the end of the queue.
318 	 * @return true if the action was completed successfully
319 	 */
320 	bool execute(iterator position);
321 
322 
323 	/**
324 	 * Indicates whether the action queue is empty.
325 	 */
empty() const326 	bool empty() const { return actions_.empty(); }
327 
328 	/**
329 	 * Returns the number of actions in the action queue.
330 	 */
size() const331 	size_t size() const { return actions_.size(); }
332 
333 	/**
334 	 * Returns the number of turns that have plans.
335 	 * If the container holds only one action on turn 1 (that is turn 0 is empty),
336 	 * this function will still returns 2. Indeed, turn 0 has an "empty" plan.
337 	 *
338 	 * @note The current turn is counted. That is if num_turns()==0 then empty()==true.
339 	 */
num_turns() const340 	size_t num_turns() const { return actions_.num_turns(); }
341 
342 	/** Returns the number of actions planned for turn turn_num */
turn_size(size_t turn_num) const343 	size_t turn_size(size_t turn_num) const { return actions_.turn_size(turn_num); }
344 
345 	/**
346 	 * Returns the turn of a given iterator planned execution.
347 	 *
348 	 * The value returned is the difference between the planned turn and the current turn.
349 	 *
350 	 * @retval 0 If the action is planned for the current turn.
351 	 */
get_turn(const_iterator it) const352 	size_t get_turn(const_iterator it) const { return actions_.get_turn(it); }
353 
354 	/**
355 	 * Empties the action queue.
356 	 */
clear()357 	void clear() { actions_.clear(); }
358 
359 	/** Sets whether or not the contents should be drawn on the screen. */
360 	void hide();
361 	void show();
hidden() const362 	bool hidden() const {return hidden_;}
363 
364 	/**
365 	 * Inserts an action at the specified position. The begin() and end() functions might prove useful here.
366 	 * @return The inserted action's position.
367 	 */
368 	iterator insert_action(iterator position, action_ptr action);
369 
370 	/**
371 	 * Queues an action to be executed last
372 	 * @return The queued action's position
373 	 */
374 	iterator queue_action(size_t turn_num, action_ptr action);
375 
376 	/**
377 	 * Moves an action earlier in the execution order.
378 	 * i.e. at the front of the queue by one position.
379 	 * @return The action's new position.
380 	 */
381 	iterator bump_earlier(iterator position, bool send_to_net = true);
382 
383 	/**
384 	 * Moves an action later in the execution order.
385 	 * i.e. at the back of the queue by one position.
386 	 * @return The action's new position.
387 	 */
388 	iterator bump_later(iterator position, bool send_to_net = true);
389 
390 	/**
391 	 * Deletes the action at the specified position.
392 	 * @return The position of the element after the one deleted, or end() if the queue is empty.
393 	 */
394 	iterator remove_action(iterator position, bool validate_after_delete = true);
395 
396 	/**
397 	 * @param action The action whose position you're looking for
398 	 * @return The action's position within the queue, or end() if action wasn't found.
399 	 */
get_position_of(action_ptr action)400 	iterator get_position_of(action_ptr action){ return std::find(begin(), end(), action); }
401 
402 	/**
403 	 * Returns the iterator for the first (executed earlier) action within the actions queue.
404 	 */
begin()405 	iterator begin(){ return actions_.begin(); }
406 	/** reverse version of the above */
rbegin()407 	reverse_iterator rbegin(){ return actions_.rbegin(); }
408 	/** const versions of the above */
begin() const409 	const_iterator begin() const { return actions_.begin(); }
rbegin() const410 	const_reverse_iterator rbegin() const { return actions_.rbegin(); }
411 
412 	/**
413 	 * Returns the iterator for the position *after* the last executed action within the actions queue.
414 	 */
end()415 	iterator end(){ return actions_.end(); }
416 	/** reverse version of the above */
rend()417 	reverse_iterator rend(){ return actions_.rend(); }
418 	/** const versions of the above */
end() const419 	const_iterator end() const { return actions_.end(); }
rend() const420 	const_reverse_iterator rend() const { return actions_.rend(); }
421 
turn_begin(size_t turn_num)422 	iterator turn_begin(size_t turn_num){ return actions_.turn_begin(turn_num); }
turn_end(size_t turn_num)423 	iterator turn_end(size_t turn_num){ return actions_.turn_end(turn_num); }
turn_rbegin(size_t turn_num)424 	reverse_iterator turn_rbegin(size_t turn_num){ return actions_.turn_rbegin(turn_num); }
turn_rend(size_t turn_num)425 	reverse_iterator turn_rend(size_t turn_num){ return actions_.turn_rend(turn_num); }
turn_begin(size_t turn_num) const426 	const_iterator turn_begin(size_t turn_num) const { return actions_.turn_begin(turn_num); }
turn_end(size_t turn_num) const427 	const_iterator turn_end(size_t turn_num) const { return actions_.turn_end(turn_num); }
turn_rbegin(size_t turn_num) const428 	const_reverse_iterator turn_rbegin(size_t turn_num) const { return actions_.turn_rbegin(turn_num); }
turn_rend(size_t turn_num) const429 	const_reverse_iterator turn_rend(size_t turn_num) const { return actions_.turn_rend(turn_num); }
430 
431 	/** Returns an iterator range corresponding to the requested turn. */
iter_turn(size_t turn_num)432 	range_t iter_turn(size_t turn_num){ return actions_.iter_turn(turn_num); }
riter_turn(size_t turn_num)433 	rrange_t riter_turn(size_t turn_num){ return actions_.riter_turn(turn_num); }
iter_turn(size_t turn_num) const434 	crange_t iter_turn(size_t turn_num) const { return actions_.iter_turn(turn_num); }
riter_turn(size_t turn_num) const435 	crrange_t riter_turn(size_t turn_num) const { return actions_.riter_turn(turn_num); }
436 
437 
438 	/**
439 	 * 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.
440 	 *
441 	 * This function makes sense when T is a non-chronological iterator.
442 	 * If T is @ref iterator and Compare is std::less<iterator>,
443 	 * this function returns limit if limit is in [between.first, between.second)
444 	 * or between.first if between.first>limit or end() otherwise.
445 	 *
446 	 * @param between the two iterators between which the action will be searched.
447 	 * @param limit the lower bound to search from, that is the return value `it' will verify !comp(limit, it).
448 	 * @param comp the predicate to compare with.
449 	 * @return `it' so that for all values `x' in [between.first, between.second), chronologically, !comp(x, it) and !comp(it, limit).
450 	 * @retval end() if no such action exist.
451 	 */
452 	template <typename T, typename Compare>
453 	iterator find_first_action_of(std::pair<T,T> between, iterator limit, Compare comp);
454 	template <typename T, typename Compare>
455 	const_iterator find_first_action_of(std::pair<T,T> between, const_iterator limit, Compare comp) const;
456 
457 	/**
458 	 * Find the first action occurring at a given hex.
459 	 *
460 	 * @retval end() if no action occurs at the given location.
461 	 */
462 	iterator find_first_action_at(map_location hex);
463 
464 	/**
465 	 * Finds the first action that belongs to this unit, starting the search at the specified position.
466 	 * @return The position, or end() if not found.
467 	 */
468 	iterator find_first_action_of(const unit& unit, iterator start_position);
469 	iterator find_first_action_of(size_t unit_id, iterator start_position);
470 	/** Variant of this method that always start searching at the beginning of the queue */
find_first_action_of(const unit & unit)471 	iterator find_first_action_of(const unit& unit){ return find_first_action_of(unit, begin()); }
find_first_action_of(size_t unit_id)472 	iterator find_first_action_of(size_t unit_id){ return find_first_action_of(unit_id, begin()); }
473 
474 	/**
475 	 * Finds the last action that belongs to this unit, starting the search backwards from the specified position.
476 	 * @return The position, or end() if not found.
477 	 */
478 	iterator find_last_action_of(const unit& unit, iterator start_position);
479 	iterator find_last_action_of(size_t unit_id, iterator start_position);
480 	/** const variant of the previous function */
481 	const_iterator find_last_action_of(const unit& unit, const_iterator start_position) const;
482 	const_iterator find_last_action_of(size_t unit_id, iterator start_position) const;
483 	/** Variant of the previous method that always start searching at the end of the queue */
484 	iterator find_last_action_of(const unit& unit);
485 	iterator find_last_action_of(size_t unit_id);
486 	/** const variant of the previous function */
487 	const_iterator find_last_action_of(const unit& unit) const;
488 	const_iterator find_last_action_of(size_t unit_id) const;
489 
490 	bool unit_has_actions(const unit& unit);
491 	size_t count_actions_of(const unit& unit);
492 	std::deque<action_ptr> actions_of(const unit& unit);
493 
494 	/**
495 	 * Determines the appropriate turn number for the next action planned for this unit
496 	 *
497 	 * @warning A return value of 0 can mean that the unit has one action planned on turn 0 or that the unit doesn't have any action planned on any turn.
498 	 *
499 	 * @retval 0 if the unit doesn't have any planned action
500 	 */
501 	size_t get_turn_num_of(const unit&) const;
502 
503 	/** Used to track gold spending by recruits/recalls when building the future unit map */
get_gold_spent() const504 	int get_gold_spent() const { return gold_spent_; }
505 	/** Used to track gold spending by recruits/recalls when building the future unit map */
506 	void change_gold_spent_by(int difference);
507 	/** Set gold spent back to zero */
508 	void reset_gold_spent();
509 	/** After a recruit action was executed the id of the unit was changed so we need to update the unitid of all following actions on that unit*/
510 	void update_recruited_unit(std::size_t old_id, unit& new_unit);
511 
512 	void raw_turn_shift();
513 	void synced_turn_shift();
514 
515 	/**
516 	 * Queues a move to be executed last
517 	 * @return The queued move's position
518 	 */
519 	iterator queue_move(size_t turn_num, unit& mover, const pathfind::marked_route& route,
520 			arrow_ptr arrow, fake_unit_ptr fake_unit);
521 
522 	/**
523 	 * Queues an attack or attack-move to be executed last
524 	 * @return The queued attack's position
525 	 */
526 	iterator queue_attack(size_t turn_num, unit& mover, const map_location& target_hex, int weapon_choice, const pathfind::marked_route& route,
527 			arrow_ptr arrow, fake_unit_ptr fake_unit);
528 
529 	/**
530 	 * Queues a recruit to be executed last
531 	 * @return The queued recruit's position
532 	 */
533 	iterator queue_recruit(size_t turn_num, const std::string& unit_name, const map_location& recruit_hex);
534 
535 	/**
536 	 * Queues a recall to be executed last
537 	 * @return The queued recall's position
538 	 */
539 	iterator queue_recall(size_t turn_num, const unit& unit, const map_location& recall_hex);
540 
541 	/**
542 	 * Queues a suppose_dead to be executed last
543 	 * @return The queued suppose_dead's position (an iterator to it)
544 	 */
545 	iterator queue_suppose_dead(size_t turn_num, unit& curr_unit, const map_location& loc);
546 
547 	/**
548 	 * Network code. A net_cmd object (a config in disguise) represents a modification
549 	 * to a side_actions object. execute_net_cmd() translates one of these into
550 	 * a real modification of *this. The make_net_cmd_***() family of functions is
551 	 * convenient for building specific types of net_cmds.
552 	 */
553 	typedef config net_cmd;
554 	void execute_net_cmd(const net_cmd&);
555 	net_cmd make_net_cmd_insert(size_t turn_num, size_t pos, action_const_ptr) const;
556 	net_cmd make_net_cmd_insert(const const_iterator& pos, action_const_ptr) const;
557 	net_cmd make_net_cmd_replace(const const_iterator& pos, action_const_ptr) const;
558 	net_cmd make_net_cmd_remove(const const_iterator& pos) const;
559 	net_cmd make_net_cmd_bump_later(const const_iterator& pos) const;
560 	net_cmd make_net_cmd_clear() const;
561 	net_cmd make_net_cmd_refresh() const;
562 
563 private:
564 	iterator safe_insert(size_t turn_num, size_t pos, action_ptr to_insert);
565 	iterator synced_erase(iterator itor);
566 	iterator synced_insert(iterator itor, action_ptr to_insert);
567 	iterator synced_enqueue(size_t turn_num, action_ptr to_insert);
568 	iterator safe_erase(const iterator& itor);
569 
570 	container actions_;
571 
572 	size_t team_index_;
573 	bool team_index_defined_;
574 
575 	/** Used to store gold "spent" in planned recruits/recalls when the future unit map is applied */
576 	int gold_spent_;
577 
578 	bool hidden_;
579 };
580 
581 /** Dumps side_actions on a stream, for debug purposes. */
582 std::ostream& operator<<(std::ostream &out, const wb::side_actions& side_actions);
583 
584 struct side_actions::numbers_t
585 {
586 	std::vector<int> numbers_to_draw;
587 	std::vector<size_t> team_numbers;
588 	int main_number;
589 	std::set<size_t> secondary_numbers;
590 
numbers_twb::side_actions::numbers_t591 	numbers_t()
592 			: numbers_to_draw()
593 			, team_numbers()
594 			, main_number(-1)
595 			, secondary_numbers()
596 		{}
597 };
598 
599 template <typename T, typename Compare>
find_first_action_of(std::pair<T,T> between,iterator limit,Compare comp)600 side_actions::iterator side_actions::find_first_action_of(std::pair<T,T> between, iterator limit, Compare comp)
601 {
602 	iterator first = actions_.end();
603 	for(T it = between.first; it != between.second; ++it) {
604 		iterator chrono_it = actions_.project<container::chronological>(it);
605 		if((comp(chrono_it, first) || first==actions_.end()) && !comp(chrono_it, limit)) {
606 			first = chrono_it;
607 		}
608 	}
609 	return first;
610 }
611 
612 template <typename T, typename Compare>
find_first_action_of(std::pair<T,T> between,const_iterator limit,Compare comp) const613 side_actions::const_iterator side_actions::find_first_action_of(std::pair<T,T> between, const_iterator limit, Compare comp) const
614 {
615 	const_iterator first = actions_.end();
616 	for(T it = between.first; it != between.second; ++it) {
617 		const_iterator chrono_it = actions_.project<container::chronological>(it);
618 		if((comp(chrono_it, first) || first==actions_.end()) && !comp(chrono_it, limit)) {
619 			first = chrono_it;
620 		}
621 	}
622 	return first;
623 }
624 
625 } //end namespace wb
626