Merge pathfind branch
This commit is contained in:
parent
2279bc0e77
commit
93776cb5ac
23 changed files with 571 additions and 90 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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_);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ¤t_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;
|
||||
|
|
|
@ -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
230
src/pathfind/teleport.cpp
Normal 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
119
src/pathfind/teleport.hpp
Normal 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 */
|
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Add table
Reference in a new issue