src/ai/core/ai_factory.hpp
author truelight
Wed, 14 Mar 2007 23:00:06 +0000
branchnoai
changeset 9391 2d6da2e48112
parent 9390 4042c17c8055
child 9392 7791ceeea57b
permissions -rw-r--r--
(svn r9183) [NoAI] -Fix: use 'instance' instead of 'this' in RegisterFactory
/* $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 */