Added go-to
This commit is contained in:
parent
70d4334fb1
commit
b6f0f71260
16 changed files with 371 additions and 119 deletions
|
@ -72,7 +72,7 @@ Defeat:
|
|||
gold=100
|
||||
[unit]
|
||||
description=Delfador
|
||||
type=Elder Mage
|
||||
type=Great Mage
|
||||
experience=500
|
||||
side=1
|
||||
x=19
|
||||
|
|
100
src/actions.cpp
100
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<team>& teams,
|
||||
const std::vector<gamemap::location>& 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<gamemap::location>::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<gamemap::location>::const_iterator begin = route.begin();
|
||||
|
||||
std::vector<gamemap::location> 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<gamemap::location,unit>(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();
|
||||
}
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
#include "display.hpp"
|
||||
#include "gamestatus.hpp"
|
||||
#include "map.hpp"
|
||||
#include "replay.hpp"
|
||||
#include "unit.hpp"
|
||||
#include "unit_types.hpp"
|
||||
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
|
@ -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<gamemap::location>& rt,int sm,int orig=-1)
|
||||
: route(rt), starting_moves(sm), original_village_owner(orig) {}
|
||||
std::vector<gamemap::location> route;
|
||||
int starting_moves;
|
||||
int original_village_owner;
|
||||
};
|
||||
|
||||
typedef std::deque<undo_action> undo_list;
|
||||
|
||||
size_t move_unit(display* disp, const gamemap& map,
|
||||
unit_map& units, std::vector<team>& teams,
|
||||
const std::vector<gamemap::location>& steps,
|
||||
replay* move_recorder, undo_list* undos);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<gamemap::location>::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<gamemap::location>& path, unit& u)
|
||||
{
|
||||
for(size_t i = 0; i+1 < path.size(); ++i) {
|
||||
|
|
|
@ -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<gamemap::location> invalidated_;
|
||||
bool invalidateAll_;
|
||||
|
|
|
@ -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<gamemap::location,unit>& units,
|
||||
const gamemap::location& loc, const team& current_team, int side)
|
||||
{
|
||||
|
@ -126,6 +124,8 @@ bool enemy_zoc(const gamemap& map,const std::map<gamemap::location,unit>& units,
|
|||
return false;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void find_routes(const gamemap& map, const game_data& gamedata,
|
||||
const std::map<gamemap::location,unit>& units,
|
||||
const unit& u,
|
||||
|
@ -147,8 +147,7 @@ void find_routes(const gamemap& map, const game_data& gamedata,
|
|||
//teleport to
|
||||
for(std::vector<gamemap::location>::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<int>(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;
|
||||
}
|
||||
|
|
|
@ -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<gamemap::location,unit>& units,
|
||||
const gamemap::location& loc,const team& current_team,int side);
|
||||
|
||||
struct paths
|
||||
{
|
||||
paths() {}
|
||||
|
@ -50,6 +53,19 @@ struct paths
|
|||
std::map<gamemap::location,route> 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<typename T>
|
||||
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<gamemap::location>* 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<location> 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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
207
src/playturn.cpp
207
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 <cmath>
|
||||
#include <deque>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
struct undo_action {
|
||||
undo_action(const std::vector<gamemap::location>& rt,int sm,int orig=-1)
|
||||
: route(rt), starting_moves(sm), original_village_owner(orig) {}
|
||||
std::vector<gamemap::location> 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<gamemap::location,unit> 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_action> 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<gamemap::location>* 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<gamemap::location>* 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<gamemap::location,paths::route>::const_iterator
|
||||
std::map<gamemap::location,paths::route>::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<attack_type>& attacks = u->second.attacks();
|
||||
std::vector<std::string> items;
|
||||
//UNUSED: const std::vector<attack_type>& defends = enemy->second.attacks();
|
||||
|
||||
std::vector<unit> 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<gamemap::location> 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<gamemap::location,unit>(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<gamemap::location>* 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<unit> 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<gamemap::location> 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<gamemap::location> 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<gamemap::location> 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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -97,9 +97,9 @@ void team::lose_tower(const gamemap::location& loc)
|
|||
towers_.erase(towers_.find(loc));
|
||||
}
|
||||
|
||||
int team::towers() const
|
||||
const std::set<gamemap::location>& team::towers() const
|
||||
{
|
||||
return towers_.size();
|
||||
return towers_;
|
||||
}
|
||||
|
||||
bool team::owns_tower(const gamemap::location& loc) const
|
||||
|
|
|
@ -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<gamemap::location>& towers() const;
|
||||
bool owns_tower(const gamemap::location&) const;
|
||||
|
||||
int gold() const;
|
||||
|
|
10
src/unit.cpp
10
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"];
|
||||
|
|
|
@ -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<gamemap::location,unit> unit_map;
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue