Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "validate_visitor.hpp"
00021 #include "attack.hpp"
00022 #include "manager.hpp"
00023 #include "move.hpp"
00024 #include "recall.hpp"
00025 #include "recruit.hpp"
00026 #include "side_actions.hpp"
00027 #include "suppose_dead.hpp"
00028 #include "utility.hpp"
00029
00030 #include "arrow.hpp"
00031 #include "foreach.hpp"
00032 #include "pathfind/pathfind.hpp"
00033 #include "play_controller.hpp"
00034 #include "resources.hpp"
00035 #include "team.hpp"
00036
00037 namespace wb
00038 {
00039
00040 validate_visitor::validate_visitor(unit_map& unit_map)
00041 : builder_(unit_map,*this)
00042 , viewer_actions_(*viewer_actions())
00043 , actions_to_erase_()
00044 , arg_itor_()
00045 {
00046 assert(!resources::whiteboard->has_planned_unit_map());
00047 }
00048
00049 validate_visitor::~validate_visitor()
00050 {
00051 }
00052
00053 bool validate_visitor::validate_actions()
00054 {
00055 builder_.build_map();
00056
00057
00058
00059 if (!actions_to_erase_.empty())
00060 {
00061 int side_actions_size_before = viewer_actions_.size();
00062 LOG_WB << "Erasing " << actions_to_erase_.size() << " invalid actions.\n";
00063 foreach(action_ptr action, actions_to_erase_)
00064 {
00065 viewer_actions_.remove_action(viewer_actions_.get_position_of(action), false);
00066 }
00067 assert(side_actions_size_before - viewer_actions_.size() == actions_to_erase_.size());
00068 actions_to_erase_.clear();
00069 return false;
00070 }
00071 else
00072 {
00073 return true;
00074 }
00075 }
00076
00077
00078 validate_visitor::VALIDITY validate_visitor::evaluate_move_validity(move_ptr m_ptr)
00079 {
00080 move& m = *m_ptr;
00081
00082 if (!(m.get_source_hex().valid() && m.get_dest_hex().valid()))
00083 return WORTHLESS;
00084
00085
00086 unit_map::iterator unit_it;
00087 unit_it = resources::units->find(m.get_source_hex());
00088 if (unit_it == resources::units->end())
00089 return WORTHLESS;
00090
00091
00092
00093 if (m.unit_id_ != unit_it->id() || m.unit_underlying_id_ != unit_it->underlying_id())
00094 return WORTHLESS;
00095
00096
00097 if (m.get_route().steps.size() >= 2 && get_visible_unit(m.get_dest_hex(),resources::teams->at(viewer_team())) != NULL) {
00098 return WORTHLESS;
00099 }
00100
00101
00102 if (m.get_source_hex() != m.get_dest_hex())
00103 {
00104
00105
00106 pathfind::marked_route checked_route = pathfind::mark_route(m.get_route().route);
00107
00108 if (checked_route.marks[checked_route.steps.back()].turns != 1)
00109 return OBSTRUCTED;
00110 }
00111
00112 return VALID;
00113 }
00114
00115
00116
00117
00118 bool validate_visitor::no_previous_invalids(side_actions::iterator const& itor)
00119 {
00120 if(itor == viewer_actions_.begin())
00121 return true;
00122 side_actions::iterator prev_action_of_unit = viewer_actions_.find_last_action_of((*itor)->get_unit(),itor-1);
00123 if(prev_action_of_unit == viewer_actions_.end())
00124 return true;
00125 return (*prev_action_of_unit)->is_valid();
00126 }
00127
00128 void validate_visitor::visit(move_ptr move)
00129 {
00130 DBG_WB <<"visiting move from " << move->get_source_hex()
00131 << " to " << move->get_dest_hex() << "\n";
00132
00133 resources::screen->invalidate(move->get_source_hex());
00134 resources::screen->invalidate(move->get_dest_hex());
00135
00136 switch(evaluate_move_validity(move))
00137 {
00138 case VALID:
00139
00140
00141 move->set_valid(true);
00142 break;
00143 case OBSTRUCTED:
00144 move->set_valid(false);
00145 break;
00146 case WORTHLESS:
00147 move->set_valid(false);
00148
00149
00150 if(viewer_team() == move->team_index()
00151 && no_previous_invalids(arg_itor_))
00152 {
00153 LOG_WB << "Worthless invalid move detected, adding to actions_to_erase_.\n";
00154 actions_to_erase_.insert(move);
00155 }
00156 break;
00157 }
00158 }
00159
00160 void validate_visitor::visit(attack_ptr attack)
00161 {
00162 DBG_WB <<"visiting attack from " << attack->get_dest_hex()
00163 << " to " << attack->target_hex_ << "\n";
00164
00165 resources::screen->invalidate(attack->get_dest_hex());
00166 resources::screen->invalidate(attack->target_hex_);
00167
00168 if (
00169
00170 attack->get_unit()
00171
00172 && attack->target_hex_.valid()
00173
00174 && resources::units->find(attack->target_hex_) != resources::units->end()
00175
00176 && attack->get_unit()->attacks_left() > 0
00177
00178 && (*resources::teams)[attack->get_unit()->side() - 1].is_enemy(resources::units->find(attack->target_hex_)->side())
00179
00180
00181
00182 )
00183 {
00184
00185 visit(boost::static_pointer_cast<move>(attack));
00186 }
00187 else
00188 {
00189 attack->set_valid(false);
00190
00191 if (viewer_team() == attack->team_index())
00192 {
00193 LOG_WB << "Worthless invalid attack detected, adding to actions_to_erase_.\n";
00194 actions_to_erase_.insert(attack);
00195 }
00196 }
00197 }
00198
00199 void validate_visitor::visit(recruit_ptr recruit)
00200 {
00201 DBG_WB << "visiting recruit on hex " << recruit->recruit_hex_ << "\n";
00202
00203 resources::screen->invalidate(recruit->recruit_hex_);
00204
00205 size_t team_index = recruit->team_index();
00206
00207
00208 if(resources::units->find(recruit->recruit_hex_) != resources::units->end())
00209 {
00210 LOG_WB << "Recruit set as invalid because target hex is occupied.\n";
00211 recruit->set_valid(false);
00212 }
00213
00214 if (recruit->is_valid())
00215 {
00216 const std::set<std::string>& recruits = (*resources::teams)[team_index].recruits();
00217 if (recruits.find(recruit->unit_name_) == recruits.end())
00218 {
00219 recruit->set_valid(false);
00220 LOG_WB << " Validate visitor: Planned recruit invalid since unit is not in recruit list anymore.\n";
00221 }
00222 }
00223
00224 if (recruit->is_valid() && recruit->temp_unit_->cost() > (*resources::teams)[team_index].gold())
00225 {
00226 LOG_WB << "Recruit set as invalid, team doesn't have enough gold.\n";
00227 recruit->set_valid(false);
00228 }
00229
00230 if(recruit->is_valid() && !find_recruiter(recruit->team_index(),recruit->get_recruit_hex()))
00231 {
00232 LOG_WB << "Recruit set as invalid, no leader can recruit this unit.\n";
00233 recruit->set_valid(false);
00234 }
00235
00236 if(!recruit->is_valid())
00237 {
00238 if(viewer_team() == recruit->team_index())
00239 {
00240 LOG_WB << "Invalid recruit detected, adding to actions_to_erase_.\n";
00241 actions_to_erase_.insert(recruit);
00242 }
00243 }
00244 }
00245
00246 void validate_visitor::visit(recall_ptr recall)
00247 {
00248 DBG_WB << "visiting recall on hex " << recall->recall_hex_ << "\n";
00249
00250 resources::screen->invalidate(recall->recall_hex_);
00251
00252 size_t team_index = recall->team_index();
00253
00254
00255 if(resources::units->find(recall->recall_hex_) != resources::units->end())
00256 {
00257 LOG_WB << "Recall set as invalid because target hex is occupied.\n";
00258 recall->set_valid(false);
00259 }
00260
00261 if (recall->is_valid())
00262 {
00263 const std::vector<unit>& recalls = (*resources::teams)[team_index].recall_list();
00264 if ( find_if_matches_id(recalls, recall->temp_unit_->id()) == recalls.end() )
00265 {
00266 recall->set_valid(false);
00267 LOG_WB << " Validate visitor: Planned recall invalid since unit is not in recall list anymore.\n";
00268 }
00269 }
00270
00271 if (recall->is_valid()
00272 && (*resources::teams)[team_index].recall_cost() > (*resources::teams)[team_index].gold())
00273 {
00274 LOG_WB << "Recall set as invalid, team doesn't have enough gold.\n";
00275 recall->set_valid(false);
00276 }
00277
00278 if(recall->is_valid() && !find_recruiter(recall->team_index(),recall->get_recall_hex()))
00279 {
00280 LOG_WB << "Recall set as invalid, no leader can recall this unit.\n";
00281 recall->set_valid(false);
00282 }
00283
00284
00285 if(!recall->is_valid())
00286 {
00287 if(viewer_team() == recall->team_index())
00288 {
00289 LOG_WB << "Invalid recall detected, adding to actions_to_erase_.\n";
00290 actions_to_erase_.insert(recall);
00291 }
00292 }
00293 }
00294
00295 void validate_visitor::visit(suppose_dead_ptr sup_d)
00296 {
00297 DBG_WB << "visiting suppose_dead on hex " << sup_d->loc_ << "\n";
00298
00299 resources::screen->invalidate(sup_d->loc_);
00300
00301 if(!sup_d->get_source_hex().valid())
00302 sup_d->set_valid(false);
00303
00304 unit_map::const_iterator unit_it;
00305
00306 if(sup_d->valid_)
00307 {
00308 unit_it = resources::units->find(sup_d->get_source_hex());
00309
00310 if(unit_it == resources::units->end())
00311 {
00312 sup_d->set_valid(false);
00313 }
00314 }
00315
00316
00317
00318 if(sup_d->valid_ && sup_d->unit_id_ != unit_it->id())
00319 {
00320 sup_d->set_valid(false);
00321 }
00322
00323 if(!sup_d->valid_)
00324 {
00325 if(viewer_team() == sup_d->team_index())
00326 {
00327 LOG_WB << "Invalid suppose_dead detected, adding to actions_to_erase_.\n";
00328 actions_to_erase_.insert(sup_d);
00329 }
00330 }
00331 }
00332
00333 void validate_visitor::helper::validate(side_actions::iterator const& itor)
00334 {
00335 parent_.arg_itor_ = itor;
00336 (*itor)->accept(parent_);
00337 }
00338
00339 }