Whiteboard: add a new "Execute all actions" command,

...bound to ctrl+y by default, and added to the actions (not context)
menu. It executes actions in sequence until the first attack, or until
an action fails to execute. Fulfills the feature request of bug
#16807.

Simplified some return type in the process in side_actions: returning
iterators wasn't really useful for the execute functions.
This commit is contained in:
Gabriel Morin 2010-10-10 03:33:24 +00:00
parent 8db7212c73
commit ef81324150
10 changed files with 104 additions and 40 deletions

View file

@ -265,6 +265,11 @@
command=wbexecuteaction
key=y
[/hotkey]
[hotkey]
command=wbexecuteallactions
key=y
ctrl=yes
[/hotkey]
[hotkey]
command=wbdeleteaction
key=h

View file

@ -130,7 +130,7 @@
id=actions-menu
title= _ "Actions"
image=lite
items=undo,redo,wbexecuteaction,wbdeleteaction,cycle,speak,recruit,recall,showenemymoves,bestenemymoves,wbtoggle,delayshroud,updateshroud,endturn
items=undo,redo,wbexecuteallactions,wbexecuteaction,wbdeleteaction,cycle,speak,recruit,recall,showenemymoves,bestenemymoves,wbtoggle,delayshroud,updateshroud,endturn
rect="+2,=,+100,="
xanchor=fixed
yanchor=fixed

View file

@ -105,6 +105,7 @@ const struct {
// Whiteboard commands
{ hotkey::HOTKEY_WB_TOGGLE, "wbtoggle", N_("Toggle planning mode"), false, hotkey::SCOPE_GAME },
{ hotkey::HOTKEY_WB_EXECUTE_ACTION, "wbexecuteaction", N_("Execute planned action"), false, hotkey::SCOPE_GAME },
{ hotkey::HOTKEY_WB_EXECUTE_ALL_ACTIONS, "wbexecuteallactions", N_("Execute all actions"), false, hotkey::SCOPE_GAME },
{ hotkey::HOTKEY_WB_DELETE_ACTION, "wbdeleteaction", N_("Delete planned action"), false, hotkey::SCOPE_GAME },
{ hotkey::HOTKEY_WB_BUMP_UP_ACTION, "wbbumpupaction", N_("Move action up queue"), false, hotkey::SCOPE_GAME },
{ hotkey::HOTKEY_WB_BUMP_DOWN_ACTION, "wbbumpdownaction", N_("Move action down queue"), false, hotkey::SCOPE_GAME },
@ -923,6 +924,9 @@ bool command_executor::execute_command(HOTKEY_COMMAND command, int /*index*/)
case HOTKEY_WB_EXECUTE_ACTION:
whiteboard_execute_action();
break;
case HOTKEY_WB_EXECUTE_ALL_ACTIONS:
whiteboard_execute_all_actions();
break;
case HOTKEY_WB_DELETE_ACTION:
whiteboard_delete_action();
break;

View file

@ -65,6 +65,7 @@ enum HOTKEY_COMMAND {
// Whiteboard commands
HOTKEY_WB_TOGGLE,
HOTKEY_WB_EXECUTE_ACTION,
HOTKEY_WB_EXECUTE_ALL_ACTIONS,
HOTKEY_WB_DELETE_ACTION,
HOTKEY_WB_BUMP_UP_ACTION,
HOTKEY_WB_BUMP_DOWN_ACTION,
@ -311,6 +312,7 @@ public:
virtual void replay_skip_animation() {}
virtual void whiteboard_toggle() {}
virtual void whiteboard_execute_action() {}
virtual void whiteboard_execute_all_actions() {}
virtual void whiteboard_delete_action() {}
virtual void whiteboard_bump_up_action() {}
virtual void whiteboard_bump_down_action() {}

View file

@ -225,6 +225,10 @@ void playsingle_controller::whiteboard_execute_action(){
whiteboard_manager_->contextual_execute();
}
void playsingle_controller::whiteboard_execute_all_actions(){
whiteboard_manager_->execute_all_actions();
}
void playsingle_controller::whiteboard_delete_action(){
whiteboard_manager_->contextual_delete();
}
@ -1020,6 +1024,7 @@ bool playsingle_controller::can_execute_command(hotkey::HOTKEY_COMMAND command,
case hotkey::HOTKEY_WB_TOGGLE:
return true;
case hotkey::HOTKEY_WB_EXECUTE_ACTION:
case hotkey::HOTKEY_WB_EXECUTE_ALL_ACTIONS:
case hotkey::HOTKEY_WB_DELETE_ACTION:
return resources::whiteboard->can_execute_hotkey();
case hotkey::HOTKEY_WB_BUMP_UP_ACTION:

View file

@ -61,6 +61,7 @@ public:
// Whiteboard hotkeys
virtual void whiteboard_toggle();
virtual void whiteboard_execute_action();
virtual void whiteboard_execute_all_actions();
virtual void whiteboard_delete_action();
virtual void whiteboard_bump_up_action();
virtual void whiteboard_bump_down_action();

View file

@ -90,6 +90,11 @@ void manager::print_help_once()
//print_to_chat("[execute action]", "'" + hk_execute.get_name() + "'");
hotkeys << "Execute: " << hk_execute.get_name() << ", ";
}
const hotkey::hotkey_item& hk_execute_all = hotkey::get_hotkey(hotkey::HOTKEY_WB_EXECUTE_ALL_ACTIONS);
if(!hk_execute_all.null()) {
//print_to_chat("[execute action]", "'" + hk_execute_all.get_name() + "'");
hotkeys << "Execute all: " << hk_execute_all.get_name() << ", ";
}
const hotkey::hotkey_item& hk_delete = hotkey::get_hotkey(hotkey::HOTKEY_WB_DELETE_ACTION);
if(!hk_delete.null()) {
//print_to_chat("[delete action]", "'" + hk_delete.get_name() + "'");
@ -598,6 +603,19 @@ void manager::contextual_execute()
}
}
void manager::execute_all_actions()
{
if (!(executing_actions_ || viewer_actions()->empty() || resources::controller->is_linger_mode())
&& resources::controller->current_side() == resources::screen->viewing_side())
{
erase_temp_move();
validate_viewer_actions();
executing_actions_ = true;
viewer_actions()->execute_all();
executing_actions_ = false;
}
}
void manager::contextual_delete()
{
if (!(executing_actions_ || viewer_actions()->empty() || resources::controller->is_linger_mode()))

View file

@ -123,6 +123,8 @@ public:
/** Executes first action in the queue for current side */
void contextual_execute();
/** Executes all actions in the queue in sequence */
void execute_all_actions();
/** Deletes last action in the queue for current side */
void contextual_delete();
/** Moves the action determined by the UI toward the beginning of the queue */

View file

@ -139,7 +139,7 @@ void side_actions::draw_hex(const map_location& hex)
}
}
side_actions::iterator side_actions::execute_next()
bool side_actions::execute_next()
{
if (!actions_.empty())
{
@ -147,51 +147,75 @@ side_actions::iterator side_actions::execute_next()
}
else
{
return end();
return false;
}
}
side_actions::iterator side_actions::execute(side_actions::iterator position)
void side_actions::execute_all()
{
if (actions_.empty())
{
WRN_WB << "\"Execute All\" attempt with empty queue.\n";
return;
}
if (resources::whiteboard->has_planned_unit_map())
{
ERR_WB << "Modifying action queue while temp modifiers are applied!!!\n";
}
LOG_WB << "Before executing all actions, " << *this << "\n";
bool keep_executing = true;
while (keep_executing)
{
iterator position = begin();
bool is_attack = boost::dynamic_pointer_cast<attack>(*position);
bool finished = execute(position);
keep_executing = finished && !is_attack && !empty();
}
}
bool side_actions::execute(side_actions::iterator position)
{
if (resources::whiteboard->has_planned_unit_map())
{
ERR_WB << "Modifying action queue while temp modifiers are applied!!!\n";
}
if (!actions_.empty() && validate_iterator(position))
{
LOG_WB << "Before execution, " << *this << "\n";
size_t distance = std::distance(begin(), position);
action_ptr action = *position;
bool finished;
try {
finished = action->execute();
} catch (end_turn_exception e) {
actions_.erase(position);
LOG_WB << "End turn exception caught during execution, deleting action. " << *this << "\n";
validate_actions();
throw;
}
if (actions_.empty() || !validate_iterator(position))
return false;
if (finished)
{
actions_.erase(position);
LOG_WB << "After execution and deletion, " << *this << "\n";
validate_actions();
return begin() + distance;
}
else
{
actions_.erase(position);
actions_.insert(end(), action);
LOG_WB << "After execution *without* deletion, " << *this << "\n";
validate_actions();
return end() - 1;
}
LOG_WB << "Before execution, " << *this << "\n";
action_ptr action = *position;
bool finished;
try {
finished = action->execute();
} catch (end_turn_exception e) {
actions_.erase(position);
LOG_WB << "End turn exception caught during execution, deleting action. " << *this << "\n";
validate_actions();
throw;
}
if (finished)
{
actions_.erase(position);
LOG_WB << "After execution and deletion, " << *this << "\n";
validate_actions();
return true;
}
else
{
return end();
//Idea that needs refining: move action at the end of the queue if it failed executing:
//actions_.erase(position);
//actions_.insert(end(), action);
LOG_WB << "After execution *without* deletion, " << *this << "\n";
validate_actions();
return false;
}
}

View file

@ -64,18 +64,21 @@ public:
/**
* Executes the first action in the queue, and then deletes it.
* @return An iterator to the action itself if not finished, or else to the new first in line.
* Returns end() if no actions remain.
* @return true - if the action was completed successfully
*/
iterator execute_next();
bool execute_next();
/**
* Execute all actions in sequence until the fist attack, or until an action fails to execute.
*/
void execute_all();
/**
* Executes the specified action, if it exists in the queue.
* If the action is not finished, it's moved at the end of the queue.
* @return An iterator to the action itself if not finished, or else the next action in the queue.
* Returns end() if no actions remain.
* @return true - if the action was completed successfully
*/
iterator execute(iterator position);
bool execute(iterator position);
/**
* Returns the iterator for the first (executed earlier) action within the actions queue.