add [on_undo]/[on_redo] actionwml

[on_undo]/[on_redo] contains tags that are executed when undoing the
current actions.
This commit is contained in:
gfgtdf 2015-09-11 20:30:08 +00:00
parent f01252a42c
commit 6010455f56
9 changed files with 117 additions and 3 deletions

View file

@ -1 +1,43 @@
#include "undo_action.hpp"
#include "scripting/game_lua_kernel.hpp"
#include "resources.hpp"
#include "variable.hpp" // vconfig
#include "game_events/pump.hpp" //game_events::queued_event
#include <cassert>
#include <boost/foreach.hpp>
namespace actions
{
void undo_action::execute_undo_umc_wml()
{
assert(resources::lua_kernel);
BOOST_FOREACH(const config& c, umc_commands_undo)
{
resources::lua_kernel->run_wml_action("command", vconfig(c), game_events::queued_event("undo", map_location(), map_location(), config()));
}
}
void undo_action::execute_redo_umc_wml()
{
assert(resources::lua_kernel);
BOOST_FOREACH(const config& c, umc_commands_redo)
{
resources::lua_kernel->run_wml_action("command", vconfig(c), game_events::queued_event("redo", map_location(), map_location(), config()));
}
}
void undo_action::read_tconfig_vector(tconfig_vector& vec, const config& cfg, const std::string& tag)
{
config::const_child_itors r = cfg.child_range(tag);
vec.insert(vec.end(), r.first, r.second);
}
void undo_action::write_tconfig_vector(const tconfig_vector& vec, config& cfg, const std::string& tag)
{
BOOST_FOREACH(const config& c, vec)
{
cfg.add_child(tag, c);
}
}
}

View file

@ -44,12 +44,22 @@ namespace actions {
: undo_action_base()
, replay_data()
, unit_id_diff(synced_context::get_unit_id_diff())
{ }
, umc_commands_undo()
, umc_commands_redo()
{
umc_commands_undo.swap(synced_context::get_undo_commands());
umc_commands_redo.swap(synced_context::get_redo_commands());
}
undo_action(const config& cfg)
: undo_action_base()
, replay_data(cfg.child_or_empty("replay_data"))
, unit_id_diff(cfg["unit_id_diff"])
{ }
, umc_commands_undo()
, umc_commands_redo()
{
read_tconfig_vector(umc_commands_undo, cfg, "undo_actions");
read_tconfig_vector(umc_commands_redo, cfg, "redo_actions");
}
// Virtual destructor to support derived classes.
virtual ~undo_action() {}
@ -58,6 +68,8 @@ namespace actions {
{
cfg.add_child("replay_data", replay_data);
cfg["unit_id_diff"] = unit_id_diff;
write_tconfig_vector(umc_commands_undo, cfg, "undo_actions");
write_tconfig_vector(umc_commands_redo, cfg, "redo_actions");
undo_action_base::write(cfg);
}
@ -71,8 +83,18 @@ namespace actions {
/// 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 boost::ptr_vector<config> tconfig_vector;
tconfig_vector umc_commands_undo;
tconfig_vector umc_commands_redo;
void execute_undo_umc_wml();
void execute_redo_umc_wml();
static void read_tconfig_vector(tconfig_vector& vec, const config& cfg, const std::string& tag);
static void write_tconfig_vector(const tconfig_vector& vec, config& cfg, const std::string& tag);
};
/// entry for player actions that do not need any special code to be performed when undoing such as right-click menu items.

View file

@ -26,6 +26,7 @@ bool dismiss_action::undo(int side)
team &current_team = (*resources::teams)[side-1];
current_team.recall_list().add(dismissed_unit);
execute_undo_umc_wml();
return true;
}
@ -40,6 +41,7 @@ bool dismiss_action::redo(int side)
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;
}

View file

@ -88,6 +88,7 @@ bool move_action::undo(int side)
u->anim_comp().set_standing();
gui.invalidate_unit_after_move(rev_route.front(), rev_route.back());
execute_undo_umc_wml();
return true;
}
@ -136,6 +137,7 @@ bool move_action::redo(int side)
gui.invalidate_unit_after_move(route.front(), route.back());
resources::recorder->redo(replay_data);
replay_data.clear();
execute_redo_umc_wml();
return true;
}

View file

@ -66,6 +66,7 @@ bool recall_action::undo(int side)
// to also do the overlapped hexes
gui.invalidate(recall_loc);
units.erase(recall_loc);
execute_undo_umc_wml();
return true;
}

View file

@ -59,6 +59,7 @@ bool recruit_action::undo(int side)
// to also do the overlapped hexes
gui.invalidate(recruit_loc);
units.erase(recruit_loc);
execute_undo_umc_wml();
return true;
}

View file

@ -1792,5 +1792,15 @@ WML_HANDLER_FUNCTION(wml_message, /*event_info*/, cfg)
handle_wml_log_message( cfg.get_parsed_config() );
}
WML_HANDLER_FUNCTION(on_undo, /*event_info*/, cfg)
{
synced_context::add_undo_commands(cfg.get_parsed_config());
}
WML_HANDLER_FUNCTION(on_redo, /*event_info*/, cfg)
{
synced_context::add_redo_commands(cfg.get_parsed_config());
}
} // end namespace game_events

View file

@ -53,6 +53,8 @@ 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::tconfig_vector synced_context::undo_commands_ = synced_context::tconfig_vector();
synced_context::tconfig_vector synced_context::redo_commands_ = synced_context::tconfig_vector();
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)
@ -388,6 +390,16 @@ config synced_context::ask_server_choice(const server_choice& sch)
}
}
void synced_context::add_undo_commands(const config& commands)
{
undo_commands_.insert(undo_commands_.begin(), new config(commands));
}
void synced_context::add_redo_commands(const config& commands)
{
redo_commands_.insert(redo_commands_.begin(), new config(commands));
}
set_scontext_synced_base::set_scontext_synced_base()
: new_rng_(synced_context::get_rng_for_action())
, old_rng_(random_new::generator)
@ -398,6 +410,8 @@ set_scontext_synced_base::set_scontext_synced_base()
synced_context::set_synced_state(synced_context::SYNCED);
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();
}

View file

@ -24,6 +24,8 @@
#include "mouse_handler_base.hpp"
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
class config;
//only static methods.
@ -144,6 +146,14 @@ public:
if we are in a mp game, ask the server, otherwise generate the answer ourselves.
*/
static config ask_server_choice(const server_choice&);
typedef boost::ptr_vector<config> tconfig_vector;
static tconfig_vector& get_undo_commands() { return undo_commands_; }
static tconfig_vector& get_redo_commands() { return redo_commands_; }
static void add_undo_commands(const config& commands);
static void add_redo_commands(const config& commands);
static void reset_undo_commands() { undo_commands_ = tconfig_vector(); }
static void reset_redo_commands() { redo_commands_ = tconfig_vector(); }
private:
/*
weather we are in a synced move, in a user_choice, or none of them
@ -154,12 +164,22 @@ private:
It's impossible to undo data that has been sended over the network.
false = we are on a local turn and haven't sended anything yet.
TODO: it would be better if the following variable were not static.
*/
static bool is_simultaneously_;
/**
Used to restore the unit id manager when undoing.
*/
static int last_unit_id_;
/**
Actions wml to be executed when the current actio is undone.
*/
static tconfig_vector undo_commands_;
/**
Actions wml to be executed when the current actio is redone.
*/
static tconfig_vector redo_commands_;
};