aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/scripts/world_scripts_full.sql4
-rw-r--r--sql/updates/world/2011_02_10_3_world_creature_template.sql2
-rw-r--r--sql/updates/world/2011_02_10_4_world_scriptname.sql2
-rwxr-xr-xsrc/server/game/AI/CoreAI/GuardAI.cpp44
-rwxr-xr-xsrc/server/game/AI/CoreAI/GuardAI.h6
-rwxr-xr-xsrc/server/game/AI/CreatureAI.h1
-rwxr-xr-xsrc/server/game/AI/ScriptedAI/ScriptedGuardAI.cpp198
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedGuardAI.h45
-rwxr-xr-xsrc/server/game/Entities/Creature/Creature.cpp21
-rwxr-xr-xsrc/server/game/Entities/Creature/Creature.h7
-rwxr-xr-xsrc/server/game/Entities/Object/Object.cpp2
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.cpp12
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.h7
-rwxr-xr-xsrc/server/game/Server/Protocol/Handlers/NPCHandler.cpp2
-rw-r--r--src/server/scripts/CMakeLists.txt1
-rw-r--r--src/server/scripts/World/guards.cpp363
16 files changed, 328 insertions, 389 deletions
diff --git a/sql/scripts/world_scripts_full.sql b/sql/scripts/world_scripts_full.sql
index 8f3aa125b13..d8f8dae3a49 100644
--- a/sql/scripts/world_scripts_full.sql
+++ b/sql/scripts/world_scripts_full.sql
@@ -96,9 +96,7 @@ UPDATE `gameobject_template` SET `ScriptName`='go_massive_seaforium_charge' WHER
UPDATE `gameobject_template` SET `ScriptName`='go_harpoon_launcher' WHERE `entry` IN (192175,192176,192177);
/* GUARD */
-UPDATE `creature_template` SET `ScriptName`='guard_generic' WHERE `entry` IN (727,1423,1735,1738,1742,1743,1744,1745,1746,2209,2210,3084,3212,3215,3217,3218,3219,3220,3221,3222,3223,3224,3502,3571,4262,4264,5595,5624,5725,5953,9460,11190,13076,15184,16221,16222,16733,18038,19687);
-UPDATE `creature_template` SET `ScriptName`='guard_orgrimmar' WHERE `entry`=3296;
-UPDATE `creature_template` SET `ScriptName`='guard_stormwind' WHERE `entry` IN (68,1976);
+UPDATE `creature_template` SET `ScriptName`='guard_generic' WHERE `entry` IN (68,1976,3218,3296,3502,4624,9460,11190,15184);
UPDATE `creature_template` SET `ScriptName`='guard_shattrath_aldor' WHERE `entry`=18549;
UPDATE `creature_template` SET `ScriptName`='guard_shattrath_scryer' WHERE `entry`=18568;
diff --git a/sql/updates/world/2011_02_10_3_world_creature_template.sql b/sql/updates/world/2011_02_10_3_world_creature_template.sql
new file mode 100644
index 00000000000..1bcf6d69dc3
--- /dev/null
+++ b/sql/updates/world/2011_02_10_3_world_creature_template.sql
@@ -0,0 +1,2 @@
+UPDATE `creature_template` SET `flags_extra`=`flags_extra`|0x00008000,`npcflag`=`npcflag`&~0x10000000 WHERE `npcflag` & 0x10000000;
+UPDATE `creature_template` SET `npcflag`=`npcflag`&~0x20000000 WHERE `npcflag` & 0x20000000; \ No newline at end of file
diff --git a/sql/updates/world/2011_02_10_4_world_scriptname.sql b/sql/updates/world/2011_02_10_4_world_scriptname.sql
new file mode 100644
index 00000000000..9745c5a3b0a
--- /dev/null
+++ b/sql/updates/world/2011_02_10_4_world_scriptname.sql
@@ -0,0 +1,2 @@
+UPDATE `creature_template` SET `ScriptName`='' WHERE `ScriptName` LIKE 'guard_generic' AND (`spell1`=0 AND `spell2`=0);
+UPDATE `creature_template` SET `ScriptName`='guard_generic' WHERE `ScriptName`='guard_stormwind' OR `ScriptName`='guard_orgrimmar'; \ No newline at end of file
diff --git a/src/server/game/AI/CoreAI/GuardAI.cpp b/src/server/game/AI/CoreAI/GuardAI.cpp
index b500a916266..5715e6fde1c 100755
--- a/src/server/game/AI/CoreAI/GuardAI.cpp
+++ b/src/server/game/AI/CoreAI/GuardAI.cpp
@@ -23,7 +23,7 @@
#include "World.h"
#include "CreatureAIImpl.h"
-int GuardAI::Permissible(const Creature *creature)
+int GuardAI::Permissible(const Creature* creature)
{
if (creature->isGuard())
return PERMIT_BASE_SPECIAL;
@@ -31,25 +31,42 @@ int GuardAI::Permissible(const Creature *creature)
return PERMIT_BASE_NO;
}
-GuardAI::GuardAI(Creature *c) : CreatureAI(c), i_victimGuid(0), i_state(STATE_NORMAL), i_tracker(TIME_INTERVAL_LOOK)
+GuardAI::GuardAI(Creature* creature) : ScriptedAI(creature), i_victimGuid(0), i_state(STATE_NORMAL), i_tracker(TIME_INTERVAL_LOOK)
{
}
-void GuardAI::MoveInLineOfSight(Unit *u)
+
+bool GuardAI::CanSeeAlways(WorldObject const* obj)
+{
+ if (!obj->isType(TYPEMASK_UNIT))
+ return false;
+
+ std::list<HostileReference *> t_list = me->getThreatManager().getThreatList();
+ for (std::list<HostileReference *>::const_iterator itr = t_list.begin(); itr!= t_list.end(); ++itr)
+ {
+ if (Unit* unit = Unit::GetUnit(*me, (*itr)->getUnitGuid()))
+ if (unit == obj)
+ return true;
+ }
+
+ return false;
+}
+
+void GuardAI::MoveInLineOfSight(Unit* unit)
{
// Ignore Z for flying creatures
- if (!me->canFly() && me->GetDistanceZ(u) > CREATURE_Z_ATTACK_RANGE)
+ if (!me->canFly() && me->GetDistanceZ(unit) > CREATURE_Z_ATTACK_RANGE)
return;
- if (!me->getVictim() && me->canAttack(u) &&
- (u->IsHostileToPlayers() || me->IsHostileTo(u) /*|| u->getVictim() && me->IsFriendlyTo(u->getVictim())*/) &&
- u->isInAccessiblePlaceFor(me))
+ if (!me->getVictim() && me->canAttack(unit) &&
+ (unit->IsHostileToPlayers() || me->IsHostileTo(unit) /*|| u->getVictim() && me->IsFriendlyTo(u->getVictim())*/) &&
+ unit->isInAccessiblePlaceFor(me))
{
- float attackRadius = me->GetAttackDistance(u);
- if (me->IsWithinDistInMap(u,attackRadius))
+ float attackRadius = me->GetAttackDistance(unit);
+ if (me->IsWithinDistInMap(unit,attackRadius))
{
//Need add code to let guard support player
- AttackStart(u);
+ AttackStart(unit);
//u->RemoveAurasByType(SPELL_AURA_MOD_STEALTH);
}
}
@@ -122,13 +139,8 @@ void GuardAI::UpdateAI(const uint32 /*diff*/)
}
}
-bool GuardAI::IsVisible(Unit *pl) const
-{
- return me->IsWithinDist(pl,sWorld->getFloatConfig(CONFIG_SIGHT_GUARDER))
- && me->canSeeOrDetect(pl);
-}
-void GuardAI::JustDied(Unit *killer)
+void GuardAI::JustDied(Unit* killer)
{
if (Player* pkiller = killer->GetCharmerOrOwnerPlayerOrPlayerItself())
me->SendZoneUnderAttackMessage(pkiller);
diff --git a/src/server/game/AI/CoreAI/GuardAI.h b/src/server/game/AI/CoreAI/GuardAI.h
index 02f8fb741f9..7b9c8d6808c 100755
--- a/src/server/game/AI/CoreAI/GuardAI.h
+++ b/src/server/game/AI/CoreAI/GuardAI.h
@@ -19,12 +19,12 @@
#ifndef TRINITY_GUARDAI_H
#define TRINITY_GUARDAI_H
-#include "CreatureAI.h"
+#include "ScriptedCreature.h"
#include "Timer.h"
class Creature;
-class GuardAI : public CreatureAI
+class GuardAI : public ScriptedAI
{
enum GuardState
{
@@ -39,7 +39,7 @@ class GuardAI : public CreatureAI
void MoveInLineOfSight(Unit *);
void EnterEvadeMode();
void JustDied(Unit *);
- bool IsVisible(Unit *) const;
+ bool CanSeeAlways(WorldObject const* obj);
void UpdateAI(const uint32);
static int Permissible(const Creature *);
diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h
index a48f0cd9875..12b200f1311 100755
--- a/src/server/game/AI/CreatureAI.h
+++ b/src/server/game/AI/CreatureAI.h
@@ -168,6 +168,7 @@ class CreatureAI : public UnitAI
virtual void PassengerBoarded(Unit * /*who*/, int8 /*seatId*/, bool /*apply*/) {}
+ virtual bool CanSeeAlways(WorldObject const* obj) {return false;}
protected:
virtual void MoveInLineOfSight(Unit *);
diff --git a/src/server/game/AI/ScriptedAI/ScriptedGuardAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedGuardAI.cpp
deleted file mode 100755
index a141f9adf6c..00000000000
--- a/src/server/game/AI/ScriptedAI/ScriptedGuardAI.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2008-2011 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* ScriptData
-SDName: Guard_AI
-SD%Complete: 90
-SDComment:
-SDCategory: Guards
-EndScriptData */
-
-#include "ScriptPCH.h"
-#include "ScriptedGuardAI.h"
-
-// **** This script is for use within every single guard to save coding time ****
-
-#define GENERIC_CREATURE_COOLDOWN 5000
-
-#define SAY_GUARD_SIL_AGGRO1 -1070001
-#define SAY_GUARD_SIL_AGGRO2 -1070002
-#define SAY_GUARD_SIL_AGGRO3 -1070003
-
-guardAI::guardAI(Creature* pCreature) : ScriptedAI(pCreature),
- GlobalCooldown(0),
- BuffTimer(0)
-{}
-
-void guardAI::Reset()
-{
- GlobalCooldown = 0;
- BuffTimer = 0; //Rebuff as soon as we can
-}
-
-void guardAI::EnterCombat(Unit *who)
-{
- if (me->GetEntry() == 15184)
- DoScriptText(RAND(SAY_GUARD_SIL_AGGRO1,SAY_GUARD_SIL_AGGRO2,SAY_GUARD_SIL_AGGRO3), me, who);
-
- if (SpellEntry const *spell = me->reachWithSpellAttack(who))
- DoCastSpell(who, spell);
-}
-
-void guardAI::JustDied(Unit *Killer)
-{
- //Send Zone Under Attack message to the LocalDefense and WorldDefense Channels
- if (Player* pKiller = Killer->GetCharmerOrOwnerPlayerOrPlayerItself())
- me->SendZoneUnderAttackMessage(pKiller);
-}
-
-void guardAI::UpdateAI(const uint32 diff)
-{
- //Always decrease our global cooldown first
- if (GlobalCooldown > diff)
- GlobalCooldown -= diff;
- else GlobalCooldown = 0;
-
- //Buff timer (only buff when we are alive and not in combat
- if (me->isAlive() && !me->isInCombat())
- {
- if (BuffTimer <= diff)
- {
- //Find a spell that targets friendly and applies an aura (these are generally buffs)
- SpellEntry const *info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_AURA);
-
- if (info && !GlobalCooldown)
- {
- //Cast the buff spell
- DoCastSpell(me, info);
-
- //Set our global cooldown
- GlobalCooldown = GENERIC_CREATURE_COOLDOWN;
-
- //Set our timer to 10 minutes before rebuff
- BuffTimer = 600000;
- } //Try again in 30 seconds
- else BuffTimer = 30000;
- } else BuffTimer -= diff;
- }
-
- //Return since we have no target
- if (!UpdateVictim())
- return;
-
- // Make sure our attack is ready and we arn't currently casting
- if (me->isAttackReady() && !me->IsNonMeleeSpellCasted(false))
- {
- //If we are within range melee the target
- if (me->IsWithinMeleeRange(me->getVictim()))
- {
- bool Healing = false;
- SpellEntry const *info = NULL;
-
- //Select a healing spell if less than 30% hp
- if (HealthBelowPct(30))
- info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_HEALING);
-
- //No healing spell available, select a hostile spell
- if (info) Healing = true;
- else info = SelectSpell(me->getVictim(), 0, 0, SELECT_TARGET_ANY_ENEMY, 0, 0, 0, 0, SELECT_EFFECT_DONTCARE);
-
- //20% chance to replace our white hit with a spell
- if (info && rand() % 5 == 0 && !GlobalCooldown)
- {
- //Cast the spell
- if (Healing)DoCastSpell(me, info);
- else DoCastSpell(me->getVictim(), info);
-
- //Set our global cooldown
- GlobalCooldown = GENERIC_CREATURE_COOLDOWN;
- }
- else me->AttackerStateUpdate(me->getVictim());
-
- me->resetAttackTimer();
- }
- }
- else
- {
- //Only run this code if we arn't already casting
- if (!me->IsNonMeleeSpellCasted(false))
- {
- bool Healing = false;
- SpellEntry const *info = NULL;
-
- //Select a healing spell if less than 30% hp ONLY 33% of the time
- if (HealthBelowPct(30) && rand() % 3 == 0)
- info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_HEALING);
-
- //No healing spell available, See if we can cast a ranged spell (Range must be greater than ATTACK_DISTANCE)
- if (info) Healing = true;
- else info = SelectSpell(me->getVictim(), 0, 0, SELECT_TARGET_ANY_ENEMY, 0, 0, NOMINAL_MELEE_RANGE, 0, SELECT_EFFECT_DONTCARE);
-
- //Found a spell, check if we arn't on cooldown
- if (info && !GlobalCooldown)
- {
- //If we are currently moving stop us and set the movement generator
- if ((*me).GetMotionMaster()->GetCurrentMovementGeneratorType() != IDLE_MOTION_TYPE)
- {
- (*me).GetMotionMaster()->Clear(false);
- (*me).GetMotionMaster()->MoveIdle();
- }
-
- //Cast spell
- if (Healing) DoCastSpell(me,info);
- else DoCastSpell(me->getVictim(),info);
-
- //Set our global cooldown
- GlobalCooldown = GENERIC_CREATURE_COOLDOWN;
-
- } //If no spells available and we arn't moving run to target
- else if ((*me).GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE)
- {
- //Cancel our current spell and then mutate new movement generator
- me->InterruptNonMeleeSpells(false);
- (*me).GetMotionMaster()->Clear(false);
- (*me).GetMotionMaster()->MoveChase(me->getVictim());
- }
- }
- }
-}
-
-void guardAI::DoReplyToTextEmote(uint32 em)
-{
- switch(em)
- {
- case TEXTEMOTE_KISS: me->HandleEmoteCommand(EMOTE_ONESHOT_BOW); break;
- case TEXTEMOTE_WAVE: me->HandleEmoteCommand(EMOTE_ONESHOT_WAVE); break;
- case TEXTEMOTE_SALUTE: me->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); break;
- case TEXTEMOTE_SHY: me->HandleEmoteCommand(EMOTE_ONESHOT_FLEX); break;
- case TEXTEMOTE_RUDE:
- case TEXTEMOTE_CHICKEN: me->HandleEmoteCommand(EMOTE_ONESHOT_POINT); break;
- }
-}
-
-void guardAI_orgrimmar::ReceiveEmote(Player* pPlayer, uint32 text_emote)
-{
- if (pPlayer->GetTeam() == HORDE)
- DoReplyToTextEmote(text_emote);
-}
-
-void guardAI_stormwind::ReceiveEmote(Player* pPlayer, uint32 text_emote)
-{
- if (pPlayer->GetTeam() == ALLIANCE)
- DoReplyToTextEmote(text_emote);
-}
diff --git a/src/server/game/AI/ScriptedAI/ScriptedGuardAI.h b/src/server/game/AI/ScriptedAI/ScriptedGuardAI.h
deleted file mode 100644
index d28f612625e..00000000000
--- a/src/server/game/AI/ScriptedAI/ScriptedGuardAI.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* 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_GUARDAI_H
-#define SC_GUARDAI_H
-
-#define GENERIC_CREATURE_COOLDOWN 5000
-
-struct guardAI : public ScriptedAI
-{
- public:
- explicit guardAI(Creature* pCreature);
- ~guardAI() {}
-
- uint32 GlobalCooldown; //This variable acts like the global cooldown that players have (1.5 seconds)
- uint32 BuffTimer; //This variable keeps track of buffs
-
- void Reset();
-
- void EnterCombat(Unit * /*who*/);
-
- void JustDied(Unit *Killer);
-
- void UpdateAI(const uint32 diff);
-
- //common used for guards in main cities
- void DoReplyToTextEmote(uint32 em);
-};
-
-struct guardAI_orgrimmar : public guardAI
-{
- guardAI_orgrimmar(Creature *c) : guardAI(c) {}
-
- void ReceiveEmote(Player *player, uint32 text_emote);
-};
-
-struct guardAI_stormwind : public guardAI
-{
- guardAI_stormwind(Creature *c) : guardAI(c) {}
-
- void ReceiveEmote(Player *player, uint32 text_emote);
-};
-#endif
-
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 782a2a2aace..0634d89fba1 100755
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -1421,6 +1421,17 @@ bool Creature::isVisibleForInState(WorldObject const* seer) const
return false;
}
+bool Creature::canSeeAlways(WorldObject const* obj) const
+{
+ if (Unit::canSeeAlways(obj))
+ return true;
+
+ if (IsAIEnabled && AI()->CanSeeAlways(obj))
+ return true;
+
+ return false;
+}
+
bool Creature::canStartAttack(Unit const* who, bool force) const
{
if (isCivilian())
@@ -1960,10 +1971,18 @@ bool Creature::_IsTargetAcceptable(const Unit *target) const
// if the target cannot be attacked, the target is not acceptable
if (IsFriendlyTo(target)
|| !target->isAttackableByAOE()
- || target->HasUnitState(UNIT_STAT_DIED)
|| (m_vehicle && (IsOnVehicle(target) || m_vehicle->GetBase()->IsOnVehicle(target))))
return false;
+ if (target->HasUnitState(UNIT_STAT_DIED))
+ {
+ // guards can detect fake death
+ if (isGuard() && target->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH))
+ return true;
+ else
+ return false;
+ }
+
const Unit *myVictim = getAttackerForHelper();
const Unit *targetVictim = target->getAttackerForHelper();
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 2cb9d6f859b..43ff73df08c 100755
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -49,7 +49,7 @@ enum CreatureFlagsExtra
CREATURE_FLAG_EXTRA_TRIGGER = 0x00000080, // trigger creature
CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00000100, // creature is immune to taunt auras and effect attack me
CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000, // custom flag for world event creatures (left room for merging)
- //CREATURE_FLAG_EXTRA_CHARM_AI = 0x00008000, // use ai when charmed
+ CREATURE_FLAG_EXTRA_GUARD = 0x00008000, // Creature is guard
CREATURE_FLAG_EXTRA_NO_CRIT = 0x00020000, // creature can't do critical strikes
CREATURE_FLAG_EXTRA_NO_SKILLGAIN = 0x00040000, // creature won't increase weapon skills
CREATURE_FLAG_EXTRA_TAUNT_DIMINISH = 0x00080000, // Taunt is a subject to diminishing returns on this creautre
@@ -61,7 +61,8 @@ enum CreatureFlagsExtra
CREATURE_FLAG_EXTRA_NO_PARRY | CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN | CREATURE_FLAG_EXTRA_NO_BLOCK | \
CREATURE_FLAG_EXTRA_NO_CRUSH | CREATURE_FLAG_EXTRA_NO_XP_AT_KILL | CREATURE_FLAG_EXTRA_TRIGGER | \
CREATURE_FLAG_EXTRA_NO_TAUNT | CREATURE_FLAG_EXTRA_WORLDEVENT | CREATURE_FLAG_EXTRA_NO_CRIT | \
- CREATURE_FLAG_EXTRA_NO_SKILLGAIN | CREATURE_FLAG_EXTRA_TAUNT_DIMINISH | CREATURE_FLAG_EXTRA_ALL_DIMINISH)
+ CREATURE_FLAG_EXTRA_NO_SKILLGAIN | CREATURE_FLAG_EXTRA_TAUNT_DIMINISH | CREATURE_FLAG_EXTRA_ALL_DIMINISH | \
+ CREATURE_FLAG_EXTRA_GUARD)
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform
#if defined(__GNUC__)
@@ -435,6 +436,7 @@ class Creature : public Unit, public GridObject<Creature>
bool isRacialLeader() const { return GetCreatureInfo()->RacialLeader; }
bool isCivilian() const { return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_CIVILIAN; }
bool isTrigger() const { return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER; }
+ bool isGuard() const { return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_GUARD; }
bool canWalk() const { return GetCreatureInfo()->InhabitType & INHABIT_GROUND; }
bool canSwim() const { return GetCreatureInfo()->InhabitType & INHABIT_WATER; }
//bool canFly() const { return GetCreatureInfo()->InhabitType & INHABIT_AIR; }
@@ -729,6 +731,7 @@ class Creature : public Unit, public GridObject<Creature>
uint32 guid_transport;
bool isVisibleForInState(WorldObject const* seer) const;
+ bool canSeeAlways(WorldObject const* obj) const;
private:
//WaypointMovementGenerator vars
uint32 m_waypointID;
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index ff08de30841..0cd1f8e6143 100755
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -529,7 +529,7 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask
if (index == UNIT_NPC_FLAGS)
{
// remove custom flag before sending
- uint32 appendValue = m_uint32Values[ index ] & ~(UNIT_NPC_FLAG_GUARD + UNIT_NPC_FLAG_OUTDOORPVP);
+ uint32 appendValue = m_uint32Values[ index ];
if (GetTypeId() == TYPEID_UNIT)
{
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index e143ac0c8f1..67090442e76 100755
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -11879,9 +11879,19 @@ bool Unit::canAttack(Unit const* target, bool force) const
else if (!IsHostileTo(target))
return false;
- if (!target->isAttackableByAOE() || target->HasUnitState(UNIT_STAT_DIED))
+ if (!target->isAttackableByAOE())
return false;
+ if (target->HasUnitState(UNIT_STAT_DIED))
+ {
+ if (!ToCreature() || !ToCreature()->isGuard())
+ return false;
+
+ // guards can detect fake death
+ if (!target->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH))
+ return false;
+ }
+
if (m_vehicle)
if (IsOnVehicle(target) || m_vehicle->GetBase()->IsOnVehicle(target))
return false;
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index cf885ff4a98..050770668d8 100755
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -624,8 +624,6 @@ enum NPCFlags
UNIT_NPC_FLAG_GUILD_BANKER = 0x00800000, // cause client to send 997 opcode
UNIT_NPC_FLAG_SPELLCLICK = 0x01000000, // cause client to send 1015 opcode (spell click), dynamic, set at loading and don't must be set in DB
UNIT_NPC_FLAG_PLAYER_VEHICLE = 0x02000000, // players with mounts that have vehicle data should have it set
- UNIT_NPC_FLAG_GUARD = 0x10000000, // custom flag for guards
- UNIT_NPC_FLAG_OUTDOORPVP = 0x20000000, // custom flag for outdoor pvp creatures
};
enum MovementFlags
@@ -1422,14 +1420,11 @@ class Unit : public WorldObject
return HasFlag(UNIT_NPC_FLAGS,
UNIT_NPC_FLAG_VENDOR | UNIT_NPC_FLAG_TRAINER | UNIT_NPC_FLAG_FLIGHTMASTER |
UNIT_NPC_FLAG_PETITIONER | UNIT_NPC_FLAG_BATTLEMASTER | UNIT_NPC_FLAG_BANKER |
- UNIT_NPC_FLAG_INNKEEPER | UNIT_NPC_FLAG_GUARD | UNIT_NPC_FLAG_SPIRITHEALER |
+ UNIT_NPC_FLAG_INNKEEPER | UNIT_NPC_FLAG_SPIRITHEALER |
UNIT_NPC_FLAG_SPIRITGUIDE | UNIT_NPC_FLAG_TABARDDESIGNER | UNIT_NPC_FLAG_AUCTIONEER);
}
bool isSpiritService() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPIRITHEALER | UNIT_NPC_FLAG_SPIRITGUIDE); }
- //Need fix or use this
- bool isGuard() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GUARD); }
-
bool isInFlight() const { return HasUnitState(UNIT_STAT_IN_FLIGHT); }
bool isInCombat() const { return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); }
diff --git a/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp b/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp
index 73406262b2d..48fa099eb81 100755
--- a/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp
+++ b/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp
@@ -321,7 +321,7 @@ void WorldSession::HandleGossipHelloOpcode(WorldPacket & recv_data)
//if (GetPlayer()->HasUnitState(UNIT_STAT_DIED))
// GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
- if (unit->isArmorer() || unit->isCivilian() || unit->isQuestGiver() || unit->isServiceProvider())
+ if (unit->isArmorer() || unit->isCivilian() || unit->isQuestGiver() || unit->isServiceProvider() || unit->isGuard())
{
unit->StopMoving();
}
diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt
index 17d4bfc91e5..9fd63fdde8f 100644
--- a/src/server/scripts/CMakeLists.txt
+++ b/src/server/scripts/CMakeLists.txt
@@ -34,7 +34,6 @@ set(scripts_STAT_SRCS
../game/AI/ScriptedAI/ScriptedEscortAI.cpp
../game/AI/ScriptedAI/ScriptedCreature.cpp
../game/AI/ScriptedAI/ScriptedFollowerAI.cpp
- ../game/AI/ScriptedAI/ScriptedGuardAI.cpp
../game/AI/ScriptedAI/ScriptedSimpleAI.cpp
)
diff --git a/src/server/scripts/World/guards.cpp b/src/server/scripts/World/guards.cpp
index c7c91fed3e9..107ada81863 100644
--- a/src/server/scripts/World/guards.cpp
+++ b/src/server/scripts/World/guards.cpp
@@ -19,220 +19,361 @@
/* ScriptData
SDName: Guards
SD%Complete: 100
-SDComment: All Guard gossip data, quite some npc_text-id's still missing, adding constantly as new id's are known. CombatAI should be organized better for future.
+SDComment:
SDCategory: Guards
EndScriptData */
/* ContentData
guard_generic
-guard_orgrimmar
guard_shattrath_aldor
guard_shattrath_scryer
-guard_stormwind
EndContentData */
#include "ScriptPCH.h"
-#include "ScriptedGuardAI.h"
+#include "GuardAI.h"
-/*******************************************************
- * guard_generic
- *******************************************************/
+enum GuardGeneric
+{
+ GENERIC_CREATURE_COOLDOWN = 5000,
+
+ SAY_GUARD_SIL_AGGRO1 = -1070001,
+ SAY_GUARD_SIL_AGGRO2 = -1070002,
+ SAY_GUARD_SIL_AGGRO3 = -1070003,
+
+ NPC_CENARION_HOLD_INFANTRY = 15184,
+ NPC_STORMWIND_CITY_GUARD = 68,
+ NPC_STORMWIND_CITY_PATROLLER = 1976,
+ NPC_ORGRIMMAR_GRUNT = 3296
+};
class guard_generic : public CreatureScript
{
public:
guard_generic() : CreatureScript("guard_generic") { }
- CreatureAI *GetAI(Creature *creature) const
+ struct guard_genericAI : public GuardAI
{
- return new guardAI(creature);
- }
-};
+ guard_genericAI(Creature* creature) : GuardAI(creature) {}
-/*******************************************************
- * guard_orgrimmar
- *******************************************************/
+ void Reset()
+ {
+ globalCooldown = 0;
+ buffTimer = 0;
+ }
-class guard_orgrimmar : public CreatureScript
-{
-public:
- guard_orgrimmar() : CreatureScript("guard_orgrimmar") { }
+ void EnterCombat(Unit* who)
+ {
+ if (me->GetEntry() == NPC_CENARION_HOLD_INFANTRY)
+ DoScriptText(RAND(SAY_GUARD_SIL_AGGRO1,SAY_GUARD_SIL_AGGRO2,SAY_GUARD_SIL_AGGRO3), me, who);
+ if (SpellEntry const* spell = me->reachWithSpellAttack(who))
+ DoCast(who, spell->Id);
+ }
- CreatureAI *GetAI(Creature *creature) const
+ void UpdateAI(const uint32 diff)
+ {
+ //Always decrease our global cooldown first
+ if (globalCooldown > diff)
+ globalCooldown -= diff;
+ else
+ globalCooldown = 0;
+
+ //Buff timer (only buff when we are alive and not in combat
+ if (me->isAlive() && !me->isInCombat())
+ {
+ if (buffTimer <= diff)
+ {
+ //Find a spell that targets friendly and applies an aura (these are generally buffs)
+ SpellEntry const *info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_AURA);
+
+ if (info && !globalCooldown)
+ {
+ //Cast the buff spell
+ DoCast(me, info->Id);
+
+ //Set our global cooldown
+ globalCooldown = GENERIC_CREATURE_COOLDOWN;
+
+ //Set our timer to 10 minutes before rebuff
+ buffTimer = 600000;
+ } //Try again in 30 seconds
+ else buffTimer = 30000;
+ } else buffTimer -= diff;
+ }
+
+ //Return since we have no target
+ if (!UpdateVictim())
+ return;
+
+ // Make sure our attack is ready and we arn't currently casting
+ if (me->isAttackReady() && !me->IsNonMeleeSpellCasted(false))
+ {
+ //If we are within range melee the target
+ if (me->IsWithinMeleeRange(me->getVictim()))
+ {
+ bool healing = false;
+ SpellEntry const *info = NULL;
+
+ //Select a healing spell if less than 30% hp
+ if (me->HealthBelowPct(30))
+ info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_HEALING);
+
+ //No healing spell available, select a hostile spell
+ if (info)
+ healing = true;
+ else
+ info = SelectSpell(me->getVictim(), 0, 0, SELECT_TARGET_ANY_ENEMY, 0, 0, 0, 0, SELECT_EFFECT_DONTCARE);
+
+ //20% chance to replace our white hit with a spell
+ if (info && urand(0,99) < 20 && !globalCooldown)
+ {
+ //Cast the spell
+ if (healing)
+ DoCast(me, info->Id);
+ else
+ DoCast(me->getVictim(), info->Id);
+
+ //Set our global cooldown
+ globalCooldown = GENERIC_CREATURE_COOLDOWN;
+ }
+ else
+ me->AttackerStateUpdate(me->getVictim());
+
+ me->resetAttackTimer();
+ }
+ }
+ else
+ {
+ //Only run this code if we arn't already casting
+ if (!me->IsNonMeleeSpellCasted(false))
+ {
+ bool healing = false;
+ SpellEntry const *info = NULL;
+
+ //Select a healing spell if less than 30% hp ONLY 33% of the time
+ if (me->HealthBelowPct(30) && 33 > urand(0, 99))
+ info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_HEALING);
+
+ //No healing spell available, See if we can cast a ranged spell (Range must be greater than ATTACK_DISTANCE)
+ if (info)
+ healing = true;
+ else
+ info = SelectSpell(me->getVictim(), 0, 0, SELECT_TARGET_ANY_ENEMY, 0, 0, NOMINAL_MELEE_RANGE, 0, SELECT_EFFECT_DONTCARE);
+
+ //Found a spell, check if we arn't on cooldown
+ if (info && !globalCooldown)
+ {
+ //If we are currently moving stop us and set the movement generator
+ if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != IDLE_MOTION_TYPE)
+ {
+ me->GetMotionMaster()->Clear(false);
+ me->GetMotionMaster()->MoveIdle();
+ }
+
+ //Cast spell
+ if (healing)
+ DoCast(me,info->Id);
+ else
+ DoCast(me->getVictim(),info->Id);
+
+ //Set our global cooldown
+ globalCooldown = GENERIC_CREATURE_COOLDOWN;
+
+ } //If no spells available and we arn't moving run to target
+ else if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE)
+ {
+ //Cancel our current spell and then mutate new movement generator
+ me->InterruptNonMeleeSpells(false);
+ me->GetMotionMaster()->Clear(false);
+ me->GetMotionMaster()->MoveChase(me->getVictim());
+ }
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ void DoReplyToTextEmote(uint32 emote)
+ {
+ switch(emote)
+ {
+ case TEXTEMOTE_KISS: me->HandleEmoteCommand(EMOTE_ONESHOT_BOW); break;
+ case TEXTEMOTE_WAVE: me->HandleEmoteCommand(EMOTE_ONESHOT_WAVE); break;
+ case TEXTEMOTE_SALUTE: me->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); break;
+ case TEXTEMOTE_SHY: me->HandleEmoteCommand(EMOTE_ONESHOT_FLEX); break;
+ case TEXTEMOTE_RUDE:
+ case TEXTEMOTE_CHICKEN: me->HandleEmoteCommand(EMOTE_ONESHOT_POINT); break;
+ }
+ }
+
+ void ReceiveEmote(Player* player, uint32 textEmote)
+ {
+ switch(me->GetEntry())
+ {
+ case NPC_STORMWIND_CITY_GUARD:
+ case NPC_STORMWIND_CITY_PATROLLER:
+ case NPC_ORGRIMMAR_GRUNT:
+ break;
+ default:
+ return;
+ }
+
+ if (!me->IsFriendlyTo(player))
+ return;
+
+ DoReplyToTextEmote(textEmote);
+ }
+
+ private:
+ uint32 globalCooldown;
+ uint32 buffTimer;
+ };
+
+ CreatureAI *GetAI(Creature* creature) const
{
- return new guardAI_orgrimmar(creature);
+ return new guard_genericAI(creature);
}
};
-/*******************************************************
- * guard_shattrath_aldor
- *******************************************************/
-
-#define SPELL_BANISHED_SHATTRATH_A 36642
-#define SPELL_BANISHED_SHATTRATH_S 36671
-#define SPELL_BANISH_TELEPORT 36643
-#define SPELL_EXILE 39533
+enum GuardShattrath
+{
+ SPELL_BANISHED_SHATTRATH_A = 36642,
+ SPELL_BANISHED_SHATTRATH_S = 36671,
+ SPELL_BANISH_TELEPORT = 36643,
+ SPELL_EXILE = 39533
+};
-class guard_shattrath_aldor : public CreatureScript
+class guard_shattrath_scryer : public CreatureScript
{
public:
- guard_shattrath_aldor() : CreatureScript("guard_shattrath_aldor") { }
+ guard_shattrath_scryer() : CreatureScript("guard_shattrath_scryer") { }
- struct guard_shattrath_aldorAI : public guardAI
+ struct guard_shattrath_scryerAI : public GuardAI
{
- guard_shattrath_aldorAI(Creature *c) : guardAI(c) {}
-
- uint32 Exile_Timer;
- uint32 Banish_Timer;
- uint64 PlayerGUID;
- bool CanTeleport;
+ guard_shattrath_scryerAI(Creature* creature) : GuardAI(creature) {}
void Reset()
{
- Banish_Timer = 5000;
- Exile_Timer = 8500;
- PlayerGUID = 0;
- CanTeleport = false;
+ banishTimer = 5000;
+ exileTimer = 8500;
+ playerGUID = 0;
+ canTeleport = false;
}
- void EnterCombat(Unit * /*who*/) {}
-
void UpdateAI(const uint32 diff)
{
if (!UpdateVictim())
return;
- if (CanTeleport)
+ if (canTeleport)
{
- if (Exile_Timer <= diff)
+ if (exileTimer <= diff)
{
- if (Unit* temp = Unit::GetUnit(*me,PlayerGUID))
+ if (Unit* temp = Unit::GetUnit(*me,playerGUID))
{
temp->CastSpell(temp,SPELL_EXILE,true);
temp->CastSpell(temp,SPELL_BANISH_TELEPORT,true);
}
- PlayerGUID = 0;
- Exile_Timer = 8500;
- CanTeleport = false;
- } else Exile_Timer -= diff;
+ playerGUID = 0;
+ exileTimer = 8500;
+ canTeleport = false;
+ } else exileTimer -= diff;
}
- else if (Banish_Timer <= diff)
+ else if (banishTimer <= diff)
{
Unit* temp = me->getVictim();
if (temp && temp->GetTypeId() == TYPEID_PLAYER)
{
DoCast(temp, SPELL_BANISHED_SHATTRATH_A);
- Banish_Timer = 9000;
- PlayerGUID = temp->GetGUID();
- if (PlayerGUID)
- CanTeleport = true;
+ banishTimer = 9000;
+ playerGUID = temp->GetGUID();
+ if (playerGUID)
+ canTeleport = true;
}
- } else Banish_Timer -= diff;
+ } else banishTimer -= diff;
DoMeleeAttackIfReady();
}
+
+ private:
+ uint32 exileTimer;
+ uint32 banishTimer;
+ uint64 playerGUID;
+ bool canTeleport;
};
CreatureAI *GetAI(Creature *creature) const
{
- return new guard_shattrath_aldorAI(creature);
+ return new guard_shattrath_scryerAI(creature);
}
};
-/*******************************************************
- * guard_shattrath_scryer
- *******************************************************/
-
-class guard_shattrath_scryer : public CreatureScript
+class guard_shattrath_aldor : public CreatureScript
{
public:
- guard_shattrath_scryer() : CreatureScript("guard_shattrath_scryer") { }
+ guard_shattrath_aldor() : CreatureScript("guard_shattrath_aldor") { }
- struct guard_shattrath_scryerAI : public guardAI
+ struct guard_shattrath_aldorAI : public GuardAI
{
- guard_shattrath_scryerAI(Creature *c) : guardAI(c) {}
-
- uint32 Exile_Timer;
- uint32 Banish_Timer;
- uint64 PlayerGUID;
- bool CanTeleport;
+ guard_shattrath_aldorAI(Creature* creature) : GuardAI(creature) {}
void Reset()
{
- Banish_Timer = 5000;
- Exile_Timer = 8500;
- PlayerGUID = 0;
- CanTeleport = false;
+ banishTimer = 5000;
+ exileTimer = 8500;
+ playerGUID = 0;
+ canTeleport = false;
}
- void EnterCombat(Unit * /*who*/) {}
-
void UpdateAI(const uint32 diff)
{
if (!UpdateVictim())
return;
- if (CanTeleport)
+ if (canTeleport)
{
- if (Exile_Timer <= diff)
+ if (exileTimer <= diff)
{
- if (Unit* temp = Unit::GetUnit(*me,PlayerGUID))
+ if (Unit* temp = Unit::GetUnit(*me,playerGUID))
{
temp->CastSpell(temp,SPELL_EXILE,true);
temp->CastSpell(temp,SPELL_BANISH_TELEPORT,true);
}
- PlayerGUID = 0;
- Exile_Timer = 8500;
- CanTeleport = false;
- } else Exile_Timer -= diff;
+ playerGUID = 0;
+ exileTimer = 8500;
+ canTeleport = false;
+ } else exileTimer -= diff;
}
- else if (Banish_Timer <= diff)
+ else if (banishTimer <= diff)
{
Unit* temp = me->getVictim();
if (temp && temp->GetTypeId() == TYPEID_PLAYER)
{
DoCast(temp, SPELL_BANISHED_SHATTRATH_S);
- Banish_Timer = 9000;
- PlayerGUID = temp->GetGUID();
- if (PlayerGUID)
- CanTeleport = true;
+ banishTimer = 9000;
+ playerGUID = temp->GetGUID();
+ if (playerGUID)
+ canTeleport = true;
}
- } else Banish_Timer -= diff;
+ } else banishTimer -= diff;
DoMeleeAttackIfReady();
}
+ private:
+ uint32 exileTimer;
+ uint32 banishTimer;
+ uint64 playerGUID;
+ bool canTeleport;
};
CreatureAI *GetAI(Creature *creature) const
{
- return new guard_shattrath_scryerAI(creature);
- }
-};
-
-/*******************************************************
- * guard_stormwind
- *******************************************************/
-
-class guard_stormwind : public CreatureScript
-{
-public:
- guard_stormwind() : CreatureScript("guard_stormwind") { }
-
- CreatureAI *GetAI(Creature *creature) const
- {
- return new guardAI_stormwind(creature);
+ return new guard_shattrath_aldorAI(creature);
}
};
-/*******************************************************
- * AddSC
- *******************************************************/
-
void AddSC_guards()
{
new guard_generic;
- new guard_orgrimmar;
new guard_shattrath_aldor;
new guard_shattrath_scryer;
- new guard_stormwind;
}