move_unit_spectator

collect info about allies/enemies/ambushers/failed_teleports/bugs/etc
spotted during a move, for the AI to use
This commit is contained in:
Iurii Chernyi 2009-07-09 10:36:19 +00:00
parent 7775ac8ad0
commit e7ebf1fa0c
7 changed files with 241 additions and 43 deletions

View file

@ -70,6 +70,86 @@ private:
const gamemap& map_; const gamemap& map_;
}; };
void move_unit_spectator::add_seen_friend(const unit_map::const_iterator &u)
{
seen_friends_.push_back(u);
}
void move_unit_spectator::add_seen_enemy(const unit_map::const_iterator &u)
{
seen_enemies_.push_back(u);
}
const unit_map::const_iterator& move_unit_spectator::get_ambusher() const
{
return ambusher_;
}
const unit_map::const_iterator& move_unit_spectator::get_failed_teleport() const
{
return failed_teleport_;
}
const std::vector<unit_map::const_iterator>& move_unit_spectator::get_seen_enemies() const
{
return seen_enemies_;
}
const std::vector<unit_map::const_iterator>& move_unit_spectator::get_seen_friends() const
{
return seen_friends_;
}
const unit_map::const_iterator& move_unit_spectator::get_unit() const
{
return unit_;
}
move_unit_spectator::move_unit_spectator(const unit_map &units)
: ambusher_(units.end()),failed_teleport_(units.end()),seen_enemies_(),seen_friends_(),unit_(units.end())
{
}
move_unit_spectator::~move_unit_spectator()
{
}
void move_unit_spectator::reset(const unit_map &units)
{
ambusher_ = units.end();
failed_teleport_ = units.end();
seen_enemies_.clear();
seen_friends_.clear();
unit_ = units.end();
}
void move_unit_spectator::set_ambusher(const unit_map::const_iterator &u)
{
ambusher_ = u;
}
void move_unit_spectator::set_failed_teleport(const unit_map::const_iterator &u)
{
failed_teleport_ = u;
}
void move_unit_spectator::set_unit(const unit_map::const_iterator &u)
{
unit_ = u;
}
// Conditions placed on victory must be accessible from the global function // Conditions placed on victory must be accessible from the global function
// check_victory, but shouldn't be passed to that function as parameters, // check_victory, but shouldn't be passed to that function as parameters,
// since it is called from a variety of places. // since it is called from a variety of places.
@ -2177,6 +2257,7 @@ bool clear_shroud(game_display& disp, const gamemap& map,
} }
size_t move_unit(game_display* disp, size_t move_unit(game_display* disp,
move_unit_spectator *move_spectator,
const gamemap& map, const gamemap& map,
unit_map& units, std::vector<team>& teams, unit_map& units, std::vector<team>& teams,
std::vector<map_location> route, std::vector<map_location> route,
@ -2239,11 +2320,17 @@ size_t move_unit(game_display* disp,
const unit_map::const_iterator enemy_unit = units.find(*step); const unit_map::const_iterator enemy_unit = units.find(*step);
if (enemy_unit != units.end()) { if (enemy_unit != units.end()) {
if (team.is_enemy(enemy_unit->second.side())) { if (team.is_enemy(enemy_unit->second.side())) {
if (move_spectator!=NULL) {
move_spectator->set_ambusher(enemy_unit);
}
// can't traverse enemy (bug in fog or pathfinding?) // can't traverse enemy (bug in fog or pathfinding?)
should_clear_stack = true; // assuming that this enemy was hidden somehow should_clear_stack = true; // assuming that this enemy was hidden somehow
break; break;
} else if (!tiles_adjacent(*(step-1),*step)) { } else if (!tiles_adjacent(*(step-1),*step)) {
// can't teleport on ally (on fogged village, with no-leader and view not-shared) // can't teleport on ally (on fogged village, with no-leader and view not-shared)
if (move_spectator!=NULL) {
move_spectator->set_failed_teleport(enemy_unit);
}
teleport_failed = true; teleport_failed = true;
should_clear_stack = true; // we have info not supposed to be shared should_clear_stack = true; // we have info not supposed to be shared
break; break;
@ -2304,6 +2391,9 @@ size_t move_unit(game_display* disp,
discovered_unit = true; discovered_unit = true;
should_clear_stack = true; should_clear_stack = true;
moves_left = 0; moves_left = 0;
if (move_spectator!=NULL) {
move_spectator->set_ambusher(it);
}
unit_ability_list hides = it->second.get_abilities("hides"); unit_ability_list hides = it->second.get_abilities("hides");
@ -2408,6 +2498,9 @@ size_t move_unit(game_display* disp,
event_mutated |= game_events::pump(); event_mutated |= game_events::pump();
ui = units.find(steps.back()); ui = units.find(steps.back());
if (move_spectator!=NULL) {
move_spectator->set_unit(ui);
}
if(undo_stack != NULL) { if(undo_stack != NULL) {
if(event_mutated || should_clear_stack || ui == units.end()) { if(event_mutated || should_clear_stack || ui == units.end()) {
@ -2419,7 +2512,7 @@ size_t move_unit(game_display* disp,
} }
} }
if(disp != NULL) { if ( (disp != NULL) || (move_spectator!=NULL) ) {
bool redraw = false; bool redraw = false;
// Show messages on the screen here // Show messages on the screen here
@ -2427,13 +2520,17 @@ size_t move_unit(game_display* disp,
if (ambushed_string.empty()) if (ambushed_string.empty())
ambushed_string = _("Ambushed!"); ambushed_string = _("Ambushed!");
// We've been ambushed, display an appropriate message // We've been ambushed, display an appropriate message
if (disp!=NULL) {
disp->announce(ambushed_string, font::BAD_COLOUR); disp->announce(ambushed_string, font::BAD_COLOUR);
}
redraw = true; redraw = true;
} }
if(teleport_failed) { if(teleport_failed) {
std::string teleport_string = _ ("Failed teleport! Exit not empty"); std::string teleport_string = _ ("Failed teleport! Exit not empty");
if (disp!=NULL) {
disp->announce(teleport_string, font::BAD_COLOUR); disp->announce(teleport_string, font::BAD_COLOUR);
}
redraw = true; redraw = true;
} }
@ -2453,14 +2550,21 @@ size_t move_unit(game_display* disp,
if(team.is_enemy(u->second.side())) { if(team.is_enemy(u->second.side())) {
++nenemies; ++nenemies;
if (move_spectator!=NULL) {
move_spectator->add_seen_enemy(u);
}
} else { } else {
++nfriends; ++nfriends;
if (move_spectator!=NULL) {
move_spectator->add_seen_friend(u);
}
} }
DBG_NG << "processed...\n"; DBG_NG << "processed...\n";
team.see(u->second.side()-1); team.see(u->second.side()-1);
} }
if (disp!=NULL) {
// The message we display is different depending on // The message we display is different depending on
// whether the units sighted were enemies or friends, // whether the units sighted were enemies or friends,
// and their respective number. // and their respective number.
@ -2497,13 +2601,18 @@ size_t move_unit(game_display* disp,
disp->announce(message, msg_colour); disp->announce(message, msg_colour);
redraw = true; redraw = true;
} }
}
if (redraw) { if (redraw) {
// Not sure why this would be needed. Maybe during replays? // Not sure why this would be needed. Maybe during replays?
if (disp!=NULL) {
disp->draw(); disp->draw();
} }
}
if (disp!=NULL) {
disp->recalculate_minimap(); disp->recalculate_minimap();
} }
}
assert(steps.size() <= route.size()); assert(steps.size() <= route.size());

View file

@ -227,6 +227,66 @@ class attack {
}; };
class move_unit_spectator {
public:
/** add a location of a seen friend */
void add_seen_friend(const unit_map::const_iterator &u);
/** add the location of new seen enemy */
void add_seen_enemy(const unit_map::const_iterator &u);
/** get the location of an ambusher */
const unit_map::const_iterator& get_ambusher() const;
/** get the location of a failed teleport */
const unit_map::const_iterator& get_failed_teleport() const;
/** get the locations of seen enemies */
const std::vector<unit_map::const_iterator>& get_seen_enemies() const;
/** get the locations of seen friends */
const std::vector<unit_map::const_iterator>& get_seen_friends() const;
/** get new location of moved unit */
const unit_map::const_iterator& get_unit() const;
/** constructor */
move_unit_spectator(const unit_map &units);
/** destructor */
virtual ~move_unit_spectator();
/** reset all locations to empty values*/
void reset(const unit_map &units);
/** set the location of an ambusher */
void set_ambusher(const unit_map::const_iterator &u);
/** set the location of a failed teleport */
void set_failed_teleport(const unit_map::const_iterator &u);
/** set the iterator to moved unit*/
void set_unit(const unit_map::const_iterator &u);
private:
unit_map::const_iterator ambusher_;
unit_map::const_iterator failed_teleport_;
std::vector<unit_map::const_iterator> seen_enemies_;
std::vector<unit_map::const_iterator> seen_friends_;
unit_map::const_iterator unit_;
};
/** /**
* Given the location of a village, will return the 0-based index * Given the location of a village, will return the 0-based index
* of the team that currently owns it, and -1 if it is unowned. * of the team that currently owns it, and -1 if it is unowned.
@ -360,6 +420,7 @@ typedef std::deque<undo_action> undo_list;
* If undos is not NULL, undo information will be added. * If undos is not NULL, undo information will be added.
*/ */
size_t move_unit(game_display* disp, size_t move_unit(game_display* disp,
move_unit_spectator* move_spectator,
const gamemap& map, const gamemap& map,
unit_map& units, std::vector<team>& teams, unit_map& units, std::vector<team>& teams,
std::vector<map_location> steps, std::vector<map_location> steps,

View file

@ -306,6 +306,7 @@ move_result::move_result(side_number side, const map_location& from,
const map_location& to, bool remove_movement) const map_location& to, bool remove_movement)
: action_result(side) : action_result(side)
, from_(from) , from_(from)
, move_spectator(get_info().units)
, to_(to) , to_(to)
, remove_movement_(remove_movement) , remove_movement_(remove_movement)
, route_() , route_()
@ -336,7 +337,7 @@ const unit *move_result::get_unit(const unit_map &units, const std::vector<team>
bool move_result::test_route(const unit &un, const team &my_team, const unit_map &units, const std::vector<team> &teams, const gamemap &map, bool) bool move_result::test_route(const unit &un, const team &my_team, const unit_map &units, const std::vector<team> &teams, const gamemap &map, bool)
{ {
if (from_==to_) { if (from_==to_) {//@todo 1.7 move is ok in this case if remove_movement_ is set and movement_left is >0
set_error(E_EMPTY_MOVE); set_error(E_EMPTY_MOVE);
return false; return false;
} }
@ -349,7 +350,7 @@ bool move_result::test_route(const unit &un, const team &my_team, const unit_map
//do an A*-search //do an A*-search
route_ = a_star_search(un.get_location(), to_, 10000.0, &calc, map.w(), map.h(), &allowed_teleports); route_ = a_star_search(un.get_location(), to_, 10000.0, &calc, map.w(), map.h(), &allowed_teleports);
return true; return true;//@todo 1.7 do some tests on returned route
} }
void move_result::do_check_before() void move_result::do_check_before()
@ -390,6 +391,20 @@ const map_location& move_result::get_unit_location() const
void move_result::do_check_after() void move_result::do_check_after()
{ {
if (move_spectator.get_ambusher().valid()) {
set_error(E_AMBUSHED);
return;
}
if (move_spectator.get_failed_teleport().valid()) {
set_error(E_FAILED_TELEPORT);
return;
}
//@todo 1.7 add 'new units spotted' failure mode
if (unit_location_!=to_) {
set_error(E_NOT_REACHED_DESTINATION);
return;
}
} }
@ -418,6 +433,7 @@ void move_result::do_execute()
move_unit( move_unit(
/*game_display* disp*/ &info.disp, /*game_display* disp*/ &info.disp,
/*move_unit_spectator* move_spectator*/ &move_spectator,
/*const gamemap& map*/ info.map, /*const gamemap& map*/ info.map,
/*unit_map& units*/ info.units, /*unit_map& units*/ info.units,
/*std::vector<team>& teams*/ info.teams, /*std::vector<team>& teams*/ info.teams,
@ -428,7 +444,14 @@ void move_result::do_execute()
/*bool continue_move*/ true, //@todo: 1.7 set to false after implemeting interrupt awareness /*bool continue_move*/ true, //@todo: 1.7 set to false after implemeting interrupt awareness
/*bool should_clear_shroud*/ true, /*bool should_clear_shroud*/ true,
/*bool is_replay*/ false); /*bool is_replay*/ false);
unit_location_ = to_;//@todo: 1.7 modify move_unit to get this info from it
if (move_spectator.get_unit().valid()){
unit_location_ = move_spectator.get_unit()->first;
} else {
unit_location_ = map_location();
}
set_gamestate_changed(); set_gamestate_changed();
manager::raise_unit_moved(); manager::raise_unit_moved();
@ -437,6 +460,7 @@ void move_result::do_execute()
void move_result::do_init_for_execution() void move_result::do_init_for_execution()
{ {
move_spectator.reset(get_info().units);
} }

View file

@ -166,6 +166,9 @@ public:
static const int E_NO_UNIT = 2002; static const int E_NO_UNIT = 2002;
static const int E_NOT_OWN_UNIT = 2003; static const int E_NOT_OWN_UNIT = 2003;
static const int E_INCAPACITATED_UNIT = 2004; static const int E_INCAPACITATED_UNIT = 2004;
static const int E_AMBUSHED = 2005;
static const int E_FAILED_TELEPORT = 2006;
static const int E_NOT_REACHED_DESTINATION = 2007;
virtual std::string do_describe() const; virtual std::string do_describe() const;
virtual const map_location& get_unit_location() const; virtual const map_location& get_unit_location() const;
protected: protected:
@ -177,6 +180,7 @@ private:
const unit *get_unit(const unit_map &units, const std::vector<team> &teams, bool update_knowledge = false); const unit *get_unit(const unit_map &units, const std::vector<team> &teams, bool update_knowledge = false);
bool test_route(const unit &un, const team &my_team, const unit_map &units, const std::vector<team> &teams, const gamemap &map, bool update_knowledge = false); bool test_route(const unit &un, const team &my_team, const unit_map &units, const std::vector<team> &teams, const gamemap &map, bool update_knowledge = false);
const map_location from_; const map_location from_;
move_unit_spectator move_spectator;
const map_location to_; const map_location to_;
bool remove_movement_; bool remove_movement_;
plain_route route_; plain_route route_;

View file

@ -1565,7 +1565,7 @@ private:
assert(route.steps.front() == ui->first); assert(route.steps.front() == ui->first);
gui_->set_route(&route); gui_->set_route(&route);
move_unit(gui_,map_,units_,teams_,route.steps,&recorder,&undo_stack_,NULL,continue_move); move_unit(gui_,NULL,map_,units_,teams_,route.steps,&recorder,&undo_stack_,NULL,continue_move);
gui_->invalidate_game_status(); gui_->invalidate_game_status();
} }

View file

@ -517,7 +517,7 @@ bool mouse_handler::move_unit_along_current_route(bool check_shroud, bool attack
attackmove_ = attackmove; attackmove_ = attackmove;
size_t moves = 0; size_t moves = 0;
try{ try{
moves = ::move_unit(&gui(),map_,units_,teams_, moves = ::move_unit(&gui(),NULL,map_,units_,teams_,
steps,&recorder,&undo_stack_,&next_unit_,false,check_shroud); steps,&recorder,&undo_stack_,&next_unit_,false,check_shroud);
} catch(end_turn_exception&) { } catch(end_turn_exception&) {
attackmove_ = false; attackmove_ = false;

View file

@ -1057,7 +1057,7 @@ bool do_replay_handle(game_display& disp, const gamemap& map,
replay::throw_error(errbuf.str()); replay::throw_error(errbuf.str());
} }
::move_unit(&disp, map, units, teams, steps, NULL, NULL, NULL, true, true, true); ::move_unit(&disp, NULL, map, units, teams, steps, NULL, NULL, NULL, true, true, true);
//NOTE: The AI fire sighetd event whem moving in the FoV of team 1 //NOTE: The AI fire sighetd event whem moving in the FoV of team 1
// (supposed to be the human player in SP) // (supposed to be the human player in SP)