truelight@9390: /* $Id$ */ truelight@9390: truelight@9390: /** @file ai_factory.hpp declaration of class for AIFactory class */ truelight@9390: truelight@9390: #ifndef AI_FACTORY_HPP truelight@9390: #define AI_FACTORY_HPP truelight@9390: truelight@9390: #include truelight@9390: #include truelight@9390: #include truelight@9433: #include "../stdafx.h" truelight@9433: #include "../functions.h" rubidium@9723: #include "../network/network.h" truelight@9390: truelight@9390: class AIController; truelight@9390: truelight@9390: class AIFactoryBase { truelight@9390: private: truelight@9471: char *name; truelight@9390: typedef std::map Factories; truelight@9390: truelight@9390: static Factories &GetFactories() truelight@9390: { glx@9443: static Factories &s_factories = *new Factories(); truelight@9390: return s_factories; truelight@9390: } truelight@9390: truelight@9390: protected: truelight@9390: /** truelight@9390: * This registers your AI to the main system so we know about you. truelight@9390: */ truelight@9392: void RegisterFactory(const char *name) truelight@9390: { truelight@9400: /* Don't register nameless Factories */ truelight@9400: if (name == NULL) return; truelight@9400: truelight@9471: this->name = strdup(name); truelight@9392: std::pair P = GetFactories().insert(Factories::value_type(name, this)); truelight@9390: assert(P.second); truelight@9390: } truelight@9390: truelight@9390: public: truelight@9442: AIFactoryBase() : truelight@9442: name(NULL) truelight@9442: {} truelight@9471: virtual ~AIFactoryBase() { if (this->name != NULL) GetFactories().erase(this->name); free(this->name); } truelight@9390: truelight@9400: /** truelight@9400: * Run all initializers. truelight@9400: */ truelight@9400: static void RunInitializers() truelight@9400: { truelight@9400: /* Protect this function from being run several times */ truelight@9400: static bool run_once = false; truelight@9400: if (run_once) return; truelight@9400: run_once = true; truelight@9400: if (GetFactories().size() == 0) return; truelight@9400: Factories::iterator it = GetFactories().begin(); truelight@9400: for (; it != GetFactories().end(); it++) { truelight@9400: AIFactoryBase *f = (*it).second; truelight@9400: f->Initializer(); truelight@9400: } truelight@9400: } truelight@9400: truelight@9400: /** truelight@9400: * Select a random AI from all known AIs. truelight@9400: */ truebrain@9770: static AIFactoryBase *SelectRandomAI() truelight@9390: { truelight@9390: if (GetFactories().size() == 0) return NULL; truelight@9390: truelight@9390: /* Find a random AI */ truelight@9390: uint i; truelight@9390: if (_networking) i = InteractiveRandomRange(GetFactories().size()); truelight@9390: else i = RandomRange(GetFactories().size()); truelight@9390: truelight@9390: /* Find the Nth item from the array */ truelight@9390: Factories::iterator it = GetFactories().begin(); truelight@9390: Factories::iterator first_it; truelight@9390: for (; i > 0; i--) it++; truelight@9390: first_it = it; truelight@9402: AIFactoryBase *f = it->second; truelight@9390: truelight@9390: if (!f->AllowStartup()) { truelight@9390: /* We can't start this AI, try to find the next best */ truelight@9390: do { truelight@9402: it++; truelight@9390: if (it == GetFactories().end()) it = GetFactories().begin(); truelight@9390: /* Back at the beginning? Drop out! */ truelight@9390: if (first_it == it) break; truelight@9402: f = it->second; truelight@9390: } while (!f->AllowStartup()); truelight@9390: /* Unable to start any AI */ truelight@9390: if (first_it == it) return NULL; truelight@9390: } truebrain@9770: return f; truelight@9390: } truelight@9390: rubidium@9467: /** rubidium@9467: * Select the AI with the given name. rubidium@9467: * @param name the AI to select. rubidium@9467: */ truebrain@9770: static AIFactoryBase *SelectAI(const char *name) rubidium@9467: { rubidium@9467: if (GetFactories().size() == 0) return NULL; rubidium@9467: rubidium@9467: Factories::iterator it = GetFactories().begin(); rubidium@9467: for (; it != GetFactories().end(); it++) { rubidium@9467: AIFactoryBase *f = (*it).second; rubidium@9467: rubidium@9467: if (strcasecmp(name, f->name) == 0 && f->AllowStartup()) { truebrain@9770: return f; rubidium@9467: } rubidium@9467: } rubidium@9467: rubidium@9467: return NULL; rubidium@9467: } rubidium@9467: rubidium@9467: /** rubidium@9467: * Fills the given buffer with the AIs we know. rubidium@9467: * @param p start of the buffer. rubidium@9467: * @param last till were we may write. rubidium@9467: * @return till were we have written. rubidium@9467: */ rubidium@9467: static char *GetAIConsoleList(char *p, const char *last) rubidium@9467: { rubidium@9467: p += snprintf(p, last - p, "List of AIs:\n"); rubidium@9467: Factories::iterator it = GetFactories().begin(); rubidium@9467: for (; it != GetFactories().end(); it++) { rubidium@9467: AIFactoryBase *f = (*it).second; rubidium@9467: if (!f->AllowStartup()) continue; rubidium@9467: p += snprintf(p, last - p, "%10s: %s\n", f->name, f->GetDescription()); rubidium@9467: } rubidium@9467: p += snprintf(p, last - p, "\n"); rubidium@9467: rubidium@9467: return p; rubidium@9467: } rubidium@9467: truelight@9390: truebrain@9770: /** truebrain@9770: * Get the name of the AI internally. truebrain@9770: */ truebrain@9770: const char *GetAIName() { return this->name; } truelight@9390: truelight@9390: /** truelight@9390: * Get the author of the AI. truelight@9390: */ truelight@9390: virtual const char *GetAuthor() = 0; truelight@9390: truelight@9390: /** truelight@9390: * Get a description of the AI. truelight@9390: */ truelight@9390: virtual const char *GetDescription() = 0; truelight@9390: truelight@9390: /** truelight@9390: * Get the version of this AI. truelight@9390: */ truelight@9390: virtual int GetVersion() = 0; truelight@9390: truelight@9390: /** truelight@9390: * Get the date of the version. truelight@9390: * @return A string like '2007-08-29'. truelight@9390: */ truelight@9390: virtual const char *GetDate() = 0; truelight@9390: truelight@9390: /** truelight@9390: * Create an instance of your AI. truelight@9390: */ truelight@9390: virtual AIController *CreateInstance() = 0; truelight@9390: truelight@9390: /** truelight@9390: * In this function you can do some very limited querying of the game. truelight@9390: * If you for example only supply road-vehicle-based AI, and RVs are truelight@9390: * disabled, you return 'false', so you won't boot. truelight@9390: */ truelight@9390: virtual bool AllowStartup() { return true; } truelight@9400: truelight@9400: /** truelight@9400: * Normally you just make a static instance of AIFactory, and you truelight@9400: * will be registered. In very limited cases, like Squirrel-module, truelight@9400: * it is needed to be called when OpenTTD is launched (so not as truelight@9400: * constructor). Then you can use this function. truelight@9400: * @note Avoid using it! truelight@9400: */ truelight@9400: virtual void Initializer() { } truelight@9390: }; truelight@9390: truelight@9390: /** truelight@9390: * The template to define your AIFactory. This makes sure RegisterFactory truelight@9390: * works correctly on initialization. truelight@9390: * Example: class FYourClass: public AIFactory { } truelight@9390: */ truelight@9390: template truelight@9390: class AIFactory: public AIFactoryBase { truelight@9390: public: truelight@9392: AIFactory() { this->RegisterFactory(((T *)this)->GetName()); } truelight@9400: truelight@9400: /** truelight@9400: * Get a short name for the AI. truelight@9400: */ truelight@9400: const char *GetName(); truelight@9390: }; truelight@9390: truelight@9390: #endif /* AI_FACTORY_HPP */