Resolve crash when unit is killed before its planned actions are completed (Bug #20071)

Attempt to resolve bug #20071 where a unit with planned actions is killed before those actions can be completed. This would otherwise result in an assertion failure or crash to desktop because sa.find_last_action_of() would be making a null pointer reference (get_unit() returns null when the unit is killed).

I have tested this with one unit killed before planned actions are completed, two units killed before planned actions are completed, and a mixture of live units with planned actions completed, live units with planned actions incomplete, and units killed before planned actions are completed. The catch is that planned actions painted on the screen get left behind after their respective units are killed off, until the mouse cursor hovers over the actions and triggers a redraw. But it is better than nothing and at the very least the game should not crash any more.

I'm not familiar with all the code, but at a high level I suppose a solution to the above is to do a check on side_actions whenever a unit is killed. (I think last_action_redraw() is only called when the mouse cursor hovers over a planned action or its unit.) I think this would be more work, in places outside of the whiteboard area of code used for action planning.
This commit is contained in:
Wedge009 2015-09-24 00:11:17 +10:00
parent 4d0fbc1d4e
commit 1b6f997834

View file

@ -190,6 +190,22 @@ void highlighter::last_action_redraw(move_ptr move)
//Last action with a fake unit always gets normal appearance
if(move->get_fake_unit()) {
side_actions& sa = *resources::gameboard->teams().at(move->team_index()).get_side_actions().get();
// Units with planned actions may have been killed in the previous turn before all actions were completed.
// In these cases, remove these planned actions for any invalid units and do not redraw anything.
if (move->get_unit() == NULL)
{
// Note: the planned actions seem to only get removed from the screen when
// a redraw is triggered by the mouse cursor moving over them.
for (side_actions::iterator iterator = sa.begin(); iterator < sa.end(); iterator++)
{
if (iterator->get()->get_unit() == NULL)
sa.remove_action (iterator);
}
return;
}
side_actions::iterator last_action = sa.find_last_action_of(*(move->get_unit()));
side_actions::iterator second_to_last_action = last_action != sa.end() && last_action != sa.begin() ? last_action - 1 : sa.end();