Merge pull request #936 from gfgtdf/no_on_redo
use the original action codepath when redoing
This commit is contained in:
commit
33c2e6aa67
15 changed files with 17 additions and 252 deletions
|
@ -310,15 +310,7 @@ void undo_list::read(const config & cfg)
|
|||
// Build the redo stack.
|
||||
for (const config & child : cfg.child_range("redo")) {
|
||||
try {
|
||||
undo_action_base * action = create_action(child);
|
||||
if ( undo_action* undoable_action = dynamic_cast<undo_action*>(action)) {
|
||||
redos_.push_back(undoable_action);
|
||||
} else {
|
||||
delete action;
|
||||
ERR_NG << "Error: redo contained action that is not undoable" << std::endl;
|
||||
ERR_NG << "config was: " << child.debug() << std::endl;
|
||||
ERR_NG << "Skipping this redo action..." << std::endl;
|
||||
}
|
||||
redos_.push_back(new config(child));
|
||||
} catch (bad_lexical_cast &) {
|
||||
ERR_NG << "Error when parsing redo list from config: bad lexical cast." << std::endl;
|
||||
ERR_NG << "config was: " << child.debug() << std::endl;
|
||||
|
@ -344,7 +336,7 @@ void undo_list::write(config & cfg) const
|
|||
it->write(cfg.add_child("undo"));
|
||||
|
||||
for ( redos_list::const_iterator it = redos_.begin(); it != redos_.end(); ++it )
|
||||
it->write(cfg.add_child("redo"));
|
||||
cfg.add_child("redo") = *it;
|
||||
}
|
||||
|
||||
|
||||
|
@ -375,9 +367,9 @@ void undo_list::undo()
|
|||
resources::gameboard->unit_id_manager().set_save_id(last_unit_id - undoable_action->unit_id_diff);
|
||||
|
||||
// Bookkeeping.
|
||||
resources::recorder->undo_cut(undoable_action->replay_data);
|
||||
//we can do a static cast here because we alreeady checked with the dynamic cast above.
|
||||
redos_.push_back(static_cast<undo_action*>(action.release()));
|
||||
redos_.push_back(new config());
|
||||
resources::recorder->undo_cut(redos_.back());
|
||||
|
||||
resources::whiteboard->on_gamestate_change();
|
||||
|
||||
// Screen updates.
|
||||
|
@ -415,39 +407,20 @@ void undo_list::redo()
|
|||
// only if the redo is successful.)
|
||||
redos_list::auto_type action = redos_.pop_back();
|
||||
|
||||
if (preferences::get("no_on_redo", false)) {
|
||||
// And alterntive redo codepath which just call the original actions, using this over the othr one has some advantages:
|
||||
// 1) wml no longer needs [on_redo] since the engine will execute the original moveto etc. events
|
||||
// 2) It simplifies the c++ code since all undo_actions::redo functions can be removed.
|
||||
|
||||
const config& command_wml = action->replay_data.child("command");
|
||||
std::string commandname = command_wml.all_children_range().front().key;
|
||||
const config& data = command_wml.all_children_range().front().cfg;
|
||||
const config& command_wml = action->child("command");
|
||||
std::string commandname = command_wml.all_children_range().front().key;
|
||||
const config& data = command_wml.all_children_range().front().cfg;
|
||||
|
||||
resources::recorder->redo(const_cast<const config&>(action->replay_data));
|
||||
resources::recorder->redo(const_cast<const config&>(*action));
|
||||
|
||||
|
||||
// synced_context::run readds the undo command with the normal undo_lis::add function whihc clears the
|
||||
// redo stack which makes redoign of more than one move impossible. to work around that we save redo stack here and set it later.
|
||||
redos_list temp;
|
||||
temp.swap(redos_);
|
||||
synced_context::run(commandname, data, /*use_undo*/ true, /*show*/ true);
|
||||
temp.swap(redos_);
|
||||
}
|
||||
else {
|
||||
int last_unit_id = resources::gameboard->unit_id_manager().get_save_id();
|
||||
if (!action->redo(side_)) {
|
||||
return;
|
||||
}
|
||||
if (last_unit_id + action->unit_id_diff < static_cast<int>(resources::gameboard->unit_id_manager().get_save_id())) {
|
||||
ERR_NG << "Too many units were generated during redoing." << std::endl;
|
||||
}
|
||||
resources::gameboard->unit_id_manager().set_save_id(last_unit_id + action->unit_id_diff);
|
||||
// synced_context::run readds the undo command with the normal undo_lis::add function whihc clears the
|
||||
// redo stack which makes redoign of more than one move impossible. to work around that we save redo stack here and set it later.
|
||||
redos_list temp;
|
||||
temp.swap(redos_);
|
||||
synced_context::run(commandname, data, /*use_undo*/ true, /*show*/ true);
|
||||
temp.swap(redos_);
|
||||
|
||||
// Bookkeeping.
|
||||
undos_.push_back(action.release());
|
||||
resources::whiteboard->on_gamestate_change();
|
||||
}
|
||||
// Screen updates.
|
||||
gui.invalidate_unit();
|
||||
gui.invalidate_game_status();
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace actions {
|
|||
class undo_list {
|
||||
|
||||
typedef boost::ptr_vector<undo_action_base> action_list;
|
||||
typedef boost::ptr_vector<undo_action> redos_list;
|
||||
typedef boost::ptr_vector<config> redos_list;
|
||||
|
||||
public:
|
||||
undo_list(const undo_list&) = delete;
|
||||
|
|
|
@ -49,27 +49,21 @@ undo_event::undo_event(const config& first, const config& second, const config&
|
|||
|
||||
undo_action::undo_action()
|
||||
: undo_action_base()
|
||||
, replay_data()
|
||||
, unit_id_diff(synced_context::get_unit_id_diff())
|
||||
{
|
||||
auto& undo = synced_context::get_undo_commands();
|
||||
auto& redo = synced_context::get_redo_commands();
|
||||
auto command_transformer = [](const std::pair<config, game_events::queued_event>& p) {
|
||||
return undo_event(p.first, p.second);
|
||||
};
|
||||
std::transform(undo.begin(), undo.end(), std::back_inserter(umc_commands_undo), command_transformer);
|
||||
std::transform(redo.begin(), redo.end(), std::back_inserter(umc_commands_redo), command_transformer);
|
||||
undo.clear();
|
||||
redo.clear();
|
||||
}
|
||||
|
||||
undo_action::undo_action(const config& cfg)
|
||||
: undo_action_base()
|
||||
, replay_data(cfg.child_or_empty("replay_data"))
|
||||
, unit_id_diff(cfg["unit_id_diff"])
|
||||
{
|
||||
read_event_vector(umc_commands_undo, cfg, "undo_actions");
|
||||
read_event_vector(umc_commands_redo, cfg, "redo_actions");
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -120,22 +114,11 @@ void undo_action::execute_undo_umc_wml()
|
|||
}
|
||||
}
|
||||
|
||||
void undo_action::execute_redo_umc_wml()
|
||||
{
|
||||
assert(resources::lua_kernel);
|
||||
assert(resources::gamedata);
|
||||
for(const undo_event& e : umc_commands_redo)
|
||||
{
|
||||
execute_event(e, "redo");
|
||||
}
|
||||
}
|
||||
|
||||
void undo_action::write(config & cfg) const
|
||||
{
|
||||
cfg.add_child("replay_data", replay_data);
|
||||
cfg["unit_id_diff"] = unit_id_diff;
|
||||
write_event_vector(umc_commands_undo, cfg, "undo_actions");
|
||||
write_event_vector(umc_commands_redo, cfg, "redo_actions");
|
||||
undo_action_base::write(cfg);
|
||||
}
|
||||
|
||||
|
|
|
@ -60,22 +60,13 @@ namespace actions {
|
|||
/// Undoes this action.
|
||||
/// @return true on success; false on an error.
|
||||
virtual bool undo(int side) = 0;
|
||||
/// Redoes this action.
|
||||
/// @return true on success; false on an error.
|
||||
virtual bool redo(int side) = 0;
|
||||
/// the replay data to do this action, this is only !empty() when this action is on the redo stack
|
||||
/// we need this because we don't recalculate the redos like they would be in real game,
|
||||
/// but even undoable commands can have "dependent" (= user_input) commands, which we save here.
|
||||
config replay_data;
|
||||
/// the difference in the unit ids
|
||||
/// TODO: does it really make sense to allow undoing if the unit id counter has changed?
|
||||
int unit_id_diff;
|
||||
/// actions wml (specified by wml) that should be executed when undoing this command.
|
||||
typedef std::vector<undo_event> event_vector;
|
||||
event_vector umc_commands_undo;
|
||||
event_vector umc_commands_redo;
|
||||
void execute_undo_umc_wml();
|
||||
void execute_redo_umc_wml();
|
||||
|
||||
static void read_event_vector(event_vector& vec, const config& cfg, const std::string& tag);
|
||||
static void write_event_vector(const event_vector& vec, config& cfg, const std::string& tag);
|
||||
|
@ -99,12 +90,6 @@ namespace actions {
|
|||
{
|
||||
return true;
|
||||
}
|
||||
/// Redoes this action.
|
||||
virtual bool redo(int)
|
||||
{
|
||||
replay_data.clear();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -31,20 +31,5 @@ bool dismiss_action::undo(int side)
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redoes this action.
|
||||
* @return true on success; false on an error.
|
||||
*/
|
||||
bool dismiss_action::redo(int side)
|
||||
{
|
||||
team ¤t_team = resources::gameboard->teams()[side-1];
|
||||
|
||||
resources::recorder->redo(replay_data);
|
||||
replay_data.clear();
|
||||
current_team.recall_list().erase_if_matches_id(dismissed_unit->id());
|
||||
execute_redo_umc_wml();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,8 +32,6 @@ struct dismiss_action : undo_action
|
|||
|
||||
/// Undoes this action.
|
||||
virtual bool undo(int side);
|
||||
/// Redoes this action.
|
||||
virtual bool redo(int side);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -79,46 +79,6 @@ bool move_action::undo(int)
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redoes this action.
|
||||
* @return true on success; false on an error.
|
||||
*/
|
||||
bool move_action::redo(int)
|
||||
{
|
||||
game_display & gui = *resources::screen;
|
||||
unit_map & units = resources::gameboard->units();
|
||||
|
||||
// Check units.
|
||||
unit_map::iterator u = units.find(route.front());
|
||||
if ( u == units.end() ) {
|
||||
ERR_NG << "Illegal movement 'redo'." << std::endl;
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Adjust starting moves.
|
||||
const int saved_moves = starting_moves;
|
||||
starting_moves = u->movement_left();
|
||||
|
||||
// Move the unit.
|
||||
unit_display::move_unit(route, u.get_shared_ptr());
|
||||
units.move(u->get_location(), route.back());
|
||||
u = units.find(route.back());
|
||||
unit::clear_status_caches();
|
||||
|
||||
// Set the unit's state.
|
||||
u->set_goto(goto_hex);
|
||||
u->set_movement(saved_moves, true);
|
||||
u->anim_comp().set_standing();
|
||||
|
||||
this->take_village();
|
||||
|
||||
gui.invalidate_unit_after_move(route.front(), route.back());
|
||||
resources::recorder->redo(replay_data, true);
|
||||
replay_data.clear();
|
||||
execute_redo_umc_wml();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,8 +46,6 @@ struct move_action : undo_action, shroud_clearing_action
|
|||
|
||||
/// Undoes this action.
|
||||
virtual bool undo(int side);
|
||||
/// Redoes this action.
|
||||
virtual bool redo(int side);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -72,47 +72,5 @@ bool recall_action::undo(int side)
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redoes this action.
|
||||
* @return true on success; false on an error.
|
||||
*/
|
||||
bool recall_action::redo(int side)
|
||||
{
|
||||
game_display & gui = *resources::screen;
|
||||
team ¤t_team = resources::gameboard->teams()[side-1];
|
||||
|
||||
map_location loc = route.front();
|
||||
map_location from = recall_from;
|
||||
|
||||
unit_ptr un = current_team.recall_list().find_if_matches_id(id);
|
||||
if ( !un ) {
|
||||
ERR_NG << "Trying to redo a recall of '" << id
|
||||
<< "', but that unit is not in the recall list.";
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string &msg = find_recall_location(side, loc, from, *un);
|
||||
if ( msg.empty() ) {
|
||||
resources::recorder->redo(replay_data);
|
||||
replay_data.clear();
|
||||
set_scontext_synced sync;
|
||||
recall_unit(id, current_team, loc, from, true, false);
|
||||
|
||||
// Quick error check. (Abuse of [allow_undo]?)
|
||||
if ( loc != route.front() ) {
|
||||
ERR_NG << "When redoing a recall at " << route.front()
|
||||
<< ", the location was moved to " << loc << ".\n";
|
||||
// Not really fatal, I suppose. Just update the action so
|
||||
// undoing this works.
|
||||
route.front() = loc;
|
||||
}
|
||||
sync.do_final_checkup();
|
||||
} else {
|
||||
gui2::show_transient_message(gui.video(), "", msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,8 +39,6 @@ struct recall_action : undo_action, shroud_clearing_action
|
|||
|
||||
/// Undoes this action.
|
||||
virtual bool undo(int side);
|
||||
/// Redoes this action.
|
||||
virtual bool redo(int side);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -65,52 +65,5 @@ bool recruit_action::undo(int side)
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redoes this action.
|
||||
* @return true on success; false on an error.
|
||||
*/
|
||||
bool recruit_action::redo(int side)
|
||||
{
|
||||
game_display & gui = *resources::screen;
|
||||
team ¤t_team = resources::gameboard->teams()[side-1];
|
||||
|
||||
map_location loc = route.front();
|
||||
map_location from = recruit_from;
|
||||
const std::string & name = u_type.base_id();
|
||||
|
||||
//search for the unit to be recruited in recruits
|
||||
if ( !util::contains(get_recruits(side, loc), name) ) {
|
||||
ERR_NG << "Trying to redo a recruit for side " << side
|
||||
<< ", which does not recruit type \"" << name << "\"\n";
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
current_team.last_recruit(name);
|
||||
const std::string &msg = find_recruit_location(side, loc, from, name);
|
||||
if ( msg.empty() ) {
|
||||
//MP_COUNTDOWN: restore recruitment bonus
|
||||
current_team.set_action_bonus_count(1 + current_team.action_bonus_count());
|
||||
resources::recorder->redo(replay_data);
|
||||
replay_data.clear();
|
||||
set_scontext_synced sync;
|
||||
recruit_unit(u_type, side, loc, from, true, false);
|
||||
|
||||
// Quick error check. (Abuse of [allow_undo]?)
|
||||
if ( loc != route.front() ) {
|
||||
ERR_NG << "When redoing a recruit at " << route.front()
|
||||
<< ", the location was moved to " << loc << ".\n";
|
||||
// Not really fatal, I suppose. Just update the action so
|
||||
// undoing this works.
|
||||
route.front() = loc;
|
||||
}
|
||||
sync.do_final_checkup();
|
||||
} else {
|
||||
gui2::show_transient_message(gui.video(), "", msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,8 +38,6 @@ struct recruit_action : undo_action, shroud_clearing_action
|
|||
|
||||
/// Undoes this action.
|
||||
virtual bool undo(int side);
|
||||
/// Redoes this action.
|
||||
virtual bool redo(int side);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -966,13 +966,8 @@ WML_HANDLER_FUNCTION(on_undo, event_info, cfg)
|
|||
}
|
||||
}
|
||||
|
||||
WML_HANDLER_FUNCTION(on_redo, event_info, cfg)
|
||||
WML_HANDLER_FUNCTION(on_redo, , )
|
||||
{
|
||||
if(cfg["delayed_variable_substitution"].to_bool(false)) {
|
||||
synced_context::add_redo_commands(cfg.get_config(), event_info);
|
||||
} else {
|
||||
synced_context::add_redo_commands(cfg.get_parsed_config(), event_info);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace game_events
|
||||
|
|
|
@ -51,7 +51,6 @@ static lg::log_domain log_replay("replay");
|
|||
synced_context::synced_state synced_context::state_ = synced_context::UNSYNCED;
|
||||
int synced_context::last_unit_id_ = 0;
|
||||
synced_context::event_list synced_context::undo_commands_;
|
||||
synced_context::event_list synced_context::redo_commands_;
|
||||
bool synced_context::is_simultaneously_ = false;
|
||||
|
||||
bool synced_context::run(const std::string& commandname, const config& data, bool use_undo, bool show, synced_command::error_handler_function error_handler)
|
||||
|
@ -371,21 +370,11 @@ void synced_context::add_undo_commands(const config& commands, const game_events
|
|||
undo_commands_.emplace_front(commands, ctx);
|
||||
}
|
||||
|
||||
void synced_context::add_redo_commands(const config& commands, const game_events::queued_event& ctx)
|
||||
{
|
||||
redo_commands_.emplace_front(commands, ctx);
|
||||
}
|
||||
|
||||
void synced_context::reset_undo_commands()
|
||||
{
|
||||
undo_commands_.clear();
|
||||
}
|
||||
|
||||
void synced_context::reset_redo_commands()
|
||||
{
|
||||
redo_commands_.clear();
|
||||
}
|
||||
|
||||
set_scontext_synced_base::set_scontext_synced_base()
|
||||
: new_rng_(synced_context::get_rng_for_action())
|
||||
, old_rng_(random_new::generator)
|
||||
|
@ -397,7 +386,6 @@ set_scontext_synced_base::set_scontext_synced_base()
|
|||
synced_context::reset_is_simultaneously();
|
||||
synced_context::set_last_unit_id(resources::gameboard->unit_id_manager().get_save_id());
|
||||
synced_context::reset_undo_commands();
|
||||
synced_context::reset_redo_commands();
|
||||
old_rng_ = random_new::generator;
|
||||
random_new::generator = new_rng_.get();
|
||||
}
|
||||
|
|
|
@ -148,11 +148,8 @@ public:
|
|||
|
||||
typedef std::deque<std::pair<config,game_events::queued_event>> event_list;
|
||||
static event_list& get_undo_commands() { return undo_commands_; }
|
||||
static event_list& get_redo_commands() { return redo_commands_; }
|
||||
static void add_undo_commands(const config& commands, const game_events::queued_event& ctx);
|
||||
static void add_redo_commands(const config& commands, const game_events::queued_event& ctx);
|
||||
static void reset_undo_commands();
|
||||
static void reset_redo_commands();
|
||||
private:
|
||||
/*
|
||||
weather we are in a synced move, in a user_choice, or none of them
|
||||
|
@ -175,10 +172,6 @@ private:
|
|||
Actions wml to be executed when the current actio is undone.
|
||||
*/
|
||||
static event_list undo_commands_;
|
||||
/**
|
||||
Actions wml to be executed when the current actio is redone.
|
||||
*/
|
||||
static event_list redo_commands_;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue