- added initial code for switching dropped network players to AI (currently hard coded to normal CPU)

This commit is contained in:
Mark Vejvoda 2010-10-18 23:09:43 +00:00
parent 3d4ccb460c
commit 7564635643
7 changed files with 84 additions and 44 deletions

View File

@ -10,20 +10,16 @@
// ============================================================== // ==============================================================
#include "ai.h" #include "ai.h"
#include <ctime>
#include "ai_interface.h" #include "ai_interface.h"
#include "ai_rule.h" #include "ai_rule.h"
#include "unit_type.h" #include "unit_type.h"
#include "unit.h" #include "unit.h"
#include "program.h"
#include "config.h"
//#include <limits>
#include "leak_dumper.h" #include "leak_dumper.h"
using namespace Shared::Graphics; using namespace Shared::Graphics;
using namespace Shared::Util; using namespace Shared::Util;
namespace Glest{ namespace Game{ namespace Glest { namespace Game {
// ===================================================== // =====================================================
// class ProduceTask // class ProduceTask
@ -111,42 +107,50 @@ string UpgradeTask::toString() const{
// class Ai // class Ai
// ===================================================== // =====================================================
void Ai::init(AiInterface *aiInterface){ void Ai::init(AiInterface *aiInterface, int useStartLocation) {
this->aiInterface= aiInterface; this->aiInterface= aiInterface;
startLoc= random.randRange(0, aiInterface->getMapMaxPlayers()-1); if(useStartLocation == -1) {
upgradeCount= 0; startLoc = random.randRange(0, aiInterface->getMapMaxPlayers()-1);
}
else {
startLoc = useStartLocation;
}
minWarriors= minMinWarriors; minWarriors= minMinWarriors;
randomMinWarriorsReached= false; randomMinWarriorsReached= false;
//add ai rules //add ai rules
aiRules.resize(14); aiRules.clear();
aiRules[0]= new AiRuleWorkerHarvest(this); aiRules.push_back(new AiRuleWorkerHarvest(this));
aiRules[1]= new AiRuleRefreshHarvester(this); aiRules.push_back(new AiRuleRefreshHarvester(this));
aiRules[2]= new AiRuleScoutPatrol(this); aiRules.push_back(new AiRuleScoutPatrol(this));
aiRules[3]= new AiRuleReturnBase(this); aiRules.push_back(new AiRuleReturnBase(this));
aiRules[4]= new AiRuleMassiveAttack(this); aiRules.push_back(new AiRuleMassiveAttack(this));
aiRules[5]= new AiRuleAddTasks(this); aiRules.push_back(new AiRuleAddTasks(this));
aiRules[6]= new AiRuleProduceResourceProducer(this); aiRules.push_back(new AiRuleProduceResourceProducer(this));
aiRules[7]= new AiRuleBuildOneFarm(this); aiRules.push_back(new AiRuleBuildOneFarm(this));
aiRules[8]= new AiRuleProduce(this); aiRules.push_back(new AiRuleProduce(this));
aiRules[9]= new AiRuleBuild(this); aiRules.push_back(new AiRuleBuild(this));
aiRules[10]= new AiRuleUpgrade(this); aiRules.push_back(new AiRuleUpgrade(this));
aiRules[11]= new AiRuleExpand(this); aiRules.push_back(new AiRuleExpand(this));
aiRules[12]= new AiRuleRepair(this); aiRules.push_back(new AiRuleRepair(this));
aiRules[13]= new AiRuleRepair(this); aiRules.push_back(new AiRuleRepair(this));
} }
Ai::~Ai(){ Ai::~Ai() {
deleteValues(tasks.begin(), tasks.end()); deleteValues(tasks.begin(), tasks.end());
deleteValues(aiRules.begin(), aiRules.end()); deleteValues(aiRules.begin(), aiRules.end());
} }
void Ai::update(){ void Ai::update() {
//process ai rules //process ai rules
for(AiRules::iterator it= aiRules.begin(); it!=aiRules.end(); ++it){ for(int ruleIdx = 0; ruleIdx < aiRules.size(); ++ruleIdx) {
if((aiInterface->getTimer() % ((*it)->getTestInterval()*GameConstants::updateFps/1000))==0){ AiRule *rule = aiRules[ruleIdx];
if((*it)->test()){ if(rule == NULL) {
aiInterface->printLog(3, intToStr(1000*aiInterface->getTimer()/GameConstants::updateFps) + ": Executing rule: " + (*it)->getName() + '\n'); throw runtime_error("rule == NULL");
(*it)->execute(); }
if((aiInterface->getTimer() % (rule->getTestInterval() * GameConstants::updateFps / 1000)) == 0){
if(rule->test()) {
aiInterface->printLog(3, intToStr(1000 * aiInterface->getTimer() / GameConstants::updateFps) + ": Executing rule: " + rule->getName() + '\n');
rule->execute();
} }
} }
} }

View File

@ -111,7 +111,7 @@ public:
/// Main AI class /// Main AI class
// =============================== // ===============================
class Ai{ class Ai {
private: private:
static const int harvesterPercent= 30; static const int harvesterPercent= 30;
static const int maxBuildRadius= 40; static const int maxBuildRadius= 40;
@ -123,7 +123,7 @@ private:
static const int villageRadius= 15; static const int villageRadius= 15;
public: public:
enum ResourceUsage{ enum ResourceUsage {
ruHarvester, ruHarvester,
ruWarrior, ruWarrior,
ruBuilding, ruBuilding,
@ -131,7 +131,8 @@ public:
}; };
private: private:
typedef vector<AiRule*> AiRules; //typedef vector<AiRule*> AiRules;
typedef vector<AiRule *> AiRules;
typedef list<const Task*> Tasks; typedef list<const Task*> Tasks;
typedef deque<Vec2i> Positions; typedef deque<Vec2i> Positions;
@ -140,7 +141,6 @@ private:
AiRules aiRules; AiRules aiRules;
int startLoc; int startLoc;
bool randomMinWarriorsReached; bool randomMinWarriorsReached;
int upgradeCount;
Tasks tasks; Tasks tasks;
Positions expansionPositions; Positions expansionPositions;
RandomGen random; RandomGen random;
@ -148,12 +148,12 @@ private:
public: public:
int minWarriors; int minWarriors;
~Ai(); ~Ai();
void init(AiInterface *aiInterface); void init(AiInterface *aiInterface,int useStartLocation=-1);
void update(); void update();
//state requests //state requests
AiInterface *getAiInterface() const {return aiInterface;} AiInterface *getAiInterface() const {return aiInterface;}
RandomGen* getRandom() {return &random;} RandomGen* getRandom() {return &random;}
int getCountOfType(const UnitType *ut); int getCountOfType(const UnitType *ut);
int getCountOfClass(UnitClass uc); int getCountOfClass(UnitClass uc);

View File

@ -31,7 +31,7 @@ using namespace Shared::Graphics;
namespace Glest{ namespace Game{ namespace Glest{ namespace Game{
AiInterface::AiInterface(Game &game, int factionIndex, int teamIndex){ AiInterface::AiInterface(Game &game, int factionIndex, int teamIndex, int useStartLocation) {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
this->world= game.getWorld(); this->world= game.getWorld();
@ -44,7 +44,7 @@ AiInterface::AiInterface(Game &game, int factionIndex, int teamIndex){
timer= 0; timer= 0;
//init ai //init ai
ai.init(this); ai.init(this,useStartLocation);
//config //config
logLevel= Config::getInstance().getInt("AiLog"); logLevel= Config::getInstance().getInt("AiLog");

View File

@ -48,7 +48,7 @@ private:
int logLevel; int logLevel;
public: public:
AiInterface(Game &game, int factionIndex, int teamIndex); AiInterface(Game &game, int factionIndex, int teamIndex, int useStartLocation=-1);
//main //main
void update(); void update();

View File

@ -633,15 +633,18 @@ void Game::update() {
if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
NetworkManager &networkManager= NetworkManager::getInstance(); NetworkManager &networkManager= NetworkManager::getInstance();
bool enableServerControlledAI = this->gameSettings.getEnableServerControlledAI();
bool isNetworkGame = this->gameSettings.isNetworkGame();
NetworkRole role = networkManager.getNetworkRole();
// Check to see if we are playing a network game and if any players
// have disconnected?
ReplaceDisconnectedNetworkPlayersWithAI(isNetworkGame, role);
//update //update
for(int i = 0; i < updateLoops; ++i) { for(int i = 0; i < updateLoops; ++i) {
chrono.start(); chrono.start();
Renderer &renderer= Renderer::getInstance();
//SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
bool enableServerControlledAI = this->gameSettings.getEnableServerControlledAI();
bool isNetworkGame = this->gameSettings.isNetworkGame();
NetworkRole role = networkManager.getNetworkRole();
//AiInterface //AiInterface
for(int i = 0; i < world.getFactionCount(); ++i) { for(int i = 0; i < world.getFactionCount(); ++i) {
@ -683,6 +686,7 @@ void Game::update() {
if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld [weather particle updating]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld [weather particle updating]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
if(chrono.getMillis() > 0) chrono.start(); if(chrono.getMillis() > 0) chrono.start();
Renderer &renderer= Renderer::getInstance();
renderer.updateParticleManager(rsGame,avgRenderFps); renderer.updateParticleManager(rsGame,avgRenderFps);
if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld [particle manager updating]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld [particle manager updating]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
if(chrono.getMillis() > 0) chrono.start(); if(chrono.getMillis() > 0) chrono.start();
@ -726,6 +730,34 @@ void Game::update() {
} }
} }
void Game::ReplaceDisconnectedNetworkPlayersWithAI(bool isNetworkGame, NetworkRole role) {
if(role == nrServer && isNetworkGame == true) {
Logger &logger= Logger::getInstance();
ServerInterface *server = NetworkManager::getInstance().getServerInterface();
for(int i = 0; i < world.getFactionCount(); ++i) {
Faction *faction = world.getFaction(i);
if( faction->getControlType() == ctNetwork ||
faction->getControlType() == ctNetworkCpuEasy ||
faction->getControlType() == ctNetworkCpu ||
faction->getControlType() == ctNetworkCpuUltra ||
faction->getControlType() == ctNetworkCpuMega) {
ConnectionSlot *slot = server->getSlot(i);
if(aiInterfaces[i] == NULL && (slot == NULL || slot->isConnected() == false)) {
faction->setControlType(ctCpu);
aiInterfaces[i] = new AiInterface(*this, i, faction->getTeam(), faction->getStartLocationIndex());
logger.add("Creating AI for faction " + intToStr(i), true);
char szBuf[255]="";
sprintf(szBuf,"Player #%d [%s] has disconnected, switching player to AI mode!",i+1,this->gameSettings.getNetworkPlayerName(i).c_str());
server->sendTextMessage(szBuf,-1,true);
}
}
}
}
}
void Game::updateCamera(){ void Game::updateCamera(){
gameCamera.update(); gameCamera.update();
} }

View File

@ -186,6 +186,8 @@ private:
void renderWorker(); void renderWorker();
static int ErrorDisplayMessage(const char *msg, bool exitApp); static int ErrorDisplayMessage(const char *msg, bool exitApp);
void ReplaceDisconnectedNetworkPlayersWithAI(bool isNetworkGame, NetworkRole role);
}; };
}}//end namespace }}//end namespace

View File

@ -141,6 +141,8 @@ public:
void incResourceAmount(const ResourceType *rt, int amount); void incResourceAmount(const ResourceType *rt, int amount);
void setResourceBalance(const ResourceType *rt, int balance); void setResourceBalance(const ResourceType *rt, int balance);
void setControlType(ControlType value) { control = value; }
std::string toString() const; std::string toString() const;
private: private: