Applied patch #3786 from InvPhi for a more intuitive move-and-attack.

This commit is contained in:
Guillaume Melquiond 2005-03-24 21:18:26 +00:00
parent 912cfe245d
commit aeda20b9c4
4 changed files with 85 additions and 49 deletions

View file

@ -238,7 +238,7 @@ void display::highlight_hex(gamemap::location hex)
invalidate_unit();
}
gamemap::location display::hex_clicked_on(int xclick, int yclick, gamemap::location::DIRECTION* nearest_hex)
gamemap::location display::hex_clicked_on(int xclick, int yclick, gamemap::location::DIRECTION* nearest_hex, gamemap::location::DIRECTION* second_nearest_hex)
{
const SDL_Rect& rect = map_area();
if(point_in_rect(xclick,yclick,rect) == false) {
@ -248,10 +248,10 @@ gamemap::location display::hex_clicked_on(int xclick, int yclick, gamemap::locat
xclick -= rect.x;
yclick -= rect.y;
return pixel_position_to_hex(xpos_ + xclick, ypos_ + yclick, nearest_hex);
return pixel_position_to_hex(xpos_ + xclick, ypos_ + yclick, nearest_hex, second_nearest_hex);
}
gamemap::location display::pixel_position_to_hex(int x, int y, gamemap::location::DIRECTION* nearest_hex)
gamemap::location display::pixel_position_to_hex(int x, int y, gamemap::location::DIRECTION* nearest_hex, gamemap::location::DIRECTION* second_nearest_hex)
{
const int s = hex_size();
const int tesselation_x_size = s * 3 / 2;
@ -292,26 +292,55 @@ gamemap::location display::pixel_position_to_hex(int x, int y, gamemap::location
const gamemap::location res(x_base + x_modifier, y_base + y_modifier);
if(nearest_hex != NULL) {
const int westx = (get_location_x(res) - map_area().x + xpos_) + hex_size()/3;
const int eastx = westx + hex_size()/3;
const int centerx = (get_location_x(res) - map_area().x + xpos_) + hex_size()/2;
const int centery = (get_location_y(res) - map_area().y + ypos_) + hex_size()/2;
const bool west = x < westx;
const bool east = x > eastx;
const bool north = y < centery;
if(north && west) {
*nearest_hex = gamemap::location::NORTH_WEST;
} else if(north && east) {
*nearest_hex = gamemap::location::NORTH_EAST;
} else if(north) {
*nearest_hex = gamemap::location::NORTH;
} else if(west) {
*nearest_hex = gamemap::location::SOUTH_WEST;
} else if(east) {
*nearest_hex = gamemap::location::SOUTH_EAST;
} else {
*nearest_hex = gamemap::location::SOUTH;
const int x_offset = x - centerx;
const int y_offset = y - centery;
if(y_offset > 0) {
if(x_offset > y_offset/2) {
*nearest_hex = gamemap::location::SOUTH_EAST;
if(second_nearest_hex != NULL) {
if(x_offset/2 > y_offset) *second_nearest_hex = gamemap::location::NORTH_EAST;
else *second_nearest_hex = gamemap::location::SOUTH;
}
}
else if(-x_offset > y_offset/2) {
*nearest_hex = gamemap::location::SOUTH_WEST;
if(second_nearest_hex != NULL) {
if(-x_offset/2 > y_offset) *second_nearest_hex = gamemap::location::NORTH_WEST;
else *second_nearest_hex = gamemap::location::SOUTH;
}
}
else {
*nearest_hex = gamemap::location::SOUTH;
if(second_nearest_hex != NULL) {
if(x_offset > 0) *second_nearest_hex = gamemap::location::SOUTH_EAST;
else *second_nearest_hex = gamemap::location::SOUTH_WEST;
}
}
}
else {
if(x_offset > -y_offset/2) {
*nearest_hex = gamemap::location::NORTH_EAST;
if(second_nearest_hex != NULL) {
if(x_offset/2 > -y_offset) *second_nearest_hex = gamemap::location::SOUTH_EAST;
else *second_nearest_hex = gamemap::location::NORTH;
}
}
else if(-x_offset > -y_offset/2) {
*nearest_hex = gamemap::location::NORTH_WEST;
if(second_nearest_hex != NULL) {
if(-x_offset/2 > -y_offset) *second_nearest_hex = gamemap::location::SOUTH_WEST;
else *second_nearest_hex = gamemap::location::NORTH;
}
}
else {
*nearest_hex = gamemap::location::NORTH;
if(second_nearest_hex != NULL) {
if(x_offset > 0) *second_nearest_hex = gamemap::location::NORTH_EAST;
else *second_nearest_hex = gamemap::location::NORTH_WEST;
}
}
}
}

View file

@ -138,12 +138,12 @@ public:
//given x,y co-ordinates of an onscreen pixel, will return the
//location of the hex that this pixel corresponds to. Returns an
//invalid location is the mouse isn't over any valid location.
gamemap::location hex_clicked_on(int x, int y, gamemap::location::DIRECTION* nearest_hex=NULL);
gamemap::location hex_clicked_on(int x, int y, gamemap::location::DIRECTION* nearest_hex=NULL, gamemap::location::DIRECTION* second_nearest_hex=NULL);
//given x,y co-ordinates of a pixel on the map, will return the
//location of the hex that this pixel corresponds to. Returns an
//invalid location is the mouse isn't over any valid location.
gamemap::location pixel_position_to_hex(int x, int y, gamemap::location::DIRECTION* nearest_hex=NULL);
gamemap::location pixel_position_to_hex(int x, int y, gamemap::location::DIRECTION* nearest_hex=NULL, gamemap::location::DIRECTION* second_nearest_hex=NULL);
//given x,y co-ordinates of the mouse, will return the location of the
//hex in the minimap that the mouse is currently over, or an invalid

View file

@ -152,7 +152,7 @@ turn_info::turn_info(const game_data& gameinfo, game_state& state_of_game,
key_(key), gui_(gui), map_(map), teams_(teams), team_num_(team_num),
units_(units), browse_(mode != PLAY_TURN), allow_network_commands_(mode == BROWSE_NETWORKED),
left_button_(false), right_button_(false), middle_button_(false),
minimap_scrolling_(false), enemy_paths_(false), last_nearest_(gamemap::location::NORTH),
minimap_scrolling_(false), enemy_paths_(false), last_nearest_(gamemap::location::NORTH), last_second_nearest_(gamemap::location::NORTH),
path_turns_(0), end_turn_(false), start_ncmd_(-1), textbox_(textbox), replay_sender_(replay_sender)
{
enemies_visible_ = enemies_visible();
@ -305,11 +305,11 @@ void turn_info::mouse_motion(int x, int y)
if(minimap_scrolling_) return;
}
gamemap::location::DIRECTION nearest_hex;
gamemap::location::DIRECTION nearest_hex, second_nearest_hex;
const team& current_team = teams_[team_num_-1];
const gamemap::location new_hex = gui_.hex_clicked_on(x,y,&nearest_hex);
const gamemap::location new_hex = gui_.hex_clicked_on(x,y,&nearest_hex,&second_nearest_hex);
if(new_hex != last_hex_ || nearest_hex != last_nearest_) {
if(new_hex != last_hex_ || nearest_hex != last_nearest_ || second_nearest_hex != last_second_nearest_) {
if(new_hex.valid() == false) {
current_route_.steps.clear();
gui_.set_route(NULL);
@ -326,8 +326,7 @@ void turn_info::mouse_motion(int x, int y)
gamemap::location attack_from;
if(selected_unit != units_.end() && mouseover_unit != units_.end()) {
const gamemap::location preferred = new_hex.get_direction(nearest_hex);
attack_from = current_unit_attacks_from(new_hex,&preferred);
attack_from = current_unit_attacks_from(new_hex, nearest_hex, second_nearest_hex);
}
if(selected_unit != units_.end() && (current_paths_.routes.count(new_hex) ||
@ -349,18 +348,17 @@ void turn_info::mouse_motion(int x, int y)
gui_.set_paths(NULL);
}
if(new_hex == selected_hex_) {
const gamemap::location& dest = attack_from.valid() ? attack_from : new_hex;
const unit_map::const_iterator dest_un = find_unit(dest);
if(dest == selected_hex_ || dest_un != units_.end()) {
current_route_.steps.clear();
gui_.set_route(NULL);
} else if(!current_paths_.routes.empty() && map_.on_board(selected_hex_) &&
map_.on_board(new_hex)) {
const gamemap::location& dest = attack_from.valid() ? attack_from : new_hex;
unit_map::const_iterator un = find_unit(selected_hex_);
const unit_map::const_iterator dest_un = find_unit(dest);
if((new_hex != last_hex_ || attack_from.valid()) && un != units_.end() && dest_un == units_.end() && !un->second.stone()) {
if((new_hex != last_hex_ || attack_from.valid()) && un != units_.end() && !un->second.stone()) {
const shortest_path_calculator calc(un->second,current_team,
visible_units(),teams_,map_,status_);
const bool can_teleport = un->second.type().teleports();
@ -402,6 +400,7 @@ void turn_info::mouse_motion(int x, int y)
last_hex_ = new_hex;
last_nearest_ = nearest_hex;
last_second_nearest_ = second_nearest_hex;
}
namespace {
@ -790,8 +789,8 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
return;
}
gamemap::location::DIRECTION nearest_hex;
gamemap::location hex = gui_.hex_clicked_on(event.x,event.y,&nearest_hex);
gamemap::location::DIRECTION nearest_hex, second_nearest_hex;
gamemap::location hex = gui_.hex_clicked_on(event.x,event.y,&nearest_hex,&second_nearest_hex);
unit_map::iterator u = find_unit(selected_hex_);
@ -813,8 +812,7 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
//see if we're trying to do a move-and-attack
if(!browse_ && u != units_.end() && enemy != units_.end() && !current_route_.steps.empty()) {
const gamemap::location preferred = hex.get_direction(nearest_hex);
const gamemap::location& attack_from = current_unit_attacks_from(hex,&preferred);
const gamemap::location& attack_from = current_unit_attacks_from(hex, nearest_hex, second_nearest_hex);
if(attack_from.valid()) {
if(move_unit_along_current_route(false)) { //move the unit without updating shroud
u = find_unit(attack_from);
@ -920,7 +918,7 @@ void turn_info::show_attack_options(unit_map::const_iterator u)
}
}
gamemap::location turn_info::current_unit_attacks_from(const gamemap::location& loc, const gamemap::location* preferred) const
gamemap::location turn_info::current_unit_attacks_from(const gamemap::location& loc, const gamemap::location::DIRECTION preferred, const gamemap::location::DIRECTION second_preferred) const
{
const unit_map::const_iterator current = find_unit(selected_hex_);
if(current == units_.end() || current->second.side() != team_num_) {
@ -932,7 +930,7 @@ gamemap::location turn_info::current_unit_attacks_from(const gamemap::location&
return gamemap::location();
}
int best_defense = 100;
int best_rating = 100;//smaller is better
gamemap::location res;
gamemap::location adj[6];
get_adjacent_tiles(loc,adj);
@ -942,7 +940,7 @@ gamemap::location turn_info::current_unit_attacks_from(const gamemap::location&
}
if(adj[n] == selected_hex_) {
return gamemap::location();
return selected_hex_;
}
if(find_unit(adj[n]) != units_.end()) {
@ -950,9 +948,18 @@ gamemap::location turn_info::current_unit_attacks_from(const gamemap::location&
}
if(current_paths_.routes.count(adj[n])) {
const int defense = preferred != NULL && *preferred == adj[n] ? 0 : current->second.defense_modifier(map_,map_.get_terrain(loc));
if(defense < best_defense || res.valid() == false) {
best_defense = defense;
static const size_t NDIRECTIONS = gamemap::location::NDIRECTIONS;
int difference = std::abs(int(preferred - n));
if(difference > NDIRECTIONS/2) {
difference = NDIRECTIONS - difference;
}
int second_difference = std::abs(int(second_preferred - n));
if(second_difference > NDIRECTIONS/2) {
second_difference = NDIRECTIONS - second_difference;
}
const int rating = difference * 2 + (second_difference > difference);
if(rating < best_rating || res.valid() == false) {
best_rating = rating;
res = adj[n];
}
}

View file

@ -188,7 +188,7 @@ private:
//function which, given the location of a potential enemy to attack, will return the location
//that the currently selected unit would move to and attack it from this turn. Returns an
//invalid location if not possible.
gamemap::location current_unit_attacks_from(const gamemap::location& loc, const gamemap::location* preferred) const;
gamemap::location current_unit_attacks_from(const gamemap::location& loc, const gamemap::location::DIRECTION preferred, const gamemap::location::DIRECTION second_preferred) const;
bool attack_enemy(unit_map::iterator attacker, unit_map::iterator defender);
bool move_unit_along_current_route(bool check_shroud=true);
@ -226,7 +226,7 @@ private:
paths::route current_route_;
bool enemy_paths_;
gamemap::location last_hex_;
gamemap::location::DIRECTION last_nearest_;
gamemap::location::DIRECTION last_nearest_, last_second_nearest_;
gamemap::location selected_hex_;
undo_list undo_stack_;
undo_list redo_stack_;