From b6f0f712600271c6f481e81e37157cd8762f921b Mon Sep 17 00:00:00 2001 From: Dave White Date: Sat, 20 Sep 2003 07:41:15 +0000 Subject: [PATCH] Added go-to --- data/scenarios/scenario01.cfg | 2 +- src/actions.cpp | 100 +++++++++++++++- src/actions.hpp | 17 +++ src/ai.cpp | 5 +- src/ai_move.cpp | 2 +- src/display.cpp | 31 ++++- src/display.hpp | 6 + src/pathfind.cpp | 52 ++++++++- src/pathfind.hpp | 36 ++++-- src/playlevel.cpp | 6 - src/playturn.cpp | 207 ++++++++++++++++++++-------------- src/preferences.cpp | 2 - src/team.cpp | 4 +- src/team.hpp | 2 +- src/unit.cpp | 10 ++ src/unit.hpp | 8 +- 16 files changed, 371 insertions(+), 119 deletions(-) diff --git a/data/scenarios/scenario01.cfg b/data/scenarios/scenario01.cfg index 0b9a8b8dc0a..d1b4f312169 100644 --- a/data/scenarios/scenario01.cfg +++ b/data/scenarios/scenario01.cfg @@ -72,7 +72,7 @@ Defeat: gold=100 [unit] description=Delfador - type=Elder Mage + type=Great Mage experience=500 side=1 x=19 diff --git a/src/actions.cpp b/src/actions.cpp index bf2bf61c391..6a1fd04f877 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -33,7 +33,7 @@ struct castle_cost_calculator castle_cost_calculator(const gamemap& map) : map_(map) {} - double cost(const gamemap::location& loc) const + double cost(const gamemap::location& loc, double cost_so_far) const { if(!map_.on_board(loc) || map_[loc.x][loc.y] != gamemap::CASTLE) return 10000; @@ -770,3 +770,101 @@ double combat_modifier(const gamestatus& status, return 1.0; } + +size_t move_unit(display* disp, const gamemap& map, + unit_map& units, std::vector& teams, + const std::vector& route, + replay* move_recorder, undo_list* undo_stack) +{ + assert(!route.empty()); + + const unit_map::iterator ui = units.find(route.front()); + + assert(ui != units.end()); + + ui->second.set_goto(gamemap::location()); + + unit u = ui->second; + + const int team_num = u.side()-1; + + const bool skirmisher = u.type().is_skirmisher(); + + //start off by seeing how far along the given path we can move + const int starting_moves = u.movement_left(); + int moves_left = starting_moves; + std::vector::const_iterator step; + for(step = route.begin()+1; step != route.end(); ++step) { + const gamemap::TERRAIN terrain = map[step->x][step->y]; + + const int mv = u.type().movement_type().movement_cost(map,terrain); + if(mv > moves_left) { + break; + } else { + moves_left -= mv; + } + + if(!skirmisher && enemy_zoc(map,units,*step,teams[team_num],u.side())) { + moves_left = 0; + } + } + + //make sure we don't tread on another unit + std::vector::const_iterator begin = route.begin(); + + std::vector steps(begin,step); + while(!steps.empty() && units.count(steps.back()) != 0) { + steps.pop_back(); + } + + //if we can't get all the way there and have to set a go-to + if(steps.size() != route.size()) { + ui->second.set_goto(route.back()); + u.set_goto(route.back()); + } + + if(steps.size() < 2) { + return 0; + } + + units.erase(ui); + if(disp != NULL) + disp->move_unit(steps,u); + + if(move_recorder != NULL) + move_recorder->add_movement(steps.front(),steps.back()); + + u.set_movement(moves_left); + + int orig_tower_owner = -1; + if(map[steps.back().x][steps.back().y] == gamemap::TOWER) { + orig_tower_owner = tower_owner(steps.back(),teams); + + if(orig_tower_owner != team_num) { + get_tower(steps.back(),teams,team_num); + u.set_movement(0); + } + } + + units.insert(std::pair(steps.back(),u)); + if(disp != NULL) + disp->invalidate_unit(); + + const bool event_mutated = game_events::fire("moveto",steps.back()); + + if(undo_stack != NULL) { + if(event_mutated) { + undo_stack->clear(); + } else { + undo_stack->push_back(undo_action(steps,starting_moves, + orig_tower_owner)); + } + } + + if(disp != NULL) { + disp->set_route(NULL); + disp->draw(); + } + + return steps.size(); +} diff --git a/src/actions.hpp b/src/actions.hpp index b470261a36c..e5406ae7583 100644 --- a/src/actions.hpp +++ b/src/actions.hpp @@ -16,9 +16,11 @@ #include "display.hpp" #include "gamestatus.hpp" #include "map.hpp" +#include "replay.hpp" #include "unit.hpp" #include "unit_types.hpp" +#include #include #include @@ -95,4 +97,19 @@ double combat_modifier(const gamestatus& status, const gamemap::location& loc, unit_type::ALIGNMENT alignment); +struct undo_action { + undo_action(const std::vector& rt,int sm,int orig=-1) + : route(rt), starting_moves(sm), original_village_owner(orig) {} + std::vector route; + int starting_moves; + int original_village_owner; +}; + +typedef std::deque undo_list; + +size_t move_unit(display* disp, const gamemap& map, + unit_map& units, std::vector& teams, + const std::vector& steps, + replay* move_recorder, undo_list* undos); + #endif diff --git a/src/ai.cpp b/src/ai.cpp index 2ed1f6c284d..e0113b9d747 100644 --- a/src/ai.cpp +++ b/src/ai.cpp @@ -225,7 +225,8 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo, ++num_units; } - const int cash_flow = current_team.towers()*game_config::tower_income + + const int cash_flow = current_team.towers().size()* + game_config::tower_income + game_config::base_income - num_units; const int min_gold = 10 + (cash_flow < 0 ? -cash_flow*10 : 0); @@ -235,7 +236,7 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo, const int towers = map.towers().size(); int taken_towers = 0; for(size_t j = 0; j != teams.size(); ++j) { - taken_towers += teams[j].towers(); + taken_towers += teams[j].towers().size(); } const int neutral_towers = towers - taken_towers; diff --git a/src/ai_move.cpp b/src/ai_move.cpp index afff6d3ce7a..e6a5bf76af3 100644 --- a/src/ai_move.cpp +++ b/src/ai_move.cpp @@ -31,7 +31,7 @@ struct move_cost_calculator move_type_(u.type().movement_type()), loc_(loc), dstsrc_(dstsrc) {} - double cost(const location& loc) const + double cost(const location& loc, double so_far) const { if(!map_.on_board(loc)) return 1000.0; diff --git a/src/display.cpp b/src/display.cpp index df652f9a4d2..f9cc7850f1d 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -508,7 +508,7 @@ void display::draw_game_status(int x, int y) << status_.number_of_turns() << "\n" << string_table["gold"] << ": " << teams_[currentTeam_].gold() << "\n" << string_table["villages"] << ": " - << teams_[currentTeam_].towers() << "\n" + << teams_[currentTeam_].towers().size() << "\n" << string_table["units"] << ": " << nunits << "\n" << string_table["income"] << ": " << income << "\n"; @@ -908,9 +908,12 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image, if(pathsList_ != NULL && pathsList_->routes.find(gamemap::location(x,y)) == pathsList_->routes.end()) { image_type = GREYED; - } else if(gamemap::location(x,y) == mouseoverHex_ || - gamemap::location(x,y) == selectedHex_ && - units_.count(gamemap::location(x,y)) == 1) { + } + + if(loc == mouseoverHex_ || loc == selectedHex_ && + units_.count(gamemap::location(x,y)) == 1 || + std::find(route_.steps.begin(),route_.steps.end(),loc) != + route_.steps.end()) { image_type = BRIGHTENED; } @@ -1578,6 +1581,26 @@ void display::set_paths(const paths* paths_list) invalidate_all(); } +void display::invalidate_route() +{ + for(std::vector::const_iterator i = route_.steps.begin(); + i != route_.steps.end(); ++i) { + invalidate(*i); + } +} + +void display::set_route(const paths::route* route) +{ + invalidate_route(); + + if(route != NULL) + route_ = *route; + else + route_.steps.clear(); + + invalidate_route(); +} + void display::move_unit(const std::vector& path, unit& u) { for(size_t i = 0; i+1 < path.size(); ++i) { diff --git a/src/display.hpp b/src/display.hpp index bd88b11aeb7..0c732a37e2d 100644 --- a/src/display.hpp +++ b/src/display.hpp @@ -62,8 +62,12 @@ public: gamemap::location hex_clicked_on(int x, int y); gamemap::location minimap_location_on(int x, int y); + //paths_list must remain valid until it is set again void set_paths(const paths* paths_list); + //route does not have to remain valid after being set + void set_route(const paths::route* route); + double get_location_x(const gamemap::location& loc) const; double get_location_y(const gamemap::location& loc) const; @@ -175,6 +179,7 @@ private: bool minimapDecorationsDrawn_; const paths* pathsList_; + paths::route route_; const gamestatus& status_; @@ -184,6 +189,7 @@ private: int drawSkips_; void invalidate(const gamemap::location& loc); + void invalidate_route(); std::set invalidated_; bool invalidateAll_; diff --git a/src/pathfind.cpp b/src/pathfind.cpp index 1dae927e96e..b262ec8582c 100644 --- a/src/pathfind.cpp +++ b/src/pathfind.cpp @@ -105,8 +105,6 @@ bool tiles_adjacent(const gamemap::location& a, const gamemap::location& b) xdiff == 1 && ydiff == 1 && (a.y > b.y ? (a.x%2) == 1 : (b.x%2) == 1); } -namespace { - bool enemy_zoc(const gamemap& map,const std::map& units, const gamemap::location& loc, const team& current_team, int side) { @@ -126,6 +124,8 @@ bool enemy_zoc(const gamemap& map,const std::map& units, return false; } +namespace { + void find_routes(const gamemap& map, const game_data& gamedata, const std::map& units, const unit& u, @@ -147,8 +147,7 @@ void find_routes(const gamemap& map, const game_data& gamedata, //teleport to for(std::vector::const_iterator t = towers.begin(); t != towers.end(); ++t) { - if(!teams[u.side()-1].owns_tower(*t) || - units.find(*t) != units.end()) + if(!teams[u.side()-1].owns_tower(*t)) continue; locs.push_back(*t); @@ -238,3 +237,48 @@ paths::paths(const gamemap& map, const game_data& gamedata, } } +shortest_path_calculator::shortest_path_calculator(const unit& u, const team& t, + const unit_map& units, + const gamemap& map) + : unit_(u), team_(t), units_(units), map_(map) +{ +} + +double shortest_path_calculator::cost(const gamemap::location& loc, + double so_far) const +{ + if(!map_.on_board(loc)) + return 100000.0; + + if(unit_.type().is_skirmisher() == false) { + gamemap::location adj[6]; + get_adjacent_tiles(loc,adj); + + for(size_t i = 0; i != 6; ++i) { + const unit_map::const_iterator u = units_.find(adj[i]); + if(u != units_.end() && team_.is_enemy(u->second.side())) { + return 100000.0; + } + } + } + + const double base_cost( + unit_.type().movement_type().movement_cost(map_,map_[loc.x][loc.y])); + + //supposing we had 2 movement left, and wanted to move onto a hex which + //takes 3 movement, it's going to cost us 5 movement in total, since we + //sacrifice this turn's movement. Take that into account here. + assert(so_far == double(int(so_far))); + + const int current_cost(static_cast(so_far)); + + const int starting_movement = unit_.movement_left(); + const int remaining_movement = current_cost <= starting_movement ? + starting_movement - current_cost : + (current_cost-starting_movement)%unit_.total_movement(); + + const double additional_cost = int(base_cost) > remaining_movement ? + double(remaining_movement) : double(0); + + return base_cost + additional_cost; +} diff --git a/src/pathfind.hpp b/src/pathfind.hpp index 695e7dded78..015a2cc7e59 100644 --- a/src/pathfind.hpp +++ b/src/pathfind.hpp @@ -32,6 +32,9 @@ gamemap::location find_vacant_tile(const gamemap& map, const gamemap::location& loc, gamemap::TERRAIN terrain=0); +bool enemy_zoc(const gamemap& map,const std::map& units, + const gamemap::location& loc,const team& current_team,int side); + struct paths { paths() {} @@ -50,6 +53,19 @@ struct paths std::map routes; }; +struct shortest_path_calculator +{ + shortest_path_calculator(const unit& u, const team& t, + const unit_map& units, const gamemap& map); + double cost(const gamemap::location& loc, double so_far) const; + +private: + const unit& unit_; + const team& team_; + const unit_map& units_; + const gamemap& map_; +}; + namespace detail { struct node { node(const gamemap::location& pos, const gamemap::location& dst, @@ -69,7 +85,8 @@ struct node { template paths::route a_star_search(const gamemap::location& src, - const gamemap::location& dst, double stop_at, T obj) + const gamemap::location& dst, double stop_at, T obj, + const std::set* teleports=NULL) { std::cout << "a* search: " << src.x << ", " << src.y << " - " << dst.x << ", " << dst.y << "\n"; using namespace detail; @@ -92,15 +109,19 @@ paths::route a_star_search(const gamemap::location& src, break; } - //std::cerr << "processing " << (lowest->loc.x+1) << "," << (lowest->loc.y+1) << " with cost = " << lowest->g << " (known) + " << lowest->h << " (estimated) = " << lowest->f << "\n"; - //move the lowest element from the open list to the closed list closed_list.splice(closed_list.begin(),open_list,lowest); //find nodes we can go to from this node - location locs[6]; - get_adjacent_tiles(lowest->loc,locs); - for(int j = 0; j != 6; ++j) { + static std::vector locs; + locs.resize(6); + get_adjacent_tiles(lowest->loc,&locs[0]); + if(teleports != NULL && teleports->count(lowest->loc) != 0) { + std::copy(teleports->begin(),teleports->end(), + std::back_inserter(locs)); + } + + for(size_t j = 0; j != locs.size(); ++j) { //if we have found a solution if(locs[j] == dst) { @@ -118,7 +139,8 @@ paths::route a_star_search(const gamemap::location& src, return rt; } - const node nd(locs[j],dst,lowest->g+obj.cost(locs[j]),&*lowest); + const node nd(locs[j],dst,lowest->g+obj.cost(locs[j],lowest->g), + &*lowest); for(i = open_list.begin(); i != open_list.end(); ++i) { if(i->loc == nd.loc && i->f <= nd.f) { diff --git a/src/playlevel.cpp b/src/playlevel.cpp index 3fde6b2c6c6..f2137d9446f 100644 --- a/src/playlevel.cpp +++ b/src/playlevel.cpp @@ -110,16 +110,10 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config, (*overlay)->values["image"]); } - //UNUSED: const double scroll_speed = 30.0; - //UNUSED: const double zoom_amount = 5.0; - for(units_map::iterator i = units.begin(); i != units.end(); ++i) { i->second.new_turn(); } - //UNUSED: bool left_button = false, right_button = false; - //UNUSED: gamemap::location selected_hex; - gui.scroll_to_tile(map.starting_position(1).x,map.starting_position(1).y, display::WARP); diff --git a/src/playturn.cpp b/src/playturn.cpp index a7233fa7561..a02c8e5f362 100644 --- a/src/playturn.cpp +++ b/src/playturn.cpp @@ -10,6 +10,8 @@ See the COPYING file for more details. */ + +#include "actions.hpp" #include "hotkeys.hpp" #include "language.hpp" #include "playlevel.hpp" @@ -18,19 +20,10 @@ #include "replay.hpp" #include -#include #include #include #include -struct undo_action { - undo_action(const std::vector& rt,int sm,int orig=-1) - : route(rt), starting_moves(sm), original_village_owner(orig) {} - std::vector route; - int starting_moves; - int original_village_owner; -}; - void play_turn(game_data& gameinfo, game_state& state_of_game, gamestatus& status, config& terrain_config, config* level, CVideo& video, CKey& key, display& gui, @@ -46,7 +39,6 @@ void play_turn(game_data& gameinfo, game_state& state_of_game, team& current_team = teams[team_num-1]; const double scroll_speed = 30.0; - //UNUSED: const double zoom_amount = 5.0; const std::string menu_items[] = {"scenario_objectives","recruit", "recall","unit_list","save_game", @@ -58,20 +50,49 @@ void play_turn(game_data& gameinfo, game_state& state_of_game, menu.push_back(string_table[*menu_items_ptr]); } - typedef std::map units_map; - gamemap::location next_unit; bool left_button = false, right_button = false; const paths_wiper wiper(gui); paths current_paths; + paths::route current_route; bool enemy_paths = false; gamemap::location last_hex; gamemap::location selected_hex; - std::deque undo_stack, redo_stack; + undo_list undo_stack, redo_stack; + + //execute gotos + for(unit_map::iterator ui = units.begin(); ui != units.end(); ++ui) { + if(ui->second.get_goto() == ui->first) + ui->second.set_goto(gamemap::location()); + + if(ui->second.side() != team_num || + map.on_board(ui->second.get_goto()) == false) + continue; + + unit u = ui->second; + const shortest_path_calculator calc(u,current_team,units,map); + const bool can_teleport = u.type().teleports() && + map[ui->first.x][ui->first.y] == gamemap::TOWER; + + const std::set* const teleports = + can_teleport ? ¤t_team.towers() : NULL; + + paths::route route = a_star_search(ui->first,ui->second.get_goto(), + 10000.0,calc,teleports); + gui.set_route(&route); + const size_t moves = + move_unit(&gui,map,units,teams,route.steps,&recorder,&undo_stack); + if(moves > 0) { + redo_stack.clear(); + if(moves == route.steps.size()) { + u.set_goto(gamemap::location()); + } + } + } for(;;) { int mousex, mousey; @@ -90,6 +111,30 @@ void play_turn(game_data& gameinfo, game_state& state_of_game, current_paths = paths(); enemy_paths = false; } + + if(new_hex == selected_hex) { + current_route.steps.clear(); + gui.set_route(NULL); + } else if(!enemy_paths && new_hex != last_hex && + !current_paths.routes.empty() && map.on_board(selected_hex) && + map.on_board(new_hex)) { + + const unit_map::const_iterator un = units.find(selected_hex); + if(un != units.end()) { + const shortest_path_calculator calc(un->second,current_team, + units,map); + const bool can_teleport = un->second.type().teleports() && + map[selected_hex.x][selected_hex.y] == gamemap::TOWER; + + const std::set* const teleports = + can_teleport ? ¤t_team.towers() : NULL; + + current_route = a_star_search(selected_hex,new_hex, + 10000.0,calc,teleports); + + gui.set_route(¤t_route); + } + } } HOTKEY_COMMAND command = HOTKEY_NULL; @@ -100,7 +145,7 @@ void play_turn(game_data& gameinfo, game_state& state_of_game, gui.scroll_to_tile(loc.x,loc.y,display::WARP); } } else if(new_hex != last_hex && current_paths.routes.empty()) { - const units_map::iterator u = units.find(new_hex); + const unit_map::iterator u = units.find(new_hex); if(u != units.end() && u->second.side() != team_num) { const bool ignore_zocs = u->second.type().is_skirmisher(); const bool teleport = u->second.type().teleports(); @@ -114,26 +159,23 @@ void play_turn(game_data& gameinfo, game_state& state_of_game, last_hex = new_hex; if(!left_button && new_left_button) { - const gamemap::location& hex = gui.hex_clicked_on(mousex,mousey); + gamemap::location hex = gui.hex_clicked_on(mousex,mousey); - units_map::iterator u = units.find(selected_hex); + unit_map::iterator u = units.find(selected_hex); //if we can move to that tile - const std::map::const_iterator + std::map::const_iterator route = enemy_paths ? current_paths.routes.end() : current_paths.routes.find(hex); - units_map::iterator enemy = units.find(hex); + unit_map::iterator enemy = units.find(hex); //see if we're trying to attack an enemy if(route != current_paths.routes.end() && enemy != units.end() && hex != selected_hex && enemy->second.side() != u->second.side()) { - //UNUSED: const unit_type& type = u->second.type(); - //UNUSED: const unit_type& enemy_type = enemy->second.type(); const std::vector& attacks = u->second.attacks(); std::vector items; - //UNUSED: const std::vector& defends = enemy->second.attacks(); std::vector units_list; @@ -194,6 +236,7 @@ void play_turn(game_data& gameinfo, game_state& state_of_game, gui::OK_CANCEL,&items,&units_list); if(size_t(res) < attacks.size()) { + u->second.set_goto(gamemap::location()); undo_stack.clear(); redo_stack.clear(); @@ -223,6 +266,8 @@ void play_turn(game_data& gameinfo, game_state& state_of_game, dialogs::advance_unit(gameinfo,units,hex,gui); selected_hex = gamemap::location(); + current_route.steps.clear(); + gui.set_route(NULL); gui.invalidate_unit(); gui.draw(); //clear the screen @@ -238,95 +283,76 @@ void play_turn(game_data& gameinfo, game_state& state_of_game, } } - //otherwise we're just trying to move to a hex + //otherwise we're trying to move to a hex else if(selected_hex.valid() && selected_hex != hex && - enemy == units.end() && - route != current_paths.routes.end()) { - std::vector steps = route->second.steps; - steps.push_back(hex); - - //if an event mutates the game environment, then this - //move must be marked un-redoable - bool event_mutated = false; - - int orig_tower_owner = -1; - int starting_moves = 0; - int unit_side = 0; - if(u != units.end()) { - unit un = u->second; - starting_moves = un.movement_left(); - unit_side = un.side(); - units.erase(u); - gui.move_unit(steps,un); - recorder.add_movement(selected_hex,hex); - un.set_movement(route->second.move_left); - - //see if the unit has gotten a tower - if(map[hex.x][hex.y] == gamemap::TOWER) { - orig_tower_owner = tower_owner(hex,teams); - get_tower(hex,teams,team_num-1); - un.set_movement(0); //end of turn if you get a tower - } - - units.insert(std::pair(hex,un)); - gui.invalidate_unit(); - - //fire the move to event. If the event mutates - //the game state, then the user cannot undo the move - event_mutated = game_events::fire("moveto",hex); - } else { - assert(false); - continue; - } + enemy == units.end() && !current_route.steps.empty()) { + const size_t moves = + move_unit(&gui,map,units,teams,current_route.steps, + &recorder,&undo_stack); + redo_stack.clear(); selected_hex = gamemap::location(); + gui.set_route(NULL); gui.select_hex(gamemap::location()); gui.set_paths(NULL); current_paths = paths(); + assert(moves <= current_route.steps.size()); + const gamemap::location& dst = current_route.steps[moves-1]; + + current_route.steps.clear(); + //if there is an enemy in a surrounding hex, then //highlight attack options gamemap::location adj[6]; - get_adjacent_tiles(steps.back(),adj); + get_adjacent_tiles(dst,adj); int n; for(n = 0; n != 6; ++n) { - const units_map::const_iterator u_it = units.find(adj[n]); - if(u_it != units.end() && u_it->second.side() != unit_side + const unit_map::const_iterator u_it = units.find(adj[n]); + if(u_it != units.end() && u_it->second.side() != team_num && current_team.is_enemy(u_it->second.side())){ current_paths.routes[adj[n]] = paths::route(); } } if(current_paths.routes.empty() == false) { - current_paths.routes[steps.back()] = paths::route(); - selected_hex = steps.back(); - gui.select_hex(steps.back()); + current_paths.routes[dst] = paths::route(); + selected_hex = dst; + gui.select_hex(dst); gui.set_paths(¤t_paths); } - undo_stack.push_back(undo_action(steps,starting_moves, - orig_tower_owner)); - redo_stack.clear(); - - if(event_mutated) { - undo_stack.clear(); - } - } else { gui.set_paths(NULL); current_paths = paths(); selected_hex = hex; gui.select_hex(hex); + current_route.steps.clear(); + gui.set_route(NULL); - const units_map::iterator it = units.find(hex); + const unit_map::iterator it = units.find(hex); if(it != units.end() && it->second.side() == team_num) { const bool ignore_zocs = it->second.type().is_skirmisher(); const bool teleport = it->second.type().teleports(); current_paths = paths(map,gameinfo,units,hex,teams, ignore_zocs,teleport); gui.set_paths(¤t_paths); + + unit u = it->second; + const gamemap::location go_to = u.get_goto(); + if(map.on_board(go_to)) { + const shortest_path_calculator calc(u,current_team, + units,map); + + const std::set* const teleports = + teleport ? ¤t_team.towers() : NULL; + + paths::route route = a_star_search(it->first,go_to, + 10000.0,calc,teleports); + gui.set_route(&route); + } } } } @@ -339,8 +365,10 @@ void play_turn(game_data& gameinfo, game_state& state_of_game, gui.select_hex(gamemap::location()); gui.set_paths(NULL); current_paths = paths(); + current_route.steps.clear(); + gui.set_route(NULL); } else { - const units_map::const_iterator un = units.find( + const unit_map::const_iterator un = units.find( gui.hex_clicked_on(mousex,mousey)); if(un != units.end()) { menu.push_back(string_table["describe_unit"]); @@ -544,7 +572,7 @@ void play_turn(game_data& gameinfo, game_state& state_of_game, items.push_back(heading); std::vector units_list; - for(units_map::const_iterator i = units.begin(); + for(unit_map::const_iterator i = units.begin(); i != units.end(); ++i) { if(i->second.side() != team_num) continue; @@ -608,7 +636,7 @@ void play_turn(game_data& gameinfo, game_state& state_of_game, if(command == HOTKEY_NULL) command = check_keys(gui); - units_map::const_iterator un = units.find(new_hex); + unit_map::const_iterator un = units.find(new_hex); if(un == units.end()) un = units.find(selected_hex); @@ -694,7 +722,7 @@ void play_turn(game_data& gameinfo, game_state& state_of_game, } if(command == HOTKEY_END_UNIT_TURN) { - const units_map::iterator un = units.find(selected_hex); + const unit_map::iterator un = units.find(selected_hex); if(un != units.end() && un->second.side() == team_num && un->second.movement_left() > 0) { std::vector steps; @@ -715,21 +743,22 @@ void play_turn(game_data& gameinfo, game_state& state_of_game, //look for the next unit that is unmoved on our side if(command == HOTKEY_CYCLE_UNITS) { - units_map::const_iterator it = units.find(next_unit); + unit_map::const_iterator it = units.find(next_unit); if(it != units.end()) { for(++it; it != units.end(); ++it) { if(it->second.side() == team_num && - it->second.movement_left() > 0) { + it->second.movement_left() > 0 && + it->second.get_goto().valid() == false) { break; } } } if(it == units.end()) { - for(it = units.begin(); it != units.end(); - ++it) { + for(it = units.begin(); it != units.end(); ++it) { if(it->second.side() == team_num && - it->second.movement_left() > 0) { + it->second.movement_left() > 0 && + it->second.get_goto().valid() == false) { break; } } @@ -751,12 +780,14 @@ void play_turn(game_data& gameinfo, game_state& state_of_game, next_unit = it->first; selected_hex = next_unit; gui.select_hex(selected_hex); + current_route.steps.clear(); + gui.set_route(NULL); } else next_unit = gamemap::location(); } if(command == HOTKEY_LEADER) { - for(units_map::const_iterator i = units.begin(); i != units.end(); + for(unit_map::const_iterator i = units.begin(); i != units.end(); ++i) { if(i->second.side() == team_num && i->second.can_recruit()) { gui.scroll_to_tile(i->first.x,i->first.y,display::WARP); @@ -770,7 +801,7 @@ void play_turn(game_data& gameinfo, game_state& state_of_game, const int starting_moves = undo_stack.back().starting_moves; std::vector route = undo_stack.back().route; std::reverse(route.begin(),route.end()); - const units_map::iterator u = units.find(route.front()); + const unit_map::iterator u = units.find(route.front()); if(u == units.end()) { assert(false); continue; @@ -784,6 +815,7 @@ void play_turn(game_data& gameinfo, game_state& state_of_game, undo_stack.back().starting_moves = u->second.movement_left(); unit un = u->second; + un.set_goto(gamemap::location()); units.erase(u); gui.move_unit(route,un); un.set_movement(starting_moves); @@ -803,7 +835,7 @@ void play_turn(game_data& gameinfo, game_state& state_of_game, if(command == HOTKEY_REDO && !redo_stack.empty()) { const int starting_moves = redo_stack.back().starting_moves; std::vector route = redo_stack.back().route; - const units_map::iterator u = units.find(route.front()); + const unit_map::iterator u = units.find(route.front()); if(u == units.end()) { assert(false); continue; @@ -812,6 +844,7 @@ void play_turn(game_data& gameinfo, game_state& state_of_game, redo_stack.back().starting_moves = u->second.movement_left(); unit un = u->second; + un.set_goto(gamemap::location()); units.erase(u); gui.move_unit(route,un); un.set_movement(starting_moves); diff --git a/src/preferences.cpp b/src/preferences.cpp index baf02d02511..2540cf4ce38 100644 --- a/src/preferences.cpp +++ b/src/preferences.cpp @@ -202,7 +202,6 @@ void set_grid(bool ison) void show_preferences_dialog(display& disp) { - //UNUSED: const int border_size = 6; const int xpos = disp.x()/2 - 300; const int ypos = disp.y()/2 - 200; const int width = 600; @@ -286,7 +285,6 @@ void show_preferences_dialog(display& disp) const int mouse_flags = SDL_GetMouseState(&mousex,&mousey); const bool left_button = mouse_flags&SDL_BUTTON_LMASK; - //UNUSED: const bool right_button = mouse_flags&SDL_BUTTON_RMASK; if(close_button.process(mousex,mousey,left_button)) { break; diff --git a/src/team.cpp b/src/team.cpp index 9d1e31235ed..80f47c114c8 100644 --- a/src/team.cpp +++ b/src/team.cpp @@ -97,9 +97,9 @@ void team::lose_tower(const gamemap::location& loc) towers_.erase(towers_.find(loc)); } -int team::towers() const +const std::set& team::towers() const { - return towers_.size(); + return towers_; } bool team::owns_tower(const gamemap::location& loc) const diff --git a/src/team.hpp b/src/team.hpp index 494cb772133..4d06c64ca79 100644 --- a/src/team.hpp +++ b/src/team.hpp @@ -50,7 +50,7 @@ public: team(config& cfg, int gold=100); void get_tower(const gamemap::location&); void lose_tower(const gamemap::location&); - int towers() const; + const std::set& towers() const; bool owns_tower(const gamemap::location&) const; int gold() const; diff --git a/src/unit.cpp b/src/unit.cpp index 6f143a9d989..ab746db0cf7 100644 --- a/src/unit.cpp +++ b/src/unit.cpp @@ -533,6 +533,16 @@ bool unit::is_guardian() const return guardian_; } +const gamemap::location& unit::get_goto() const +{ + return goto_; +} + +void unit::set_goto(const gamemap::location& new_goto) +{ + goto_ = new_goto; +} + void unit::add_modification(const std::string& type, config& mod, bool no_add) { const std::string& span = mod.values["duration"]; diff --git a/src/unit.hpp b/src/unit.hpp index 22cb06ec35c..d5d41a8536a 100644 --- a/src/unit.hpp +++ b/src/unit.hpp @@ -91,10 +91,12 @@ public: int value() const; bool is_guardian() const; + const gamemap::location& get_goto() const; + void set_goto(const gamemap::location& new_goto); + void add_modification(const std::string& type, config& modification, bool no_add=false); - private: const unit_type* type_; @@ -132,6 +134,8 @@ private: bool guardian_; + gamemap::location goto_; + void apply_modifications(); }; @@ -140,4 +144,6 @@ struct compare_unit_values bool operator()(const unit& a, const unit& b) const; }; +typedef std::map unit_map; + #endif