void mapbuilder::pre_build() { for (team& t : resources::gameboard->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(); for (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::gameboard->teams()[viewer_team()], *resources::gameboard, false)) { removers_.push_back(new temporary_unit_remover(*resources::units, u.get_location())); //Don't do anything else to the removed unit! continue; } //Reset movement points, to be restored by destruction of resetters_ //restore movement points only to units not on the current side resetters_.push_back(new unit_movement_resetter(u,!on_current_side)); //make sure current side's units are not reset to full moves on first turn if(on_current_side) { acted_this_turn_.insert(&u); } } }
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 = complete = false; return; } if (get_source_hex() == get_dest_hex()) { //zero-hex move, used by attack subclass success = complete = true; return; } //Ensure destination hex is free if (get_visible_unit(get_dest_hex(),resources::teams->at(viewer_team())) != NULL) { success = complete = false; return; } LOG_WB << "Executing: " << shared_from_this() << "\n"; set_arrow_brightness(ARROW_BRIGHTNESS_HIGHLIGHTED); hide_fake_unit(); unghost_owner_unit(get_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 = complete = false; } 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 { 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); success = 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"; success = 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 = complete = true; } if(!complete) { set_arrow_brightness(ARROW_BRIGHTNESS_STANDARD); show_fake_unit(); ghost_owner_unit(get_unit()); } //if unit has other moves besides this one, set it back to ghosted visuals //@todo handle this in a more centralized fashion if (resources::teams->at(team_index()).get_side_actions()->count_actions_of(get_unit()) > 1) { ghost_owner_unit(get_unit()); } }