Merge pathfind branch

This commit is contained in:
Alexander van Gessel 2011-02-06 15:54:27 +01:00
parent 2279bc0e77
commit 93776cb5ac
23 changed files with 571 additions and 90 deletions

View file

@ -379,6 +379,33 @@ Any units adjacent to this unit will fight as if it were dusk when it is night,
female_name= _ "female^teleport"
description= _ "Teleport:
This unit may teleport between any two empty villages owned by its side using one of its moves."
[tunnel]
id=village_teleport
[source]
terrain=*^V*
owner_side=$teleport_unit.side
[not]
[filter]
[not]
id=$teleport_unit.id
[/not]
[/filter]
[/not]
[/source]
[target]
terrain=*^V*
owner_side=$teleport_unit.side
[not]
[filter]
[/filter]
[/not]
[/target]
[filter]
ability=teleport
[/filter]
[/tunnel]
[/teleport]
#enddef

View file

@ -190,6 +190,78 @@ Xu , Xu , Qxu , Qxu , Ql , Ql
[/filter]
{MODIFY_UNIT (id=$second_unit.id) side 1}
[/event]
[event]
name=prestart
{VARIABLE teleports_on no}
[/event]
[label]
x,y=20,13
text="Teleport switch"
[/label]
[event]
name=moveto
first_time_only=no
[filter]
x,y=20,13
[/filter]
[if]
[variable]
name=teleports_on
boolean_equals=no
[/variable]
[then]
[tunnel]
id="one"
bidirectional=yes
always_visible=yes
[source]
x=8
y=6
[/source]
[target]
x=20
y=12
[/target]
[filter]
[/filter]
[/tunnel]
[tunnel]
id="two"
bidirectional=no
[source]
x=20
y=14
[/source]
[target]
x=21
y=4
[/target]
[filter]
[/filter]
[/tunnel]
{VARIABLE teleports_on yes}
[message]
speaker=narrator
icon=wesnoth-icon.png
message="Teleporters activated"
[/message]
[/then]
[else]
[tunnel]
id="one,two"
remove=yes
[/tunnel]
{VARIABLE teleports_on no}
[message]
speaker=narrator
icon=wesnoth-icon.png
message="Teleporters deactivated"
[/message]
[/else]
[/if]
[/event]
[side]
type=Orcish Warlord
id="Urug-Telfar"

View file

@ -487,6 +487,8 @@ set(wesnoth-main_SRC
multiplayer_create.cpp
multiplayer_lobby.cpp
${network_implementation_files} # network.cpp and network_worker.cpp are included by default (without USE_ANA_NETWORK)
pathfind/pathfind.cpp
pathfind/teleport.cpp
persist_context.cpp
persist_manager.cpp
persist_var.cpp
@ -627,11 +629,6 @@ set(libwesnoth-game_STAT_SRC
wml_exception.cpp
)
set(libwesnoth-game_STAT_SRC
${libwesnoth-game_STAT_SRC}
pathfind/pathfind.cpp
)
if(ENABLE_GAME AND ENABLE_TESTS)
set(libwesnoth-game_STAT_SRC
${libwesnoth-game_STAT_SRC}

View file

@ -229,6 +229,7 @@ wesnoth_sources = Split("""
multiplayer_lobby.cpp
multiplayer_connect.cpp
pathfind/pathfind.cpp
pathfind/teleport.cpp
persist_context.cpp
persist_manager.cpp
persist_var.cpp

View file

@ -42,6 +42,7 @@
#include "../game_preferences.hpp"
#include "../log.hpp"
#include "../mouse_handler_base.hpp"
#include "../pathfind/teleport.hpp"
#include "../play_controller.hpp"
#include "../replay.hpp"
#include "../resources.hpp"
@ -391,7 +392,7 @@ bool move_result::test_route(const unit &un)
const pathfind::shortest_path_calculator calc(un, my_team, *resources::units, *resources::teams, *resources::game_map);
//allowed teleports
std::set<map_location> allowed_teleports = pathfind::get_teleport_locations(un, my_team, true);///@todo 1.9: see_all -> false
pathfind::teleport_map allowed_teleports = pathfind::get_teleport_locations(un, my_team, true);///@todo 1.9: see_all -> false
//do an A*-search
route_ = boost::shared_ptr<pathfind::plain_route>( new pathfind::plain_route(pathfind::a_star_search(un.get_location(), to_, 10000.0, &calc, resources::game_map->w(), resources::game_map->h(), &allowed_teleports)));

View file

@ -349,11 +349,10 @@ void readonly_context_impl::calculate_moves(const unit_map& units, std::map<map_
srcdst.insert(trivial_mv);
dstsrc.insert(trivial_mv);
}
bool teleports = un_it->get_ability_bool("teleport");
res.insert(std::pair<map_location,pathfind::paths>(
un_it->get_location(), pathfind::paths(*resources::game_map,
units, un_it->get_location(), *resources::teams, false,
teleports, current_team(), 0, see_all)));
true, current_team(), 0, see_all)));
}
// deactivate terrain filtering if it's just the dummy 'matches nothing'
@ -922,8 +921,7 @@ bool readonly_context_impl::leader_can_reach_keep() const
// Find where the leader can move
const pathfind::paths leader_paths(*resources::game_map, *resources::units,
leader->get_location(), *resources::teams, false, false, current_team());
leader->get_location(), *resources::teams, false, true, current_team());
return leader_paths.destinations.contains(start_pos);
}

View file

@ -36,6 +36,7 @@
#include "../../formula_debugger.hpp"
#include "../../log.hpp"
#include "../../menu_events.hpp"
#include "../../pathfind/teleport.hpp"
#include "../../resources.hpp"
#include "../../terrain_filter.hpp"
#include "../../tod_manager.hpp"
@ -172,7 +173,7 @@ variant formula_ai::make_action(game_logic::const_formula_ptr formula_, const ga
pathfind::plain_route formula_ai::shortest_path_calculator(const map_location &src,
const map_location &dst, unit_map::iterator &unit_it,
std::set<map_location> & allowed_teleports) const
pathfind::teleport_map& allowed_teleports) const
{
map_location destination = dst;
@ -224,7 +225,7 @@ pathfind::plain_route formula_ai::shortest_path_calculator(const map_location &s
return route;
}
std::set<map_location> formula_ai::get_allowed_teleports(unit_map::iterator& unit_it) const
pathfind::teleport_map formula_ai::get_allowed_teleports(unit_map::iterator& unit_it) const
{
return pathfind::get_teleport_locations(*unit_it, current_team(), true);
}

View file

@ -27,6 +27,7 @@
#include "function_table.hpp"
#include "../default/ai.hpp"
#include "../../pathfind/teleport.hpp"
#include <boost/noncopyable.hpp>
@ -108,8 +109,8 @@ public:
void handle_exception(game_logic::formula_error& e) const;
void handle_exception(game_logic::formula_error& e, const std::string& failed_operation) const;
std::set<map_location> get_allowed_teleports(unit_map::iterator& unit_it) const;
pathfind::plain_route shortest_path_calculator(const map_location& src, const map_location& dst, unit_map::iterator& unit_it, std::set<map_location>& allowed_teleports) const;
pathfind::teleport_map get_allowed_teleports(unit_map::iterator& unit_it) const;
pathfind::plain_route shortest_path_calculator(const map_location& src, const map_location& dst, unit_map::iterator& unit_it, pathfind::teleport_map& allowed_teleports) const;
/** Create a new formula from the string, using the symbol table which is stored in the AI.
*

View file

@ -29,6 +29,7 @@
#include "../../log.hpp"
#include "../../map_label.hpp"
#include "../../menu_events.hpp"
#include "../../pathfind/teleport.hpp"
#include "../../replay.hpp"
#include "../../resources.hpp"
#include "../../terrain_filter.hpp"
@ -664,7 +665,7 @@ private:
if (units.find(loc) == units.end()){
return variant();
}
const pathfind::paths unit_paths(*resources::game_map, units, loc ,*resources::teams, false, false, ai_.current_team());
const pathfind::paths unit_paths(*resources::game_map, units, loc ,*resources::teams, false, true, ai_.current_team());
return variant(new location_callable(ai_.suitable_keep(loc,unit_paths)));
}
@ -979,7 +980,7 @@ private:
throw formula_error( str.str(), "", "", 0);
}
std::set<map_location> allowed_teleports = ai_.get_allowed_teleports(unit_it);
pathfind::teleport_map allowed_teleports = ai_.get_allowed_teleports(unit_it);
pathfind::plain_route route = ai_.shortest_path_calculator( src, dst, unit_it, allowed_teleports );
@ -1029,7 +1030,7 @@ private:
throw formula_error( str.str(), "", "", 0);
}
std::set<map_location> allowed_teleports = ai_.get_allowed_teleports(unit_it);
pathfind::teleport_map allowed_teleports = ai_.get_allowed_teleports(unit_it);
pathfind::emergency_path_calculator em_calc(*unit_it, *resources::game_map);
@ -1083,7 +1084,7 @@ private:
throw formula_error( str.str(), "", "", 0);
}
std::set<map_location> allowed_teleports = ai_.get_allowed_teleports(unit_it);
pathfind::teleport_map allowed_teleports = ai_.get_allowed_teleports(unit_it);
pathfind::plain_route route = ai_.shortest_path_calculator( src, dst, unit_it, allowed_teleports );

View file

@ -680,7 +680,7 @@ double move_leader_to_goals_phase::evaluate()
}
const pathfind::paths leader_paths(*resources::game_map, *resources::units, leader->get_location(),
*resources::teams, false, false, current_team());
*resources::teams, false, true, current_team());
std::map<map_location,pathfind::paths> possible_moves;
possible_moves.insert(std::pair<map_location,pathfind::paths>(leader->get_location(), leader_paths));
@ -754,7 +754,7 @@ double move_leader_to_keep_phase::evaluate()
// Find where the leader can move
const pathfind::paths leader_paths(*resources::game_map, units_, leader->get_location(),
*resources::teams, false, false, current_team());
*resources::teams, false, true, current_team());
const map_location& keep = suitable_keep(leader->get_location(), leader_paths);
std::map<map_location,pathfind::paths> possible_moves;

View file

@ -37,6 +37,7 @@
#include "map.hpp"
#include "map_label.hpp"
#include "map_exception.hpp"
#include "pathfind/teleport.hpp"
#include "replay.hpp"
#include "reports.hpp"
#include "resources.hpp"
@ -579,6 +580,30 @@ WML_HANDLER_FUNCTION(place_shroud, /*event_info*/,cfg)
toggle_shroud(false,cfg );
}
WML_HANDLER_FUNCTION(tunnel, /*event_info*/, cfg)
{
const bool remove = utils::string_bool(cfg["remove"], false);
if (remove) {
const std::vector<std::string> ids = utils::split(cfg["id"]);
foreach(const std::string &id, ids) {
resources::tunnels->remove(id);
}
} else if (cfg.get_children("source").empty() ||
cfg.get_children("target").empty() ||
cfg.get_children("filter").empty()) {
ERR_WML << "[tunnel] is missing a mandatory tag:\n"
<< cfg.get_config().debug();
} else {
pathfind::teleport_group tunnel(cfg, false);
resources::tunnels->add(tunnel);
if (utils::string_bool(cfg["bidirectional"], true)) {
tunnel = pathfind::teleport_group(cfg, true);
resources::tunnels->add(tunnel);
}
}
}
WML_HANDLER_FUNCTION(teleport, event_info, cfg)
{
unit_map::iterator u = resources::units->find(event_info.loc1);

View file

@ -1319,9 +1319,8 @@ void menu_handler::show_enemy_moves(bool ignore_units, int side_num)
!gui_->fogged(u->get_location()) && !u->incapacitated() && !invisible)
{
const unit_movement_resetter move_reset(*u);
bool teleports = u->get_ability_bool("teleport");
const pathfind::paths& path = pathfind::paths(map_,units_,
u->get_location(), teams_, false, teleports,
u->get_location(), teams_, false, true,
teams_[gui_->viewing_team()], 0, false, ignore_units);
gui_->highlight_another_reach(path);

View file

@ -34,6 +34,7 @@
#include "map.hpp"
#include "marked-up_text.hpp"
#include "menu_events.hpp"
#include "pathfind/teleport.hpp"
#include "play_controller.hpp"
#include "sound.hpp"
#include "replay.hpp"
@ -274,12 +275,11 @@ void mouse_handler::mouse_motion(int x, int y, const bool browse, bool update)
//since the future state includes changes to units' movement.
unit_movement_resetter move_reset(*un);
bool teleport = un->get_ability_bool("teleport");
{ // start planned unit map scope
wb::scoped_planned_pathfind_map planned_pathfind_map;
current_paths_ = pathfind::paths(map_,units_,new_hex,teams_,
false,teleport,viewing_team(),path_turns_);
false,true,viewing_team(),path_turns_);
} // end planned unit map scope
gui().highlight_reach(current_paths_);
@ -415,7 +415,7 @@ pathfind::marked_route mouse_handler::get_route(unit* un, map_location go_to, co
// The pathfinder will check unit visibility (fogged/stealthy).
const pathfind::shortest_path_calculator calc(*un, team, units_, teams_, map_);
std::set<map_location> allowed_teleports = pathfind::get_teleport_locations(*un, viewing_team());
pathfind::teleport_map allowed_teleports = pathfind::get_teleport_locations(*un, viewing_team());
pathfind::plain_route route;
@ -681,10 +681,9 @@ void mouse_handler::select_hex(const map_location& hex, const bool browse) {
wb::scoped_real_unit_map real_unit_map;
unit_movement_resetter move_reset(*u, u->side() != side_num_);
} // end enforced real unit map scope
bool teleport = u->get_ability_bool("teleport");
current_paths_ = pathfind::paths(map_, units_, hex, teams_,
false, teleport, viewing_team(), path_turns_);
false, true, viewing_team(), path_turns_);
}
show_attack_options(u);
gui().highlight_reach(current_paths_);

View file

@ -19,6 +19,7 @@
#include "log.hpp"
#include "map.hpp"
#include "pathfind/pathfind.hpp"
#include "pathfind/teleport.hpp"
#include "foreach.hpp"
#include <queue>
@ -79,24 +80,34 @@ struct node {
, in(bad_search_counter)
{
}
node(double s, const map_location &c, const map_location &p, const map_location &dst, bool i, const std::set<map_location>* teleports):
node(double s, const map_location &c, const map_location &p, const map_location &dst, bool i, const pathfind::teleport_map* teleports):
g(s), h(heuristic(c, dst)), t(g + h), curr(c), prev(p), in(search_counter + i)
{
if (teleports != NULL) {
double srch = h, dsth = h;
std::set<map_location>::const_iterator i;
for(i = teleports->begin(); i != teleports->end(); ++i) {
const double new_srch = heuristic(c, *i);
const double new_dsth = heuristic(*i, dst);
if(new_srch < srch) {
srch = new_srch;
}
if(new_dsth < dsth) {
dsth = new_dsth;
}
if (teleports && !teleports->empty()) {
double new_srch = 1.0;
std::set<map_location> sources;
teleports->get_sources(sources);
std::set<map_location>::const_iterator it = sources.begin();
for(; it != sources.end(); ++it) {
const double tmp_srch = heuristic(c, *it);
if (tmp_srch < new_srch) { new_srch = tmp_srch; }
}
if(srch + dsth + 1.0 < h) {
h = srch + dsth + 1.0;
double new_dsth = 1.0;
std::set<map_location> targets;
teleports->get_targets(targets);
for(it = targets.begin(); it != targets.end(); ++it) {
const double tmp_dsth = heuristic(*it, dst);
if (tmp_dsth < new_dsth) { new_dsth = tmp_dsth; }
}
double new_h = new_srch + new_dsth + 1.0;
if (new_h < h) {
h = new_h;
t = g + h;
}
}
@ -130,8 +141,9 @@ public:
pathfind::plain_route pathfind::a_star_search(const map_location& src, const map_location& dst,
double stop_at, const pathfind::cost_calculator *calc, const size_t width,
const size_t height, const std::set<map_location>* teleports) {
double stop_at, const cost_calculator *calc, const size_t width,
const size_t height,
const teleport_map *teleports) {
//----------------- PRE_CONDITIONS ------------------
assert(src.valid(width, height));
assert(dst.valid(width, height));
@ -148,13 +160,6 @@ pathfind::plain_route pathfind::a_star_search(const map_location& src, const map
return locRoute;
}
if (teleports && teleports->empty()) teleports = NULL;
std::vector<map_location> locs(teleports ? 6 + teleports->size() : 6 );
if (teleports) {
std::copy(teleports->begin(), teleports->end(), locs.begin() + 6);
}
// increment search_counter but skip the range equivalent to uninitialized
search_counter += 2;
if (search_counter - bad_search_counter <= 1u)
@ -182,12 +187,26 @@ pathfind::plain_route pathfind::a_star_search(const map_location& src, const map
if (n.t >= nodes[index(dst)].g) break;
std::vector<map_location> locs;
int i;
if (teleports && !teleports->empty()) {
std::set<map_location> allowed_teleports;
teleports->get_adjacents(allowed_teleports, n.curr);
i = allowed_teleports.size() +6;
locs = std::vector<map_location>(i);
std::copy(allowed_teleports.begin(), allowed_teleports.end(), locs.begin() + 6);
} else
{ locs = std::vector<map_location>(6); i = 6;}
get_adjacent_tiles(n.curr, &locs[0]);
int i = teleports && teleports->count(n.curr) ? locs.size() : 6;
for (; i-- > 0;) {
if (!locs[i].valid(width, height)) continue;
if (locs[i] == n.curr) continue;
node& next = nodes[index(locs[i])];
double thresh = (next.in - search_counter <= 1u) ? next.g : stop_at + 1;

View file

@ -22,6 +22,7 @@
#include "global.hpp"
#include "pathfind/pathfind.hpp"
#include "pathfind/teleport.hpp"
#include "foreach.hpp"
#include "game_display.hpp"
@ -106,29 +107,6 @@ bool pathfind::enemy_zoc(std::vector<team> const &teams,
return false;
}
std::set<map_location> pathfind::get_teleport_locations(const unit &u,
const team &viewing_team,
bool see_all, bool ignore_units)
{
std::set<map_location> res;
if (!u.get_ability_bool("teleport")) return res;
const team &current_team = (*resources::teams)[u.side() - 1];
const map_location &loc = u.get_location();
foreach (const map_location &l, current_team.villages())
{
// This must be a vacant village (or occupied by the unit)
// to be able to teleport.
if (!see_all && viewing_team.is_enemy(u.side()) && viewing_team.fogged(l))
continue;
if (!ignore_units && l != loc &&
get_visible_unit(l, viewing_team, see_all))
continue;
res.insert(l);
}
return res;
}
static unsigned search_counter;
namespace {
@ -195,16 +173,13 @@ static void find_routes(const gamemap& map, const unit_map& /*units*/,
bool see_all, bool ignore_units)
{
const team& current_team = teams[u.side() - 1];
std::set<map_location> teleports;
pathfind::teleport_map teleports;
if (allow_teleport) {
teleports = pathfind::get_teleport_locations(u, viewing_team, see_all, ignore_units);
}
const int total_movement = u.total_movement();
std::vector<map_location> locs(6 + teleports.size());
std::copy(teleports.begin(), teleports.end(), locs.begin() + 6);
search_counter += 2;
if (search_counter == 0) search_counter = 2;
@ -226,10 +201,16 @@ static void find_routes(const gamemap& map, const unit_map& /*units*/,
pq.pop_back();
n.in = search_counter;
std::set<map_location> allowed_teleports;
teleports.get_adjacents(allowed_teleports, n.curr);
std::vector<map_location> locs(6 + allowed_teleports.size());
std::copy(allowed_teleports.begin(), allowed_teleports.end(), locs.begin() + 6);
get_adjacent_tiles(n.curr, &locs[0]);
for (int i = teleports.count(n.curr) ? locs.size() : 6; i-- > 0; ) {
for (int i = locs.size(); i-- > 0; ) {
if (!locs[i].valid(map.w(), map.h())) continue;
if (locs[i] == n.curr) continue;
node& next = nodes[index(locs[i])];
bool next_visited = next.in - search_counter <= 1u;

View file

@ -35,7 +35,7 @@ class unit_movement_type;
namespace pathfind {
typedef std::set<map_location> teleport_map;
class teleport_map;
enum VACANT_TILE_TYPE { VACANT_CASTLE, VACANT_ANY };
@ -54,9 +54,6 @@ map_location find_vacant_tile(const gamemap& map,
bool enemy_zoc(std::vector<team> const &teams, map_location const &loc,
team const &viewing_team, int side, bool see_all=false);
std::set<map_location> get_teleport_locations(const unit &u,
const team &viewing_team,
bool see_all = false, bool ignore_units = false);
struct cost_calculator
{
@ -82,7 +79,7 @@ struct paths
// Construct a list of paths for the unit at loc.
// - force_ignore_zocs: find the path ignoring ZOC entirely,
// if false, will use the unit on the loc's ability
// - allow_teleport: indicates whether unit teleports between villages
// - allow_teleport: indicates whether the paths should include teleportation (false for sight)
// - additional_turns: if 0, paths for how far the unit can move this turn will be calculated.
// If 1, paths for how far the unit can move by the end of next turn
// will be calculated, and so forth.
@ -173,7 +170,7 @@ struct marked_route
plain_route a_star_search(map_location const &src, map_location const &dst,
double stop_at, const cost_calculator* costCalculator,
const size_t parWidth, const size_t parHeight,
std::set<map_location> const *teleports = NULL);
const teleport_map* teleports = NULL);
/**
* Add marks on a route @a rt assuming that the unit located at the first hex of

230
src/pathfind/teleport.cpp Normal file
View file

@ -0,0 +1,230 @@
/* $Id: teleport.cpp $ */
/*
Copyright (C) 2010 by Fabian Mueller <fabianmueller5@gmx.de>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "pathfind/teleport.hpp"
#include "serialization/string_utils.hpp"
#include "unit.hpp"
#include "log.hpp"
#include "resources.hpp"
#include "foreach.hpp"
static lg::log_domain log_engine("engine");
#define ERR_PF LOG_STREAM(err, log_engine)
namespace {
const std::string reversed_suffix = "-__REVERSED__";
}
// This constructor is *only* meant for loading from saves
pathfind::teleport_group::teleport_group(const config cfg) : cfg_(cfg, true), reversed_(utils::string_bool(cfg["reversed"], false)), id_(cfg["id"])
{
assert(cfg.has_attribute("id"));
assert(cfg.has_attribute("reversed"));
assert(!cfg_.get_children("source").empty());
assert(!cfg_.get_children("target").empty());
assert(!cfg_.get_children("filter").empty());
}
pathfind::teleport_group::teleport_group(vconfig cfg, bool reversed) : cfg_(cfg), reversed_(reversed), id_()
{
assert(!cfg_.get_children("source").empty());
assert(!cfg_.get_children("target").empty());
assert(!cfg_.get_children("filter").empty());
if (cfg["id"].empty()) {
id_ = resources::tunnels->next_unique_id();
} else {
id_ = cfg["id"].str();
if (reversed_) // Differentiate the reverse tunnel from the forward one
id_ += reversed_suffix;
}
}
void pathfind::teleport_group::get_teleport_pair(teleport_pair& loc_pair, const unit& u, bool ignore_units)
{
const map_location &loc = u.get_location();
static unit_map empty_unit_map;
unit_map *units;
if (ignore_units) {
units = &empty_unit_map;
} else {
units = resources::units;
}
if (u.matches_filter(cfg_.child("filter"), loc)) {
scoped_xy_unit teleport_unit("teleport_unit", loc.x, loc.y, *resources::units);
terrain_filter source_filter(cfg_.child("source"), *units);
source_filter.get_locations(reversed_ ? loc_pair.second : loc_pair.first);
terrain_filter target_filter(cfg_.child("target"), *units);
target_filter.get_locations(reversed_ ? loc_pair.first : loc_pair.second);
}
}
const std::string& pathfind::teleport_group::get_teleport_id() const {
return id_;
}
bool pathfind::teleport_group::always_visible() const {
return utils::string_bool(cfg_["always_visible"], false);
}
config pathfind::teleport_group::to_config() const {
config retval = cfg_.get_config();
retval["reversed"] = reversed_ ? "yes" : "no";
retval["id"] = id_;
return retval;
}
pathfind::teleport_map::teleport_map(std::vector<teleport_group> groups, const unit& u, const unit_map &/*units*/, const team &viewing_team, bool see_all, bool ignore_units)
: teleport_map_(), sources_(), targets_() {
for (std::vector<teleport_group>::iterator it = groups.begin(); it != groups.end(); ++it) {
teleport_pair locations;
it->get_teleport_pair(locations, u, ignore_units);
if (!see_all && !it->always_visible() && viewing_team.is_enemy(u.side())) {
teleport_pair filter_locs;
foreach(const map_location &loc, locations.first)
if(!viewing_team.fogged(loc))
filter_locs.first.insert(loc);
foreach(const map_location &loc, locations.second)
if(!viewing_team.fogged(loc))
filter_locs.second.insert(loc);
locations.first.swap(filter_locs.first);
locations.second.swap(filter_locs.second);
}
std::string teleport_id = it->get_teleport_id();
std::set<map_location>::iterator source_it = locations.first.begin();
for (; source_it != locations.first.end(); ++source_it ) {
if(teleport_map_.count(*source_it) == 0) {
std::set<std::string> id_set;
id_set.insert(teleport_id);
teleport_map_.insert(std::make_pair(*source_it, id_set));
} else {
(teleport_map_.find(*source_it)->second).insert(teleport_id);
}
}
sources_.insert(std::make_pair(teleport_id, locations.first));
targets_.insert(std::make_pair(teleport_id, locations.second));
}
}
void pathfind::teleport_map::get_adjacents(std::set<map_location>& adjacents, map_location loc) const {
if (teleport_map_.count(loc) == 0) {
return;
} else {
const std::set<std::string>& keyset = (teleport_map_.find(loc)->second);
for(std::set<std::string>::const_iterator it = keyset.begin(); it != keyset.end(); ++it) {
const std::set<map_location>& target = targets_.find(*it)->second;
adjacents.insert(target.begin(), target.end());
}
}
}
void pathfind::teleport_map::get_sources(std::set<map_location>& sources) const {
std::map<std::string, std::set<map_location> >::const_iterator it;
for(it = sources_.begin(); it != sources_.end(); ++it) {
sources.insert(it->second.begin(), it->second.end());
}
}
void pathfind::teleport_map::get_targets(std::set<map_location>& targets) const {
std::map<std::string, std::set<map_location> >::const_iterator it;
for(it = targets_.begin(); it != targets_.end(); ++it) {
targets.insert(it->second.begin(), it->second.end());
}
}
const pathfind::teleport_map pathfind::get_teleport_locations(const unit &u,
const team &viewing_team,
bool see_all, bool ignore_units)
{
std::vector<teleport_group> groups;
if (u.get_ability_bool("teleport")) {
unit_ability_list teleport_list = u.get_abilities("teleport");
std::vector<std::pair<const config *, map_location> > teleports = teleport_list.cfgs;
std::vector<std::pair<const config *, map_location> >::const_iterator it = teleports.begin();
for(; it != teleports.end(); ++it) {
const int tunnel_count = (it->first)->child_count("tunnel");
for(int i = 0; i < tunnel_count; ++i) {
config teleport_group_cfg = (it->first)->child("tunnel", i);
teleport_group group = teleport_group(vconfig(teleport_group_cfg, true), false);
groups.push_back(group);
}
}
}
const std::vector<teleport_group>& global_groups = resources::tunnels->get();
groups.insert(groups.end(), global_groups.begin(), global_groups.end());
return teleport_map(groups, u, *resources::units, viewing_team, see_all, ignore_units);
}
pathfind::manager::manager(const config &cfg) : tunnels_(), id_(lexical_cast_default<int>(cfg["next_teleport_group_id"], 0)) {
const int tunnel_count = cfg.child_count("tunnel");
for(int i = 0; i < tunnel_count; ++i) {
const config& t = cfg.child("tunnel", i);
const pathfind::teleport_group tunnel(t);
this->add(tunnel);
}
}
void pathfind::manager::add(const teleport_group &group) {
tunnels_.push_back(group);
}
void pathfind::manager::remove(const std::string &id) {
std::vector<pathfind::teleport_group>::iterator t = tunnels_.begin();
for(;t != tunnels_.end();) {
if (t->get_teleport_id() == id || t->get_teleport_id() == id + reversed_suffix) {
t = tunnels_.erase(t);
} else {
++t;
}
}
}
const std::vector<pathfind::teleport_group>& pathfind::manager::get() const {
return tunnels_;
}
config pathfind::manager::to_config() const {
config store;
std::vector<pathfind::teleport_group>::const_iterator tunnel = tunnels_.begin();
for(; tunnel != tunnels_.end(); ++tunnel) {
store.add_child("tunnel", tunnel->to_config());
}
store["next_teleport_group_id"] = str_cast(id_);
return store;
}
std::string pathfind::manager::next_unique_id() {
return str_cast(++id_);
}

119
src/pathfind/teleport.hpp Normal file
View file

@ -0,0 +1,119 @@
/* $Id: teleport.hpp $ */
/*
Copyright (C) 2010 by Fabian Mueller <fabianmueller5@gmx.de>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#ifndef TELEPORT_H_INCLUDED
#define TELEPORT_H_INCLUDED
#include "map.hpp"
#include "config.hpp"
#include "team.hpp"
#include "terrain_filter.hpp"
#include "savegame_config.hpp"
#include "pathfind/pathfind.hpp"
namespace pathfind {
typedef std::pair<std::set<map_location>, std::set<map_location> >
teleport_pair;
/*
* Represents the tunnel wml tag.
*/
class teleport_group: public savegame::savegame_config {
public:
/*
* Used to create the object from a saved file.
*/
teleport_group(const config cfg);
/*
*
*/
teleport_group(vconfig cfg, bool way_back = false);
/*
* Fills the argument loc_pair if the unit u matches the groups filter.
*/
void get_teleport_pair(teleport_pair& loc_pair, const unit& u, bool ignore_units);
/*
* Returns the unique id of the teleport group.
* Can be set by the id attribute or is randomly chosen.
*/
const std::string& get_teleport_id() const;
/*
* Returns whether the group should always be visible,
* even for enemy movement under shroud.
*/
bool always_visible() const;
config to_config() const;
private:
vconfig cfg_;
bool reversed_;
std::string id_;
};
class teleport_map {
public:
teleport_map(std::vector<teleport_group> teleport_groups, const unit& u,
const unit_map &units, const team &viewing_team, bool see_all,
bool ignore_units);
teleport_map() :
teleport_map_(), sources_(), targets_() {
}
;
void get_adjacents(std::set<map_location>& adjacents, map_location loc) const;
void get_sources(std::set<map_location>& sources) const;
void get_targets(std::set<map_location>& targets) const;
bool empty() const {
return sources_.empty();
}
private:
std::map<map_location, std::set<std::string> > teleport_map_;
std::map<std::string, std::set<map_location> > sources_;
std::map<std::string, std::set<map_location> > targets_;
};
//TODO clean up the interface
const teleport_map get_teleport_locations(const unit &u, const team &viewing_team,
bool see_all = false, bool ignore_units = false);
class manager: public savegame::savegame_config {
public:
manager(const config &cfg);
void add(const teleport_group &group);
void remove(const std::string &id);
const std::vector<teleport_group>& get() const;
config to_config() const;
// For unique tunnel IDs
std::string next_unique_id();
private:
std::vector<teleport_group> tunnels_;
int id_;
};
}
#endif /* TELEPORT_H_INCLUDED */

View file

@ -27,6 +27,7 @@
#include "halo.hpp"
#include "loadscreen.hpp"
#include "log.hpp"
#include "pathfind/teleport.hpp"
#include "resources.hpp"
#include "savegame.hpp"
#include "sound.hpp"
@ -83,6 +84,7 @@ play_controller::play_controller(const config& level, game_state& state_of_game,
menu_handler_(NULL, units_, teams_, level, map_, game_config, tod_manager_, state_of_game),
soundsources_manager_(),
tod_manager_(level, num_turns, &state_of_game),
pathfind_manager_(),
persist_(),
gui_(),
statistics_context_(level["name"]),
@ -141,6 +143,7 @@ play_controller::play_controller(const config& level, game_state& state_of_game,
play_controller::~play_controller()
{
clear_resources();
resources::tunnels = NULL;
}
void play_controller::init(CVideo& video){
@ -281,9 +284,11 @@ void play_controller::init_managers(){
prefs_disp_manager_.reset(new preferences::display_manager(gui_.get()));
tooltips_manager_.reset(new tooltips::manager(gui_->video()));
soundsources_manager_.reset(new soundsource::manager(*gui_));
pathfind_manager_.reset(new pathfind::manager(level_));
whiteboard_manager_.reset(new wb::manager());
resources::soundsources = soundsources_manager_.get();
resources::tunnels = pathfind_manager_.get();
resources::whiteboard = whiteboard_manager_.get();
halo_manager_.reset(new halo::manager(*gui_));
@ -661,6 +666,7 @@ config play_controller::to_config() const
//write out the current state of the map
cfg["map_data"] = map_.write();
cfg.merge_with(pathfind_manager_->to_config());
return cfg;
}
@ -1005,13 +1011,11 @@ void play_controller::process_keyup_event(const SDL_Event& event) {
const unit_map::iterator u = mouse_handler_.selected_unit();
if(u != units_.end()) {
bool teleport = u->get_ability_bool("teleport");
// if it's not the unit's turn, we reset its moves
unit_movement_resetter move_reset(*u, u->side() != player_number_);
mouse_handler_.set_current_paths(pathfind::paths(map_, units_, u->get_location(),
teams_,false,teleport, teams_[gui_->viewing_team()],
teams_,false,true, teams_[gui_->viewing_team()],
mouse_handler_.get_path_turns()));
gui_->highlight_reach(mouse_handler_.current_paths());

View file

@ -51,6 +51,9 @@ namespace soundsource {
class manager;
} // namespace soundsource
namespace pathfind {
class manager;
}
namespace tooltips {
struct manager;
@ -186,6 +189,7 @@ protected:
events::menu_handler menu_handler_;
boost::scoped_ptr<soundsource::manager> soundsources_manager_;
tod_manager tod_manager_;
boost::scoped_ptr<pathfind::manager> pathfind_manager_;
persist_manager persist_;
//other objects

View file

@ -26,6 +26,7 @@ namespace resources
LuaKernel *lua_kernel;
play_controller *controller;
::tod_manager *tod_manager;
pathfind::manager *tunnels;
wb::manager *whiteboard;
std::vector<undo_action> *undo_stack;
std::vector<undo_action> *redo_stack;

View file

@ -31,6 +31,8 @@ struct undo_action;
namespace soundsource { class manager; }
namespace pathfind { class manager; }
namespace wb { class manager; } //whiteboard manager
namespace resources
@ -44,6 +46,7 @@ namespace resources
extern LuaKernel *lua_kernel;
extern play_controller *controller;
extern tod_manager *tod_manager;
extern pathfind::manager *tunnels;
extern wb::manager *whiteboard;
extern std::vector<undo_action> *undo_stack;
extern std::vector<undo_action> *redo_stack;

View file

@ -44,6 +44,7 @@
#include "log.hpp"
#include "map.hpp"
#include "pathfind/pathfind.hpp"
#include "pathfind/teleport.hpp"
#include "play_controller.hpp"
#include "replay.hpp"
#include "reports.hpp"