aboutsummaryrefslogtreecommitdiff
path: root/src/bindings/scripts/base
diff options
context:
space:
mode:
authorKudlaty <none@none>2009-08-16 18:34:45 +0200
committerKudlaty <none@none>2009-08-16 18:34:45 +0200
commita4b91e2cc4a4d0a09bce01c686df1fc7c812a12a (patch)
treef8530a665348452f6a59cda0661451c6958b54cd /src/bindings/scripts/base
parent9ddfd5bf22269f8622f72ee3797a56b0dcc37422 (diff)
Merge [SD2]
r1311 Move SetData from Reset to JustReachedHome for channelers and boss. r1312 Added class for FollowerAI. Note this is under development and may have issues in some situations. FollowerAI is generally to be used for escort quests where NPC follow leader instead of using a predefined path. --HG-- branch : trunk
Diffstat (limited to 'src/bindings/scripts/base')
-rw-r--r--src/bindings/scripts/base/escort_ai.cpp (renamed from src/bindings/scripts/base/escortAI.cpp)2
-rw-r--r--src/bindings/scripts/base/escort_ai.h (renamed from src/bindings/scripts/base/escortAI.h)0
-rw-r--r--src/bindings/scripts/base/follower_ai.cpp309
-rw-r--r--src/bindings/scripts/base/follower_ai.h50
4 files changed, 360 insertions, 1 deletions
diff --git a/src/bindings/scripts/base/escortAI.cpp b/src/bindings/scripts/base/escort_ai.cpp
index 2c9b968d281..3f4c8601f90 100644
--- a/src/bindings/scripts/base/escortAI.cpp
+++ b/src/bindings/scripts/base/escort_ai.cpp
@@ -10,7 +10,7 @@ SDCategory: Npc
EndScriptData */
#include "precompiled.h"
-#include "escortAI.h"
+#include "escort_ai.h"
enum
{
diff --git a/src/bindings/scripts/base/escortAI.h b/src/bindings/scripts/base/escort_ai.h
index 8ce82eb370a..8ce82eb370a 100644
--- a/src/bindings/scripts/base/escortAI.h
+++ b/src/bindings/scripts/base/escort_ai.h
diff --git a/src/bindings/scripts/base/follower_ai.cpp b/src/bindings/scripts/base/follower_ai.cpp
new file mode 100644
index 00000000000..eb847c219db
--- /dev/null
+++ b/src/bindings/scripts/base/follower_ai.cpp
@@ -0,0 +1,309 @@
+/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
+ * This program is free software licensed under GPL version 2
+ * Please see the included DOCS/LICENSE.TXT for more information */
+
+/* ScriptData
+SDName: FollowerAI
+SD%Complete: 50
+SDComment: This AI is under development
+SDCategory: Npc
+EndScriptData */
+
+#include "precompiled.h"
+#include "follower_ai.h"
+
+const float MAX_PLAYER_DISTANCE = 100.0f;
+
+enum
+{
+ POINT_COMBAT_START = 0xFFFFFF
+};
+
+FollowerAI::FollowerAI(Creature* pCreature) : ScriptedAI(pCreature),
+ m_uiLeaderGUID(0),
+ m_pQuestForFollow(NULL),
+ m_uiUpdateFollowTimer(2500),
+ m_bIsFollowing(false),
+ m_bIsReturnToLeader(false),
+ m_bIsFollowComplete(false)
+{}
+
+void FollowerAI::AttackStart(Unit* pWho)
+{
+ if (!pWho)
+ return;
+
+ if (m_creature->Attack(pWho, true))
+ {
+ m_creature->AddThreat(pWho, 0.0f);
+ m_creature->SetInCombatWith(pWho);
+ pWho->SetInCombatWith(m_creature);
+
+ if (m_creature->hasUnitState(UNIT_STAT_FOLLOW))
+ m_creature->clearUnitState(UNIT_STAT_FOLLOW);
+
+ if (IsCombatMovement())
+ m_creature->GetMotionMaster()->MoveChase(pWho);
+ }
+}
+
+void FollowerAI::MoveInLineOfSight(Unit* pWho)
+{
+ if (!m_creature->hasUnitState(UNIT_STAT_STUNNED) && pWho->isTargetableForAttack() &&
+ m_creature->IsHostileTo(pWho) && pWho->isInAccessiblePlaceFor(m_creature))
+ {
+ if (!m_creature->canFly() && m_creature->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE)
+ return;
+
+ //This part provides assistance to a player that are attacked by pWho, even if out of normal aggro range
+ //It will cause m_creature to attack pWho that are attacking _any_ player (which has been confirmed may happen also on offi)
+ //The flag (type_flag) is unconfirmed, but used here for further research and is a good candidate.
+ if (m_creature->hasUnitState(UNIT_STAT_FOLLOW) &&
+ m_creature->GetCreatureInfo()->type_flags & 0x01000 &&
+ pWho->getVictim() &&
+ pWho->getVictim()->GetCharmerOrOwnerPlayerOrPlayerItself() &&
+ m_creature->IsWithinDistInMap(pWho, MAX_PLAYER_DISTANCE) &&
+ m_creature->IsWithinLOSInMap(pWho))
+ {
+ pWho->RemoveAurasDueToSpell(SPELL_AURA_MOD_STEALTH);
+ AttackStart(pWho);
+ }
+ else
+ {
+ float attackRadius = m_creature->GetAttackDistance(pWho);
+ if (m_creature->IsWithinDistInMap(pWho, attackRadius) && m_creature->IsWithinLOSInMap(pWho))
+ {
+ if (!m_creature->getVictim())
+ {
+ pWho->RemoveAurasDueToSpell(SPELL_AURA_MOD_STEALTH);
+ AttackStart(pWho);
+ }
+ else if (m_creature->GetMap()->IsDungeon())
+ {
+ pWho->SetInCombatWith(m_creature);
+ m_creature->AddThreat(pWho, 0.0f);
+ }
+ }
+ }
+ }
+}
+
+void FollowerAI::JustDied(Unit* pKiller)
+{
+ if (!m_bIsFollowing || !m_uiLeaderGUID)
+ return;
+
+ //TODO: need a better check for quests with time limit.
+ if (Player* pPlayer = GetLeaderForFollower())
+ {
+ if (Group* pGroup = pPlayer->GetGroup())
+ {
+ for(GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next())
+ {
+ if (Player* pMember = pRef->getSource())
+ {
+ if (pPlayer->GetQuestStatus(m_pQuestForFollow->GetQuestId()) == QUEST_STATUS_INCOMPLETE)
+ pPlayer->FailQuest(m_pQuestForFollow->GetQuestId());
+ }
+ }
+ }
+ else
+ {
+ if (pPlayer->GetQuestStatus(m_pQuestForFollow->GetQuestId()) == QUEST_STATUS_INCOMPLETE)
+ pPlayer->FailQuest(m_pQuestForFollow->GetQuestId());
+ }
+ }
+}
+
+void FollowerAI::JustRespawned()
+{
+ m_bIsFollowing = false;
+ m_bIsReturnToLeader = false;
+ m_bIsFollowComplete = false;
+
+ if (!IsCombatMovement())
+ SetCombatMovement(true);
+
+ if (m_creature->getFaction() != m_creature->GetCreatureInfo()->faction_A)
+ m_creature->setFaction(m_creature->GetCreatureInfo()->faction_A);
+
+ Reset();
+}
+
+void FollowerAI::EnterEvadeMode()
+{
+ m_creature->RemoveAllAuras();
+ m_creature->DeleteThreatList();
+ m_creature->CombatStop(true);
+ m_creature->SetLootRecipient(NULL);
+
+ if (m_bIsFollowing)
+ {
+ debug_log("SD2: FollowerAI left combat, returning to CombatStartPosition.");
+
+ if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE)
+ {
+ float fPosX, fPosY, fPosZ;
+ m_creature->GetPosition(fPosX, fPosY, fPosZ);
+ m_creature->GetMotionMaster()->MovePoint(POINT_COMBAT_START, fPosX, fPosY, fPosZ);
+ }
+ }
+ else
+ {
+ if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE)
+ m_creature->GetMotionMaster()->MoveTargetedHome();
+ }
+
+ Reset();
+}
+
+void FollowerAI::UpdateAI(const uint32 uiDiff)
+{
+ if (m_bIsFollowing && !m_creature->getVictim())
+ {
+ if (m_uiUpdateFollowTimer < uiDiff)
+ {
+ if (m_bIsFollowComplete)
+ {
+ debug_log("SD2: FollowerAI is set completed, despawns.");
+ m_creature->ForcedDespawn();
+ return;
+ }
+
+ bool bIsMaxRangeExceeded = true;
+
+ if (Player* pPlayer = GetLeaderForFollower())
+ {
+ if (m_bIsReturnToLeader)
+ {
+ debug_log("SD2: FollowerAI is returning to leader.");
+ m_creature->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
+ m_bIsReturnToLeader = false;
+ return;
+ }
+
+ if (Group* pGroup = pPlayer->GetGroup())
+ {
+ for(GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next())
+ {
+ Player* pMember = pRef->getSource();
+
+ if (pMember && m_creature->IsWithinDistInMap(pMember, MAX_PLAYER_DISTANCE))
+ {
+ bIsMaxRangeExceeded = false;
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (m_creature->IsWithinDistInMap(pPlayer, MAX_PLAYER_DISTANCE))
+ bIsMaxRangeExceeded = false;
+ }
+ }
+
+ if (bIsMaxRangeExceeded)
+ {
+ debug_log("SD2: FollowerAI failed because player/group was to far away or not found");
+ m_creature->ForcedDespawn();
+ return;
+ }
+
+ m_uiUpdateFollowTimer = 1000;
+ }
+ else
+ m_uiUpdateFollowTimer -= uiDiff;
+ }
+
+ UpdateFollowerAI(uiDiff);
+}
+
+void FollowerAI::UpdateFollowerAI(const uint32 uiDiff)
+{
+ if (!UpdateVictim())
+ return;
+
+ DoMeleeAttackIfReady();
+}
+
+void FollowerAI::MovementInform(uint32 uiMotionType, uint32 uiPointId)
+{
+ if (uiMotionType != POINT_MOTION_TYPE || !m_bIsFollowing)
+ return;
+
+ if (uiPointId == POINT_COMBAT_START)
+ {
+ if (GetLeaderForFollower())
+ m_bIsReturnToLeader = true;
+ else
+ m_creature->ForcedDespawn();
+ }
+}
+
+void FollowerAI::StartFollow(Player* pLeader, uint32 uiFactionForFollower, const Quest* pQuest)
+{
+ if (m_creature->getVictim())
+ {
+ debug_log("SD2: FollowerAI attempt to StartFollow while in combat.");
+ return;
+ }
+
+ if (m_bIsFollowing)
+ {
+ error_log("SD2: FollowerAI attempt to StartFollow while already following.");
+ return;
+ }
+
+ //set variables
+ m_uiLeaderGUID = pLeader->GetGUID();
+
+ if (uiFactionForFollower)
+ m_creature->setFaction(uiFactionForFollower);
+
+ m_pQuestForFollow = pQuest;
+
+ if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE)
+ {
+ m_creature->GetMotionMaster()->Clear();
+ m_creature->GetMotionMaster()->MoveIdle();
+ debug_log("SD2: FollowerAI start with WAYPOINT_MOTION_TYPE, set to MoveIdle.");
+ }
+
+ m_creature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
+
+ m_creature->GetMotionMaster()->MoveFollow(pLeader, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
+
+ m_bIsFollowing = true;
+
+ debug_log("SD2: FollowerAI start follow %s (GUID %u)", pLeader->GetName(), m_uiLeaderGUID);
+}
+
+Player* FollowerAI::GetLeaderForFollower()
+{
+ if (Player* pLeader = (Player*)Unit::GetUnit(*m_creature, m_uiLeaderGUID))
+ {
+ if (pLeader->isAlive())
+ return pLeader;
+ else
+ {
+ if (Group* pGroup = pLeader->GetGroup())
+ {
+ for(GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next())
+ {
+ Player* pMember = pRef->getSource();
+
+ if (pMember && pMember->isAlive() && m_creature->IsWithinDistInMap(pMember, MAX_PLAYER_DISTANCE))
+ {
+ debug_log("SD2: FollowerAI GetLeader changed and returned new leader.");
+ m_uiLeaderGUID = pMember->GetGUID();
+ return pMember;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ debug_log("SD2: FollowerAI GetLeader can not find suitable leader.");
+ return NULL;
+}
diff --git a/src/bindings/scripts/base/follower_ai.h b/src/bindings/scripts/base/follower_ai.h
new file mode 100644
index 00000000000..d62980d4951
--- /dev/null
+++ b/src/bindings/scripts/base/follower_ai.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
+ * This program is free software licensed under GPL version 2
+ * Please see the included DOCS/LICENSE.TXT for more information */
+
+#ifndef SC_FOLLOWERAI_H
+#define SC_FOLLOWERAI_H
+
+class TRINITY_DLL_DECL FollowerAI : public ScriptedAI
+{
+ public:
+ explicit FollowerAI(Creature* pCreature);
+ ~FollowerAI() {}
+
+ //virtual void WaypointReached(uint32 uiPointId) = 0;
+
+ void MovementInform(uint32 uiMotionType, uint32 uiPointId);
+
+ void AttackStart(Unit*);
+
+ void MoveInLineOfSight(Unit*);
+
+ void EnterEvadeMode();
+
+ void JustDied(Unit*);
+
+ void JustRespawned();
+
+ void UpdateAI(const uint32); //the "internal" update, calls UpdateFollowerAI()
+ virtual void UpdateFollowerAI(const uint32); //used when it's needed to add code in update (abilities, scripted events, etc)
+
+ void StartFollow(Player* pPlayer, uint32 uiFactionForFollower = 0, const Quest* pQuest = NULL);
+
+ protected:
+ void SetFollowComplete() { m_bIsFollowComplete = true; }
+ bool IsFollowComplete() { return m_bIsFollowComplete; }
+
+ Player* GetLeaderForFollower();
+
+ private:
+ uint64 m_uiLeaderGUID;
+ uint32 m_uiUpdateFollowTimer;
+
+ bool m_bIsFollowing;
+ bool m_bIsReturnToLeader;
+ bool m_bIsFollowComplete;
+
+ const Quest* m_pQuestForFollow; //normally we have a quest
+};
+
+#endif