mirror of
https://github.com/1dot13/source.git
synced 2026-08-05 14:00:23 +02:00
Further refinement of new ModularizedTacticalAI architecture; added plans for Crows
git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@6017 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
#ifndef ABSTRACT_PLAN_FACTORY_H_
|
||||
#define ABSTRACT_PLAN_FACTORY_H_
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
class SOLDIERTYPE;
|
||||
|
||||
namespace AI
|
||||
@@ -13,16 +15,48 @@ namespace AI
|
||||
namespace tactical
|
||||
{
|
||||
/**@class AIInputData
|
||||
* @brief Wrapper class around the environmental data required to build an AI plan
|
||||
* @brief Wrapper class around the environmental data required to build or update an AI plan
|
||||
*
|
||||
* At the moment, simply a wrapper around SOLDIERTYPE. Future versions might require more data; without the
|
||||
* wrapper, *every* Concrete Factory ever created would need to be changed in this event. With the wrapper, no
|
||||
* change is required at all.
|
||||
* The data contained in objects of this class are currently collected in HanldeNoise() and ManSeesMan(), both
|
||||
* defined in Tactical/opplist.cpp
|
||||
* Future versions might require more or different data; without the wrapper, *every* Concrete Factory ever
|
||||
* created would need to be changed in this event. With the wrapper, no change is required at all.
|
||||
*/
|
||||
struct AIInputData
|
||||
class AIInputData
|
||||
{
|
||||
SOLDIERTYPE* npc_to_plan_for_;
|
||||
private:
|
||||
enum event_type {no_event, auditive_event, visual_event};
|
||||
event_type event_type_;
|
||||
/// Only visual: the opponent seen by the updated NPC
|
||||
SOLDIERTYPE* opponent_;
|
||||
/// Only auditive: ID of the noise maker; (at least for NPC-generated sounds) ID of NPC
|
||||
int noise_maker_;
|
||||
/// Location of event
|
||||
int grid_no_;
|
||||
int level_;
|
||||
/// Only auditive: volume of heard sound (at the hearing NPC, not the source)
|
||||
int volume_;
|
||||
int type_;
|
||||
int caller1_;
|
||||
int caller2_;
|
||||
public:
|
||||
/// Empty types are used for overload resolution in order to generate different types of events with
|
||||
/// simple constructor calls.
|
||||
struct Auditive{ };
|
||||
struct Visual{ };
|
||||
/// Constructor for noise events
|
||||
AIInputData(Auditive, int noise_maker, int grid_no, int level, int volume, int type);
|
||||
/// Constructor for sight events
|
||||
AIInputData(Visual, SOLDIERTYPE* opponent, int grid_no, int level, int caller1, int caller2);
|
||||
/// Default constructor, called when no event occurred
|
||||
AIInputData();
|
||||
bool is_auditive_event() const {return event_type_ == auditive_event;}
|
||||
bool is_visual_event() const {return event_type_ == visual_event;}
|
||||
/// Allow the output function used for debugging to access the members directly
|
||||
friend std::ostream& operator<<(std::ostream& os, const AIInputData& i);
|
||||
};
|
||||
std::ostream& operator<<(std::ostream& os, const AIInputData& i);
|
||||
|
||||
class Plan;
|
||||
/**@class AbstractPlanFactory
|
||||
* @brief Abstract Factory. Base class for all plan factories.
|
||||
@@ -37,6 +71,7 @@ namespace AI
|
||||
class AbstractPlanFactory
|
||||
{
|
||||
private:
|
||||
/// Flag set iff delayed initialization was already performed
|
||||
bool initialize_called_;
|
||||
public:
|
||||
AbstractPlanFactory() : initialize_called_(false) { }
|
||||
@@ -54,21 +89,25 @@ namespace AI
|
||||
* The subclasses (i.e., Concrete Factories) implpmenting this routine contain
|
||||
* the decision-making AI core.
|
||||
*
|
||||
* @param input A pointer to a structure containing all required input data in order for the AI
|
||||
* algorithms to perform their task. At the moment, simply a wrapper around SOLDIERTYPE. Future versions
|
||||
* @param npc The NPC the plan is for
|
||||
* @param input A reference to a structure containing all required input data in order for the AI
|
||||
* algorithms to perform their task. At the moment, empty. Future versions
|
||||
* might require other datatypes; without the wrapper, *every* Concrete Factory ever created would need
|
||||
* to be changed in this event.
|
||||
* @return A Plan object tree representing the produced strategy
|
||||
*/
|
||||
virtual Plan* create_plan(const AIInputData& input) = 0;
|
||||
/**@brief Abstract Plan object hierarchy update function, called in order to update an already created
|
||||
* plan
|
||||
virtual Plan* create_plan(SOLDIERTYPE* npc, const AIInputData& input) = 0;
|
||||
|
||||
/**@brief Abstract Plan object hierarchy update function, called in order to update an already created plan
|
||||
*
|
||||
* @param input A pointer to a structure containing all required input data in order for the AI
|
||||
* algorithms to perform their task
|
||||
* @param plan_to_change The Plan object hierarchy that is to be updated
|
||||
* If no plan exists, it is created; this should not be the general case, but might happen for
|
||||
* 'interrupted' NPCs that haven't had the chance to plan yet.
|
||||
*
|
||||
* @param npc A pointer to the npc owning the ai_masterplan_ to be changed.
|
||||
* @param input A reference to a structure containing all required input data in order for the AI
|
||||
* @post npc->ai_masterplan_ is not null
|
||||
*/
|
||||
virtual void update_plan(const AIInputData& input, Plan* plan_to_change) = 0;
|
||||
virtual void update_plan(SOLDIERTYPE* npc, const AIInputData& input) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,17 +13,19 @@ namespace AI
|
||||
namespace tactical
|
||||
{
|
||||
/**@class LegacyAIPlan
|
||||
* @brief Component/Concrete Product. Generates a Plan that executes the AI as it was before modularization.
|
||||
* @brief Component/Concrete Product. Wrapper/Re-Write of DecideAction()
|
||||
*
|
||||
* A simple encapsulation of the functions TurnBasedHandleNPCAI() and RTHandleAI(), defined in
|
||||
* TacticalAI/AIMain.cpp and TacticalAI/Realtime.cpp, respectively. The AI handles decisions for all kinds of
|
||||
* NPCs (enemies, zombies, civilians, ...)
|
||||
* This plan began as a simple forwarding object for DecideAction(), and will, in the course of the AI redesign,
|
||||
* be split into elementary NPC actions. It is as such only a intermediate product used to bring structure where
|
||||
* the is currently none.
|
||||
*/
|
||||
class LegacyAIPlan: public Plan
|
||||
{
|
||||
private:
|
||||
public:
|
||||
virtual void execute(bool turn_based, PlanInputData& manipulated_object);
|
||||
LegacyAIPlan(SOLDIERTYPE* npc);
|
||||
virtual void execute(PlanInputData& environment);
|
||||
virtual bool done() const {return false;}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,16 +14,21 @@ namespace AI
|
||||
namespace tactical
|
||||
{
|
||||
/**@class LegacyAIPlanFactory
|
||||
* @brief Concrete Factory. Generates the LegacyAIPlan, making NPCs do exactly what it did before this AI
|
||||
* modularization/re-write.
|
||||
* @brief Concrete Factory. Generates the appropriate LegacyAIPlan, making NPCs do exactly what it did before
|
||||
* this AI modularization/re-write.
|
||||
*
|
||||
* Currently, the factory handles the "outermost" layer of selection statements by instantiating plans that will
|
||||
* call CreatureDecideAction(), ZombieDecideAction() or DecideAction(), respectively. This is not the intended
|
||||
* use of factories, but for the time of the AI redesign a necessity nonetheless.
|
||||
*/
|
||||
class LegacyAIPlanFactory : public AbstractPlanFactory
|
||||
{
|
||||
private:
|
||||
public:
|
||||
/// The name is required for registration in the PlanFactoryLibrary
|
||||
static std::string get_name() {return "LegacyAIPlanFactory";}
|
||||
virtual Plan* create_plan(const AIInputData& input);
|
||||
virtual void update_plan(const AIInputData& input, Plan* plan_to_change);
|
||||
virtual Plan* create_plan(SOLDIERTYPE* npc, const AIInputData& input);
|
||||
virtual void update_plan(SOLDIERTYPE* npc, const AIInputData& input);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,9 @@ namespace AI
|
||||
{
|
||||
private:
|
||||
public:
|
||||
virtual void execute(bool turn_based, PlanInputData& manipulated_object);
|
||||
NullPlan(SOLDIERTYPE* npc);
|
||||
virtual void execute(PlanInputData& environment);
|
||||
bool done() const {return false;}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ namespace AI
|
||||
private:
|
||||
public:
|
||||
static std::string get_name() {return "NullPlanFactory";}
|
||||
virtual Plan* create_plan(const AIInputData& input);
|
||||
virtual void update_plan(const AIInputData& input, Plan* plan_to_change);
|
||||
virtual Plan* create_plan(SOLDIERTYPE* npc, const AIInputData& input);
|
||||
virtual void update_plan(SOLDIERTYPE* npc, const AIInputData& input);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,44 +6,84 @@
|
||||
#ifndef PLAN_H_
|
||||
#define PLAN_H_
|
||||
|
||||
#include <iostream>
|
||||
|
||||
class SOLDIERTYPE;
|
||||
struct TacticalStatusType;
|
||||
|
||||
namespace AI
|
||||
{
|
||||
namespace tactical
|
||||
{
|
||||
/**@class PlanInputData
|
||||
* @brief Wrapper class around the entity manipulated through plan execution
|
||||
* @brief Wrapper class for environmental data required for plan execution
|
||||
*
|
||||
* At the moment, simply a wrapper around SOLDIERTYPE. Future versions might require other datatypes; without
|
||||
* the wrapper, *every* Plan subclass ever created would need to be changed in this event. With the wrapper, no
|
||||
* change is required at all.
|
||||
* Future versions might require other data types; without the wrapper, *every* Plan subclass ever created would
|
||||
* need to be changed in this event. With the wrapper, no change is required at all (see also AIInputData).
|
||||
*/
|
||||
struct PlanInputData
|
||||
class PlanInputData
|
||||
{
|
||||
SOLDIERTYPE* controlled_npc_;
|
||||
private:
|
||||
/// True iff we are in turn based mode
|
||||
bool turn_based_;
|
||||
/// Reference to the global variable gTacticalStatus (we want to keep this place tidy and don't use global variables here)
|
||||
const TacticalStatusType& tactical_status_;
|
||||
/// left undefined to prevent copying
|
||||
PlanInputData(const TacticalStatusType&);
|
||||
/// left undefined to prevent assignment
|
||||
PlanInputData& operator=(const TacticalStatusType&);
|
||||
public:
|
||||
/// Trivial member initialization
|
||||
PlanInputData(bool turn_based, const TacticalStatusType& tactical_status);
|
||||
/** @name Accessor functions */ /*@{*/
|
||||
/// Return a reference to a global "tactical status" struct, formerly known as gTacticalStatus
|
||||
const TacticalStatusType& get_tactical_status() const { return tactical_status_; }
|
||||
bool turn_based() const { return turn_based_; }
|
||||
/*@}*/
|
||||
};
|
||||
|
||||
|
||||
/**@class Plan
|
||||
* @brief Composite/Abstract Product. Base class for all plan compositions and components.
|
||||
*
|
||||
* The Plan class provides a common interface for both plan compositions and plan components.
|
||||
* The Plan class provides a common interface for both plan compositions and plan components. The composite
|
||||
* design pattern chosen for plan representation allows objects inheriting from this class to form trees,
|
||||
* allowing a clean and easy representation of sub- and super-plans
|
||||
*/
|
||||
class Plan
|
||||
{
|
||||
private:
|
||||
/// A pointer to the NPC who owns this plan.
|
||||
SOLDIERTYPE* npc_;
|
||||
protected:
|
||||
/// Return a pointer to the controlled NPC
|
||||
SOLDIERTYPE* get_npc() {return npc_;}
|
||||
/// Return a pointer to the controlled NPC
|
||||
const SOLDIERTYPE* get_npc() const {return npc_;}
|
||||
public:
|
||||
/** @brief Plan execution is the encapsulation of an action sequence, making up higher-level building blocks
|
||||
Plan(SOLDIERTYPE* npc);
|
||||
/// A virtual destructor is essential here, destruction will be handled through this interface.
|
||||
virtual ~Plan() { };
|
||||
/** @brief Plan execution is the encapsulation of an "action sequence", which can be used to make up
|
||||
* higher-level building blocks
|
||||
*
|
||||
* Each plan objects represents a high-level action, implemented by means of lower-level actions. These
|
||||
* lower level actions can be other Plans subtypes; at some point, a Plan object has no further
|
||||
* sub-plans, i.e., the objet is no composition, but a component, forming a leaf in the Plan hierarchy.
|
||||
* The components' lower level actions are formed by the fundamental npc actions made available outside
|
||||
* the AI framework.
|
||||
* The components' lower level actions are formed by the fundamental NPC actions which must be made
|
||||
* available outside the AI framework.
|
||||
*
|
||||
* @param turn_based true if turn-based mode is active, false for real-time mode
|
||||
* @param manipulated_object Encapsulation of around object(s) a plan may manipulate.
|
||||
* @param environment Encapsulation of environmental data required for plan execution
|
||||
*/
|
||||
virtual void execute(bool turn_based, PlanInputData& manipulated_object) = 0;
|
||||
virtual void execute(PlanInputData& environment) = 0;
|
||||
/** Determine if the plan is finished.
|
||||
*
|
||||
* The semantics are not "this plan *can* be aborted" - every plan must anticipate that - but instead
|
||||
* "this plan cannot be continued"; for example, a movement plan is finished once the destination is
|
||||
* reached, as no further movement can be carried out by the plan.
|
||||
*@return true iff the plan can no longer be executed (or execution will always lead to AI_ACTION_NONE)
|
||||
*/
|
||||
virtual bool done() const = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <map>
|
||||
#include <deque>
|
||||
|
||||
class SOLDIERTYPE;
|
||||
|
||||
namespace AI
|
||||
{
|
||||
namespace tactical
|
||||
@@ -17,23 +19,29 @@ namespace AI
|
||||
// forward declarations
|
||||
class AbstractPlanFactory;
|
||||
class Plan;
|
||||
struct AIInputData;
|
||||
class AIInputData;
|
||||
|
||||
/**@class PlanFactoryLibrary
|
||||
* @brief Singleton. A "library" containing all available PlanFactories, accessible via the strings returned by
|
||||
* their get_name() function.
|
||||
*
|
||||
* Used as one "entry point" for the new AI system within the legacy code (the other being the 'execute()' methods of Plan)
|
||||
* Handles the mapping of a SOLDIERTYPE's bAIIndex to a concrete plan factory instantiation.
|
||||
*/
|
||||
class PlanFactoryLibrary
|
||||
{
|
||||
private:
|
||||
/// Only instance, required for singleton pattern implementation
|
||||
static PlanFactoryLibrary* instance_;
|
||||
/// A mapping of factory names to pointers of said factories
|
||||
std::map<std::string, AbstractPlanFactory*> registred_factories_;
|
||||
/// A mapping of bAIIndex to factory pointers
|
||||
std::deque<AbstractPlanFactory*> ai_index_to_factory_mapping_;
|
||||
PlanFactoryLibrary();
|
||||
public:
|
||||
static PlanFactoryLibrary* instance();
|
||||
Plan* create_plan(size_t index, AIInputData& input) const;
|
||||
Plan* create_plan(size_t index, SOLDIERTYPE* npc, const AIInputData& input) const;
|
||||
void update_plan(size_t intdex, SOLDIERTYPE* npc, const AIInputData& input) const;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user