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:
parent
7775ac8ad0
commit
e7ebf1fa0c
7 changed files with 241 additions and 43 deletions
183
src/actions.cpp
183
src/actions.cpp
|
@ -70,6 +70,86 @@ private:
|
|||
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
|
||||
// check_victory, but shouldn't be passed to that function as parameters,
|
||||
// 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,
|
||||
move_unit_spectator *move_spectator,
|
||||
const gamemap& map,
|
||||
unit_map& units, std::vector<team>& teams,
|
||||
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);
|
||||
if (enemy_unit != units.end()) {
|
||||
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?)
|
||||
should_clear_stack = true; // assuming that this enemy was hidden somehow
|
||||
break;
|
||||
} else if (!tiles_adjacent(*(step-1),*step)) {
|
||||
// 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;
|
||||
should_clear_stack = true; // we have info not supposed to be shared
|
||||
break;
|
||||
|
@ -2304,6 +2391,9 @@ size_t move_unit(game_display* disp,
|
|||
discovered_unit = true;
|
||||
should_clear_stack = true;
|
||||
moves_left = 0;
|
||||
if (move_spectator!=NULL) {
|
||||
move_spectator->set_ambusher(it);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
ui = units.find(steps.back());
|
||||
if (move_spectator!=NULL) {
|
||||
move_spectator->set_unit(ui);
|
||||
}
|
||||
|
||||
if(undo_stack != NULL) {
|
||||
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;
|
||||
|
||||
// Show messages on the screen here
|
||||
|
@ -2427,13 +2520,17 @@ size_t move_unit(game_display* disp,
|
|||
if (ambushed_string.empty())
|
||||
ambushed_string = _("Ambushed!");
|
||||
// We've been ambushed, display an appropriate message
|
||||
disp->announce(ambushed_string, font::BAD_COLOUR);
|
||||
if (disp!=NULL) {
|
||||
disp->announce(ambushed_string, font::BAD_COLOUR);
|
||||
}
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
if(teleport_failed) {
|
||||
std::string teleport_string = _ ("Failed teleport! Exit not empty");
|
||||
disp->announce(teleport_string, font::BAD_COLOUR);
|
||||
if (disp!=NULL) {
|
||||
disp->announce(teleport_string, font::BAD_COLOUR);
|
||||
}
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
|
@ -2453,56 +2550,68 @@ size_t move_unit(game_display* disp,
|
|||
|
||||
if(team.is_enemy(u->second.side())) {
|
||||
++nenemies;
|
||||
if (move_spectator!=NULL) {
|
||||
move_spectator->add_seen_enemy(u);
|
||||
}
|
||||
} else {
|
||||
++nfriends;
|
||||
if (move_spectator!=NULL) {
|
||||
move_spectator->add_seen_friend(u);
|
||||
}
|
||||
}
|
||||
|
||||
DBG_NG << "processed...\n";
|
||||
team.see(u->second.side()-1);
|
||||
}
|
||||
|
||||
// The message we display is different depending on
|
||||
// whether the units sighted were enemies or friends,
|
||||
// and their respective number.
|
||||
utils::string_map symbols;
|
||||
symbols["friends"] = lexical_cast<std::string>(nfriends);
|
||||
symbols["enemies"] = lexical_cast<std::string>(nenemies);
|
||||
std::string message;
|
||||
SDL_Color msg_colour;
|
||||
if(nfriends == 0 || nenemies == 0) {
|
||||
if(nfriends > 0) {
|
||||
message = vngettext("Friendly unit sighted", "$friends friendly units sighted", nfriends, symbols);
|
||||
msg_colour = font::GOOD_COLOUR;
|
||||
} else if(nenemies > 0) {
|
||||
message = vngettext("Enemy unit sighted!", "$enemies enemy units sighted!", nenemies, symbols);
|
||||
msg_colour = font::BAD_COLOUR;
|
||||
if (disp!=NULL) {
|
||||
// The message we display is different depending on
|
||||
// whether the units sighted were enemies or friends,
|
||||
// and their respective number.
|
||||
utils::string_map symbols;
|
||||
symbols["friends"] = lexical_cast<std::string>(nfriends);
|
||||
symbols["enemies"] = lexical_cast<std::string>(nenemies);
|
||||
std::string message;
|
||||
SDL_Color msg_colour;
|
||||
if(nfriends == 0 || nenemies == 0) {
|
||||
if(nfriends > 0) {
|
||||
message = vngettext("Friendly unit sighted", "$friends friendly units sighted", nfriends, symbols);
|
||||
msg_colour = font::GOOD_COLOUR;
|
||||
} else if(nenemies > 0) {
|
||||
message = vngettext("Enemy unit sighted!", "$enemies enemy units sighted!", nenemies, symbols);
|
||||
msg_colour = font::BAD_COLOUR;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
symbols["friendphrase"] = vngettext("Part of 'Units sighted! (...)' sentence^1 friendly", "$friends friendly", nfriends, symbols);
|
||||
symbols["enemyphrase"] = vngettext("Part of 'Units sighted! (...)' sentence^1 enemy", "$enemies enemy", nenemies, symbols);
|
||||
message = vgettext("Units sighted! ($friendphrase, $enemyphrase)", symbols);
|
||||
msg_colour = font::NORMAL_COLOUR;
|
||||
}
|
||||
|
||||
if(steps.size() < route.size()) {
|
||||
// See if the "Continue Move" action has an associated hotkey
|
||||
const hotkey::hotkey_item& hk = hotkey::get_hotkey(hotkey::HOTKEY_CONTINUE_MOVE);
|
||||
if(!hk.null()) {
|
||||
symbols["hotkey"] = hk.get_name();
|
||||
message += "\n" + vgettext("(press $hotkey to keep moving)", symbols);
|
||||
else {
|
||||
symbols["friendphrase"] = vngettext("Part of 'Units sighted! (...)' sentence^1 friendly", "$friends friendly", nfriends, symbols);
|
||||
symbols["enemyphrase"] = vngettext("Part of 'Units sighted! (...)' sentence^1 enemy", "$enemies enemy", nenemies, symbols);
|
||||
message = vgettext("Units sighted! ($friendphrase, $enemyphrase)", symbols);
|
||||
msg_colour = font::NORMAL_COLOUR;
|
||||
}
|
||||
}
|
||||
|
||||
disp->announce(message, msg_colour);
|
||||
redraw = true;
|
||||
if(steps.size() < route.size()) {
|
||||
// See if the "Continue Move" action has an associated hotkey
|
||||
const hotkey::hotkey_item& hk = hotkey::get_hotkey(hotkey::HOTKEY_CONTINUE_MOVE);
|
||||
if(!hk.null()) {
|
||||
symbols["hotkey"] = hk.get_name();
|
||||
message += "\n" + vgettext("(press $hotkey to keep moving)", symbols);
|
||||
}
|
||||
}
|
||||
|
||||
disp->announce(message, msg_colour);
|
||||
redraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (redraw) {
|
||||
// Not sure why this would be needed. Maybe during replays?
|
||||
disp->draw();
|
||||
if (disp!=NULL) {
|
||||
disp->draw();
|
||||
}
|
||||
}
|
||||
if (disp!=NULL) {
|
||||
disp->recalculate_minimap();
|
||||
}
|
||||
disp->recalculate_minimap();
|
||||
}
|
||||
|
||||
assert(steps.size() <= route.size());
|
||||
|
|
|
@ -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
|
||||
* 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.
|
||||
*/
|
||||
size_t move_unit(game_display* disp,
|
||||
move_unit_spectator* move_spectator,
|
||||
const gamemap& map,
|
||||
unit_map& units, std::vector<team>& teams,
|
||||
std::vector<map_location> steps,
|
||||
|
|
|
@ -306,6 +306,7 @@ move_result::move_result(side_number side, const map_location& from,
|
|||
const map_location& to, bool remove_movement)
|
||||
: action_result(side)
|
||||
, from_(from)
|
||||
, move_spectator(get_info().units)
|
||||
, to_(to)
|
||||
, remove_movement_(remove_movement)
|
||||
, 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)
|
||||
{
|
||||
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);
|
||||
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
|
||||
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()
|
||||
|
@ -390,6 +391,20 @@ const map_location& move_result::get_unit_location() const
|
|||
|
||||
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(
|
||||
/*game_display* disp*/ &info.disp,
|
||||
/*move_unit_spectator* move_spectator*/ &move_spectator,
|
||||
/*const gamemap& map*/ info.map,
|
||||
/*unit_map& units*/ info.units,
|
||||
/*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 should_clear_shroud*/ true,
|
||||
/*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();
|
||||
manager::raise_unit_moved();
|
||||
|
||||
|
@ -437,6 +460,7 @@ void move_result::do_execute()
|
|||
|
||||
void move_result::do_init_for_execution()
|
||||
{
|
||||
move_spectator.reset(get_info().units);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -166,6 +166,9 @@ public:
|
|||
static const int E_NO_UNIT = 2002;
|
||||
static const int E_NOT_OWN_UNIT = 2003;
|
||||
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 const map_location& get_unit_location() const;
|
||||
protected:
|
||||
|
@ -177,6 +180,7 @@ private:
|
|||
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);
|
||||
const map_location from_;
|
||||
move_unit_spectator move_spectator;
|
||||
const map_location to_;
|
||||
bool remove_movement_;
|
||||
plain_route route_;
|
||||
|
|
|
@ -1565,7 +1565,7 @@ private:
|
|||
assert(route.steps.front() == ui->first);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -517,7 +517,7 @@ bool mouse_handler::move_unit_along_current_route(bool check_shroud, bool attack
|
|||
attackmove_ = attackmove;
|
||||
size_t moves = 0;
|
||||
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);
|
||||
} catch(end_turn_exception&) {
|
||||
attackmove_ = false;
|
||||
|
|
|
@ -1057,7 +1057,7 @@ bool do_replay_handle(game_display& disp, const gamemap& map,
|
|||
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
|
||||
// (supposed to be the human player in SP)
|
||||
|
|
Loading…
Add table
Reference in a new issue