AI Refactoring: new AI base recruit command,
...with more strict error checking and ability to take subjective AI knowledge about the game state into account. (not yet used, just added)
This commit is contained in:
parent
b42d20ce14
commit
441949239e
5 changed files with 462 additions and 67 deletions
|
@ -17,8 +17,30 @@
|
|||
* @file ai/ai_actions.cpp
|
||||
*/
|
||||
|
||||
/**
|
||||
* A small explanation about what's going on here:
|
||||
* Each action has access to two ai_interface::info objects
|
||||
* First is 'info' - real information
|
||||
* Second is 'subjective info' - AIs perception of what's going on
|
||||
* So, when we check_before action, we use 'subjective info' and don't
|
||||
* touch real 'info' at all.
|
||||
* But when we actually want to execute an action, we firstly check
|
||||
* 'subjective info' and then (if subjective check is ok) do the same
|
||||
* check on real 'info'. There's a caveat: if we fail an action based
|
||||
* on real 'info', then we NEED to update AIs knowlegge to avoid the ai
|
||||
* doing the same thing again.
|
||||
* So far the use of 'subjective info' is stubbed out.
|
||||
*/
|
||||
|
||||
#include "ai_actions.hpp"
|
||||
#include "ai_manager.hpp"
|
||||
#include "../actions.hpp"
|
||||
#include "../game_preferences.hpp"
|
||||
#include "../log.hpp"
|
||||
#include "../pathfind.hpp"
|
||||
#include "../replay.hpp"
|
||||
#include "../statistics.hpp"
|
||||
|
||||
|
||||
#define DBG_AI_ACTIONS LOG_STREAM(debug, ai_actions)
|
||||
#define LOG_AI_ACTIONS LOG_STREAM(info, ai_actions)
|
||||
|
@ -28,14 +50,15 @@
|
|||
// =======================================================================
|
||||
// AI ACTIONS
|
||||
// =======================================================================
|
||||
ai_action_result::ai_action_result()
|
||||
ai_action_result::ai_action_result( unsigned int side )
|
||||
: return_value_checked_(true),side_(side),status_(AI_ACTION_SUCCESS),is_execution_(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ai_action_result::~ai_action_result()
|
||||
{
|
||||
if (tried_ && !return_value_checked_) {
|
||||
if (!return_value_checked_) {
|
||||
ERR_AI_ACTIONS << "Return value of AI ACTION was not checked. This may cause bugs!" << std::endl;
|
||||
}
|
||||
}
|
||||
|
@ -49,33 +72,26 @@ void ai_action_result::check_after()
|
|||
|
||||
void ai_action_result::check_before()
|
||||
{
|
||||
init_for_check_before();
|
||||
do_check_before();
|
||||
}
|
||||
|
||||
|
||||
void ai_action_result::execute()
|
||||
{
|
||||
is_execution_ = true;
|
||||
init_for_execution();
|
||||
check_before();
|
||||
if (is_success()){
|
||||
init_for_execution();
|
||||
do_execute();
|
||||
}
|
||||
if (is_success()){
|
||||
check_after();
|
||||
}
|
||||
is_execution_ = false;
|
||||
}
|
||||
|
||||
|
||||
void ai_action_result::init_for_check_before()
|
||||
{
|
||||
do_init_for_check_before();
|
||||
}
|
||||
|
||||
|
||||
void ai_action_result::init_for_execution()
|
||||
{
|
||||
tried_ = true;
|
||||
return_value_checked_ = false;
|
||||
status_ = ai_action_result::AI_ACTION_STARTED;
|
||||
do_init_for_execution();
|
||||
|
@ -88,13 +104,57 @@ bool ai_action_result::is_ok()
|
|||
return is_success();
|
||||
}
|
||||
|
||||
|
||||
void ai_action_result::set_error(int error_code){
|
||||
status_ = error_code;
|
||||
}
|
||||
|
||||
|
||||
bool ai_action_result::is_success()
|
||||
{
|
||||
return (status_ == ai_action_result::AI_ACTION_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
bool ai_action_result::is_execution()
|
||||
{
|
||||
return is_execution_;
|
||||
}
|
||||
|
||||
|
||||
unsigned int ai_action_result::get_side()
|
||||
{
|
||||
return side_;
|
||||
}
|
||||
|
||||
|
||||
ai_interface::info& ai_action_result::get_info()
|
||||
{
|
||||
return ai_manager::get_active_ai_info_for_side(get_side());
|
||||
}
|
||||
|
||||
|
||||
ai_interface::info& ai_action_result::get_subjective_info()
|
||||
{
|
||||
return get_info();
|
||||
}
|
||||
|
||||
|
||||
bool ai_action_result::using_subjective_info()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
team& ai_action_result::get_my_team(ai_interface::info info)
|
||||
{
|
||||
return info.teams[side_-1];
|
||||
}
|
||||
|
||||
// ai_attack_result
|
||||
ai_attack_result::ai_attack_result( unsigned int side, const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon)
|
||||
: ai_action_result(side), attacker_loc_(attacker_loc), defender_loc_(defender_loc), attacker_weapon_(attacker_weapon){
|
||||
}
|
||||
|
||||
void ai_attack_result::do_check_before()
|
||||
{
|
||||
|
@ -111,17 +171,15 @@ void ai_attack_result::do_execute()
|
|||
}
|
||||
|
||||
|
||||
void ai_attack_result::do_init_for_check_before()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void ai_attack_result::do_init_for_execution()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// ai_move_result
|
||||
ai_move_result::ai_move_result( unsigned int side, const map_location& from, const map_location& to, bool remove_movement)
|
||||
: ai_action_result(side), from_(from), to_(to), remove_movement_(remove_movement){
|
||||
}
|
||||
|
||||
void ai_move_result::do_check_before()
|
||||
{
|
||||
|
@ -138,35 +196,198 @@ void ai_move_result::do_execute()
|
|||
}
|
||||
|
||||
|
||||
void ai_move_result::do_init_for_check_before()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void ai_move_result::do_init_for_execution()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// ai_recruit_result
|
||||
ai_recruit_result::ai_recruit_result( unsigned int side, const std::string& unit_name, const map_location& where)
|
||||
: ai_action_result(side), unit_name_(unit_name), where_(where), recruit_location_(where){
|
||||
}
|
||||
|
||||
bool ai_recruit_result::test_available_for_recruiting( const team& team, std::set<std::string>::const_iterator& recruit, bool /*update_knowledge*/ )
|
||||
{
|
||||
const std::set<std::string>& recruit_set = team.recruits();
|
||||
recruit = recruit_set.find(unit_name_);
|
||||
if(recruit == recruit_set.end()) {
|
||||
set_error(E_NOT_AVAILABLE_FOR_RECRUITING);
|
||||
return false;
|
||||
}
|
||||
num_ = std::distance(recruit_set.begin(),recruit);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ai_recruit_result::test_unit_type_known( const std::set<std::string>::const_iterator& recruit, unit_type_data::unit_type_map::const_iterator& unit_type, bool /*update_knowledge*/ )
|
||||
{
|
||||
unit_type = unit_type_data::types().find_unit_type(*recruit);
|
||||
if(unit_type == unit_type_data::types().end() || unit_type->first == "dummy_unit") {
|
||||
set_error(E_UNKNOWN_OR_DUMMY_UNIT_TYPE);
|
||||
return false;
|
||||
}
|
||||
unit_type_ = &unit_type;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ai_recruit_result::test_enough_gold( const team& team, const unit_type_data::unit_type_map::const_iterator& unit_type, bool /*update_knowledge*/ )
|
||||
{
|
||||
if(team.gold() < unit_type->second.cost()) {
|
||||
set_error(E_NO_GOLD);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ai_recruit_result::test_leader_present( const unit_map& units, unit_map::const_iterator& my_leader, bool /*update_knowledge*/ )
|
||||
{
|
||||
my_leader = find_leader(units,get_side());
|
||||
if (my_leader == units.end()){
|
||||
set_error(E_NO_LEADER);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool ai_recruit_result::test_leader_on_keep( const gamemap& map, const unit_map::const_iterator& my_leader, bool /*update_knowledge*/ )
|
||||
{
|
||||
if (!map.is_keep(my_leader->first)){
|
||||
set_error(E_LEADER_NOT_ON_KEEP);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ai_recruit_result::test_suitable_recruit_location( const gamemap& map, const unit_map& units, const unit_map::const_iterator& my_leader, bool /*update_knowledge*/ )
|
||||
{
|
||||
recruit_location_ = where_;
|
||||
|
||||
//if we have not-on-board location, such as null_location, then the caller wants us to recruit on 'any' possible tile.
|
||||
if(!map.on_board(recruit_location_)) {
|
||||
recruit_location_ = find_vacant_tile(map,units,my_leader->first, VACANT_CASTLE);
|
||||
}
|
||||
|
||||
if (!can_recruit_on(map,my_leader->first,recruit_location_)){
|
||||
set_error(E_BAD_RECRUIT_LOCATION);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ai_recruit_result::do_check_before()
|
||||
{
|
||||
const ai_interface::info& s_info = get_subjective_info();
|
||||
const ai_interface::info& info = get_info();
|
||||
|
||||
const unit_map& s_units = s_info.units;
|
||||
const unit_map& units = info.units;
|
||||
|
||||
const team& s_team = get_my_team(s_info);
|
||||
const team& team = get_my_team(info);
|
||||
|
||||
//Unit available for recruiting?
|
||||
std::set<std::string>::const_iterator s_recruit;
|
||||
std::set<std::string>::const_iterator recruit;
|
||||
|
||||
if ( !test_available_for_recruiting(s_team,s_recruit) ||
|
||||
( is_execution() && using_subjective_info() &&
|
||||
!test_available_for_recruiting(team,recruit,true) ) ){
|
||||
return;
|
||||
}
|
||||
|
||||
//Unit type known ?
|
||||
unit_type_data::unit_type_map::const_iterator s_unit_type;
|
||||
unit_type_data::unit_type_map::const_iterator unit_type;
|
||||
|
||||
if ( !test_unit_type_known(s_recruit,s_unit_type) ||
|
||||
( is_execution() && using_subjective_info() &&
|
||||
!test_unit_type_known(recruit,s_unit_type,true) ) ){
|
||||
return;
|
||||
}
|
||||
|
||||
//Enough gold?
|
||||
if (!test_enough_gold(s_team,s_unit_type) ||
|
||||
( is_execution() && using_subjective_info() &&
|
||||
!test_enough_gold(team,unit_type,true) ) ){
|
||||
return;
|
||||
}
|
||||
|
||||
//Leader present?
|
||||
unit_map::const_iterator s_my_leader;
|
||||
unit_map::const_iterator my_leader;
|
||||
|
||||
if (!test_leader_present(s_units,s_my_leader) ||
|
||||
( is_execution() && using_subjective_info() &&
|
||||
!test_leader_present(units,my_leader,true) ) ){
|
||||
return;
|
||||
}
|
||||
|
||||
//Leader on keep?
|
||||
const gamemap& s_map = s_info.map;
|
||||
const gamemap& map = info.map;
|
||||
|
||||
if (!test_leader_on_keep(s_map,s_my_leader) ||
|
||||
( is_execution() && using_subjective_info() &&
|
||||
!test_leader_on_keep(map,my_leader,true) ) ){
|
||||
return;
|
||||
}
|
||||
|
||||
//Try to get suitable recruit location. Is suitable location available ?
|
||||
if (!test_suitable_recruit_location(s_map,s_units,s_my_leader) ||
|
||||
( is_execution() && using_subjective_info() &&
|
||||
!test_suitable_recruit_location(map,units,my_leader,true) ) ){
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ai_recruit_result::do_check_after()
|
||||
{
|
||||
const ai_interface::info& info = get_info();
|
||||
const gamemap& map = info.map;
|
||||
if (!map.on_board(recruit_location_)){
|
||||
set_error(AI_ACTION_FAILURE);
|
||||
}
|
||||
|
||||
const unit_map& units = info.units;
|
||||
unit_map::const_iterator unit = units.find(recruit_location_);
|
||||
if (unit==units.end()){
|
||||
set_error(AI_ACTION_FAILURE);
|
||||
}
|
||||
if (unit->second.side()!=get_side()){
|
||||
set_error(AI_ACTION_FAILURE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ai_recruit_result::do_execute()
|
||||
{
|
||||
}
|
||||
assert(is_success());
|
||||
const ai_interface::info& info = get_info();
|
||||
const team& team = get_my_team(info);
|
||||
// We have to add the recruit command now, because when the unit
|
||||
// is created it has to have the recruit command in the recorder
|
||||
// to be able to put random numbers into to generate unit traits.
|
||||
// However, we're not sure if the transaction will be successful,
|
||||
// so use a replay_undo object to cancel it if we don't get
|
||||
// a confirmation for the transaction.
|
||||
recorder.add_recruit(num_,recruit_location_);
|
||||
replay_undo replay_guard(recorder);
|
||||
unit new_unit(&get_info().units,&get_info().map,&get_info().state,&get_info().teams,&(*unit_type_)->second,get_side(),true);
|
||||
std::string recruit_err = recruit_unit(get_info().map,get_side(),get_info().units,new_unit,recruit_location_,false,preferences::show_ai_moves());
|
||||
if(recruit_err.empty()) {
|
||||
statistics::recruit_unit(new_unit);
|
||||
get_my_team(info).spend_gold((*unit_type_)->second.cost());
|
||||
// Confirm the transaction - i.e. don't undo recruitment
|
||||
replay_guard.confirm_transaction();
|
||||
ai_manager::raise_unit_recruited();
|
||||
} else {
|
||||
set_error(AI_ACTION_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
void ai_recruit_result::do_init_for_check_before()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
@ -176,6 +397,10 @@ void ai_recruit_result::do_init_for_execution()
|
|||
|
||||
|
||||
// ai_stopunit_result
|
||||
ai_stopunit_result::ai_stopunit_result( unsigned int side, const map_location& unit_location, bool remove_movement, bool remove_attacks)
|
||||
: ai_action_result(side), unit_location_(unit_location), remove_movement_(remove_movement), remove_attacks_(remove_attacks)
|
||||
{
|
||||
}
|
||||
|
||||
void ai_stopunit_result::do_check_before()
|
||||
{
|
||||
|
@ -192,11 +417,6 @@ void ai_stopunit_result::do_execute()
|
|||
}
|
||||
|
||||
|
||||
void ai_stopunit_result::do_init_for_check_before()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void ai_stopunit_result::do_init_for_execution()
|
||||
{
|
||||
}
|
||||
|
@ -206,50 +426,50 @@ void ai_stopunit_result::do_init_for_execution()
|
|||
// STATELESS INTERFACE TO AI ACTIONS
|
||||
// =======================================================================
|
||||
|
||||
std::auto_ptr< ai_attack_result > ai_actions::execute_attack_action( int /*side*/,
|
||||
std::auto_ptr< ai_attack_result > ai_actions::execute_attack_action( unsigned int side,
|
||||
bool execute,
|
||||
const map_location& /*attacker_loc*/,
|
||||
const map_location& /*defender_loc*/,
|
||||
int /*attacks*/)
|
||||
const map_location& attacker_loc,
|
||||
const map_location& defender_loc,
|
||||
int attacker_weapon)
|
||||
{
|
||||
std::auto_ptr< ai_attack_result > ai_action(new ai_attack_result());
|
||||
std::auto_ptr< ai_attack_result > ai_action(new ai_attack_result(side,attacker_loc,defender_loc,attacker_weapon));
|
||||
execute ? ai_action->execute() : ai_action->check_before();
|
||||
return ai_action;
|
||||
}
|
||||
|
||||
|
||||
std::auto_ptr< ai_move_result > ai_actions::execute_move_action( int /*side*/,
|
||||
std::auto_ptr< ai_move_result > ai_actions::execute_move_action( unsigned int side,
|
||||
bool execute,
|
||||
const map_location& /*from*/,
|
||||
const map_location& /*to*/,
|
||||
bool /*remove_movement*/)
|
||||
const map_location& from,
|
||||
const map_location& to,
|
||||
bool remove_movement)
|
||||
{
|
||||
std::auto_ptr< ai_move_result > ai_action(new ai_move_result());
|
||||
std::auto_ptr< ai_move_result > ai_action(new ai_move_result(side,from,to,remove_movement));
|
||||
execute ? ai_action->execute() : ai_action->check_before();
|
||||
return ai_action;
|
||||
|
||||
}
|
||||
|
||||
|
||||
std::auto_ptr< ai_recruit_result > ai_actions::execute_recruit_action( int /*side*/,
|
||||
std::auto_ptr< ai_recruit_result > ai_actions::execute_recruit_action( unsigned int side,
|
||||
bool execute,
|
||||
const std::string& /*unit_name*/,
|
||||
const map_location& /*where*/)
|
||||
const std::string& unit_name,
|
||||
const map_location& where)
|
||||
{
|
||||
std::auto_ptr< ai_recruit_result > ai_action(new ai_recruit_result());
|
||||
std::auto_ptr< ai_recruit_result > ai_action(new ai_recruit_result(side,unit_name,where));
|
||||
execute ? ai_action->execute() : ai_action->check_before();
|
||||
return ai_action;
|
||||
|
||||
}
|
||||
|
||||
|
||||
std::auto_ptr< ai_stopunit_result > ai_actions::execute_stopunit_action( int /*side*/,
|
||||
std::auto_ptr< ai_stopunit_result > ai_actions::execute_stopunit_action( unsigned int side,
|
||||
bool execute,
|
||||
const map_location& /*unit_location*/,
|
||||
bool /*remove_movement*/,
|
||||
bool /*remove_attacks*/)
|
||||
const map_location& unit_location,
|
||||
bool remove_movement,
|
||||
bool remove_attacks)
|
||||
{
|
||||
std::auto_ptr< ai_stopunit_result > ai_action(new ai_stopunit_result());
|
||||
std::auto_ptr< ai_stopunit_result > ai_action(new ai_stopunit_result(side,unit_location,remove_movement,remove_attacks));
|
||||
execute ? ai_action->execute() : ai_action->check_before();
|
||||
return ai_action;
|
||||
|
||||
|
|
|
@ -22,69 +22,146 @@
|
|||
|
||||
#include "../global.hpp"
|
||||
|
||||
#include "ai_interface.hpp"
|
||||
#include "../map.hpp"
|
||||
#include "../map_location.hpp"
|
||||
#include "../team.hpp"
|
||||
#include <memory>
|
||||
|
||||
class ai_action_result {
|
||||
public:
|
||||
static const int AI_ACTION_SUCCESS = 0;
|
||||
static const int AI_ACTION_STARTED = 1;
|
||||
static const int AI_ACTION_FAILURE = -1;
|
||||
|
||||
ai_action_result();
|
||||
virtual ~ai_action_result();
|
||||
|
||||
void check_before();
|
||||
void execute();
|
||||
bool is_ok();
|
||||
protected:
|
||||
ai_action_result( unsigned int side );
|
||||
virtual void do_check_before() = 0;
|
||||
virtual void do_check_after() = 0;
|
||||
virtual void do_execute() = 0;
|
||||
virtual void do_init_for_check_before() = 0;
|
||||
virtual void do_init_for_execution() = 0;
|
||||
|
||||
bool is_execution();
|
||||
unsigned int get_side();
|
||||
ai_interface::info& get_info();
|
||||
ai_interface::info& get_subjective_info();
|
||||
bool using_subjective_info();
|
||||
team& get_my_team(ai_interface::info info);
|
||||
void set_error(int error_code);
|
||||
bool is_success();
|
||||
private:
|
||||
void check_after();
|
||||
void init_for_check_before();
|
||||
void init_for_execution();
|
||||
void set_ok_checked();
|
||||
bool init_for_execution_and_check();
|
||||
int status_;
|
||||
bool is_success();
|
||||
bool return_value_checked_;
|
||||
bool tried_;
|
||||
unsigned int side_;
|
||||
int status_;
|
||||
bool is_execution_;
|
||||
|
||||
};
|
||||
|
||||
class ai_attack_result : public ai_action_result {
|
||||
public:
|
||||
ai_attack_result( unsigned int side,
|
||||
const map_location& attacker_loc,
|
||||
const map_location& defender_loc,
|
||||
int attacker_weapon );
|
||||
protected:
|
||||
virtual void do_check_before();
|
||||
virtual void do_check_after();
|
||||
virtual void do_execute();
|
||||
virtual void do_init_for_check_before();
|
||||
virtual void do_init_for_execution();
|
||||
private:
|
||||
const map_location& attacker_loc_;
|
||||
const map_location& defender_loc_;
|
||||
int attacker_weapon_;
|
||||
};
|
||||
|
||||
class ai_move_result : public ai_action_result {
|
||||
public:
|
||||
ai_move_result( unsigned int side,
|
||||
const map_location& from,
|
||||
const map_location& to,
|
||||
bool remove_movement );
|
||||
protected:
|
||||
virtual void do_check_before();
|
||||
virtual void do_check_after();
|
||||
virtual void do_execute();
|
||||
virtual void do_init_for_check_before();
|
||||
virtual void do_init_for_execution();
|
||||
private:
|
||||
const map_location& from_;
|
||||
const map_location& to_;
|
||||
bool remove_movement_;
|
||||
};
|
||||
|
||||
class ai_recruit_result : public ai_action_result {
|
||||
public:
|
||||
ai_recruit_result( unsigned int side, const std::string& unit_name, const map_location& where);
|
||||
static const int E_NOT_AVAILABLE_FOR_RECRUITING = 3001;
|
||||
static const int E_UNKNOWN_OR_DUMMY_UNIT_TYPE = 3002;
|
||||
static const int E_NO_GOLD = 3003;
|
||||
static const int E_NO_LEADER = 3004;
|
||||
static const int E_LEADER_NOT_ON_KEEP = 3005;
|
||||
static const int E_BAD_RECRUIT_LOCATION = 3006;
|
||||
|
||||
protected:
|
||||
virtual void do_check_before();
|
||||
virtual void do_check_after();
|
||||
virtual void do_execute();
|
||||
virtual void do_init_for_check_before();
|
||||
virtual void do_init_for_execution();
|
||||
private:
|
||||
bool test_available_for_recruiting(
|
||||
const team& team,
|
||||
std::set<std::string>::const_iterator& recruit,
|
||||
bool update_knowledge = false );
|
||||
bool test_unit_type_known(
|
||||
const std::set<std::string>::const_iterator& recruit,
|
||||
unit_type_data::unit_type_map::const_iterator& unit_type,
|
||||
bool update_knowledge = false );
|
||||
bool test_enough_gold(
|
||||
const team& team,
|
||||
const unit_type_data::unit_type_map::const_iterator& unit_type,
|
||||
bool update_knowledge = false );
|
||||
bool test_leader_present(
|
||||
const unit_map& units,
|
||||
unit_map::const_iterator& my_leader,
|
||||
bool update_knowledge = false );
|
||||
bool test_leader_on_keep(
|
||||
const gamemap& map,
|
||||
const unit_map::const_iterator& my_leader,
|
||||
bool update_knowledge = false);
|
||||
bool test_suitable_recruit_location (
|
||||
const gamemap& map,
|
||||
const unit_map& units,
|
||||
const unit_map::const_iterator& my_leader,
|
||||
bool update_knowledge = false);
|
||||
const std::string& unit_name_;
|
||||
const map_location& where_;
|
||||
map_location recruit_location_;
|
||||
unit_type_data::unit_type_map::const_iterator* unit_type_;
|
||||
int num_;
|
||||
};
|
||||
|
||||
class ai_stopunit_result : public ai_action_result {
|
||||
public:
|
||||
ai_stopunit_result( unsigned int side,
|
||||
const map_location& unit_location,
|
||||
bool remove_movement,
|
||||
bool remove_attacks );
|
||||
protected:
|
||||
virtual void do_check_before();
|
||||
virtual void do_check_after();
|
||||
virtual void do_execute();
|
||||
virtual void do_init_for_check_before();
|
||||
virtual void do_init_for_execution();
|
||||
private:
|
||||
const map_location& unit_location_;
|
||||
const bool remove_movement_;
|
||||
const bool remove_attacks_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -108,11 +185,11 @@ public:
|
|||
* @retval possible result: attacker and/or defender are invalid
|
||||
* @retval possible result: attacker doesn't have the specified weapon
|
||||
*/
|
||||
static std::auto_ptr<ai_attack_result> execute_attack_action( int side,
|
||||
static std::auto_ptr<ai_attack_result> execute_attack_action( unsigned int side,
|
||||
bool execute,
|
||||
const map_location& attacker_loc,
|
||||
const map_location& defender_loc,
|
||||
int attacks );
|
||||
int attacker_weapon );
|
||||
|
||||
|
||||
/**
|
||||
|
@ -127,7 +204,7 @@ static std::auto_ptr<ai_attack_result> execute_attack_action( int side,
|
|||
* @retval possible result: move is interrupted
|
||||
* @retval possible result: move is impossible
|
||||
*/
|
||||
static std::auto_ptr<ai_move_result > execute_move_action( int side,
|
||||
static std::auto_ptr<ai_move_result > execute_move_action( unsigned int side,
|
||||
bool execute,
|
||||
const map_location& from,
|
||||
const map_location& to,
|
||||
|
@ -146,7 +223,7 @@ static std::auto_ptr<ai_move_result > execute_move_action( int side,
|
|||
* @retval possible_result: no free space on keep
|
||||
* @retval possible_result: not enough gold
|
||||
*/
|
||||
static std::auto_ptr<ai_recruit_result> execute_recruit_action( int side,
|
||||
static std::auto_ptr<ai_recruit_result> execute_recruit_action( unsigned int side,
|
||||
bool execute,
|
||||
const std::string& unit_name,
|
||||
const map_location& where );
|
||||
|
@ -163,7 +240,7 @@ static std::auto_ptr<ai_recruit_result> execute_recruit_action( int side,
|
|||
* @retval possible_result: something wrong
|
||||
* @retval possible_result: nothing to do
|
||||
*/
|
||||
static std::auto_ptr<ai_stopunit_result> execute_stopunit_action( int side,
|
||||
static std::auto_ptr<ai_stopunit_result> execute_stopunit_action( unsigned int side,
|
||||
bool execute,
|
||||
const map_location& unit_location,
|
||||
bool remove_movement,
|
||||
|
|
|
@ -250,7 +250,12 @@ ai_manager::~ai_manager()
|
|||
|
||||
|
||||
ai_manager::AI_map_of_stacks ai_manager::ai_map_;
|
||||
ai_interface::info *ai_info_;
|
||||
ai_interface::info *ai_manager::ai_info_;
|
||||
events::generic_event ai_manager::user_interact_("ai_user_interact");
|
||||
events::generic_event ai_manager::unit_recruited_("ai_unit_recruited");
|
||||
events::generic_event ai_manager::unit_moved_("ai_unit_moved");
|
||||
events::generic_event ai_manager::enemy_attacked_("ai_enemy_attacked");
|
||||
int ai_manager::last_interact_ = 0;
|
||||
|
||||
|
||||
void ai_manager::set_ai_info(const ai_interface::info& i)
|
||||
|
@ -268,6 +273,47 @@ void ai_manager::clear_ai_info(){
|
|||
ai_info_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ai_manager::add_observer( events::observer* event_observer){
|
||||
user_interact_.attach_handler(event_observer);
|
||||
unit_recruited_.attach_handler(event_observer);
|
||||
unit_moved_.attach_handler(event_observer);
|
||||
enemy_attacked_.attach_handler(event_observer);
|
||||
}
|
||||
|
||||
void ai_manager::remove_observer(events::observer* event_observer){
|
||||
user_interact_.detach_handler(event_observer);
|
||||
unit_recruited_.detach_handler(event_observer);
|
||||
unit_moved_.detach_handler(event_observer);
|
||||
enemy_attacked_.detach_handler(event_observer);
|
||||
}
|
||||
|
||||
void ai_manager::raise_unit_interact() {
|
||||
const int interact_time = 30;
|
||||
const int time_since_interact = SDL_GetTicks() - last_interact_;
|
||||
if(time_since_interact < interact_time) {
|
||||
return;
|
||||
}
|
||||
|
||||
user_interact_.notify_observers();
|
||||
|
||||
last_interact_ = SDL_GetTicks();
|
||||
|
||||
}
|
||||
|
||||
void ai_manager::raise_unit_recruited() {
|
||||
unit_recruited_.notify_observers();
|
||||
}
|
||||
|
||||
void ai_manager::raise_unit_moved() {
|
||||
unit_moved_.notify_observers();
|
||||
}
|
||||
|
||||
void ai_manager::raise_enemy_attacked() {
|
||||
enemy_attacked_.notify_observers();
|
||||
}
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// EVALUATION
|
||||
// =======================================================================
|
||||
|
@ -640,6 +686,7 @@ void ai_manager::set_active_ai_algorithm_type_for_side( int side, const std::str
|
|||
// =======================================================================
|
||||
|
||||
void ai_manager::play_turn( int side, events::observer* event_observer ){
|
||||
last_interact_ = 0;
|
||||
ai_interface& ai_obj = get_active_ai_for_side(side);
|
||||
ai_obj.user_interact().attach_handler(event_observer);
|
||||
ai_obj.unit_recruited().attach_handler(event_observer);
|
||||
|
|
|
@ -139,6 +139,7 @@ public:
|
|||
*/
|
||||
static void set_ai_info(const ai_interface::info& info);
|
||||
|
||||
|
||||
/*
|
||||
* Clear ai information
|
||||
* Should be called in playsingle_controller's destructor
|
||||
|
@ -146,6 +147,47 @@ public:
|
|||
static void clear_ai_info();
|
||||
|
||||
|
||||
/*
|
||||
* Add observer of game events
|
||||
* Should be called in playsingle_controller's constructor
|
||||
*/
|
||||
static void add_observer( events::observer* event_observer);
|
||||
|
||||
|
||||
/*
|
||||
* Remove observer of game events
|
||||
* Should be called in playsingle_controller's destructor
|
||||
*/
|
||||
static void remove_observer( events::observer* event_observer );
|
||||
|
||||
|
||||
/*
|
||||
* Notify all observers of 'user interact' event
|
||||
* Function which should be called frequently to allow the user to interact
|
||||
* with the interface. This function will make sure that interaction
|
||||
* doesn't occur too often, so there is no problem with calling it very
|
||||
* regularly.
|
||||
*/
|
||||
static void raise_unit_interact();
|
||||
|
||||
|
||||
/*
|
||||
* Notify all observers of 'unit recruited' event
|
||||
*/
|
||||
static void raise_unit_recruited();
|
||||
|
||||
|
||||
/*
|
||||
* Notify all observers of 'unit moved' event
|
||||
*/
|
||||
static void raise_unit_moved();
|
||||
|
||||
|
||||
/*
|
||||
* Notify all observers of 'enemy attack' event
|
||||
*/
|
||||
static void raise_enemy_attacked();
|
||||
|
||||
protected:
|
||||
|
||||
ai_manager();
|
||||
|
@ -396,7 +438,14 @@ private:
|
|||
static AI_map_of_stacks ai_map_;
|
||||
static std::deque< ai_command_history_item > history_;
|
||||
static long history_item_counter_;
|
||||
static ai_interface::info *ai_info;
|
||||
static ai_interface::info *ai_info_;
|
||||
|
||||
static events::generic_event user_interact_;
|
||||
static events::generic_event unit_recruited_;
|
||||
static events::generic_event unit_moved_;
|
||||
static events::generic_event enemy_attacked_;
|
||||
static int last_interact_;
|
||||
|
||||
|
||||
|
||||
// =======================================================================
|
||||
|
|
|
@ -64,11 +64,13 @@ playsingle_controller::playsingle_controller(const config& level,
|
|||
|
||||
ai_interface::info ai_info(*gui_,map_,units_,teams_,status_, gamestate_);
|
||||
ai_manager::set_ai_info(ai_info);
|
||||
ai_manager::add_observer(this) ;
|
||||
}
|
||||
|
||||
|
||||
playsingle_controller::~playsingle_controller()
|
||||
{
|
||||
ai_manager::remove_observer(this) ;
|
||||
ai_manager::clear_ais() ;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue