Simplification of the validation logic.

This commit is contained in:
Étienne Simon 2012-08-17 20:05:11 +00:00
parent 18e0ef7822
commit 3d442c6cea
24 changed files with 361 additions and 611 deletions

View file

@ -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)
)

View file

@ -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

View file

@ -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 )

View file

@ -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() {}

View file

@ -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

View file

@ -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:

View file

@ -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();

View file

@ -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

View file

@ -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_);
}
}

View file

@ -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.
};
}

View file

@ -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()

View file

@ -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_;

View file

@ -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

View file

@ -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_;
};

View file

@ -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

View file

@ -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_;

View file

@ -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

View file

@ -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 */

View file

@ -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

View file

@ -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();
};

View file

@ -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;

View file

@ -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.

View file

@ -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

View file

@ -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_ */