Simplification of the validation logic.
This commit is contained in:
parent
18e0ef7822
commit
3d442c6cea
24 changed files with 361 additions and 611 deletions
|
@ -799,7 +799,6 @@ set(wesnoth-main_SRC
|
|||
whiteboard/side_actions.cpp
|
||||
whiteboard/suppose_dead.cpp
|
||||
whiteboard/utility.cpp
|
||||
whiteboard/validate_visitor.cpp
|
||||
${network_implementation_files} # network.cpp and network_worker.cpp are included by default (without USE_ANA_NETWORK)
|
||||
)
|
||||
|
||||
|
|
|
@ -479,7 +479,6 @@ wesnoth_sources = Split("""
|
|||
whiteboard/side_actions.cpp
|
||||
whiteboard/suppose_dead.cpp
|
||||
whiteboard/utility.cpp
|
||||
whiteboard/validate_visitor.cpp
|
||||
widgets/combo.cpp
|
||||
widgets/combo_drag.cpp
|
||||
widgets/drop_target.cpp
|
||||
|
|
|
@ -40,9 +40,7 @@ struct dummy_action: action{
|
|||
map_location get_numbering_hex() const { return map_location(); }
|
||||
unit* get_unit() const { return 0; }
|
||||
fake_unit_ptr get_fake_unit(){ return fake_unit_ptr(); }
|
||||
void set_valid(bool){}
|
||||
bool is_valid() const { return true; }
|
||||
bool validate(){ return action_ptr(); }
|
||||
error check() const { return OK; }
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_SUITE( whiteboard_side_actions_container )
|
||||
|
|
|
@ -54,6 +54,8 @@ public:
|
|||
|
||||
/** Gets called by display when drawing a hex, to allow actions to draw to the screen. */
|
||||
virtual void draw_hex(const map_location& hex) = 0;
|
||||
/** Redrawing function, called each time the action situation might have changed. */
|
||||
virtual void redraw(){}
|
||||
|
||||
/** Sets whether or not the action should be drawn on the screen. */
|
||||
void hide();
|
||||
|
@ -83,20 +85,6 @@ public:
|
|||
return static_cast<int>(team_index_) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates to an action whether its status is invalid, and whether it should change its
|
||||
* display (and avoid any change to the game state) accordingly
|
||||
*/
|
||||
virtual void set_valid(bool valid) = 0;
|
||||
virtual bool is_valid() const = 0;
|
||||
|
||||
/**
|
||||
* Recalculate the validity of the action.
|
||||
*
|
||||
* @return whether the action should be kept.
|
||||
* */
|
||||
virtual bool validate() = 0;
|
||||
|
||||
/** Constructs and returns a config object representing this object. */
|
||||
virtual config to_config() const;
|
||||
/** Constructs an object of a subclass of wb::action using a config. Current behavior is to return a null pointer for unrecognized config. */
|
||||
|
@ -107,6 +95,42 @@ public:
|
|||
ctor_err(const std::string& message) : game::error(message){}
|
||||
};
|
||||
|
||||
/**
|
||||
* Possible errors.
|
||||
*
|
||||
* Returned by the @ref check function.
|
||||
*/
|
||||
enum error
|
||||
{
|
||||
OK,
|
||||
INVALID_LOCATION,
|
||||
NO_UNIT,
|
||||
UNIT_CHANGED,
|
||||
LOCATION_OCCUPIED,
|
||||
TOO_FAR,
|
||||
NO_TARGET,
|
||||
NO_ATTACK_LEFT,
|
||||
NOT_AN_ENEMY,
|
||||
UNIT_UNAVAILABLE,
|
||||
NOT_ENOUGH_GOLD,
|
||||
NO_LEADER
|
||||
};
|
||||
|
||||
/**
|
||||
* Check the validity of the action.
|
||||
*
|
||||
* @return the error preventing the action from being executed.
|
||||
* @retval OK if there isn't any error (the action can be executed.)
|
||||
*/
|
||||
virtual error check() const = 0;
|
||||
|
||||
/**
|
||||
* Returns whether this action is valid or not.
|
||||
*
|
||||
* @note This value is now calculated each time the function is called.
|
||||
*/
|
||||
bool valid(){ return check()==OK; }
|
||||
|
||||
private:
|
||||
/** Called by the non-virtual hide() and show(), respectively. */
|
||||
virtual void do_hide() {}
|
||||
|
|
|
@ -110,7 +110,7 @@ void attack::invalidate()
|
|||
|
||||
void attack::execute(bool& success, bool& complete)
|
||||
{
|
||||
if (!valid_) {
|
||||
if(!valid()) {
|
||||
success = false;
|
||||
//Setting complete to true signifies to side_actions to delete the planned action: nothing more to do with it.
|
||||
complete = true;
|
||||
|
@ -215,40 +215,38 @@ void attack::draw_hex(const map_location& hex)
|
|||
}
|
||||
}
|
||||
|
||||
bool attack::validate()
|
||||
void attack::redraw()
|
||||
{
|
||||
DBG_WB <<"validating attack from " << get_dest_hex()
|
||||
<< " to " << target_hex_ << "\n";
|
||||
//invalidate target hex to make sure attack indicators are updated
|
||||
resources::screen->invalidate(get_dest_hex());
|
||||
move::redraw();
|
||||
resources::screen->invalidate(target_hex_);
|
||||
}
|
||||
|
||||
if(
|
||||
// Verify that the unit that planned this attack exists
|
||||
get_unit()
|
||||
// Verify that the target hex is still valid
|
||||
&& target_hex_.valid()
|
||||
// Verify that the target hex isn't empty
|
||||
&& resources::units->find(target_hex_) != resources::units->end()
|
||||
// Verify that the attacking unit has attacks left
|
||||
&& get_unit()->attacks_left() > 0
|
||||
// Verify that the attacker and target are enemies
|
||||
&& (*resources::teams)[get_unit()->side() - 1].is_enemy(resources::units->find(target_hex_)->side())
|
||||
|
||||
//@todo: (maybe) verify that the target hex contains the same unit that before,
|
||||
// comparing for example the unit ID
|
||||
) {
|
||||
//All checks pass, so call validate on the superclass
|
||||
return move::validate();
|
||||
} else {
|
||||
set_valid(false);
|
||||
|
||||
if(viewer_team() == team_index()) { //< Don't mess with any other team's queue -- only our own
|
||||
LOG_WB << "Worthless invalid attack detected, adding to actions_to_erase_.\n";
|
||||
return false;
|
||||
}
|
||||
action::error attack::check() const
|
||||
{
|
||||
// Verify that the unit that planned this attack exists
|
||||
if(!get_unit()) {
|
||||
return NO_UNIT;
|
||||
}
|
||||
return true;
|
||||
// Verify that the target hex is still valid
|
||||
if(!target_hex_.valid()) {
|
||||
return INVALID_LOCATION;
|
||||
}
|
||||
// Verify that the target hex isn't empty
|
||||
if(resources::units->find(target_hex_) == resources::units->end()){
|
||||
return NO_TARGET;
|
||||
}
|
||||
// Verify that the attacking unit has attacks left
|
||||
if(get_unit()->attacks_left() <= 0) {
|
||||
return NO_ATTACK_LEFT;
|
||||
}
|
||||
// Verify that the attacker and target are enemies
|
||||
if(!(*resources::teams)[get_unit()->side() - 1].is_enemy(resources::units->find(target_hex_)->side())){
|
||||
return NOT_AN_ENEMY;
|
||||
}
|
||||
//@todo: (maybe) verify that the target hex contains the same unit that before,
|
||||
// comparing for example the unit ID
|
||||
|
||||
return move::check();
|
||||
}
|
||||
|
||||
config attack::to_config() const
|
||||
|
|
|
@ -39,6 +39,14 @@ public:
|
|||
|
||||
virtual void execute(bool& success, bool& complete);
|
||||
|
||||
/**
|
||||
* Check the validity of the action.
|
||||
*
|
||||
* @return the error preventing the action from being executed.
|
||||
* @retval OK if there isn't any error (the action can be executed.)
|
||||
*/
|
||||
virtual error check() const;
|
||||
|
||||
/** Applies temporarily the result of this action to the specified unit map. */
|
||||
virtual void apply_temp_modifier(unit_map& unit_map);
|
||||
/** Removes the result of this action from the specified unit map. */
|
||||
|
@ -46,11 +54,11 @@ public:
|
|||
|
||||
/** Gets called by display when drawing a hex, to allow actions to draw to the screen. */
|
||||
virtual void draw_hex(const map_location& hex);
|
||||
/** Redrawing function, called each time the action situation might have changed. */
|
||||
virtual void redraw();
|
||||
|
||||
map_location const& get_target_hex() const {return target_hex_; }
|
||||
|
||||
bool validate();
|
||||
|
||||
virtual config to_config() const;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -362,7 +362,7 @@ void manager::update_plan_hiding(size_t team_index)
|
|||
t.get_side_actions()->show();
|
||||
}
|
||||
}
|
||||
resources::teams->at(team_index).get_side_actions()->validate_actions();
|
||||
validate_viewer_actions();
|
||||
}
|
||||
void manager::update_plan_hiding()
|
||||
{update_plan_hiding(viewer_team());}
|
||||
|
@ -414,11 +414,13 @@ bool manager::current_side_has_actions()
|
|||
|
||||
void manager::validate_viewer_actions()
|
||||
{
|
||||
assert(!executing_actions_);
|
||||
LOG_WB << "'gamestate_mutated_' flag dirty, validating actions.\n";
|
||||
gamestate_mutated_ = false;
|
||||
if (viewer_actions()->empty()) return;
|
||||
viewer_actions()->validate_actions();
|
||||
if(has_planned_unit_map()) {
|
||||
real_map();
|
||||
} else {
|
||||
future_map();
|
||||
}
|
||||
}
|
||||
|
||||
//helper fcn
|
||||
|
@ -480,13 +482,17 @@ namespace
|
|||
}
|
||||
|
||||
virtual void visit(move_ptr move) {
|
||||
move_owners_.insert(move->get_unit_id());
|
||||
if(size_t id = move->get_unit_id()) {
|
||||
move_owners_.insert(id);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(attack_ptr attack) {
|
||||
//also add attacks if they have an associated move
|
||||
if (boost::static_pointer_cast<move>(attack)->get_route().steps.size() >= 2) {
|
||||
move_owners_.insert(attack->get_unit_id());
|
||||
if(attack->get_route().steps.size() >= 2) {
|
||||
if(size_t id = attack->get_unit_id()) {
|
||||
move_owners_.insert(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(recruit_ptr){}
|
||||
|
@ -750,7 +756,7 @@ void manager::save_temp_move()
|
|||
assert(u);
|
||||
size_t first_turn = sa.get_turn_num_of(*u);
|
||||
|
||||
on_save_action(u);
|
||||
validate_viewer_actions();
|
||||
|
||||
assert(move_arrows_.size() == fake_units_.size());
|
||||
size_t size = move_arrows_.size();
|
||||
|
@ -819,7 +825,7 @@ void manager::save_temp_attack(const map_location& attacker_loc, const map_locat
|
|||
unit* attacking_unit = future_visible_unit(source_hex);
|
||||
assert(attacking_unit);
|
||||
|
||||
on_save_action(attacking_unit);
|
||||
validate_viewer_actions();
|
||||
|
||||
side_actions& sa = *viewer_actions();
|
||||
sa.queue_attack(sa.get_turn_num_of(*attacking_unit),*attacking_unit,defender_loc,weapon_choice,*route_,move_arrow,fake_unit);
|
||||
|
@ -845,8 +851,6 @@ bool manager::save_recruit(const std::string& name, int side_num, const map_loca
|
|||
}
|
||||
else
|
||||
{
|
||||
on_save_action(NULL);
|
||||
|
||||
side_actions& sa = *viewer_actions();
|
||||
unit* recruiter;
|
||||
{ wb::future_map raii;
|
||||
|
@ -876,8 +880,6 @@ bool manager::save_recall(const unit& unit, int side_num, const map_location& re
|
|||
}
|
||||
else
|
||||
{
|
||||
on_save_action(NULL);
|
||||
|
||||
side_actions& sa = *viewer_actions();
|
||||
size_t turn = sa.num_turns();
|
||||
if(turn > 0)
|
||||
|
@ -895,18 +897,12 @@ void manager::save_suppose_dead(unit& curr_unit, map_location const& loc)
|
|||
{
|
||||
if(active_ && !executing_actions_ && !resources::controller->is_linger_mode())
|
||||
{
|
||||
on_save_action(&curr_unit);
|
||||
validate_viewer_actions();
|
||||
side_actions& sa = *viewer_actions();
|
||||
sa.queue_suppose_dead(sa.get_turn_num_of(curr_unit),curr_unit,loc);
|
||||
}
|
||||
}
|
||||
|
||||
void manager::on_save_action(unit const* u) const
|
||||
{
|
||||
if(u)
|
||||
viewer_actions()->remove_invalid_of(u);
|
||||
}
|
||||
|
||||
void manager::contextual_execute()
|
||||
{
|
||||
validate_viewer_actions();
|
||||
|
@ -1016,34 +1012,26 @@ void manager::continue_execute_all()
|
|||
void manager::contextual_delete()
|
||||
{
|
||||
validate_viewer_actions();
|
||||
if (can_enable_modifier_hotkeys())
|
||||
{
|
||||
if(can_enable_modifier_hotkeys()) {
|
||||
erase_temp_move();
|
||||
|
||||
action_ptr action;
|
||||
side_actions::iterator it = viewer_actions()->end();
|
||||
unit const* selected_unit = future_visible_unit(resources::controller->get_mouse_handler_base().get_selected_hex(), viewer_side());
|
||||
if (selected_unit &&
|
||||
(it = viewer_actions()->find_first_action_of(*selected_unit)) != viewer_actions()->end())
|
||||
{
|
||||
if(selected_unit && (it = viewer_actions()->find_first_action_of(*selected_unit)) != viewer_actions()->end()) {
|
||||
///@todo Shouldn't it be "find_last_action_of" instead of "find_first_action_of" above?
|
||||
viewer_actions()->remove_action(it);
|
||||
///@todo Shouldn't we probably deselect the unit at this point?
|
||||
}
|
||||
else if (highlighter_ && (action = highlighter_->get_delete_target()) &&
|
||||
(it = viewer_actions()->get_position_of(action)) != viewer_actions()->end())
|
||||
{
|
||||
} else if(highlighter_ && (action = highlighter_->get_delete_target()) && (it = viewer_actions()->get_position_of(action)) != viewer_actions()->end()) {
|
||||
viewer_actions()->remove_action(it);
|
||||
viewer_actions()->remove_invalid_of(action->get_unit());
|
||||
validate_viewer_actions();
|
||||
highlighter_->set_mouseover_hex(highlighter_->get_mouseover_hex());
|
||||
highlighter_->highlight();
|
||||
}
|
||||
else //we already check above for viewer_actions()->empty()
|
||||
{
|
||||
} else { //we already check above for viewer_actions()->empty()
|
||||
it = (viewer_actions()->end() - 1);
|
||||
action = *it;
|
||||
viewer_actions()->remove_action(it);
|
||||
viewer_actions()->remove_invalid_of(action->get_unit());
|
||||
validate_viewer_actions();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1051,12 +1039,11 @@ void manager::contextual_delete()
|
|||
void manager::contextual_bump_up_action()
|
||||
{
|
||||
validate_viewer_actions();
|
||||
if(can_enable_reorder_hotkeys())
|
||||
{
|
||||
if(can_enable_reorder_hotkeys()) {
|
||||
action_ptr action = highlighter_->get_bump_target();
|
||||
if (action)
|
||||
{
|
||||
if(action) {
|
||||
viewer_actions()->bump_earlier(viewer_actions()->get_position_of(action));
|
||||
validate_viewer_actions(); // Redraw arrows
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1064,12 +1051,11 @@ void manager::contextual_bump_up_action()
|
|||
void manager::contextual_bump_down_action()
|
||||
{
|
||||
validate_viewer_actions();
|
||||
if(can_enable_reorder_hotkeys())
|
||||
{
|
||||
if(can_enable_reorder_hotkeys()) {
|
||||
action_ptr action = highlighter_->get_bump_target();
|
||||
if (action)
|
||||
{
|
||||
if(action) {
|
||||
viewer_actions()->bump_later(viewer_actions()->get_position_of(action));
|
||||
validate_viewer_actions(); // Redraw arrows
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1178,7 +1164,6 @@ void manager::set_planned_unit_map()
|
|||
return;
|
||||
}
|
||||
|
||||
validate_actions_if_needed();
|
||||
log_scope2("whiteboard", "Building planned unit map");
|
||||
mapbuilder_.reset(new mapbuilder(*resources::units));
|
||||
mapbuilder_->build_map();
|
||||
|
|
|
@ -198,7 +198,6 @@ private:
|
|||
|
||||
void validate_actions_if_needed();
|
||||
/** Called by all of the save_***() methods after they have added their action to the queue */
|
||||
void on_save_action(unit const* unit_with_plan) const;
|
||||
void update_plan_hiding(size_t viewing_team);
|
||||
void update_plan_hiding(); //same as above, but uses wb::viewer_team() as default argument
|
||||
|
||||
|
|
|
@ -52,21 +52,19 @@ mapbuilder::~mapbuilder()
|
|||
|
||||
void mapbuilder::pre_build()
|
||||
{
|
||||
BOOST_FOREACH(team& t, *resources::teams)
|
||||
{
|
||||
BOOST_FOREACH(team& t, *resources::teams) {
|
||||
//Reset spent gold to zero, it'll be recalculated during the map building
|
||||
t.get_side_actions()->reset_gold_spent();
|
||||
}
|
||||
|
||||
int current_side = resources::controller->current_side();
|
||||
BOOST_FOREACH(unit& u, *resources::units)
|
||||
{
|
||||
BOOST_FOREACH(unit& u, *resources::units) {
|
||||
bool on_current_side = (u.side() == current_side);
|
||||
|
||||
//Remove any unit the current side cannot see to avoid their detection by planning
|
||||
//Units will be restored to the unit map by destruction of removers_
|
||||
|
||||
if (!on_current_side && !u.is_visible_to_team((*resources::teams)[viewer_team()], false)) {
|
||||
if(!on_current_side && !u.is_visible_to_team((*resources::teams)[viewer_team()], false)) {
|
||||
removers_.push_back(new temporary_unit_remover(*resources::units, u.get_location()));
|
||||
|
||||
//Don't do anything else to the removed unit!
|
||||
|
@ -87,51 +85,89 @@ void mapbuilder::pre_build()
|
|||
void mapbuilder::build_map()
|
||||
{
|
||||
pre_build();
|
||||
if (wb::has_actions()) {
|
||||
boost::function<void(action_ptr)> processor(boost::bind(&mapbuilder::process, this, _1));
|
||||
turn_team_filter post_filter(boost::bind(&mapbuilder::post_visit_team, this, _1, _2));
|
||||
for_each_action(processor, team_has_visible_plan, post_filter);
|
||||
if(!wb::has_actions()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
///@return whether act is valid
|
||||
bool mapbuilder::process_helper(action_ptr const& act)
|
||||
{
|
||||
if(act->is_valid()) {
|
||||
act->apply_temp_modifier(unit_map_);
|
||||
applied_actions_.push_back(act);
|
||||
applied_actions_this_turn_.push_back(act);
|
||||
return true;
|
||||
} else { //invalid
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool end = false;
|
||||
for(size_t turn=0; !end; ++turn) {
|
||||
end = true;
|
||||
BOOST_FOREACH(team &side, *resources::teams) {
|
||||
side_actions &actions = *side.get_side_actions();
|
||||
if(turn < actions.num_turns() && team_has_visible_plan(side)) {
|
||||
end = false;
|
||||
side_actions::iterator it = actions.turn_begin(turn), next = it, end = actions.turn_end(turn);
|
||||
while(it != end) {
|
||||
std::advance(next, 1);
|
||||
process(actions, it);
|
||||
it = next;
|
||||
}
|
||||
|
||||
bool mapbuilder::process(action_ptr action)
|
||||
{
|
||||
unit* unit = action->get_unit();
|
||||
|
||||
if(!unit || !action->is_valid() || acted_this_turn_.find(unit) != acted_this_turn_.end()) {
|
||||
process_helper(action);
|
||||
} else { //gotta restore MP first
|
||||
int original_moves = unit->movement_left();
|
||||
|
||||
//reset MP
|
||||
unit->set_movement(unit->total_movement());
|
||||
acted_this_turn_.insert(unit);
|
||||
|
||||
bool revert = !process_helper(action);
|
||||
|
||||
if(revert) { //< the action was invalid
|
||||
//didn't need to restore MP after all ... so let's change it back
|
||||
acted_this_turn_.erase(unit);
|
||||
unit->set_movement(original_moves);
|
||||
post_visit_team(turn);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mapbuilder::post_visit_team(team&, size_t turn)
|
||||
void mapbuilder::process(side_actions &sa, side_actions::iterator action_it)
|
||||
{
|
||||
action_ptr action = *action_it;
|
||||
bool acted=false;
|
||||
unit* unit = action->get_unit();
|
||||
if(!unit) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(acted_this_turn_.find(unit) == acted_this_turn_.end()) {
|
||||
//reset MP
|
||||
unit->set_movement(unit->total_movement());
|
||||
acted=true;
|
||||
}
|
||||
|
||||
// Validity check
|
||||
action::error erval = action->check();
|
||||
action->redraw();
|
||||
|
||||
if(erval != action::OK) {
|
||||
// We do not delete obstructed moves, nor invalid actions caused by obstructed moves.
|
||||
if(has_invalid_actions_.find(unit) == has_invalid_actions_.end()) {
|
||||
if(erval == action::TOO_FAR || (erval == action::LOCATION_OCCUPIED && boost::dynamic_pointer_cast<move>(action))) {
|
||||
has_invalid_actions_.insert(unit);
|
||||
invalid_actions_.push_back(action_it);
|
||||
} else {
|
||||
sa.remove_action(action_it, false);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
invalid_actions_.push_back(action_it);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// We do not keep invalid actions replaced by a valid one.
|
||||
std::set<class unit const*>::iterator invalid_it = has_invalid_actions_.find(unit);
|
||||
if(invalid_it != has_invalid_actions_.end()) {
|
||||
for(std::list<side_actions::iterator>::iterator it = invalid_actions_.begin(); it != invalid_actions_.end();) {
|
||||
if((**it)->get_unit() == unit) {
|
||||
sa.remove_action(*it, false);
|
||||
it = invalid_actions_.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
has_invalid_actions_.erase(invalid_it);
|
||||
}
|
||||
|
||||
if(acted) {
|
||||
acted_this_turn_.insert(unit);
|
||||
}
|
||||
|
||||
action->apply_temp_modifier(unit_map_);
|
||||
applied_actions_.push_back(action);
|
||||
applied_actions_this_turn_.push_back(action);
|
||||
}
|
||||
|
||||
void mapbuilder::post_visit_team(size_t turn)
|
||||
{
|
||||
std::set<unit const*> seen;
|
||||
|
||||
|
@ -152,14 +188,12 @@ bool mapbuilder::post_visit_team(team&, size_t turn)
|
|||
applied_actions_this_turn_.clear();
|
||||
// Clear the list of units of this team that have acted this turn
|
||||
acted_this_turn_.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
void mapbuilder::restore_normal_map()
|
||||
{
|
||||
//applied_actions_ contain only the actions that we applied to the unit map
|
||||
BOOST_REVERSE_FOREACH(action_ptr act, applied_actions_) {
|
||||
assert(act->is_valid());
|
||||
act->remove_temp_modifier(unit_map_);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,19 +41,19 @@ public:
|
|||
mapbuilder(unit_map& unit_map);
|
||||
virtual ~mapbuilder();
|
||||
|
||||
/** Builds every team's actions as far into the future as possible, in the correct order. */
|
||||
/**
|
||||
* Builds every team's actions as far into the future as possible, in the correct order.
|
||||
*
|
||||
* @return whether all the actions were valid.
|
||||
* */
|
||||
void build_map();
|
||||
|
||||
private:
|
||||
/** Function called on each action. */
|
||||
bool process(action_ptr action);
|
||||
bool process_helper(action_ptr const&);
|
||||
void process(side_actions &sa, side_actions::iterator action_it);
|
||||
|
||||
/** Function called after visiting a team. */
|
||||
bool post_visit_team(team&, size_t turn);
|
||||
|
||||
/** For validate_visitor to override. */
|
||||
virtual void validate(side_actions::iterator const&) {}
|
||||
void post_visit_team(size_t turn);
|
||||
|
||||
/** Does various preliminary actions on the unit map such as resetting moves for some units. */
|
||||
void pre_build();
|
||||
|
@ -69,8 +69,10 @@ private:
|
|||
boost::ptr_vector<unit_movement_resetter> resetters_;
|
||||
boost::ptr_vector<temporary_unit_remover> removers_;
|
||||
|
||||
//Used by visit()
|
||||
//Used by process()
|
||||
std::set<unit const*> acted_this_turn_;
|
||||
std::set<unit const*> has_invalid_actions_;
|
||||
std::list<side_actions::iterator> invalid_actions_; ///< Conserved invalid actions.
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -69,7 +69,6 @@ move::move(size_t team_index, bool hidden, unit& u, const pathfind::marked_route
|
|||
turn_number_(0),
|
||||
arrow_(arrow),
|
||||
fake_unit_(fake_unit),
|
||||
valid_(true),
|
||||
arrow_brightness_(),
|
||||
arrow_texture_(),
|
||||
mover_(),
|
||||
|
@ -92,7 +91,6 @@ move::move(config const& cfg, bool hidden)
|
|||
, turn_number_(0)
|
||||
, arrow_(new arrow(hidden))
|
||||
, fake_unit_()
|
||||
, valid_(true)
|
||||
, arrow_brightness_()
|
||||
, arrow_texture_()
|
||||
, mover_()
|
||||
|
@ -194,14 +192,14 @@ void move::accept(visitor& v)
|
|||
|
||||
void move::execute(bool& success, bool& complete)
|
||||
{
|
||||
if (!valid_) {
|
||||
if(!valid()) {
|
||||
success = false;
|
||||
//Setting complete to true signifies to side_actions to delete the planned action.
|
||||
complete = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_source_hex() == get_dest_hex()) {
|
||||
if(get_source_hex() == get_dest_hex()) {
|
||||
//zero-hex move, used by attack subclass
|
||||
success = complete = true;
|
||||
return;
|
||||
|
@ -409,54 +407,51 @@ map_location move::get_numbering_hex() const
|
|||
return get_dest_hex();
|
||||
}
|
||||
|
||||
void move::set_valid(bool valid)
|
||||
action::error move::check() const
|
||||
{
|
||||
if(valid_ != valid)
|
||||
{
|
||||
valid_ = valid;
|
||||
if(valid_)
|
||||
set_arrow_texture(ARROW_TEXTURE_VALID);
|
||||
else
|
||||
set_arrow_texture(ARROW_TEXTURE_INVALID);
|
||||
}
|
||||
}
|
||||
// Used to deal with multiple return paths.
|
||||
class arrow_texture_setter {
|
||||
public:
|
||||
arrow_texture_setter(const move *target, move::ARROW_TEXTURE current_texture, move::ARROW_TEXTURE setting_texture):
|
||||
target(target),
|
||||
current_texture(current_texture),
|
||||
setting_texture(setting_texture) {}
|
||||
|
||||
// This helper function determines whether there are any invalid actions planned for (*itor)->get_unit()
|
||||
// that occur earlier in viewer_actions() than itor.
|
||||
static bool no_previous_invalids(side_actions::iterator const& itor)
|
||||
{
|
||||
if(itor == viewer_actions()->begin()) {
|
||||
return true;
|
||||
}
|
||||
side_actions::iterator prev_action_of_unit = viewer_actions()->find_last_action_of(*((*itor)->get_unit()),itor-1);
|
||||
if(prev_action_of_unit == viewer_actions()->end()) {
|
||||
return true;
|
||||
}
|
||||
return (*prev_action_of_unit)->is_valid();
|
||||
}
|
||||
~arrow_texture_setter() {
|
||||
if(current_texture!=setting_texture) {
|
||||
target->set_arrow_texture(setting_texture);
|
||||
}
|
||||
}
|
||||
|
||||
void set_texture(move::ARROW_TEXTURE texture) { setting_texture=texture; }
|
||||
|
||||
private:
|
||||
const move *target;
|
||||
move::ARROW_TEXTURE current_texture, setting_texture;
|
||||
};
|
||||
|
||||
arrow_texture_setter setter(this, arrow_texture_, ARROW_TEXTURE_INVALID);
|
||||
|
||||
move::VALIDITY move::evaluate_validity()
|
||||
{
|
||||
if(!(get_source_hex().valid() && get_dest_hex().valid())) {
|
||||
return WORTHLESS;
|
||||
return INVALID_LOCATION;
|
||||
}
|
||||
|
||||
//Check that the unit still exists in the source hex
|
||||
unit_map::iterator unit_it;
|
||||
unit_it = resources::units->find(get_source_hex());
|
||||
if(unit_it == resources::units->end()) {
|
||||
return WORTHLESS;
|
||||
return NO_UNIT;
|
||||
}
|
||||
|
||||
//check if the unit in the source hex has the same unit id as before,
|
||||
//i.e. that it's the same unit
|
||||
if(unit_id_ != unit_it->id() || unit_underlying_id_ != unit_it->underlying_id()) {
|
||||
return WORTHLESS;
|
||||
return UNIT_CHANGED;
|
||||
}
|
||||
|
||||
//If the path has at least two hexes (it can have less with the attack subclass), ensure destination hex is free
|
||||
if(get_route().steps.size() >= 2 && get_visible_unit(get_dest_hex(),resources::teams->at(viewer_team())) != NULL) {
|
||||
return WORTHLESS;
|
||||
return LOCATION_OCCUPIED;
|
||||
}
|
||||
|
||||
//check that the path is good
|
||||
|
@ -466,43 +461,14 @@ move::VALIDITY move::evaluate_validity()
|
|||
pathfind::marked_route checked_route = pathfind::mark_route(get_route().route);
|
||||
|
||||
if(checked_route.marks[checked_route.steps.back()].turns != 1) {
|
||||
return OBSTRUCTED;
|
||||
return TOO_FAR;
|
||||
}
|
||||
}
|
||||
|
||||
return VALID;
|
||||
}
|
||||
// The move is valid, so correct the setter.
|
||||
setter.set_texture(ARROW_TEXTURE_VALID);
|
||||
|
||||
bool move::validate()
|
||||
{
|
||||
DBG_WB <<"validating move from " << get_source_hex()
|
||||
<< " to " << get_dest_hex() << "\n";
|
||||
//invalidate start and end hexes so number display is updated properly
|
||||
resources::screen->invalidate(get_source_hex());
|
||||
resources::screen->invalidate(get_dest_hex());
|
||||
|
||||
switch(evaluate_validity()) { //< private helper fcn
|
||||
case VALID:
|
||||
// Now call the superclass to apply the result of this move to the unit map,
|
||||
// so that further pathfinding takes it into account.
|
||||
set_valid(true);
|
||||
break;
|
||||
case OBSTRUCTED:
|
||||
set_valid(false);
|
||||
break;
|
||||
case WORTHLESS: {
|
||||
set_valid(false);
|
||||
// Erase only if no previous invalid actions are planned for this unit -- otherwise, just mark it invalid.
|
||||
// Otherwise, we wouldn't be able to keep invalid actions that depend on previous invalid actions.
|
||||
side_actions::iterator itor = viewer_actions()->get_position_of(shared_from_this());
|
||||
if(viewer_team() == team_index() && no_previous_invalids(itor)) { //< Don't mess with any other team's queue -- only our own
|
||||
LOG_WB << "Worthless invalid move detected, adding to actions_to_erase_.\n";
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return OK;
|
||||
}
|
||||
|
||||
config move::to_config() const
|
||||
|
@ -566,6 +532,13 @@ void move::calculate_move_cost()
|
|||
}
|
||||
}
|
||||
|
||||
void move::redraw()
|
||||
{
|
||||
resources::screen->invalidate(get_source_hex());
|
||||
resources::screen->invalidate(get_dest_hex());
|
||||
update_arrow_style();
|
||||
}
|
||||
|
||||
//If you add more arrow styles, this will need to change
|
||||
/* private */
|
||||
void move::update_arrow_style()
|
||||
|
|
|
@ -44,6 +44,14 @@ public:
|
|||
|
||||
virtual void execute(bool& success, bool& complete);
|
||||
|
||||
/**
|
||||
* Check the validity of the action.
|
||||
*
|
||||
* @return the error preventing the action from being executed.
|
||||
* @retval OK if there isn't any error (the action can be executed.)
|
||||
*/
|
||||
virtual error check() const;
|
||||
|
||||
/** Return the unit targeted by this action. Null if unit doesn't exist. */
|
||||
virtual unit* get_unit() const;
|
||||
/** @return pointer to the fake unit used only for visuals */
|
||||
|
@ -67,22 +75,21 @@ public:
|
|||
|
||||
/** Gets called by display when drawing a hex, to allow actions to draw to the screen. */
|
||||
virtual void draw_hex(map_location const& hex);
|
||||
/** Redrawing function, called each time the action situation might have changed. */
|
||||
void redraw();
|
||||
|
||||
/** Assigns a turn number to display to this planned move. Assigning zero removes any turn number. */
|
||||
virtual void set_turn_number(int turn) { turn_number_ = turn; }
|
||||
|
||||
virtual map_location get_numbering_hex() const;
|
||||
|
||||
virtual void set_valid(bool valid);
|
||||
virtual bool is_valid() const { return valid_; }
|
||||
bool validate();
|
||||
|
||||
virtual config to_config() const;
|
||||
|
||||
///@todo Make use of safe_enum idiom?
|
||||
enum ARROW_BRIGHTNESS {ARROW_BRIGHTNESS_STANDARD, ARROW_BRIGHTNESS_HIGHLIGHTED, ARROW_BRIGHTNESS_FOCUS};
|
||||
void set_arrow_brightness(ARROW_BRIGHTNESS x) {arrow_brightness_=x; update_arrow_style();}
|
||||
void set_arrow_brightness(ARROW_BRIGHTNESS x) const {arrow_brightness_=x; }
|
||||
enum ARROW_TEXTURE {ARROW_TEXTURE_VALID, ARROW_TEXTURE_INVALID};
|
||||
void set_arrow_texture(ARROW_TEXTURE x) {arrow_texture_=x; update_arrow_style();}
|
||||
void set_arrow_texture(ARROW_TEXTURE x) const {arrow_texture_=x; }
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -102,10 +109,8 @@ protected:
|
|||
arrow_ptr arrow_;
|
||||
fake_unit_ptr fake_unit_;
|
||||
|
||||
bool valid_;
|
||||
|
||||
ARROW_BRIGHTNESS arrow_brightness_;
|
||||
ARROW_TEXTURE arrow_texture_;
|
||||
mutable ARROW_BRIGHTNESS arrow_brightness_;
|
||||
mutable ARROW_TEXTURE arrow_texture_;
|
||||
|
||||
private:
|
||||
virtual void do_hide();
|
||||
|
@ -114,9 +119,6 @@ private:
|
|||
void hide_fake_unit();
|
||||
void show_fake_unit();
|
||||
|
||||
enum VALIDITY {VALID, OBSTRUCTED, WORTHLESS};
|
||||
VALIDITY evaluate_validity();
|
||||
|
||||
void init();
|
||||
void update_arrow_style();
|
||||
boost::scoped_ptr<temporary_unit_mover> mover_;
|
||||
|
|
|
@ -57,7 +57,6 @@ recall::recall(size_t team_index, bool hidden, const unit& unit, const map_locat
|
|||
action(team_index,hidden),
|
||||
temp_unit_(new class unit(unit)),
|
||||
recall_hex_(recall_hex),
|
||||
valid_(true),
|
||||
fake_unit_(new game_display::fake_unit(unit) )
|
||||
{
|
||||
this->init();
|
||||
|
@ -67,7 +66,6 @@ recall::recall(config const& cfg, bool hidden)
|
|||
: action(cfg,hidden)
|
||||
, temp_unit_()
|
||||
, recall_hex_(cfg.child("recall_hex_")["x"],cfg.child("recall_hex_")["y"])
|
||||
, valid_(true)
|
||||
, fake_unit_()
|
||||
{
|
||||
// Construct and validate temp_unit_
|
||||
|
@ -112,7 +110,7 @@ void recall::accept(visitor& v)
|
|||
|
||||
void recall::execute(bool& success, bool& complete)
|
||||
{
|
||||
assert(valid_);
|
||||
assert(valid());
|
||||
assert(temp_unit_.get());
|
||||
temporary_unit_hider const raii(*fake_unit_);
|
||||
//Give back the spent gold so we don't get "not enough gold" message
|
||||
|
@ -127,7 +125,7 @@ void recall::execute(bool& success, bool& complete)
|
|||
|
||||
void recall::apply_temp_modifier(unit_map& unit_map)
|
||||
{
|
||||
assert(valid_);
|
||||
assert(valid());
|
||||
temp_unit_->set_location(recall_hex_);
|
||||
|
||||
DBG_WB << "Inserting future recall " << temp_unit_->name() << " [" << temp_unit_->id()
|
||||
|
@ -176,44 +174,32 @@ void recall::draw_hex(map_location const& hex)
|
|||
}
|
||||
}
|
||||
|
||||
bool recall::validate()
|
||||
void recall::redraw()
|
||||
{
|
||||
DBG_WB << "validating recall on hex " << recall_hex_ << "\n";
|
||||
//invalidate recall hex so number display is updated properly
|
||||
resources::screen->invalidate(recall_hex_);
|
||||
}
|
||||
|
||||
action::error recall::check() const
|
||||
{
|
||||
//Check that destination hex is still free
|
||||
if(resources::units->find(recall_hex_) != resources::units->end()) {
|
||||
LOG_WB << "Recall set as invalid because target hex is occupied.\n";
|
||||
set_valid(false);
|
||||
return LOCATION_OCCUPIED;
|
||||
}
|
||||
//Check that unit to recall is still in side's recall list
|
||||
if(is_valid()) {
|
||||
const std::vector<unit>& recalls = (*resources::teams)[team_index()].recall_list();
|
||||
if( find_if_matches_id(recalls, temp_unit_->id()) == recalls.end() ) {
|
||||
set_valid(false);
|
||||
LOG_WB << " Validate visitor: Planned recall invalid since unit is not in recall list anymore.\n";
|
||||
}
|
||||
const std::vector<unit>& recalls = (*resources::teams)[team_index()].recall_list();
|
||||
if( find_if_matches_id(recalls, temp_unit_->id()) == recalls.end() ) {
|
||||
return UNIT_UNAVAILABLE;
|
||||
}
|
||||
//Check that there is still enough gold to recall this unit
|
||||
if(is_valid() && (*resources::teams)[team_index()].recall_cost() > (*resources::teams)[team_index()].gold()) {
|
||||
LOG_WB << "Recall set as invalid, team doesn't have enough gold.\n";
|
||||
set_valid(false);
|
||||
if((*resources::teams)[team_index()].recall_cost() > (*resources::teams)[team_index()].gold()) {
|
||||
return NOT_ENOUGH_GOLD;
|
||||
}
|
||||
//Check that there is a leader available to recall this unit
|
||||
if(is_valid() && !find_recruiter(team_index(),get_recall_hex())) {
|
||||
LOG_WB << "Recall set as invalid, no leader can recall this unit.\n";
|
||||
set_valid(false);
|
||||
if(!find_recruiter(team_index(),get_recall_hex())) {
|
||||
return NO_LEADER;
|
||||
}
|
||||
|
||||
if(!is_valid()) {
|
||||
if(viewer_team() == team_index()) { //< Don't mess with any other team's queue -- only our own
|
||||
LOG_WB << "Invalid recall detected, adding to actions_to_erase_.\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return OK;
|
||||
}
|
||||
|
||||
///@todo Find a better way to serialize unit_ because underlying_id isn't cutting it
|
||||
|
|
|
@ -38,6 +38,14 @@ public:
|
|||
|
||||
virtual void execute(bool& success, bool& complete);
|
||||
|
||||
/**
|
||||
* Check the validity of the action.
|
||||
*
|
||||
* @return the error preventing the action from being executed.
|
||||
* @retval OK if there isn't any error (the action can be executed.)
|
||||
*/
|
||||
virtual error check() const;
|
||||
|
||||
/** Applies temporarily the result of this action to the specified unit map. */
|
||||
virtual void apply_temp_modifier(unit_map& unit_map);
|
||||
/** Removes the result of this action from the specified unit map. */
|
||||
|
@ -45,6 +53,8 @@ public:
|
|||
|
||||
/** Gets called by display when drawing a hex, to allow actions to draw to the screen. */
|
||||
virtual void draw_hex(const map_location& hex);
|
||||
/** Redrawing function, called each time the action situation might have changed. */
|
||||
virtual void redraw();
|
||||
|
||||
/**
|
||||
* Indicates whether this hex is the preferred hex to draw the numbering for this action.
|
||||
|
@ -58,14 +68,6 @@ public:
|
|||
|
||||
map_location const get_recall_hex() const { return recall_hex_; }
|
||||
|
||||
/**
|
||||
* Indicates to an action whether its status is invalid, and whether it should change its
|
||||
* display (and avoid any change to the game state) accordingly
|
||||
*/
|
||||
virtual void set_valid(bool valid) { valid_ = valid; }
|
||||
virtual bool is_valid() const { return valid_; }
|
||||
bool validate();
|
||||
|
||||
virtual config to_config() const;
|
||||
|
||||
protected:
|
||||
|
@ -82,7 +84,6 @@ private:
|
|||
|
||||
std::auto_ptr<unit> temp_unit_;
|
||||
map_location recall_hex_;
|
||||
bool valid_;
|
||||
fake_unit_ptr fake_unit_;
|
||||
};
|
||||
|
||||
|
|
|
@ -57,7 +57,6 @@ recruit::recruit(size_t team_index, bool hidden, const std::string& unit_name, c
|
|||
unit_name_(unit_name),
|
||||
recruit_hex_(recruit_hex),
|
||||
temp_unit_(create_corresponding_unit()), //auto-ptr ownership transfer
|
||||
valid_(true),
|
||||
fake_unit_(new game_display::fake_unit(*temp_unit_)), //temp_unit_ *copied* into new fake unit
|
||||
cost_(0)
|
||||
{
|
||||
|
@ -69,7 +68,6 @@ recruit::recruit(config const& cfg, bool hidden)
|
|||
, unit_name_(cfg["unit_name_"])
|
||||
, recruit_hex_(cfg.child("recruit_hex_")["x"],cfg.child("recruit_hex_")["y"])
|
||||
, temp_unit_()
|
||||
, valid_(true)
|
||||
, fake_unit_()
|
||||
, cost_(0)
|
||||
{
|
||||
|
@ -106,7 +104,7 @@ void recruit::accept(visitor& v)
|
|||
|
||||
void recruit::execute(bool& success, bool& complete)
|
||||
{
|
||||
assert(valid_);
|
||||
assert(valid());
|
||||
temporary_unit_hider const raii(*fake_unit_);
|
||||
int const side_num = team_index() + 1;
|
||||
//Give back the spent gold so we don't get "not enough gold" message
|
||||
|
@ -121,7 +119,7 @@ void recruit::execute(bool& success, bool& complete)
|
|||
|
||||
void recruit::apply_temp_modifier(unit_map& unit_map)
|
||||
{
|
||||
assert(valid_);
|
||||
assert(valid());
|
||||
temp_unit_->set_location(recruit_hex_);
|
||||
|
||||
DBG_WB << "Inserting future recruit [" << temp_unit_->id()
|
||||
|
@ -161,6 +159,12 @@ void recruit::draw_hex(map_location const& hex)
|
|||
}
|
||||
}
|
||||
|
||||
void recruit::redraw()
|
||||
{
|
||||
resources::screen->invalidate(recruit_hex_);
|
||||
}
|
||||
|
||||
|
||||
std::auto_ptr<unit> recruit::create_corresponding_unit()
|
||||
{
|
||||
unit_type const* type = unit_types.find(unit_name_);
|
||||
|
@ -174,44 +178,27 @@ std::auto_ptr<unit> recruit::create_corresponding_unit()
|
|||
return result; //ownership gets transferred to returned auto_ptr copy
|
||||
}
|
||||
|
||||
bool recruit::validate()
|
||||
action::error recruit::check() const
|
||||
{
|
||||
DBG_WB << "validating recruit on hex " << recruit_hex_ << "\n";
|
||||
//invalidate recruit hex so number display is updated properly
|
||||
resources::screen->invalidate(recruit_hex_);
|
||||
|
||||
//Check that destination hex is still free
|
||||
if(resources::units->find(recruit_hex_) != resources::units->end()) {
|
||||
LOG_WB << "Recruit set as invalid because target hex is occupied.\n";
|
||||
set_valid(false);
|
||||
return LOCATION_OCCUPIED;
|
||||
}
|
||||
//Check that unit to recruit is still in side's recruit list
|
||||
if(is_valid()) {
|
||||
const std::set<std::string>& recruits = (*resources::teams)[team_index()].recruits();
|
||||
if(recruits.find(unit_name_) == recruits.end()) {
|
||||
set_valid(false);
|
||||
LOG_WB << " Validate visitor: Planned recruit invalid since unit is not in recruit list anymore.\n";
|
||||
}
|
||||
const std::set<std::string>& recruits = (*resources::teams)[team_index()].recruits();
|
||||
if(recruits.find(unit_name_) == recruits.end()) {
|
||||
return UNIT_UNAVAILABLE;
|
||||
}
|
||||
//Check that there is still enough gold to recruit this unit
|
||||
if(is_valid() && temp_unit_->cost() > (*resources::teams)[team_index()].gold()) {
|
||||
LOG_WB << "Recruit set as invalid, team doesn't have enough gold.\n";
|
||||
set_valid(false);
|
||||
if(temp_unit_->cost() > (*resources::teams)[team_index()].gold()) {
|
||||
return NOT_ENOUGH_GOLD;
|
||||
}
|
||||
//Check that there is a leader available to recruit this unit
|
||||
if(is_valid() && !find_recruiter(team_index(),get_recruit_hex())) {
|
||||
LOG_WB << "Recruit set as invalid, no leader can recruit this unit.\n";
|
||||
set_valid(false);
|
||||
if(!find_recruiter(team_index(),get_recruit_hex())) {
|
||||
return NO_LEADER;
|
||||
}
|
||||
|
||||
if(!is_valid()) {
|
||||
if(viewer_team() == team_index()) { //< Don't mess with any other team's queue -- only our own
|
||||
LOG_WB << "Invalid recruit detected, adding to actions_to_erase_.\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return OK;
|
||||
}
|
||||
|
||||
config recruit::to_config() const
|
||||
|
|
|
@ -42,6 +42,14 @@ public:
|
|||
|
||||
virtual void execute(bool& success, bool& complete);
|
||||
|
||||
/**
|
||||
* Check the validity of the action.
|
||||
*
|
||||
* @return the error preventing the action from being executed.
|
||||
* @retval OK if there isn't any error (the action can be executed.)
|
||||
*/
|
||||
virtual error check() const;
|
||||
|
||||
/** Applies temporarily the result of this action to the specified unit map. */
|
||||
virtual void apply_temp_modifier(unit_map& unit_map);
|
||||
/** Removes the result of this action from the specified unit map. */
|
||||
|
@ -49,6 +57,8 @@ public:
|
|||
|
||||
/** Gets called by display when drawing a hex, to allow actions to draw to the screen. */
|
||||
virtual void draw_hex(map_location const& hex);
|
||||
/** Redrawing function, called each time the action situation might have changed. */
|
||||
virtual void redraw();
|
||||
|
||||
/**
|
||||
* @return the preferred hex to draw the numbering for this action.
|
||||
|
@ -62,14 +72,6 @@ public:
|
|||
|
||||
map_location const get_recruit_hex() const { return recruit_hex_; }
|
||||
|
||||
/**
|
||||
* Indicates to an action whether its status is invalid, and whether it should change its
|
||||
* display (and avoid any change to the game state) accordingly
|
||||
*/
|
||||
virtual void set_valid(bool valid) { valid_ = valid; }
|
||||
virtual bool is_valid() const { return valid_; }
|
||||
bool validate();
|
||||
|
||||
virtual config to_config() const;
|
||||
|
||||
protected:
|
||||
|
@ -82,7 +84,6 @@ protected:
|
|||
map_location recruit_hex_;
|
||||
//Temp unit to insert in the future unit map when needed
|
||||
std::auto_ptr<unit> temp_unit_;
|
||||
bool valid_;
|
||||
fake_unit_ptr fake_unit_;
|
||||
int cost_;
|
||||
|
||||
|
|
|
@ -26,13 +26,13 @@
|
|||
#include "action.hpp"
|
||||
#include "attack.hpp"
|
||||
#include "manager.hpp"
|
||||
#include "mapbuilder.hpp"
|
||||
#include "move.hpp"
|
||||
#include "recall.hpp"
|
||||
#include "recruit.hpp"
|
||||
#include "suppose_dead.hpp"
|
||||
#include "highlighter.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "validate_visitor.hpp"
|
||||
|
||||
#include "actions.hpp"
|
||||
#include "game_display.hpp"
|
||||
|
@ -323,7 +323,7 @@ bool side_actions::execute(side_actions::iterator position)
|
|||
|
||||
action_ptr action = *position;
|
||||
|
||||
if(!action->is_valid()) {
|
||||
if(!action->valid()) {
|
||||
LOG_WB << "Invalid action sent to execution, deleting.\n";
|
||||
synced_erase(position);
|
||||
return true;
|
||||
|
@ -363,7 +363,7 @@ bool side_actions::execute(side_actions::iterator position)
|
|||
ss << *this << "\n";
|
||||
LOG_WB << ss.str();
|
||||
|
||||
validate_actions();
|
||||
resources::whiteboard->validate_viewer_actions();
|
||||
return action_successful;
|
||||
}
|
||||
|
||||
|
@ -400,7 +400,7 @@ side_actions::iterator side_actions::insert_action(iterator position, action_ptr
|
|||
iterator valid_position = synced_insert(position, action);
|
||||
LOG_WB << "Inserted into turn #" << get_turn(valid_position) << " at position #"
|
||||
<< actions_.position_in_turn(valid_position) << " : " << action <<"\n";
|
||||
validate_actions();
|
||||
resources::whiteboard->validate_viewer_actions();
|
||||
return valid_position;
|
||||
}
|
||||
|
||||
|
@ -411,7 +411,7 @@ side_actions::iterator side_actions::queue_action(size_t turn_num, action_ptr ac
|
|||
}
|
||||
iterator result = synced_enqueue(turn_num, action);
|
||||
LOG_WB << "Queue into turn #" << turn_num << " : " << action <<"\n";
|
||||
validate_actions();
|
||||
resources::whiteboard->validate_viewer_actions();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -520,7 +520,7 @@ side_actions::iterator side_actions::remove_action(side_actions::iterator positi
|
|||
position = synced_erase(position);
|
||||
|
||||
if(validate_after_delete) {
|
||||
validate_actions();
|
||||
resources::whiteboard->validate_viewer_actions();
|
||||
}
|
||||
|
||||
return position;
|
||||
|
@ -545,6 +545,11 @@ side_actions::iterator side_actions::find_last_action_of(unit const& unit, side_
|
|||
return find_first_action_of(actions_.get<container::by_unit>().equal_range(unit.underlying_id()), start_position, std::greater<iterator>());
|
||||
}
|
||||
|
||||
side_actions::const_iterator side_actions::find_last_action_of(unit const& unit) const
|
||||
{
|
||||
return find_last_action_of(unit, end() - 1);
|
||||
}
|
||||
|
||||
side_actions::iterator side_actions::find_last_action_of(unit const& unit)
|
||||
{
|
||||
return find_last_action_of(unit, end() - 1);
|
||||
|
@ -570,67 +575,15 @@ std::deque<action_ptr> side_actions::actions_of(unit const &target)
|
|||
return actions;
|
||||
}
|
||||
|
||||
void side_actions::remove_invalid_of(unit const* u)
|
||||
{
|
||||
if(u == NULL)
|
||||
return;
|
||||
|
||||
iterator i = begin();
|
||||
while(i != end()) {
|
||||
action& act = **i;
|
||||
if(!act.is_valid() && u == act.get_unit()) {
|
||||
i = remove_action(i,false);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
side_actions::const_iterator side_actions::find_last_valid_of(unit const& u) const
|
||||
{
|
||||
typedef container::action_set::index<container::by_unit>::type::const_iterator unit_iterator;
|
||||
|
||||
std::pair<unit_iterator, unit_iterator> acts = actions_.get<container::by_unit>().equal_range(u.underlying_id());
|
||||
|
||||
const_iterator last = end();
|
||||
|
||||
for(unit_iterator it = acts.first; it != acts.second; ++it) {
|
||||
if((*it)->is_valid()) {
|
||||
const_iterator chrono_it = actions_.project<container::chronological>(it);
|
||||
if(last == end() || chrono_it > last) {
|
||||
last = chrono_it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return last;
|
||||
}
|
||||
|
||||
size_t side_actions::get_turn_num_of(unit const& u) const
|
||||
{
|
||||
const_iterator itor = find_last_valid_of(u);
|
||||
const_iterator itor = find_last_action_of(u);
|
||||
if(itor == end()) {
|
||||
return 0;
|
||||
}
|
||||
return get_turn(itor);
|
||||
}
|
||||
|
||||
void side_actions::validate_actions()
|
||||
{
|
||||
assert(!resources::whiteboard->has_planned_unit_map());
|
||||
|
||||
bool validation_finished = false;
|
||||
int passes = 1;
|
||||
while(!validation_finished) {
|
||||
log_scope2("whiteboard", "Validating actions for side "
|
||||
+ lexical_cast<std::string>(team_index() + 1) + ", pass "
|
||||
+ lexical_cast<std::string>(passes));
|
||||
validate_visitor validator(*resources::units);
|
||||
validation_finished = validator.validate_actions();
|
||||
++passes;
|
||||
}
|
||||
}
|
||||
|
||||
void side_actions::change_gold_spent_by(int difference)
|
||||
{
|
||||
DBG_WB << "Changing gold spent for side " << (team_index() + 1) << "; old value: "
|
||||
|
@ -813,7 +766,7 @@ void side_actions::execute_net_cmd(net_cmd const& cmd)
|
|||
return;
|
||||
}
|
||||
|
||||
validate_actions();
|
||||
resources::whiteboard->validate_viewer_actions();
|
||||
}
|
||||
|
||||
side_actions::net_cmd side_actions::make_net_cmd_insert(size_t turn_num, size_t pos, action_const_ptr act) const
|
||||
|
|
|
@ -474,25 +474,17 @@ public:
|
|||
* @return The position, or end() if not found.
|
||||
*/
|
||||
iterator find_last_action_of(unit const& unit, iterator start_position);
|
||||
/** const variant of the previous function */
|
||||
const_iterator find_last_action_of(unit const& unit, const_iterator start_position) const;
|
||||
/** Variant of the previous method that always start searching at the end of the queue */
|
||||
iterator find_last_action_of(unit const& unit);
|
||||
/** const variant of the previous function */
|
||||
const_iterator find_last_action_of(unit const& unit, const_iterator start_position) const;
|
||||
const_iterator find_last_action_of(unit const& unit) const;
|
||||
|
||||
bool unit_has_actions(unit const& unit);
|
||||
size_t count_actions_of(unit const& unit);
|
||||
std::deque<action_ptr> actions_of(unit const& unit);
|
||||
|
||||
/** Removes all invalid actions "attached" to the unit */
|
||||
void remove_invalid_of(unit const*);
|
||||
|
||||
/**
|
||||
* Find the first valid action belonging to this unit.
|
||||
*
|
||||
* @return The position, or end() if not found.
|
||||
*/
|
||||
const_iterator find_last_valid_of(unit const& u) const;
|
||||
|
||||
/**
|
||||
* Determines the appropriate turn number for the next action planned for this unit
|
||||
*
|
||||
|
@ -502,9 +494,6 @@ public:
|
|||
*/
|
||||
size_t get_turn_num_of(unit const&) const;
|
||||
|
||||
/** Validates all planned actions in the queue */
|
||||
void validate_actions();
|
||||
|
||||
/** Used to track gold spending by recruits/recalls when building the future unit map */
|
||||
int get_gold_spent() const { return gold_spent_; }
|
||||
/** Used to track gold spending by recruits/recalls when building the future unit map */
|
||||
|
|
|
@ -60,21 +60,19 @@ std::ostream& suppose_dead::print(std::ostream &s) const
|
|||
}
|
||||
|
||||
suppose_dead::suppose_dead(size_t team_index, bool hidden, unit& curr_unit, map_location const& loc)
|
||||
: action(team_index,hidden)
|
||||
, unit_underlying_id_(curr_unit.underlying_id())
|
||||
, unit_id_(curr_unit.id())
|
||||
, loc_(loc)
|
||||
, valid_(true)
|
||||
: action(team_index,hidden)
|
||||
, unit_underlying_id_(curr_unit.underlying_id())
|
||||
, unit_id_(curr_unit.id())
|
||||
, loc_(loc)
|
||||
{
|
||||
this->init();
|
||||
}
|
||||
|
||||
suppose_dead::suppose_dead(config const& cfg, bool hidden)
|
||||
: action(cfg,hidden)
|
||||
, unit_underlying_id_(0)
|
||||
, unit_id_()
|
||||
, loc_(cfg.child("loc_")["x"],cfg.child("loc_")["y"])
|
||||
, valid_(true)
|
||||
: action(cfg,hidden)
|
||||
, unit_underlying_id_(0)
|
||||
, unit_id_()
|
||||
, loc_(cfg.child("loc_")["x"],cfg.child("loc_")["y"])
|
||||
{
|
||||
// Construct and validate unit_
|
||||
unit_map::iterator unit_itor = resources::units->find(cfg["unit_"]);
|
||||
|
@ -152,45 +150,28 @@ void suppose_dead::draw_hex(const map_location& hex)
|
|||
}
|
||||
}
|
||||
|
||||
void suppose_dead::set_valid(bool valid)
|
||||
void suppose_dead::redraw()
|
||||
{
|
||||
valid_ = valid;
|
||||
resources::screen->invalidate(loc_);
|
||||
}
|
||||
|
||||
bool suppose_dead::validate()
|
||||
action::error suppose_dead::check() const
|
||||
{
|
||||
DBG_WB << "validating suppose_dead on hex " << loc_ << "\n";
|
||||
//invalidate suppose-dead hex so number display is updated properly
|
||||
resources::screen->invalidate(loc_);
|
||||
|
||||
if(!get_source_hex().valid()) {
|
||||
set_valid(false);
|
||||
return INVALID_LOCATION;
|
||||
}
|
||||
|
||||
unit_map::const_iterator unit_it;
|
||||
//Check that the unit still exists in the source hex
|
||||
if(is_valid()) {
|
||||
unit_it = resources::units->find(get_source_hex());
|
||||
|
||||
if(unit_it == resources::units->end()) {
|
||||
set_valid(false);
|
||||
}
|
||||
unit_map::const_iterator unit_it = resources::units->find(get_source_hex());
|
||||
if(unit_it == resources::units->end()) {
|
||||
return NO_UNIT;
|
||||
}
|
||||
|
||||
//check if the unit in the source hex has the same unit id as before,
|
||||
//i.e. that it's the same unit
|
||||
if(is_valid() && unit_id_ != unit_it->id()) {
|
||||
set_valid(false);
|
||||
if(unit_id_ != unit_it->id()) {
|
||||
return UNIT_CHANGED;
|
||||
}
|
||||
|
||||
if(!is_valid()) {
|
||||
if(viewer_team() == team_index()) { //< Don't mess with any other team's queue -- only our own
|
||||
LOG_WB << "Invalid suppose_dead detected, adding to actions_to_erase_.\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return OK;
|
||||
}
|
||||
|
||||
config suppose_dead::to_config() const
|
||||
|
|
|
@ -48,6 +48,14 @@ public:
|
|||
|
||||
virtual void execute(bool& success, bool& complete);
|
||||
|
||||
/**
|
||||
* Check the validity of the action.
|
||||
*
|
||||
* @return the error preventing the action from being executed.
|
||||
* @retval OK if there isn't any error (the action can be executed.)
|
||||
*/
|
||||
virtual error check() const;
|
||||
|
||||
/** Applies temporarily the result of this action to the specified unit map. */
|
||||
virtual void apply_temp_modifier(unit_map& unit_map);
|
||||
/** Removes the result of this action from the specified unit map. */
|
||||
|
@ -55,13 +63,11 @@ public:
|
|||
|
||||
/** Gets called by display when drawing a hex, to allow actions to draw to the screen. */
|
||||
virtual void draw_hex(const map_location& hex);
|
||||
/** Redrawing function, called each time the action situation might have changed. */
|
||||
virtual void redraw();
|
||||
|
||||
virtual map_location get_numbering_hex() const { return loc_; }
|
||||
|
||||
virtual void set_valid(bool valid);
|
||||
virtual bool is_valid() const { return valid_; }
|
||||
bool validate();
|
||||
|
||||
virtual config to_config() const;
|
||||
|
||||
protected:
|
||||
|
@ -74,8 +80,6 @@ protected:
|
|||
std::string unit_id_;
|
||||
map_location loc_;
|
||||
|
||||
bool valid_;
|
||||
|
||||
private:
|
||||
void init();
|
||||
};
|
||||
|
|
|
@ -156,39 +156,34 @@ bool has_actions()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool team_has_visible_plan(team &t...)
|
||||
bool team_has_visible_plan(team &t)
|
||||
{
|
||||
return !t.get_side_actions()->hidden();
|
||||
}
|
||||
|
||||
void for_each_action(boost::function<void(action_ptr)> function, turn_team_filter pre_team_filter, turn_team_filter post_team_filter)
|
||||
void for_each_action(boost::function<void(action_ptr)> function, team_filter team_filter)
|
||||
{
|
||||
size_t max_turns = 0;
|
||||
BOOST_FOREACH(team &t, *resources::teams) {
|
||||
max_turns = std::max(max_turns, t.get_side_actions()->num_turns());
|
||||
}
|
||||
|
||||
for(size_t turn=0; turn < max_turns; ++turn) {
|
||||
bool end = false;
|
||||
for(size_t turn=0; !end; ++turn) {
|
||||
end = true;
|
||||
BOOST_FOREACH(team &side, *resources::teams) {
|
||||
side_actions &actions = *side.get_side_actions();
|
||||
if(actions.turn_size(turn) > 0 && pre_team_filter(side, turn)) {
|
||||
if(turn < actions.num_turns() && team_filter(side)) {
|
||||
std::for_each(actions.turn_begin(turn), actions.turn_end(turn), function);
|
||||
if(!post_team_filter(side, turn)) {
|
||||
return;
|
||||
}
|
||||
end = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action_ptr find_action_at(map_location hex, team_filter pre_team_filter)
|
||||
action_ptr find_action_at(map_location hex, team_filter team_filter)
|
||||
{
|
||||
action_ptr result;
|
||||
size_t result_turn = std::numeric_limits<size_t>::max();
|
||||
|
||||
BOOST_FOREACH(team &side, *resources::teams) {
|
||||
side_actions &actions = *side.get_side_actions();
|
||||
if(pre_team_filter(side)) {
|
||||
if(team_filter(side)) {
|
||||
side_actions::iterator chall = actions.find_first_action_at(hex);
|
||||
if(chall == actions.end()) {
|
||||
continue;
|
||||
|
|
|
@ -115,34 +115,20 @@ bool has_actions();
|
|||
*/
|
||||
typedef boost::function<bool(team&)> team_filter;
|
||||
|
||||
/**
|
||||
* Callable object class to filter turns and teams.
|
||||
*
|
||||
* The first argument is the team to consider.
|
||||
* The second argument is the relative turn number.
|
||||
*/
|
||||
typedef boost::function<bool(team&,size_t)> turn_team_filter;
|
||||
|
||||
/** Returns whether a given team's plan is visible. */
|
||||
bool team_has_visible_plan(team&...);
|
||||
|
||||
/** Always returns true. */
|
||||
inline bool default_team_filter(team&...){ return true; }
|
||||
bool team_has_visible_plan(team&);
|
||||
|
||||
/**
|
||||
* Apply a function to all the actions of the whiteboard.
|
||||
*
|
||||
* The actions are processed chronologically.
|
||||
* The second parameter is a @ref turn_team_filter, it is called for each team, if it returns false, the actions of this team won't be processed.
|
||||
* The third parameter is also a @ref turn_team_filter, it is called for each team after visiting its actions, if it returns false, for_each_action returns.
|
||||
* The second parameter is a @ref team_filter, it is called for each team, if it returns false, the actions of this team won't be processed.
|
||||
*
|
||||
* @param function the function to execute.
|
||||
* @param pre_team_filter select whether a team is visited (default to @ref team_has_visible_plan).
|
||||
* @param post_team_filter stop condition, called after visiting each team (default to @ref default_team_filter).
|
||||
* @param team_filter select whether a team is visited (default to @ref team_has_visible_plan).
|
||||
*/
|
||||
void for_each_action(boost::function<void(action_ptr)> function,
|
||||
turn_team_filter pre_team_filter = team_has_visible_plan,
|
||||
turn_team_filter post_team_filter = default_team_filter);
|
||||
team_filter team_filter = team_has_visible_plan);
|
||||
|
||||
/**
|
||||
* Find the first action occuring on a given hex.
|
||||
|
@ -151,10 +137,10 @@ void for_each_action(boost::function<void(action_ptr)> function,
|
|||
* The second parameter is a @ref team_filter, it is called for each team, if it returns false, the actions of this team won't be considered.
|
||||
*
|
||||
* @param hex where to search for an action.
|
||||
* @param pre_team_filter select whether a team is visited (default to @ref team_has_visible_plan).
|
||||
* @param team_filter select whether a team is visited (default to @ref team_has_visible_plan).
|
||||
* @retval action_ptr() when no action verifying the team_filter are present on the given hex.
|
||||
*/
|
||||
action_ptr find_action_at(map_location hex, team_filter pre_team_filter = team_has_visible_plan);
|
||||
action_ptr find_action_at(map_location hex, team_filter team_filter = team_has_visible_plan);
|
||||
|
||||
/**
|
||||
* Find the actions of an unit.
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
Copyright (C) 2010 - 2012 by Gabriel Morin <gabrielmorin (at) gmail (dot) com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*/
|
||||
|
||||
#include "validate_visitor.hpp"
|
||||
#include "attack.hpp"
|
||||
#include "manager.hpp"
|
||||
#include "move.hpp"
|
||||
#include "recall.hpp"
|
||||
#include "recruit.hpp"
|
||||
#include "side_actions.hpp"
|
||||
#include "suppose_dead.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include "arrow.hpp"
|
||||
#include "pathfind/pathfind.hpp"
|
||||
#include "play_controller.hpp"
|
||||
#include "resources.hpp"
|
||||
#include "team.hpp"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
namespace wb
|
||||
{
|
||||
|
||||
validate_visitor::validate_visitor(unit_map& unit_map)
|
||||
: builder_(unit_map,*this)
|
||||
, viewer_actions_(*viewer_actions())
|
||||
, actions_to_erase_()
|
||||
, arg_itor_()
|
||||
{
|
||||
assert(!resources::whiteboard->has_planned_unit_map());
|
||||
}
|
||||
|
||||
validate_visitor::~validate_visitor()
|
||||
{
|
||||
}
|
||||
|
||||
bool validate_visitor::validate_actions()
|
||||
{
|
||||
builder_.build_map();
|
||||
|
||||
//FIXME: by reverse iterating this can be done in a more efficiant way
|
||||
// by using the iterator returned by remove_action it could even be done in visit_all above
|
||||
if (!actions_to_erase_.empty()) {
|
||||
int side_actions_size_before = viewer_actions_.size();
|
||||
LOG_WB << "Erasing " << actions_to_erase_.size() << " invalid actions.\n";
|
||||
BOOST_FOREACH(action_ptr action, actions_to_erase_) {
|
||||
viewer_actions_.remove_action(viewer_actions_.get_position_of(action), false);
|
||||
}
|
||||
assert(side_actions_size_before - viewer_actions_.size() == actions_to_erase_.size());
|
||||
actions_to_erase_.clear();
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void validate_visitor::helper::validate(side_actions::iterator const& itor)
|
||||
{
|
||||
if((*itor)->validate()) {
|
||||
parent_.actions_to_erase_.insert(*itor);
|
||||
}
|
||||
}
|
||||
|
||||
}//end namespace wb
|
|
@ -1,72 +0,0 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
Copyright (C) 2010 - 2012 by Gabriel Morin <gabrielmorin (at) gmail (dot) com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*/
|
||||
|
||||
#ifndef WB_VALIDATE_VISITOR_HPP_
|
||||
#define WB_VALIDATE_VISITOR_HPP_
|
||||
|
||||
#include "mapbuilder.hpp"
|
||||
#include "side_actions.hpp"
|
||||
#include "visitor.hpp"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace wb
|
||||
{
|
||||
|
||||
/**
|
||||
* Works like mapbuilder, but with these differences:
|
||||
* * Instead of stopping at viewer_team, it visits all actions of every team.
|
||||
* * actions are evaluated for validity along the way.
|
||||
* * Some invalid actions are deleted.
|
||||
*/
|
||||
class validate_visitor
|
||||
{
|
||||
public:
|
||||
explicit validate_visitor(unit_map& unit_map);
|
||||
virtual ~validate_visitor();
|
||||
|
||||
/// @return false some actions had to be deleted during validation,
|
||||
/// which may warrant a second validation
|
||||
bool validate_actions();
|
||||
|
||||
private:
|
||||
struct helper: public mapbuilder
|
||||
{
|
||||
helper(unit_map& umap, validate_visitor& parent)
|
||||
: mapbuilder(umap)
|
||||
, parent_(parent)
|
||||
{}
|
||||
virtual void validate(side_actions::iterator const& itor);
|
||||
validate_visitor& parent_;
|
||||
};
|
||||
friend struct helper;
|
||||
|
||||
helper builder_;
|
||||
|
||||
side_actions& viewer_actions_;
|
||||
|
||||
std::set<action_ptr> actions_to_erase_;
|
||||
|
||||
//Parameter for the visit_***() fcns -- see helper::validate()
|
||||
side_actions::iterator arg_itor_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* WB_VALIDATE_VISITOR_HPP_ */
|
Loading…
Add table
Reference in a new issue