void move::apply_temp_modifier(unit_map& unit_map) { if (get_source_hex() == get_dest_hex()) return; //zero-hex move, used by attack subclass // Safety: Make sure the old temporary_unit_mover (if any) is destroyed // before creating a new one. mover_.reset(); //@todo: deal with multi-turn moves, which may for instance end their first turn // by capturing a village //@todo: we may need to change unit status here and change it back in remove_temp_modifier unit* unit; { unit_map::iterator unit_it = unit_map.find(get_source_hex()); assert(unit_it != unit_map.end()); unit = &*unit_it; } //Modify movement points DBG_WB <<"Move: Changing movement points for unit " << unit->name() << " [" << unit->id() << "] from " << unit->movement_left() << " to " << unit->movement_left() - movement_cost_ << ".\n"; // Move the unit DBG_WB << "Move: Temporarily moving unit " << unit->name() << " [" << unit->id() << "] from (" << get_source_hex() << ") to (" << get_dest_hex() <<")\n"; mover_.reset(new temporary_unit_mover(unit_map, get_source_hex(), get_dest_hex(), unit->movement_left() - movement_cost_)); //Update status of fake unit (not undone by remove_temp_modifiers) //@todo this contradicts the name "temp_modifiers" fake_unit_->set_movement(unit->movement_left(), true); }
void move::calculate_move_cost() { assert(get_unit()); assert(route_); if (get_source_hex().valid() && get_dest_hex().valid() && get_source_hex() != get_dest_hex()) { // @todo: find a better treatment of movement points when defining moves out-of-turn if(get_unit()->movement_left() - route_->move_cost < 0 && resources::controller->current_side() == resources::screen->viewing_side()) { WRN_WB << "Move defined with insufficient movement left.\n"; } // If unit finishes move in a village it captures, set the move cost to unit's movement_left() if (route_->marks[get_dest_hex()].capture) { movement_cost_ = get_unit()->movement_left(); } else { movement_cost_ = route_->move_cost; } } }
void move::remove_temp_modifier(unit_map&) { if (get_source_hex() == get_dest_hex()) return; //zero-hex move, probably used by attack subclass unit* unit; { unit_map::iterator unit_it = resources::units->find(get_dest_hex()); assert(unit_it != resources::units->end()); unit = &*unit_it; } // Restore movement points DBG_WB << "Move: Changing movement points for unit " << unit->name() << " [" << unit->id() << "] from " << unit->movement_left() << " to " << unit->movement_left() + movement_cost_ << ".\n"; unit->set_movement(unit->movement_left() + movement_cost_); // Restore the unit to its original position mover_.reset(); }
void move::remove_temp_modifier(unit_map&) { if (get_source_hex() == get_dest_hex()) return; //zero-hex move, probably used by attack subclass // Debug movement points if ( !lg::debug.dont_log(log_whiteboard) ) { unit* unit; { unit_map::iterator unit_it = resources::units->find(get_dest_hex()); assert(unit_it != resources::units->end()); unit = &*unit_it; } DBG_WB << "Move: Movement points for unit " << unit->name() << " [" << unit->id() << "] should get changed from " << unit->movement_left() << " to " << unit->movement_left() + movement_cost_ << ".\n"; } // Restore the unit to its original position and movement. mover_.reset(); }
void move::redraw() { resources::screen->invalidate(get_source_hex()); resources::screen->invalidate(get_dest_hex()); update_arrow_style(); }
std::ostream& move::print(std::ostream &s) const { s << "Move for unit " << get_unit()->name() << " [" << get_unit()->id() << "] " << "from (" << get_source_hex() << ") to (" << get_dest_hex() << ")"; return s; }
action::error move::check_validity() const { // 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) {} ~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); if(!(get_source_hex().valid() && get_dest_hex().valid())) { 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 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 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 LOCATION_OCCUPIED; } //check that the path is good if(get_source_hex() != get_dest_hex()) { //skip zero-hex move used by attack subclass // Mark the plain route to see if the move can still be done in one turn, // which is always the case for planned moves pathfind::marked_route checked_route = pathfind::mark_route(get_route().route); if(checked_route.marks[checked_route.steps.back()].turns != 1) { return TOO_FAR; } } // The move is valid, so correct the setter. setter.set_texture(ARROW_TEXTURE_VALID); return OK; }
void move::execute(bool& success, bool& complete) { 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()) { //zero-hex move, used by attack subclass success = complete = true; return; } LOG_WB << "Executing: " << shared_from_this() << "\n"; // Copy the current route to ensure it remains valid throughout the animation. const std::vector<map_location> steps = route_->steps; set_arrow_brightness(ARROW_BRIGHTNESS_HIGHLIGHTED); hide_fake_unit(); size_t num_steps; bool interrupted; try { events::mouse_handler& mouse_handler = resources::controller->get_mouse_handler_base(); num_steps = mouse_handler.move_unit_along_route(steps, interrupted); } catch (end_turn_exception&) { set_arrow_brightness(ARROW_BRIGHTNESS_STANDARD); throw; // we rely on the caller to delete this action } const map_location & final_location = steps[num_steps]; unit_map::const_iterator unit_it = resources::units->find(final_location); if ( num_steps == 0 ) { LOG_WB << "Move execution resulted in zero movement.\n"; success = false; complete = true; } else if ( unit_it == resources::units->end() || unit_it->id() != unit_id_ ) { WRN_WB << "Unit disappeared from map during move execution.\n"; success = false; complete = true; } else { complete = num_steps + 1 == steps.size(); success = complete && !interrupted; if ( !success ) { if ( complete ) { LOG_WB << "Move completed, but interrupted on final hex. Halting.\n"; //reset to a single-hex path, just in case *this is a wb::attack route_->steps = std::vector<map_location>(1, final_location); arrow_.reset(); } else { LOG_WB << "Move finished at (" << final_location << ") instead of at (" << get_dest_hex() << "). Setting new path.\n"; route_->steps = std::vector<map_location>(steps.begin() + num_steps, steps.end()); //FIXME: probably better to use the new calculate_new_route() instead of the above: //calculate_new_route(final_location, steps.back()); // Of course, "better" would need to be verified. arrow_->set_path(route_->steps); } } } if(!complete) { set_arrow_brightness(ARROW_BRIGHTNESS_STANDARD); show_fake_unit(); } }
void move::execute(bool& success, bool& complete) { 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()) { //zero-hex move, used by attack subclass success = complete = true; return; } LOG_WB << "Executing: " << shared_from_this() << "\n"; set_arrow_brightness(ARROW_BRIGHTNESS_HIGHLIGHTED); hide_fake_unit(); events::mouse_handler& mouse_handler = resources::controller->get_mouse_handler_base(); std::set<map_location> adj_enemies = mouse_handler.get_adj_enemies(get_dest_hex(), side_number()); map_location final_location; bool steps_finished; bool enemy_sighted; { team const& owner_team = resources::teams->at(team_index()); try { steps_finished = mouse_handler.move_unit_along_route(*route_, &final_location, owner_team.auto_shroud_updates(), &enemy_sighted); } catch (end_turn_exception&) { set_arrow_brightness(ARROW_BRIGHTNESS_STANDARD); throw; // we rely on the caller to delete this action } // final_location now contains the final unit location // if that isn't needed, pass NULL rather than &final_location // Also, enemy_sighted now tells whether a unit was sighted during the move } if(mouse_handler.get_adj_enemies(final_location,side_number()) != adj_enemies) enemy_sighted = true; //< "ambushed" on last hex unit_map::const_iterator unit_it; if (final_location == route_->steps.front()) { LOG_WB << "Move execution resulted in zero movement.\n"; success = false; complete = true; } else if (final_location.valid() && (unit_it = resources::units->find(final_location)) != resources::units->end() && unit_it->id() == unit_id_) { if (steps_finished && route_->steps.back() == final_location) //reached destination { complete = true; //check if new enemies are now visible if(enemy_sighted) { LOG_WB << "Move completed, but interrupted on final hex. Halting.\n"; //reset to a single-hex path, just in case *this is a wb::attack arrow_.reset(); route_->steps = std::vector<map_location>(1,route_->steps.back()); success = false; } else // Everything went smoothly success = true; } else // Move was interrupted, probably by enemy unit sighted { success = false; LOG_WB << "Move finished at (" << final_location << ") instead of at (" << get_dest_hex() << "), analyzing\n"; std::vector<map_location>::iterator start_new_path; bool found = false; for (start_new_path = route_->steps.begin(); ((start_new_path != route_->steps.end()) && !found); ++start_new_path) { if (*start_new_path == final_location) { found = true; } } if (found) { --start_new_path; //since the for loop incremented the iterator once after we found the right one. std::vector<map_location> new_path(start_new_path, route_->steps.end()); LOG_WB << "Setting new path for this move from (" << new_path.front() << ") to (" << new_path.back() << ").\n"; //FIXME: probably better to use the new calculate_new_route instead of doing this route_->steps = new_path; arrow_->set_path(new_path); complete = false; } else //Unit ended up in location outside path, likely due to a WML event { WRN_WB << "Unit ended up in location outside path during move execution.\n"; complete = true; } } } else //Unit disappeared from the map, likely due to a WML event { WRN_WB << "Unit disappeared from map during move execution.\n"; success = false; complete = true; } if(!complete) { set_arrow_brightness(ARROW_BRIGHTNESS_STANDARD); show_fake_unit(); } }