Make local copies of paths so that...

...they are sure to remain valid during movement.

Fixes bug# 20199.
This commit is contained in:
J. Tyne 2012-09-28 00:18:57 +00:00
parent 0960610764
commit 281e2c7467
3 changed files with 25 additions and 16 deletions

View file

@ -723,6 +723,9 @@ void mouse_handler::deselect_hex() {
*/
bool mouse_handler::move_unit_along_current_route()
{
// Copy the current route to ensure it remains valid throughout the animation.
const std::vector<map_location> steps = current_route_.steps;
// do not show footsteps during movement
gui().set_route(NULL);
gui().unhighlight_reach();
@ -732,12 +735,12 @@ bool mouse_handler::move_unit_along_current_route()
gui().select_hex(map_location());
bool interrupted = false;
if ( current_route_.steps.size() > 1 )
if ( steps.size() > 1 )
{
size_t num_moves = move_unit_along_route(current_route_, interrupted);
size_t num_moves = move_unit_along_route(steps, interrupted);
interrupted = interrupted || num_moves + 1 < current_route_.steps.size();
next_unit_ = current_route_.steps[num_moves];
interrupted = interrupted || num_moves + 1 < steps.size();
next_unit_ = steps[num_moves];
}
// invalid after the move
@ -752,18 +755,21 @@ bool mouse_handler::move_unit_along_current_route()
* This is specifically for movement at the time it is initiated by a player,
* whether via a mouse click or executing whiteboard actions. Continued moves
* (including goto execution) can bypass this and call ::move_unit() directly.
* This function call may include time for an animation, so make sure the
* provided route will remain unchanged (the caller should probably make a local
* copy).
*
* @param[in] route The route to be traveled. The unit to be moved is at the beginning of this route.
* @param[in] steps The route to be traveled. The unit to be moved is at the beginning of this route.
* @param[out] interrupted This is set to true if information was uncovered that warrants interrupting a chain of actions (and set to false otherwise).
*
* @returns The number of hexes entered. This can safely be used as an index
* into route.steps to get the location where movement ended, provided
* route.steps is not empty (the return value is guaranteed to be less
* than route.steps.size() ).
* into steps to get the location where movement ended, provided
* steps is not empty (the return value is guaranteed to be less
* than steps.size() ).
*/
size_t mouse_handler::move_unit_along_route(pathfind::marked_route const& route, bool & interrupted)
size_t mouse_handler::move_unit_along_route(const std::vector<map_location> & steps,
bool & interrupted)
{
const std::vector<map_location> steps = route.steps;
if(steps.empty()) {
interrupted = false;
return 0;

View file

@ -72,7 +72,7 @@ public:
void attack_enemy(const map_location& attacker_loc, const map_location& defender_loc, int choice);
/// Moves a unit across the board for a player.
size_t move_unit_along_route(pathfind::marked_route const& route, bool & interrupted);
size_t move_unit_along_route(const std::vector<map_location> & steps, bool & interrupted);
void select_hex(const map_location& hex, const bool browse,
const bool highlight = true,

View file

@ -207,6 +207,9 @@ void move::execute(bool& success, bool& complete)
LOG_WB << "Executing: " << shared_from_this() << "\n";
// Copy the current route to ensure it remains valid throughout the animation.
const std::vector<map_location> steps = route_->steps;
set_arrow_brightness(ARROW_BRIGHTNESS_HIGHLIGHTED);
hide_fake_unit();
@ -214,12 +217,12 @@ void move::execute(bool& success, bool& complete)
bool interrupted;
try {
events::mouse_handler& mouse_handler = resources::controller->get_mouse_handler_base();
num_steps = mouse_handler.move_unit_along_route(*route_, interrupted);
num_steps = mouse_handler.move_unit_along_route(steps, interrupted);
} catch (end_turn_exception&) {
set_arrow_brightness(ARROW_BRIGHTNESS_STANDARD);
throw; // we rely on the caller to delete this action
}
const map_location final_location = route_->steps[num_steps];
const map_location & final_location = steps[num_steps];
unit_map::const_iterator unit_it = resources::units->find(final_location);
if ( num_steps == 0 )
@ -236,7 +239,7 @@ void move::execute(bool& success, bool& complete)
}
else
{
complete = num_steps + 1 == route_->steps.size();
complete = num_steps + 1 == steps.size();
success = complete && !interrupted;
if ( !success )
@ -251,9 +254,9 @@ void move::execute(bool& success, bool& complete)
else
{
LOG_WB << "Move finished at (" << final_location << ") instead of at (" << get_dest_hex() << "). Setting new path.\n";
route_->steps = std::vector<map_location>(route_->steps.begin() + num_steps, route_->steps.end());
route_->steps = std::vector<map_location>(steps.begin() + num_steps, steps.end());
//FIXME: probably better to use the new calculate_new_route() instead of the above:
//calculate_new_route(final_location, route_->steps.back());
//calculate_new_route(final_location, steps.back());
// Of course, "better" would need to be verified.
arrow_->set_path(route_->steps);
}