00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "move.hpp"
00021
00022 #include "visitor.hpp"
00023 #include "manager.hpp"
00024 #include "side_actions.hpp"
00025 #include "utility.hpp"
00026
00027 #include "arrow.hpp"
00028 #include "config.hpp"
00029 #include "foreach.hpp"
00030 #include "game_end_exceptions.hpp"
00031 #include "mouse_events.hpp"
00032 #include "play_controller.hpp"
00033 #include "replay.hpp"
00034 #include "resources.hpp"
00035 #include "team.hpp"
00036 #include "unit.hpp"
00037 #include "unit_display.hpp"
00038 #include "unit_map.hpp"
00039
00040 namespace wb {
00041
00042 std::ostream& operator<<(std::ostream &s, move_ptr move)
00043 {
00044 assert(move);
00045 return move->print(s);
00046 }
00047
00048 std::ostream& operator<<(std::ostream &s, move_const_ptr move)
00049 {
00050 assert(move);
00051 return move->print(s);
00052 }
00053
00054 std::ostream& move::print(std::ostream &s) const
00055 {
00056 s << "Move for unit " << get_unit()->name() << " [" << get_unit()->id() << "] "
00057 << "from (" << get_source_hex() << ") to (" << get_dest_hex() << ")";
00058 return s;
00059 }
00060
00061 move::move(size_t team_index, bool hidden, unit& u, const pathfind::marked_route& route,
00062 arrow_ptr arrow, fake_unit_ptr fake_unit)
00063 : action(team_index,hidden),
00064 unit_underlying_id_(u.underlying_id()),
00065 unit_id_(),
00066 route_(new pathfind::marked_route(route)),
00067 movement_cost_(0),
00068 turn_number_(0),
00069 arrow_(arrow),
00070 fake_unit_(fake_unit),
00071 valid_(true),
00072 arrow_brightness_(),
00073 arrow_texture_(),
00074 mover_(),
00075 fake_unit_hidden_(false)
00076 {
00077 assert(!route_->steps.empty());
00078
00079 if(hidden)
00080 fake_unit_->set_hidden(true);
00081
00082 this->init();
00083 }
00084
00085 move::move(config const& cfg, bool hidden)
00086 : action(cfg,hidden)
00087 , unit_underlying_id_(0)
00088 , unit_id_()
00089 , route_(new pathfind::marked_route())
00090 , movement_cost_(0)
00091 , turn_number_(0)
00092 , arrow_(new arrow(hidden))
00093 , fake_unit_()
00094 , valid_(true)
00095 , arrow_brightness_()
00096 , arrow_texture_()
00097 , mover_()
00098 , fake_unit_hidden_(false)
00099 {
00100
00101 unit_map::iterator unit_itor = resources::units->find(cfg["unit_"]);
00102 if(unit_itor == resources::units->end())
00103 throw action::ctor_err("move: Invalid underlying_id");
00104 unit_underlying_id_ = unit_itor->underlying_id();
00105
00106
00107 config const& route_cfg = cfg.child("route_");
00108 if(!route_cfg)
00109 throw action::ctor_err("move: Invalid route_");
00110 route_->move_cost = route_cfg["move_cost"];
00111 foreach(config const& loc_cfg, route_cfg.child_range("step")) {
00112 route_->steps.push_back(map_location(loc_cfg["x"],loc_cfg["y"]));
00113 }
00114 foreach(config const& mark_cfg, route_cfg.child_range("mark")) {
00115 route_->marks[map_location(mark_cfg["x"],mark_cfg["y"])]
00116 = pathfind::marked_route::mark(mark_cfg["turns"],mark_cfg["zoc"],mark_cfg["capture"],mark_cfg["invisible"]);
00117 }
00118
00119
00120 std::vector<map_location> const& steps = route_->steps;
00121 if(steps.empty())
00122 throw action::ctor_err("move: Invalid route_");
00123
00124
00125 arrow_->set_color(team::get_side_color_index(side_number()));
00126 arrow_->set_style(arrow::STYLE_STANDARD);
00127 arrow_->set_path(route_->steps);
00128
00129
00130 fake_unit_.reset(new game_display::fake_unit(*get_unit()) );
00131 if(hidden)
00132 fake_unit_->set_hidden(true);
00133 fake_unit_->place_on_game_display(resources::screen);
00134 fake_unit_->set_ghosted(true);
00135 unit_display::move_unit(route_->steps, *fake_unit_, *resources::teams, false);
00136 fake_unit_->set_location(route_->steps.back());
00137
00138 this->init();
00139 }
00140
00141 void move::init()
00142 {
00143 assert(get_unit());
00144 unit_id_ = get_unit()->id();
00145
00146
00147
00148 if (fake_unit_)
00149 {
00150 fake_unit_->set_ghosted(true);
00151 }
00152 side_actions_ptr side_actions = resources::teams->at(team_index()).get_side_actions();
00153 side_actions::iterator action = side_actions->find_last_action_of(get_unit());
00154 if (action != side_actions->end())
00155 {
00156 if (move_ptr move = boost::dynamic_pointer_cast<class move>(*action))
00157 {
00158 if (move->fake_unit_)
00159 move->fake_unit_->set_disabled_ghosted(true);
00160 }
00161 }
00162
00163 this->calculate_move_cost();
00164
00165
00166 arrow::STYLE arrow_style = arrow_->get_style();
00167 if(arrow_style == arrow::STYLE_STANDARD)
00168 {
00169 arrow_brightness_ = ARROW_BRIGHTNESS_STANDARD;
00170 arrow_texture_ = ARROW_TEXTURE_VALID;
00171 }
00172 else if(arrow_style == arrow::STYLE_HIGHLIGHTED)
00173 {
00174 arrow_brightness_ = ARROW_BRIGHTNESS_HIGHLIGHTED;
00175 arrow_texture_ = ARROW_TEXTURE_VALID;
00176 }
00177 else if(arrow_style == arrow::STYLE_FOCUS)
00178 {
00179 arrow_brightness_ = ARROW_BRIGHTNESS_FOCUS;
00180 arrow_texture_ = ARROW_TEXTURE_VALID;
00181 }
00182 else if(arrow_style == arrow::STYLE_FOCUS_INVALID)
00183 {
00184 arrow_brightness_ = ARROW_BRIGHTNESS_STANDARD;
00185 arrow_texture_ = ARROW_TEXTURE_INVALID;
00186 }
00187 }
00188
00189 void move::accept(visitor& v)
00190 {
00191 v.visit(shared_from_this());
00192 }
00193
00194 void move::execute(bool& success, bool& complete)
00195 {
00196 if (!valid_) {
00197 success = false;
00198
00199 complete = true;
00200 return;
00201 }
00202
00203 if (get_source_hex() == get_dest_hex()) {
00204
00205 success = complete = true;
00206 return;
00207 }
00208
00209 LOG_WB << "Executing: " << shared_from_this() << "\n";
00210
00211 set_arrow_brightness(ARROW_BRIGHTNESS_HIGHLIGHTED);
00212 hide_fake_unit();
00213
00214 events::mouse_handler& mouse_handler = resources::controller->get_mouse_handler_base();
00215 std::set<map_location> adj_enemies = mouse_handler.get_adj_enemies(get_dest_hex(), side_number());
00216
00217 map_location final_location;
00218 bool steps_finished;
00219 bool enemy_sighted;
00220 {
00221 team const& owner_team = resources::teams->at(team_index());
00222 try {
00223 steps_finished = mouse_handler.move_unit_along_route(*route_, &final_location, owner_team.auto_shroud_updates(), &enemy_sighted);
00224 } catch (end_turn_exception&) {
00225 set_arrow_brightness(ARROW_BRIGHTNESS_STANDARD);
00226 throw;
00227 }
00228
00229
00230
00231 }
00232 if(mouse_handler.get_adj_enemies(final_location,side_number()) != adj_enemies)
00233 enemy_sighted = true;
00234
00235 unit_map::const_iterator unit_it;
00236
00237 if (final_location == route_->steps.front())
00238 {
00239 LOG_WB << "Move execution resulted in zero movement.\n";
00240 success = false;
00241 complete = true;
00242 }
00243 else if (final_location.valid() &&
00244 (unit_it = resources::units->find(final_location)) != resources::units->end()
00245 && unit_it->id() == unit_id_)
00246 {
00247 if (steps_finished && route_->steps.back() == final_location)
00248 {
00249 complete = true;
00250
00251
00252 if(enemy_sighted)
00253 {
00254 LOG_WB << "Move completed, but interrupted on final hex. Halting.\n";
00255
00256 arrow_.reset();
00257 route_->steps = std::vector<map_location>(1,route_->steps.back());
00258 success = false;
00259 }
00260 else
00261 success = true;
00262 }
00263 else
00264 {
00265 success = false;
00266
00267 LOG_WB << "Move finished at (" << final_location << ") instead of at (" << get_dest_hex() << "), analyzing\n";
00268 std::vector<map_location>::iterator start_new_path;
00269 bool found = false;
00270 for (start_new_path = route_->steps.begin(); ((start_new_path != route_->steps.end()) && !found); ++start_new_path)
00271 {
00272 if (*start_new_path == final_location)
00273 {
00274 found = true;
00275 }
00276 }
00277 if (found)
00278 {
00279 --start_new_path;
00280 std::vector<map_location> new_path(start_new_path, route_->steps.end());
00281 LOG_WB << "Setting new path for this move from (" << new_path.front()
00282 << ") to (" << new_path.back() << ").\n";
00283
00284 route_->steps = new_path;
00285 arrow_->set_path(new_path);
00286 complete = false;
00287 }
00288 else
00289 {
00290 WRN_WB << "Unit ended up in location outside path during move execution.\n";
00291 complete = true;
00292 }
00293 }
00294 }
00295 else
00296 {
00297 WRN_WB << "Unit disappeared from map during move execution.\n";
00298 success = false;
00299 complete = true;
00300 }
00301
00302 if(!complete)
00303 {
00304 set_arrow_brightness(ARROW_BRIGHTNESS_STANDARD);
00305 show_fake_unit();
00306 }
00307 }
00308
00309 unit* move::get_unit() const
00310 {
00311 unit_map::iterator itor = resources::units->find(unit_underlying_id_);
00312 if (itor.valid())
00313 return &*itor;
00314 else
00315 return NULL;
00316 }
00317
00318 map_location move::get_source_hex() const
00319 {
00320 assert(route_ && !route_->steps.empty());
00321 return route_->steps.front();
00322 }
00323
00324 map_location move::get_dest_hex() const
00325 {
00326 assert(route_ && !route_->steps.empty());
00327 return route_->steps.back();
00328 }
00329
00330 void move::set_route(const pathfind::marked_route& route)
00331 {
00332 route_.reset(new pathfind::marked_route(route));
00333 this->calculate_move_cost();
00334 arrow_->set_path(route_->steps);
00335 }
00336
00337 bool move::calculate_new_route(const map_location& source_hex, const map_location& dest_hex)
00338 {
00339 pathfind::plain_route new_plain_route;
00340 pathfind::shortest_path_calculator path_calc(*get_unit(),
00341 resources::teams->at(team_index()), *resources::units,
00342 *resources::teams, *resources::game_map);
00343 new_plain_route = pathfind::a_star_search(source_hex,
00344 dest_hex, 10000, &path_calc, resources::game_map->w(), resources::game_map->h());
00345 if (new_plain_route.move_cost >= path_calc.getNoPathValue()) return false;
00346 route_.reset(new pathfind::marked_route(pathfind::mark_route(new_plain_route)));
00347 calculate_move_cost();
00348 return true;
00349 }
00350
00351 void move::apply_temp_modifier(unit_map& unit_map)
00352 {
00353 if (get_source_hex() == get_dest_hex())
00354 return;
00355
00356
00357
00358
00359
00360 unit* unit;
00361 {
00362 unit_map::iterator unit_it = unit_map.find(get_source_hex());
00363 assert(unit_it != unit_map.end());
00364 unit = &*unit_it;
00365 }
00366
00367
00368 DBG_WB <<"Move: Changing movement points for unit " << unit->name() << " [" << unit->id()
00369 << "] from " << unit->movement_left() << " to "
00370 << unit->movement_left() - movement_cost_ << ".\n";
00371 unit->set_movement(unit->movement_left() - movement_cost_);
00372
00373
00374 DBG_WB << "Move: Temporarily moving unit " << unit->name() << " [" << unit->id()
00375 << "] from (" << get_source_hex() << ") to (" << get_dest_hex() <<")\n";
00376 mover_.reset(new temporary_unit_mover(unit_map,get_source_hex(), get_dest_hex()));
00377
00378
00379
00380 fake_unit_->set_movement(unit->movement_left());
00381 }
00382
00383 void move::remove_temp_modifier(unit_map&)
00384 {
00385 if (get_source_hex() == get_dest_hex())
00386 return;
00387
00388 unit* unit;
00389 {
00390 unit_map::iterator unit_it = resources::units->find(get_dest_hex());
00391 assert(unit_it != resources::units->end());
00392 unit = &*unit_it;
00393 }
00394
00395
00396 DBG_WB << "Move: Changing movement points for unit " << unit->name() << " [" << unit->id()
00397 << "] from " << unit->movement_left() << " to "
00398 << unit->movement_left() + movement_cost_ << ".\n";
00399 unit->set_movement(unit->movement_left() + movement_cost_);
00400
00401
00402 mover_.reset();
00403 }
00404
00405 void move::draw_hex(map_location const& hex)
00406 {
00407
00408 if (hex == get_dest_hex() && turn_number_ >= 2)
00409 {
00410 std::stringstream turn_text;
00411 turn_text << turn_number_;
00412 resources::screen->draw_text_in_hex(hex, display::LAYER_MOVE_INFO, turn_text.str(), 17, font::NORMAL_COLOR, 0.5,0.8);
00413 }
00414 }
00415
00416 void move::do_hide()
00417 {
00418 arrow_->hide();
00419 if(!fake_unit_hidden_)
00420 fake_unit_->set_hidden(true);
00421 }
00422
00423 void move::do_show()
00424 {
00425 arrow_->show();
00426 if(!fake_unit_hidden_)
00427 fake_unit_->set_hidden(false);
00428 }
00429
00430 void move::hide_fake_unit()
00431 {
00432 fake_unit_hidden_ = true;
00433 if(!hidden())
00434 fake_unit_->set_hidden(true);
00435 }
00436
00437 void move::show_fake_unit()
00438 {
00439 fake_unit_hidden_ = false;
00440 if(!hidden())
00441 fake_unit_->set_hidden(false);
00442 }
00443
00444 map_location move::get_numbering_hex() const
00445 {
00446 return get_dest_hex();
00447 }
00448
00449 void move::set_valid(bool valid)
00450 {
00451 if(valid_ != valid)
00452 {
00453 valid_ = valid;
00454 if(valid_)
00455 set_arrow_texture(ARROW_TEXTURE_VALID);
00456 else
00457 set_arrow_texture(ARROW_TEXTURE_INVALID);
00458 }
00459 }
00460
00461 config move::to_config() const
00462 {
00463 config final_cfg = action::to_config();
00464
00465 final_cfg["type"]="move";
00466 final_cfg["unit_"]=static_cast<int>(unit_underlying_id_);
00467
00468
00469
00470
00471 config route_cfg;
00472 route_cfg["move_cost"]=route_->move_cost;
00473 foreach(map_location const& loc, route_->steps)
00474 {
00475 config loc_cfg;
00476 loc_cfg["x"]=loc.x;
00477 loc_cfg["y"]=loc.y;
00478 route_cfg.add_child("step",loc_cfg);
00479 }
00480 typedef std::pair<map_location,pathfind::marked_route::mark> pair_loc_mark;
00481 foreach(pair_loc_mark const& item, route_->marks)
00482 {
00483 config mark_cfg;
00484 mark_cfg["x"]=item.first.x;
00485 mark_cfg["y"]=item.first.y;
00486 mark_cfg["turns"]=item.second.turns;
00487 mark_cfg["zoc"]=item.second.zoc;
00488 mark_cfg["capture"]=item.second.capture;
00489 mark_cfg["invisible"]=item.second.invisible;
00490 route_cfg.add_child("mark",mark_cfg);
00491 }
00492 final_cfg.add_child("route_",route_cfg);
00493
00494 return final_cfg;
00495 }
00496
00497 void move::calculate_move_cost()
00498 {
00499 assert(get_unit());
00500 assert(route_);
00501 if (get_source_hex().valid() && get_dest_hex().valid() && get_source_hex() != get_dest_hex())
00502 {
00503
00504
00505 if(get_unit()->movement_left() - route_->move_cost < 0
00506 && resources::controller->current_side() == resources::screen->viewing_side()) {
00507 WRN_WB << "Move defined with insufficient movement left.\n";
00508 }
00509
00510
00511 if (route_->marks[get_dest_hex()].capture)
00512 {
00513 movement_cost_ = get_unit()->movement_left();
00514 }
00515 else
00516 {
00517 movement_cost_ = route_->move_cost;
00518 }
00519 }
00520 }
00521
00522
00523
00524 void move::update_arrow_style()
00525 {
00526 if(arrow_texture_ == ARROW_TEXTURE_INVALID)
00527 {
00528 arrow_->set_style(arrow::STYLE_FOCUS_INVALID);
00529 return;
00530 }
00531
00532 switch(arrow_brightness_)
00533 {
00534 case ARROW_BRIGHTNESS_STANDARD:
00535 arrow_->set_style(arrow::STYLE_STANDARD);
00536 break;
00537 case ARROW_BRIGHTNESS_HIGHLIGHTED:
00538 arrow_->set_style(arrow::STYLE_HIGHLIGHTED);
00539 break;
00540 case ARROW_BRIGHTNESS_FOCUS:
00541 arrow_->set_style(arrow::STYLE_FOCUS);
00542 break;
00543 }
00544 }
00545
00546 }