/* $Id$ */
/** @file ai_factory.hpp declaration of class for AIFactory class */
#ifndef AI_FACTORY_HPP
#define AI_FACTORY_HPP
#include <string>
#include <map>
#include <assert.h>
#include "ai_base.hpp"
class AIController;
class AIFactoryBase {
private:
const char *name;
typedef std::map<std::string, AIFactoryBase *> Factories;
static Factories &GetFactories()
{
static Factories s_factories;
return s_factories;
}
protected:
/**
* This registers your AI to the main system so we know about you.
*/
void RegisterFactory(AIFactoryBase *instance, const char *name)
{
std::pair<Factories::iterator, bool> P = GetFactories().insert(Factories::value_type(name, instance));
assert(P.second);
instance->name = name;
}
public:
virtual ~AIFactoryBase() { GetFactories().erase(this->name); }
static AIController *SelectRandomAI()
{
if (GetFactories().size() == 0) return NULL;
/* Find a random AI */
uint i;
if (_networking) i = InteractiveRandomRange(GetFactories().size());
else i = RandomRange(GetFactories().size());
/* Find the Nth item from the array */
Factories::iterator it = GetFactories().begin();
Factories::iterator first_it;
for (; i > 0; i--) it++;
first_it = it;
AIFactoryBase *f = (*it).second;
if (!f->AllowStartup()) {
/* We can't start this AI, try to find the next best */
do {
if (it == GetFactories().end()) it = GetFactories().begin();
else it++;
/* Back at the beginning? Drop out! */
if (first_it == it) break;
f = (*it).second;
} while (!f->AllowStartup());
/* Unable to start any AI */
if (first_it == it) return NULL;
}
return f->CreateInstance();
}
/**
* Get the author of the AI.
*/
virtual const char *GetAuthor() = 0;
/**
* Get a short name for the AI.
*/
virtual const char *GetName() = 0;
/**
* Get a description of the AI.
*/
virtual const char *GetDescription() = 0;
/**
* Get the version of this AI.
*/
virtual int GetVersion() = 0;
/**
* Get the date of the version.
* @return A string like '2007-08-29'.
*/
virtual const char *GetDate() = 0;
/**
* Create an instance of your AI.
*/
virtual AIController *CreateInstance() = 0;
/**
* In this function you can do some very limited querying of the game.
* If you for example only supply road-vehicle-based AI, and RVs are
* disabled, you return 'false', so you won't boot.
*/
virtual bool AllowStartup() { return true; }
};
/**
* The template to define your AIFactory. This makes sure RegisterFactory
* works correctly on initialization.
* Example: class FYourClass: public AIFactory<FYourClass> { }
*/
template <class T>
class AIFactory: public AIFactoryBase {
public:
AIFactory() { this->RegisterFactory(this, ((T *)this)->GetName()); }
};
#endif /* AI_FACTORY_HPP */