diff options
-rw-r--r-- | sql/scripts/world_scripts_full.sql | 4 | ||||
-rw-r--r-- | sql/updates/world/2011_02_10_3_world_creature_template.sql | 2 | ||||
-rw-r--r-- | sql/updates/world/2011_02_10_4_world_scriptname.sql | 2 | ||||
-rwxr-xr-x | src/server/game/AI/CoreAI/GuardAI.cpp | 44 | ||||
-rwxr-xr-x | src/server/game/AI/CoreAI/GuardAI.h | 6 | ||||
-rwxr-xr-x | src/server/game/AI/CreatureAI.h | 1 | ||||
-rwxr-xr-x | src/server/game/AI/ScriptedAI/ScriptedGuardAI.cpp | 198 | ||||
-rw-r--r-- | src/server/game/AI/ScriptedAI/ScriptedGuardAI.h | 45 | ||||
-rwxr-xr-x | src/server/game/Entities/Creature/Creature.cpp | 21 | ||||
-rwxr-xr-x | src/server/game/Entities/Creature/Creature.h | 7 | ||||
-rwxr-xr-x | src/server/game/Entities/Object/Object.cpp | 2 | ||||
-rwxr-xr-x | src/server/game/Entities/Unit/Unit.cpp | 12 | ||||
-rwxr-xr-x | src/server/game/Entities/Unit/Unit.h | 7 | ||||
-rwxr-xr-x | src/server/game/Server/Protocol/Handlers/NPCHandler.cpp | 2 | ||||
-rw-r--r-- | src/server/scripts/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/server/scripts/World/guards.cpp | 363 |
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; } |