Merge of fendrin's new teleport and tunnel code.

The changes are guarded by the C++ and WML conditional symbol
"EXPERIMENTAL".

The experimental flag is temporarily defaulted off, so those patches
should have no effect on people doing ordinary builds. This may change
once fendrin has the tunnel code fixed and polished.
This commit is contained in:
Eric S. Raymond 2010-01-26 06:34:20 +00:00
parent 51d12123c5
commit 75925deb82
29 changed files with 439 additions and 5 deletions

View file

@ -39,8 +39,9 @@ except KeyError:
# Build-control options
#
# Experimental code is enabled by default in unstable (odd minor version).
experimental_default = (int(version.split(".")[1]) % 2) == 1
# FIXME: Experimental code enabled by default in unstable (odd minor version).
#experimental_default = (int(version.split(".")[1]) % 2) == 1
experimental_default = False
opts = Variables('.scons-option-cache')

View file

@ -11,7 +11,7 @@ AC_PREREQ([2.60])
# to match whether this is a stable or unstable release.
#######################################################################
define([WESNOTH_VERSION],[1.7.12+svn])
experimental_default=yes
experimental_default=no
define([WESNOTH_BUGS],[http://bugs.wesnoth.org])
AC_INIT([Battle for Wesnoth], WESNOTH_VERSION, WESNOTH_BUGS, [wesnoth])

View file

@ -379,6 +379,35 @@ 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."
#ifdef EXPERIMENTAL
[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]
#endif
[/teleport]
#enddef

View file

@ -155,6 +155,82 @@ Xu , Xu , Qxu , Qxu , Ql , Ql
[/unit]
[/side]
#ifdef EXPERIMENTAL
[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]
#endif
[side]
type=Orcish Warlord
id="Urug-Telfar"
@ -191,6 +267,16 @@ Xu , Xu , Qxu , Qxu , Ql , Ql
[/object]
[/modifications]
[/unit]
#ifdef EXPERIMENTAL
[village]
x,y=26,5
[/village]
[unit]
x,y=24,7
type="Silver Mage"
name= _ "Hidden Teleporter"
[/unit]
#endif
[/side]
[side]
side=3
@ -900,6 +986,7 @@ For game purposes, the races group into factions; for example, orcs often cooper
[/event]
[item]
#ifndef EXPERIMENTAL
x,y=9,1
# This doesn't work, image doesn't do animation
image="scenery/fire1.png~CS(0,0,50):150,scenery/fire2.png~CS(0,0,50):150,scenery/fire3.png~CS(0,0,50):150,scenery/fire4.png~CS(0,0,50):150,scenery/fire5.png~CS(0,0,50):150,scenery/fire6.png~CS(0,0,50):150,scenery/fire7.png~CS(0,0,50):150,scenery/fire8.png~CS(0,0,50):150"
@ -910,6 +997,7 @@ For game purposes, the races group into factions; for example, orcs often cooper
[/item]
[item]
#endif
x,y=8,8
image="items/orcish-flag.png"
[/item]

View file

@ -341,6 +341,10 @@ set(wesnoth-main_SRC
multiplayer_create.cpp
network.cpp
network_worker.cpp
#ifdef EXPERIMENTAL
pathfind/pathfind.cpp
pathfind/teleport.cpp
#endif
playcampaign.cpp
play_controller.cpp
playmp_controller.cpp
@ -434,7 +438,9 @@ SET(libwesnoth-game_STAT_SRC
marked-up_text.cpp
minimap.cpp
pathfind/astarsearch.cpp
#ifndef EXPERIMENTAL
pathfind/pathfind.cpp
#endif
pathutils.cpp
preferences.cpp
preferences_display.cpp

View file

@ -224,6 +224,9 @@ wesnoth_source = \
network.cpp \
network_worker.cpp \
pathfind/pathfind.cpp \
#ifdef EXPERIMENTAL
pathfind/teleport.cpp \
#endif
playcampaign.cpp \
play_controller.cpp \
playmp_controller.cpp \

View file

@ -219,6 +219,7 @@ wesnoth_sources = Split("""
multiplayer_create.cpp
multiplayer_connect.cpp
pathfind/pathfind.cpp
pathfind/teleport.cpp
playcampaign.cpp
play_controller.cpp
playmp_controller.cpp

View file

@ -407,8 +407,12 @@ bool move_result::test_route(const unit &un, const team &my_team, const unit_map
}
const pathfind::shortest_path_calculator calc(un, my_team, units, teams,map);
#ifndef EXPERIMENTAL
//allowed teleports
std::set<map_location> allowed_teleports = pathfind::get_teleport_locations(un, units, my_team, true);//@todo 1.9: see_all -> false
#else
pathfind::teleport_map allowed_teleports = pathfind::get_teleport_locations(un, units, my_team, true);//@todo 1.9: see_all -> false
#endif
//do an A*-search
route_ = pathfind::a_star_search(un.get_location(), to_, 10000.0, &calc, map.w(), map.h(), &allowed_teleports);
@ -505,7 +509,11 @@ void move_result::do_execute()
if (from_ != to_) {
move_unit(
/*move_unit_spectator* move_spectator*/ &move_spectator_,
#ifndef EXPERIMENTAL
/*std::vector<map_location> route*/ route_.steps,
#else
/*std::vector<map_location> pathfind::route*/ route_.steps,
#endif
/*replay* move_recorder*/ &recorder,
/*undo_list* undo_stack*/ NULL,
/*bool show_move*/ preferences::show_ai_moves(),

View file

@ -335,10 +335,16 @@ void readonly_context_impl::calculate_moves(const unit_map& units, std::map<map_
srcdst.insert(trivial_mv);
dstsrc.insert(trivial_mv);
}
#ifndef EXPERIMENTAL
bool teleports = un_it->second.get_ability_bool("teleport");
#endif
res.insert(std::pair<map_location,pathfind::paths>(
un_it->first,pathfind::paths(get_info().map,units,
#ifndef EXPERIMENTAL
un_it->first,get_info().teams,false,teleports,
#else
un_it->first,get_info().teams,false,true,
#endif
current_team(),0,see_all)));
}
@ -906,7 +912,11 @@ bool readonly_context_impl::leader_can_reach_keep() const
}
// Find where the leader can move
#ifndef EXPERIMENTAL
const pathfind::paths leader_paths(get_info().map,get_info().units,leader->first,get_info().teams,false,false,current_team());
#else
const pathfind::paths leader_paths(get_info().map,get_info().units,leader->first,get_info().teams,false,true,current_team());
#endif
return leader_paths.destinations.contains(start_pos);

View file

@ -527,7 +527,11 @@ bool ai_default::multistep_move_possible(const map_location& from,
unit temp_unit(i->second);
temp_unit.set_movement(itor->move_left);
const temporary_unit_placer unit_placer(units_,via,temp_unit);
#ifndef EXPERIMENTAL
const pathfind::paths unit_paths(map_,units_,via,teams_,false,false,current_team());
#else
const pathfind::paths unit_paths(map_,units_,via,teams_,false,true,current_team());
#endif
LOG_AI << "Found " << unit_paths.destinations.size() << " moves for temp leader.\n";
@ -1881,7 +1885,11 @@ void ai_default::move_leader_to_goals()
}
const pathfind::paths leader_paths(map_, units_, leader->first,
#ifndef EXPERIMENTAL
teams_, false, false, current_team());
#else
teams_, false, true, current_team());
#endif
std::map<map_location,pathfind::paths> possible_moves;
possible_moves.insert(std::pair<map_location,pathfind::paths>(leader->first,leader_paths));
@ -1918,7 +1926,11 @@ void ai_default::move_leader_after_recruit()
const bool passive_leader = get_passive_leader()||passive_leader_shares_keep;
const pathfind::paths leader_paths(map_, units_, leader->first,
#ifndef EXPERIMENTAL
teams_, false, false, current_team());
#else
teams_, false, true, current_team());
#endif
std::map<map_location,pathfind::paths> possible_moves;
possible_moves.insert(std::pair<map_location,pathfind::paths>(leader->first,leader_paths));
@ -1954,7 +1966,11 @@ void ai_default::move_leader_after_recruit()
unit_map temp_units;
temp_units.add(current_loc, leader->second);
const pathfind::paths p(map_, temp_units, current_loc, teams_, false,
#ifndef EXPERIMENTAL
false, current_team());
#else
true, current_team());
#endif
if (p.destinations.contains(i->first))
{

View file

@ -124,7 +124,11 @@ bool default_ai_context_impl::multistep_move_possible(const map_location& from,
unit temp_unit(i->second);
temp_unit.set_movement(itor->move_left);
const temporary_unit_placer unit_placer(units_,via,temp_unit);
#ifndef EXPERIMENTAL
const pathfind::paths unit_paths(get_info().map,units_,via,get_info().teams,false,false,current_team());
#else
const pathfind::paths unit_paths(get_info().map,units_,via,get_info().teams,false,true,current_team());
#endif
LOG_AI << "Found " << unit_paths.destinations.size() << " moves for temp leader.\n";

View file

@ -733,7 +733,11 @@ void ai_default::move_leader_to_keep()
// Find where the leader can move
const pathfind::paths leader_paths(map_, units_, leader->first,
#ifndef EXPERIMENTAL
teams_, false, false, current_team());
#else
teams_, false, true, current_team());
#endif
const map_location& keep = suitable_keep(leader->first,leader_paths);
std::map<map_location,pathfind::paths> possible_moves;

View file

@ -177,7 +177,11 @@ 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,
#ifndef EXPERIMENTAL
std::set<map_location> & allowed_teleports) const
#else
pathfind::teleport_map& allowed_teleports) const
#endif
{
map_location destination = dst;
@ -229,7 +233,11 @@ pathfind::plain_route formula_ai::shortest_path_calculator(const map_location &s
return route;
}
#ifndef EXPERIMENTAL
std::set<map_location> formula_ai::get_allowed_teleports(unit_map::iterator& unit_it) const
#else
pathfind::teleport_map formula_ai::get_allowed_teleports(unit_map::iterator& unit_it) const
#endif
{
return pathfind::get_teleport_locations(unit_it->second, get_info().units, current_team(), true);
}
@ -242,7 +250,11 @@ map_location formula_ai::path_calculator(const map_location& src, const map_loca
//check if destination is within unit's reach, if not, calculate where to move
if (!path->second.destinations.contains(dst))
{
#ifndef EXPERIMENTAL
std::set<map_location> allowed_teleports = get_allowed_teleports(unit_it);
#else
pathfind::teleport_map allowed_teleports = get_allowed_teleports(unit_it);
#endif
//destination is too far, check where unit can go
pathfind::plain_route route = shortest_path_calculator( src, dst, unit_it, allowed_teleports );

View file

@ -104,8 +104,13 @@ public:
void handle_exception(game_logic::formula_error& e) const;
void handle_exception(game_logic::formula_error& e, const std::string& failed_operation) const;
#ifndef EXPERIMENTAL
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;
#else
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;
#endif
void store_outcome_position(const variant& var);

View file

@ -658,7 +658,11 @@ private:
if (ai_.get_info().units.find(loc)==ai_.get_info().units.end()){
return variant();
}
#ifndef EXPERIMENTAL
const pathfind::paths unit_paths(ai_.get_info().map, ai_.get_info().units, loc ,ai_.get_info().teams, false, false, ai_.current_team());
#else
const pathfind::paths unit_paths(ai_.get_info().map, ai_.get_info().units, loc ,ai_.get_info().teams, false, true, ai_.current_team());
#endif
return variant(new location_callable(ai_.suitable_keep(loc,unit_paths)));
}
@ -972,7 +976,11 @@ private:
throw formula_error( str.str(), "", "", 0);
}
#ifndef EXPERIMENTAL
std::set<map_location> allowed_teleports = ai_.get_allowed_teleports(unit_it);
#else
pathfind::teleport_map allowed_teleports = ai_.get_allowed_teleports(unit_it);
#endif
pathfind::plain_route route = ai_.shortest_path_calculator( src, dst, unit_it, allowed_teleports );
@ -1022,7 +1030,11 @@ private:
throw formula_error( str.str(), "", "", 0);
}
#ifndef EXPERIMENTAL
std::set<map_location> allowed_teleports = ai_.get_allowed_teleports(unit_it);
#else
pathfind::teleport_map allowed_teleports = ai_.get_allowed_teleports(unit_it);
#endif
pathfind::emergency_path_calculator em_calc(unit_it->second, ai_.get_info().map);
@ -1076,7 +1088,11 @@ private:
throw formula_error( str.str(), "", "", 0);
}
#ifndef EXPERIMENTAL
std::set<map_location> allowed_teleports = ai_.get_allowed_teleports(unit_it);
#else
pathfind::teleport_map allowed_teleports = ai_.get_allowed_teleports(unit_it);
#endif
pathfind::plain_route route = ai_.shortest_path_calculator( src, dst, unit_it, allowed_teleports );
@ -1316,11 +1332,15 @@ public:
{}
private:
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
#ifndef EXPERIMENTAL
variant loc_var = args()[0]->evaluate(variables,add_debug_info(fdb,0,"unit_at:location"));
if (loc_var.is_null()) {
return variant();
}
const location_callable* loc = convert_variant<location_callable>(loc_var);
#else
const location_callable* loc = convert_variant<location_callable>(args()[0]->evaluate(variables,add_debug_info(fdb,0,"unit_at:location")));
#endif
const unit_map::const_iterator i = ai_.get_info().units.find(loc->loc());
if(i != ai_.get_info().units.end()) {
return variant(new unit_callable(*i));

View file

@ -670,7 +670,11 @@ double move_leader_to_goals_phase::evaluate()
}
const pathfind::paths leader_paths(get_info().map, get_info().units, leader->first,
#ifndef EXPERIMENTAL
get_info().teams, false, false, current_team());
#else
get_info().teams, false, true, current_team());
#endif
std::map<map_location,pathfind::paths> possible_moves;
possible_moves.insert(std::pair<map_location,pathfind::paths>(leader->first,leader_paths));
@ -746,7 +750,11 @@ double move_leader_to_keep_phase::evaluate()
// Find where the leader can move
const pathfind::paths leader_paths(get_info().map, units_, leader->first,
#ifndef EXPERIMENTAL
get_info().teams, false, false, current_team());
#else
get_info().teams, false, true, current_team());
#endif
const map_location& keep = suitable_keep(leader->first,leader_paths);
std::map<map_location,pathfind::paths> possible_moves;
@ -1748,7 +1756,11 @@ double retreat_phase::evaluate()
typedef move_map::const_iterator Itor;
std::pair<Itor,Itor> itors = get_srcdst().equal_range(i->first);
map_location best_pos, best_defensive(i->first);
#ifndef EXPERIMENTAL
double best_rating = -1000.0;
#else
double best_rating = 0.0;
#endif
int best_defensive_rating = i->second.defense_modifier(get_info().map.get_terrain(i->first))
- (get_info().map.is_village(i->first) ? 10 : 0);
while(itors.first != itors.second) {

View file

@ -622,6 +622,32 @@ WML_HANDLER_FUNCTION(place_shroud, /*event_info*/,cfg)
toggle_shroud(false,cfg );
}
#ifdef EXPERIMENTAL
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);
}
}
}
#endif
WML_HANDLER_FUNCTION(teleport, event_info, cfg)
{
unit_map::iterator u = resources::units->find(event_info.loc1);
@ -2107,10 +2133,14 @@ WML_HANDLER_FUNCTION(kill, event_info, cfg)
}
if(utils::string_bool(cfg["animate"])) {
resources::screen->scroll_to_tile(loc);
#ifndef EXPERIMENTAL
if (un.valid()) {
#endif
unit_display::unit_die(loc, un->second);
}
#ifndef EXPERIMENTAL
}
#endif
if (fire_event)
{
game_events::fire("die", death_loc, death_loc);

View file

@ -30,6 +30,7 @@
#include "serialization/parser.hpp"
#include "util.hpp"
#include "wml_exception.hpp"
#include "foreach.hpp"
static lg::log_domain log_config("config");
#define ERR_CF LOG_STREAM(err, log_config)

View file

@ -1256,9 +1256,15 @@ void menu_handler::show_enemy_moves(bool ignore_units, int side_num)
!gui_->fogged(u->first) && !u->second.incapacitated() && !invisible)
{
const unit_movement_resetter move_reset(u->second);
#ifndef EXPERIMENTAL
bool teleports = u->second.get_ability_bool("teleport");
#endif
const pathfind::paths& path = pathfind::paths(map_,units_,
#ifndef EXPERIMENTAL
u->first,teams_,false,teleports,teams_[gui_->viewing_team()], 0,false, ignore_units);
#else
u->first,teams_,false,true,teams_[gui_->viewing_team()], 0,false, ignore_units);
#endif
gui_->highlight_another_reach(path);
}

View file

@ -232,9 +232,15 @@ void mouse_handler::mouse_motion(int x, int y, const bool browse, bool update)
//unit under cursor is not on our team, highlight reach
unit_movement_resetter move_reset(un->second);
#ifndef EXPERIMENTAL
bool teleport = un->second.get_ability_bool("teleport");
#endif
current_paths_ = pathfind::paths(map_,units_,new_hex,teams_,
#ifndef EXPERIMENTAL
false,teleport,viewing_team(),path_turns_);
#else
false,true,viewing_team(),path_turns_);
#endif
gui().highlight_reach(current_paths_);
enemy_paths_ = true;
} else {
@ -343,7 +349,11 @@ pathfind::marked_route mouse_handler::get_route(unit_map::const_iterator un, map
// The pathfinder will check unit visibility (fogged/stealthy).
const pathfind::shortest_path_calculator calc(un->second,team,units_,teams_,map_);
#ifndef EXPERIMENTAL
std::set<map_location> allowed_teleports = pathfind::get_teleport_locations(
#else
pathfind::teleport_map allowed_teleports = pathfind::get_teleport_locations(
#endif
un->second, units_, viewing_team());
pathfind::plain_route route;
@ -534,9 +544,15 @@ void mouse_handler::select_hex(const map_location& hex, const bool browse) {
// if it's not the unit's turn, we reset its moves
// and we restore them before the "select" event is raised
unit_movement_resetter move_reset(u->second, u->second.side() != side_num_);
#ifndef EXPERIMENTAL
bool teleport = u->second.get_ability_bool("teleport");
#endif
current_paths_ = pathfind::paths(map_, units_, hex, teams_,
#ifndef EXPERIMENTAL
false, teleport, viewing_team(), path_turns_);
#else
false, true, viewing_team(), path_turns_);
#endif
}
show_attack_options(u);
gui().highlight_reach(current_paths_);

View file

@ -43,7 +43,11 @@ public:
void cycle_back_units(const bool browse) { cycle_units(browse, true); }
int get_path_turns() const { return path_turns_; }
#ifndef EXPERIMENTAL
const pathfind::paths& current_paths() const { return current_paths_; }
#else
const pathfind::paths get_current_paths() const { return current_paths_; }
#endif
const map_location& get_last_hex() const { return last_hex_; }
map_location get_selected_hex() const { return selected_hex_; }
bool get_undo() const { return undo_; }

View file

@ -18,6 +18,9 @@
#include "log.hpp"
#include "map.hpp"
#include "pathfind/pathfind.hpp"
#ifdef EXPERIMENTAL
#include "pathfind/teleport.hpp"
#endif
#include "foreach.hpp"
#include <queue>
@ -78,9 +81,14 @@ struct node {
, in(bad_search_counter)
{
}
#ifndef EXPERIMENTAL
node(double s, const map_location &c, const map_location &p, const map_location &dst, bool i, const std::set<map_location>* teleports):
#else
node(double s, const map_location &c, const map_location &p, const map_location &dst, bool i, const pathfind::teleport_map* teleports):
#endif
g(s), h(heuristic(c, dst)), t(g + h), curr(c), prev(p), in(search_counter + i)
{
#ifndef EXPERIMENTAL
if (teleports != NULL) {
double srch = h, dsth = h;
std::set<map_location>::const_iterator i;
@ -92,10 +100,40 @@ struct node {
}
if(new_dsth < dsth) {
dsth = new_dsth;
#else
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; }
#endif
}
#ifdef EXPERIMENTAL
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; }
#endif
}
#ifndef EXPERIMENTAL
if(srch + dsth + 1.0 < h) {
h = srch + dsth + 1.0;
#else
double new_h = new_srch + new_dsth + 1.0;
if (new_h < h) {
h = new_h;
#endif
t = g + h;
}
}
@ -129,8 +167,14 @@ public:
pathfind::plain_route pathfind::a_star_search(const map_location& src, const map_location& dst,
#ifndef EXPERIMENTAL
double stop_at, const pathfind::cost_calculator *calc, const size_t width,
const size_t height, const std::set<map_location>* teleports) {
#else
double stop_at, const cost_calculator *calc, const size_t width,
const size_t height,
const teleport_map *teleports) {
#endif
//----------------- PRE_CONDITIONS ------------------
assert(src.valid(width, height));
assert(dst.valid(width, height));
@ -147,6 +191,7 @@ pathfind::plain_route pathfind::a_star_search(const map_location& src, const map
return locRoute;
}
#ifndef EXPERIMENTAL
if (teleports && teleports->empty()) teleports = NULL;
std::vector<map_location> locs(teleports ? 6 + teleports->size() : 6 );
@ -154,6 +199,7 @@ pathfind::plain_route pathfind::a_star_search(const map_location& src, const map
std::copy(teleports->begin(), teleports->end(), locs.begin() + 6);
}
#endif
// increment search_counter but skip the range equivalent to uninitialized
search_counter += 2;
if (search_counter - bad_search_counter <= 1u)
@ -181,12 +227,35 @@ pathfind::plain_route pathfind::a_star_search(const map_location& src, const map
if (n.t >= nodes[index(dst)].g) break;
#ifdef EXPERIMENTAL
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;}
#endif
get_adjacent_tiles(n.curr, &locs[0]);
#ifndef EXPERIMENTAL
int i = teleports && teleports->count(n.curr) ? locs.size() : 6;
#endif
for (; i-- > 0;) {
if (!locs[i].valid(width, height)) continue;
#ifndef EXPERIMENTAL
#else
if (locs[i] == n.curr) continue;
#endif
node& next = nodes[index(locs[i])];
double thresh = (next.in - search_counter <= 1u) ? next.g : stop_at;

View file

@ -104,6 +104,7 @@ bool pathfind::enemy_zoc(unit_map const &units, std::vector<team> const &teams,
return false;
}
#ifndef EXPERIMENTAL
std::set<map_location> pathfind::get_teleport_locations(const unit &u,
const unit_map &units, const team &viewing_team,
bool see_all, bool ignore_units)
@ -127,6 +128,7 @@ std::set<map_location> pathfind::get_teleport_locations(const unit &u,
return res;
}
#endif
static unsigned search_counter;
namespace {
@ -193,16 +195,22 @@ 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];
#ifndef EXPERIMENTAL
std::set<map_location> teleports;
#else
pathfind::teleport_map teleports;
#endif
if (allow_teleport) {
teleports = pathfind::get_teleport_locations(u, units, viewing_team, see_all, ignore_units);
}
const int total_movement = u.total_movement();
#ifndef EXPERIMENTAL
std::vector<map_location> locs(6 + teleports.size());
std::copy(teleports.begin(), teleports.end(), locs.begin() + 6);
#endif
search_counter += 2;
if (search_counter == 0) search_counter = 2;
@ -224,10 +232,24 @@ static void find_routes(const gamemap& map, const unit_map& units,
pq.pop_back();
n.in = search_counter;
#ifdef EXPERIMENTAL
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);
#endif
get_adjacent_tiles(n.curr, &locs[0]);
#ifndef EXPERIMENTAL
for (int i = teleports.count(n.curr) ? locs.size() : 6; i-- > 0; ) {
#else
for (int i = locs.size(); i-- > 0; ) {
#endif
if (!locs[i].valid(map.w(), map.h())) continue;
#ifdef EXPERIMENTAL
if (locs[i] == n.curr) continue;
#endif
node& next = nodes[index(locs[i])];
bool next_visited = next.in - search_counter <= 1u;

View file

@ -26,6 +26,9 @@ class unit_movement_type;
#include "map_location.hpp"
#include "team.hpp"
#ifdef EXPERIMENTAL
#include "pathfind/teleport.hpp"
#endif
#include <map>
#include <list>
@ -35,6 +38,10 @@ class unit_movement_type;
namespace pathfind {
#ifdef EXPERIMENTAL
class teleport_map;
#endif
enum VACANT_TILE_TYPE { VACANT_CASTLE, VACANT_ANY };
/**
@ -53,10 +60,12 @@ bool enemy_zoc(unit_map const &units,
std::vector<team> const &teams, map_location const &loc,
team const &viewing_team, int side, bool see_all=false);
#ifndef EXPERIMENTAL
std::set<map_location> get_teleport_locations(const unit &u,
const unit_map &units, const team &viewing_team,
bool see_all = false, bool ignore_units = false);
#endif
struct cost_calculator
{
cost_calculator() {}
@ -81,7 +90,11 @@ 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
#ifndef EXPERIMENTAL
// - allow_teleport: indicates whether unit teleports between villages
#else
// - allow_teleport: indicates whether the paths should include teleportation (false for sight)
#endif
// - 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.
@ -146,9 +159,17 @@ struct plain_route
};
plain_route a_star_search(map_location const &src, map_location const &dst,
#ifndef EXPERIMENTAL
double stop_at, cost_calculator const* costCalculator,
#else
double stop_at, const cost_calculator* costCalculator,
#endif
const size_t parWidth, const size_t parHeight,
#ifndef EXPERIMENTAL
std::set<map_location> const *teleports = NULL);
#else
const teleport_map* teleports = NULL);
#endif
/**
* Add marks on a route @a rt assuming that a @unit u travels along it.
@ -214,7 +235,11 @@ struct dummy_path_calculator : cost_calculator
virtual double cost(const map_location& loc, const double so_far) const;
};
}
#ifndef EXPERIMENTAL
#endif
}
#ifndef EXPERIMENTAL
#endif
#endif

View file

@ -63,6 +63,9 @@ 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, undo_stack_, redo_stack_),
soundsources_manager_(),
tod_manager_(level, num_turns, &state_of_game),
#ifdef EXPERIMENTAL
pathfind_manager_(),
#endif
gui_(),
statistics_context_(level["name"]),
level_(level),
@ -117,6 +120,9 @@ play_controller::~play_controller()
resources::screen = NULL;
resources::soundsources = NULL;
resources::tod_manager = NULL;
#ifdef EXPERIMENTAL
resources::tunnels = NULL;
#endif
}
void play_controller::init(CVideo& video){
@ -245,8 +251,14 @@ 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_));
#ifdef EXPERIMENTAL
pathfind_manager_.reset(new pathfind::manager(level_));
#endif
resources::soundsources = soundsources_manager_.get();
#ifdef EXPERIMENTAL
resources::tunnels = pathfind_manager_.get();
#endif
halo_manager_.reset(new halo::manager(*gui_));
LOG_NG << "done initializing managers... " << (SDL_GetTicks() - ticks_) << "\n";
@ -611,6 +623,9 @@ config play_controller::to_config() const
//write out the current state of the map
cfg["map_data"] = map_.write();
#ifdef EXPERIMENTAL
cfg.merge_with(pathfind_manager_->to_config());
#endif
return cfg;
}
@ -897,15 +912,25 @@ void play_controller::process_keyup_event(const SDL_Event& event) {
const unit_map::iterator u = mouse_handler_.selected_unit();
if(u != units_.end()) {
#ifndef EXPERIMENTAL
bool teleport = u->second.get_ability_bool("teleport");
#endif
// if it's not the unit's turn, we reset its moves
unit_movement_resetter move_reset(u->second, u->second.side() != player_number_);
mouse_handler_.set_current_paths(pathfind::paths(map_,units_,u->first,
#ifndef EXPERIMENTAL
teams_,false,teleport, teams_[gui_->viewing_team()],
#else
teams_,false,true, teams_[gui_->viewing_team()],
#endif
mouse_handler_.get_path_turns()));
#ifndef EXPERIMENTAL
gui_->highlight_reach(mouse_handler_.current_paths());
#else
gui_->highlight_reach(mouse_handler_.get_current_paths());
#endif
}
}
}

View file

@ -194,6 +194,9 @@ protected:
events::menu_handler menu_handler_;
boost::scoped_ptr<soundsource::manager> soundsources_manager_;
tod_manager tod_manager_;
#ifdef EXPERIMENTAL
boost::scoped_ptr<pathfind::manager> pathfind_manager_;
#endif
//other objects
boost::scoped_ptr<game_display> gui_;

View file

@ -25,4 +25,7 @@ namespace resources
LuaKernel *lua_kernel;
play_controller *controller;
::tod_manager *tod_manager;
#ifdef EXPERIMENTAL
pathfind::manager *tunnels;
#endif
}

View file

@ -27,6 +27,9 @@ class tod_manager;
class unit_map;
namespace soundsource { class manager; }
#ifdef EXPERIMENTAL
namespace pathfind { class manager; }
#endif
namespace resources
{
@ -39,6 +42,9 @@ namespace resources
extern LuaKernel *lua_kernel;
extern play_controller *controller;
extern tod_manager *tod_manager;
#ifdef EXPERIMENTAL
extern pathfind::manager *tunnels;
#endif
}
#endif

View file

@ -1549,12 +1549,17 @@ static int intf_find_path(lua_State *L)
}
team &viewing_team = teams[viewing_side - 1];
#ifndef EXPERIMENTAL
std::set<map_location> teleport_locations;
if (!ignore_teleport) {
teleport_locations = pathfind::get_teleport_locations(
*u, units, viewing_team, see_all, ignore_units);
}
#else
const pathfind::teleport_map teleport_locations = !ignore_teleport ? pathfind::get_teleport_locations(
*u, units, viewing_team, see_all, ignore_units) : pathfind::teleport_map();
#endif
if (!calc) {
calc = new pathfind::shortest_path_calculator(*u, viewing_team,