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
This commit is contained in:
Kudlaty
2009-08-16 18:34:45 +02:00
parent 9ddfd5bf22
commit a4b91e2cc4
48 changed files with 444 additions and 60 deletions
+4 -2
View File
@@ -4,8 +4,10 @@
SET(trinityscript_LIB_SRCS
ScriptMgr.cpp
ScriptMgr.h
base/escortAI.cpp
base/escortAI.h
base/escort_ai.cpp
base/escort_ai.h
base/follower_ai.cpp
base/follower_ai.h
base/guard_ai.cpp
base/guard_ai.h
base/simple_ai.cpp
+10 -2
View File
@@ -364,11 +364,19 @@
Name="base"
>
<File
RelativePath="..\base\escortAI.cpp"
RelativePath="..\base\escort_ai.cpp"
>
</File>
<File
RelativePath="..\base\escortAI.h"
RelativePath="..\base\escort_ai.h"
>
</File>
<File
RelativePath="..\base\follower_ai.cpp"
>
</File>
<File
RelativePath="..\base\follower_ai.h"
>
</File>
<File
+10 -2
View File
@@ -361,11 +361,19 @@
Name="base"
>
<File
RelativePath="..\base\escortAI.cpp"
RelativePath="..\base\escort_ai.cpp"
>
</File>
<File
RelativePath="..\base\escortAI.h"
RelativePath="..\base\escort_ai.h"
>
</File>
<File
RelativePath="..\base\follower_ai.cpp"
>
</File>
<File
RelativePath="..\base\follower_ai.h"
>
</File>
<File
@@ -10,7 +10,7 @@ SDCategory: Npc
EndScriptData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
enum
{
+309
View File
@@ -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;
}
+50
View File
@@ -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
+1 -1
View File
@@ -22,7 +22,7 @@ SDCategory: Script Examples
EndScriptData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
struct TRINITY_DLL_DECL npc_testAI : public npc_escortAI
{
@@ -26,7 +26,7 @@ npc_professor_phizzlethorpe
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
## npc_professor_phizzlethorpe
@@ -37,7 +37,7 @@ npc_rocknot
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
#include "def_blackrock_depths.h"
/*######
@@ -30,7 +30,7 @@ go_harbinger_second_trial
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
## npc_prospector_anvilward
@@ -29,7 +29,7 @@ npc_ranger_lilatha
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
## npc_blood_knight_dawnstar
@@ -26,7 +26,7 @@ npc_rinji
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
## npc_rinji
@@ -29,7 +29,7 @@ EndContentData */
#include "precompiled.h"
#include "def_karazhan.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
# npc_barnesAI
@@ -19,7 +19,7 @@
#include "precompiled.h"
#include "Vehicle.h"
#include "ObjectMgr.h"
#include "escortAI.h"
#include "escort_ai.h"
#define GCD_CAST 1
@@ -22,7 +22,7 @@ SDCategory: Scarlet Monastery
EndScriptData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
#define SAY_AGGRO -1189000
#define SAY_WHIRLWIND -1189001
@@ -26,7 +26,7 @@ npc_shadowfang_prisoner
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
#include "def_shadowfang_keep.h"
/*######
@@ -27,7 +27,7 @@ npc_deathstalker_erland
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
## npc_astor_hadren
@@ -27,7 +27,7 @@ npc_defias_traitor
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
## npc_daphne_stilwell
@@ -22,7 +22,7 @@ SDCategory: Script Examples
EndScriptData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
enum
{
@@ -27,7 +27,7 @@ npc_ruul_snowhoof
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*####
# npc_torek
@@ -31,7 +31,7 @@ mob_nestlewood_owlkin
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
#include <cmath>
/*######
@@ -6,7 +6,7 @@
#define SC_HYJALAI_H
#include "def_hyjal.h"
#include "escortAI.h"
#include "escort_ai.h"
// Trash Mobs summoned in waves
#define NECROMANCER 17899//done
@@ -3,7 +3,7 @@
#define SC_HYJAL_TRASH_AI_H
#include "def_hyjal.h"
#include "escortAI.h"
#include "escort_ai.h"
#define MINRAIDDAMAGE 700000//minimal damage before trash can drop loot and reputation, resets if faction leader dies
@@ -23,7 +23,7 @@ EndScriptData */
#include "precompiled.h"
#include "def_old_hillsbrad.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
## go_barrel_old_hillsbrad
@@ -28,7 +28,7 @@ npc_taretha
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
#include "def_old_hillsbrad.h"
#define QUEST_ENTRY_HILLSBRAD 10282
@@ -27,7 +27,7 @@ npc_threshwackonator
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*####
# npc_prospector_remtravel
@@ -22,7 +22,7 @@ SDCategory: Feralas
EndScriptData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
## npc_gregan_brewspewer
@@ -30,7 +30,7 @@ npc_clintar_dreamwalker
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
## npc_bunthen_plainswind
@@ -28,7 +28,7 @@ npc_plains_vision
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
# npc_skorn_whitecloud
@@ -26,7 +26,7 @@ npc_willix
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
#include "def_razorfen_kraul.h"
#define SAY_READY -1047000
@@ -27,7 +27,7 @@ npc_kaya_flathoof
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
## npc_braug_dimspirit
@@ -32,7 +32,7 @@ npc_tooga
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
## mob_aquementas
@@ -31,7 +31,7 @@ npc_wizzlecrank_shredder
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
## npc_beaten_corpse
@@ -29,7 +29,7 @@ npc_plucky
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*#####
# npc_kanati
@@ -26,7 +26,7 @@ npc_a-me
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
#define SAY_READY -1000200
#define SAY_AGGRO1 -1000201
@@ -25,7 +25,7 @@ EndScriptData */
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
#include "def_wailing_caverns.h"
/*######
@@ -26,7 +26,7 @@ npc_injured_rainspeaker_oracle
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
## npc_injured_rainspeaker_oracle
@@ -22,7 +22,7 @@ SDCategory: Auchindoun, Shadow Labyrinth
EndScriptData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
#include "def_shadow_labyrinth.h"
enum
@@ -23,7 +23,7 @@ EndScriptData */
#include "precompiled.h"
#include "def_serpent_shrine.h"
#include "escortAI.h"
#include "escort_ai.h"
#define SAY_AGGRO -1548021
#define SAY_GAIN_BLESSING -1548022
@@ -205,12 +205,6 @@ struct TRINITY_DLL_DECL boss_magtheridonAI : public ScriptedAI
void Reset()
{
if (pInstance)
{
pInstance->SetData(DATA_MAGTHERIDON_EVENT, NOT_STARTED);
pInstance->SetData(DATA_COLLAPSE, false);
}
Berserk_Timer = 1320000;
Quake_Timer = 40000;
Debris_Timer = 10000;
@@ -229,6 +223,15 @@ struct TRINITY_DLL_DECL boss_magtheridonAI : public ScriptedAI
m_creature->CastSpell(m_creature, SPELL_SHADOW_CAGE_C, true);
}
void JustReachedHome()
{
if (pInstance)
{
pInstance->SetData(DATA_MAGTHERIDON_EVENT, NOT_STARTED);
pInstance->SetData(DATA_COLLAPSE, false);
}
}
void SetClicker(uint64 cubeGUID, uint64 clickerGUID)
{
// to avoid multiclicks from 1 cube
@@ -432,11 +435,6 @@ struct TRINITY_DLL_DECL mob_hellfire_channelerAI : public ScriptedAI
Infernal_Timer = 10000 + rand()%40000;
Check_Timer = 5000;
if (pInstance)
pInstance->SetData(DATA_CHANNELER_EVENT, NOT_STARTED);
m_creature->CastSpell(m_creature, SPELL_SHADOW_GRASP_C, false);
}
void EnterCombat(Unit *who)
@@ -448,9 +446,18 @@ struct TRINITY_DLL_DECL mob_hellfire_channelerAI : public ScriptedAI
DoZoneInCombat();
}
void JustSummoned(Creature *summon) {summon->AI()->AttackStart(m_creature->getVictim());}
void JustReachedHome()
{
if (pInstance)
pInstance->SetData(DATA_CHANNELER_EVENT, NOT_STARTED);
void MoveInLineOfSight(Unit* who) {}
m_creature->CastSpell(m_creature, SPELL_SHADOW_GRASP_C, false);
}
void JustSummoned(Creature *summon)
{
summon->AI()->AttackStart(m_creature->getVictim());
}
void DamageTaken(Unit*, uint32 &damage)
{
@@ -30,7 +30,7 @@ npc_wounded_blood_elf
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
## npc_aeranas
@@ -29,7 +29,7 @@ npc_bessy
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
## npc_manaforge_control_console
@@ -40,7 +40,7 @@ npc_enraged_spirit
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*#####
# mob_mature_netherwing_drake
@@ -33,7 +33,7 @@ npc_khadgar
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
## npc_raliq_the_drunk
@@ -32,7 +32,7 @@ npc_slim
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
## mob_unkor_the_ruthless
@@ -30,7 +30,7 @@ npc_kayra_longmane
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
/*######
## npcs_ashyen_and_keleth
@@ -38,7 +38,7 @@ npc_snake_trap_serpents 80% AI for snakes that summoned by Snake Trap
EndContentData */
#include "precompiled.h"
#include "escortAI.h"
#include "escort_ai.h"
#include "ObjectMgr.h"
/*########