diff --git a/ModularizedTacticalAI/include/CrowPlan.h b/ModularizedTacticalAI/include/CrowPlan.h new file mode 100644 index 00000000..9ccabb32 --- /dev/null +++ b/ModularizedTacticalAI/include/CrowPlan.h @@ -0,0 +1,61 @@ +/** + * @file + * @author feynman (bears-pit.com) + */ + +#ifndef CROW_PLAN_H_ +#define CROW_PLAN_H_ + +#include "Plan.h" + +namespace AI +{ + namespace tactical + { + /**@class CrowSeekCorpsePlan + * @brief Component/Concrete Product. Let a crow seek a corpse within 4 tiles radius, and go towards it. + */ + class CrowSeekCorpsePlan : public Plan + { + private: + /// The location of the corpse the crow shall go to + int corpse_grid_; + public: + CrowSeekCorpsePlan(SOLDIERTYPE* npc); + virtual void execute(PlanInputData& environment); + /// The plan is marked as 'done' when the 'sweet spot' near the corpse is reached + virtual bool done() const; + int get_corpse_grid() const; + }; + + /**@class CrowPeckPlan + * @brief Component/Concrete Product. Let a crow sitting next to a corpse peck. + */ + class CrowPeckPlan : public Plan + { + private: + int corpse_grid_; + public: + CrowPeckPlan(SOLDIERTYPE* npc, int corpse_grid); + virtual void execute(PlanInputData& environment); + /// The plan never ends without interrupt/plan update, pecking can take forever + virtual bool done() const {return false;} + }; + + /**@class CrowFlyAwayPlan + * @brief Component/Concrete Product. Let a crow leave the tactical screen. + */ + class CrowFlyAwayPlan : public Plan + { + private: + public: + CrowFlyAwayPlan(SOLDIERTYPE* npc); + virtual void execute(PlanInputData& environment); + /// The plan is deleted with the crow once it leaves; 'done' is meaningless, flying away cannot be interrupted + virtual bool done() const {return false;} + }; + } +} + +#endif + diff --git a/ModularizedTacticalAI/include/LegacyCreaturePlan.h b/ModularizedTacticalAI/include/LegacyCreaturePlan.h new file mode 100644 index 00000000..df50a7b7 --- /dev/null +++ b/ModularizedTacticalAI/include/LegacyCreaturePlan.h @@ -0,0 +1,34 @@ +/** + * @file + * @author feynman (bears-pit.com) + */ + +#ifndef LEGACY_CREATURE_PLAN_H_ +#define LEGACY_CREATURE_PLAN_H_ + +#include "Plan.h" + +namespace AI +{ + namespace tactical + { + /**@class LegacyCreaturePlan + * @brief Component/Concrete Product. Wrapper/Re-Write of CreatureDecideAction() + * + * This plan began as a simple forwarding object for CreatureDecideAction(), 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 LegacyCreaturePlan: public Plan + { + private: + public: + LegacyCreaturePlan(SOLDIERTYPE* npc); + virtual void execute(PlanInputData& environment); + virtual bool done() const {return false;} + }; + } +} + +#endif + diff --git a/ModularizedTacticalAI/include/LegacyZombiePlan.h b/ModularizedTacticalAI/include/LegacyZombiePlan.h new file mode 100644 index 00000000..18b1ce00 --- /dev/null +++ b/ModularizedTacticalAI/include/LegacyZombiePlan.h @@ -0,0 +1,34 @@ +/** + * @file + * @author feynman (bears-pit.com) + */ + +#ifndef LEGACY_ZOMBIE_PLAN_H_ +#define LEGACY_ZOMBIE_PLAN_H_ + +#include "Plan.h" + +namespace AI +{ + namespace tactical + { + /**@class LegacyZombiePlan + * @brief Component/Concrete Product. Wrapper/Re-Write of ZombieDecideAction() + * + * This plan began as a simple forwarding object for ZombieDecideAction(), 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 LegacyZombiePlan: public Plan + { + private: + public: + LegacyZombiePlan(SOLDIERTYPE* npc); + virtual void execute(PlanInputData& environment); + virtual bool done() const {return false;} + }; + } +} + +#endif + diff --git a/ModularizedTacticalAI/include/PlanList.h b/ModularizedTacticalAI/include/PlanList.h new file mode 100644 index 00000000..b20e6266 --- /dev/null +++ b/ModularizedTacticalAI/include/PlanList.h @@ -0,0 +1,36 @@ +#ifndef PLAN_LIST_H_ +#define PLAN_LIST_H_ + +#include "Plan.h" +#include + +namespace AI +{ + namespace tactical + { + /**@class PlanList + * @brief Composition/Abstract Product. Used to concatenate plans. + * + * Plan lists can comprise an arbitrary number of sub-plans, executed in the order they were added via + * add_subplan(), and switched to the next one once the done()-flag of a sub-plan becomes true. + */ + class PlanList : public Plan + { + private: + /// The sub-plan sequence + std::deque subplans_; + public: + PlanList(SOLDIERTYPE* npc); + /// Add a plan to the list of sub-plans + virtual void add_subplan(Plan* P); + /// Execute the next plan in the list + virtual void execute(PlanInputData& environment); + /// Done will be set once the last plan is marked as done() + virtual bool done() const; + virtual ~PlanList(); + }; + } +} + +#endif + diff --git a/ModularizedTacticalAI/src/AbstractPlanFactory.cpp b/ModularizedTacticalAI/src/AbstractPlanFactory.cpp new file mode 100644 index 00000000..f22c4c8a --- /dev/null +++ b/ModularizedTacticalAI/src/AbstractPlanFactory.cpp @@ -0,0 +1,48 @@ +#include "../include/AbstractPlanFactory.h" +#include "../../Tactical/Soldier Control.h" + +#include + +namespace AI +{ + namespace tactical + { + AIInputData::AIInputData(Auditive , int noise_maker, int grid_no, int level, int volume, int type) + : noise_maker_(noise_maker), + grid_no_(grid_no), + level_(level), + volume_(volume), + type_(type) + { + event_type_ = auditive_event; + } + + AIInputData::AIInputData(Visual, SOLDIERTYPE* opponent, int grid_no, int level, int caller1, int caller2) + : opponent_(opponent), + grid_no_(grid_no), + level_(level), + caller1_(caller1), + caller2_(caller2) + { + event_type_ = visual_event; + } + + AIInputData::AIInputData() + : event_type_(no_event) + { + } + + std::ostream& operator<<(std::ostream& os, const AIInputData& i) + { + if(i.event_type_ == AIInputData::no_event) + return os<<"no_event"; + if(i.event_type_ == AIInputData::auditive_event) + return os<<"sound: "<ubID<<" was seen at "<bTeam ); + } + + CrowSeekCorpsePlan::CrowSeekCorpsePlan(SOLDIERTYPE* npc) + : Plan(npc), + corpse_grid_(FindNearestRottingCorpse(npc)) + { + } + + void CrowSeekCorpsePlan::execute(PlanInputData& environment) + { + get_npc()->aiData.bAction = AI_ACTION_NONE; + if(TileIsOutOfBounds(corpse_grid_)) + return; + // Walk to nearest corpse + UINT8 unused; + get_npc()->aiData.usActionData = FindGridNoFromSweetSpot( get_npc(), corpse_grid_, 4, &unused); + if(TileIsOutOfBounds(get_npc()->aiData.usActionData)) + return; + get_npc()->aiData.bAction = AI_ACTION_GET_CLOSER; + } + + bool CrowSeekCorpsePlan::done() const + { + return SpacesAway( get_npc()->sGridNo, corpse_grid_ ) < 2; + } + + int CrowSeekCorpsePlan::get_corpse_grid() const + { + return corpse_grid_; + } + + CrowPeckPlan::CrowPeckPlan(SOLDIERTYPE* npc, int corpse_grid) + : Plan(npc), corpse_grid_(corpse_grid) + { + } + + void CrowPeckPlan::execute(PlanInputData& environment) + { + get_npc()->aiData.bAction = AI_ACTION_NONE; + INT16 sFacingDir; + if (TileIsOutOfBounds(corpse_grid_)) + return; + + // Change facing + sFacingDir = GetDirectionFromGridNo( corpse_grid_, get_npc() ); + if ( sFacingDir != get_npc()->ubDirection ) + { + get_npc()->aiData.usActionData = sFacingDir; + get_npc()->aiData.bAction = AI_ACTION_CHANGE_FACING; + return; + } + if (!environment.turn_based()) + { + get_npc()->aiData.usActionData = 30000; + get_npc()->aiData.bAction = AI_ACTION_WAIT; + } + } + + } // namespace tactical +} // namespace AI + diff --git a/ModularizedTacticalAI/src/LegacyCreaturePlan.cpp b/ModularizedTacticalAI/src/LegacyCreaturePlan.cpp new file mode 100644 index 00000000..676df61a --- /dev/null +++ b/ModularizedTacticalAI/src/LegacyCreaturePlan.cpp @@ -0,0 +1,26 @@ +/** + * @file + * @author feynman (bears-pit.com) + */ + +#include "../include/LegacyCreaturePlan.h" +#include "../../Tactical/Soldier Control.h" + +INT8 CreatureDecideAction( SOLDIERTYPE *pSoldier ); + +namespace AI +{ + namespace tactical + { + LegacyCreaturePlan::LegacyCreaturePlan(SOLDIERTYPE* npc) + : Plan(npc) + { + } + + void LegacyCreaturePlan::execute(PlanInputData& environment) + { + get_npc()->aiData.bAction = CreatureDecideAction( get_npc() ); + } + } +} + diff --git a/ModularizedTacticalAI/src/LegacyZombiePlan.cpp b/ModularizedTacticalAI/src/LegacyZombiePlan.cpp new file mode 100644 index 00000000..c349858e --- /dev/null +++ b/ModularizedTacticalAI/src/LegacyZombiePlan.cpp @@ -0,0 +1,26 @@ +/** + * @file + * @author feynman (bears-pit.com) + */ + +#include "../include/LegacyZombiePlan.h" +#include "../../Tactical/Soldier Control.h" // definition of SOLDIERTYPE + +INT8 ZombieDecideAction( SOLDIERTYPE *pSoldier ); // defined in DecideAction.cpp + +namespace AI +{ + namespace tactical + { + LegacyZombiePlan::LegacyZombiePlan(SOLDIERTYPE* npc) + : Plan(npc) + { + } + + void LegacyZombiePlan::execute(PlanInputData& environment) + { + get_npc()->aiData.bAction = ZombieDecideAction(get_npc()); + } + } +} + diff --git a/ModularizedTacticalAI/src/Plan.cpp b/ModularizedTacticalAI/src/Plan.cpp new file mode 100644 index 00000000..11f77fb1 --- /dev/null +++ b/ModularizedTacticalAI/src/Plan.cpp @@ -0,0 +1,40 @@ +#include "../include/Plan.h" + +#include "../../TacticalAI/ai.h" +#include "../../TacticalAI/AIInternals.h" // ACTING_ON_SCHEDULE +#include "../../TacticalAI/NPC.h" // NPCReachedDestination +#include "../../Tactical/Animation Control.h" // defines ANIM_... +#include "../../Tactical/Soldier Macros.h" // CREATURE_OR_BLOODCAT +#include "../../Tactical/opplist.h" // EndMuzzleFlash +#include "../../Tactical/Dialogue Control.h" // DialogueQueueIsEmpty +#include "../../TileEngine/Isometric Utils.h" // defines NOWHERE +#include "../../Utils/Debug Control.h" // LiveMessage +#include "../../Utils/Font Control.h" // ScreenMsg about deadlock +#include "../../Utils/message.h" // ditto +#include "../../TileEngine/Render Fun.h" // defines InARoom +#include "../../Strategic/quests.h" // IN_BROTHEL + + // FIXME uagh, these need to go +extern BOOLEAN gfUIInDeadlock; +extern UINT8 gUIDeadlockedSoldier; + +void HandleAITacticalTraversal(SOLDIERTYPE* pSoldier); // defined in TacticalAI/AIMain.cpp + +namespace AI +{ + namespace tactical + { + PlanInputData::PlanInputData(bool turn_based, const TacticalStatusType& tactical_status) + : turn_based_(turn_based), + tactical_status_(tactical_status) + { + } + + Plan::Plan(SOLDIERTYPE* npc) + : npc_(npc) + { + } + + } +} + diff --git a/ModularizedTacticalAI/src/PlanList.cpp b/ModularizedTacticalAI/src/PlanList.cpp new file mode 100644 index 00000000..9294c2df --- /dev/null +++ b/ModularizedTacticalAI/src/PlanList.cpp @@ -0,0 +1,47 @@ +#include "../include/PlanList.h" +#include "../../TacticalAI/AIInternals.h" + +#include + +namespace AI +{ + namespace tactical + { + PlanList::PlanList(SOLDIERTYPE* npc) + : Plan(npc) + { + } + + PlanList::~PlanList() + { + for(std::deque::iterator subplan_iter(subplans_.begin()); subplan_iter != subplans_.end(); ++subplan_iter) + delete *subplan_iter; + } + + void PlanList::add_subplan(Plan* p) + { + if(!p) + throw std::logic_error("No empty plans in PlanList allowed"); + subplans_.push_back(p); + } + + void PlanList::execute(PlanInputData& environment) + { + while(!subplans_.empty() && subplans_.front()->done()) + { + delete subplans_.front(); + subplans_.pop_front(); + DEBUGAIMSG("Plan done, switching to next..."); + } + if(subplans_.empty()) + return; + subplans_.front()->execute(environment); + } + + bool PlanList::done() const + { + return subplans_.empty(); + } + } +} +