aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.cpp30
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.h17
-rw-r--r--src/server/game/AI/CreatureAI.h6
-rw-r--r--src/server/game/AI/PlayerAI/PlayerAI.cpp224
-rw-r--r--src/server/game/AI/PlayerAI/PlayerAI.h60
-rw-r--r--src/server/game/CMakeLists.txt1
-rw-r--r--src/server/game/Conditions/ConditionMgr.cpp41
-rw-r--r--src/server/game/Conditions/ConditionMgr.h3
-rw-r--r--src/server/game/Entities/Creature/Creature.h2
-rw-r--r--src/server/game/Entities/Player/Player.cpp39
-rw-r--r--src/server/game/Entities/Player/Player.h5
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp103
-rw-r--r--src/server/game/Entities/Unit/Unit.h10
-rw-r--r--src/server/game/Weather/Weather.cpp2
-rw-r--r--src/server/scripts/CMakeLists.txt2
-rw-r--r--src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp57
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp12
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp3
-rw-r--r--src/server/scripts/Outland/zone_terokkar_forest.cpp160
-rw-r--r--src/server/scripts/Spells/spell_dk.cpp8
20 files changed, 561 insertions, 224 deletions
diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp
index a3a5e7f7663..3aadf6e59a0 100644
--- a/src/server/game/AI/CoreAI/UnitAI.cpp
+++ b/src/server/game/AI/CoreAI/UnitAI.cpp
@@ -259,36 +259,6 @@ void UnitAI::FillAISpellInfo()
}
}
-//Enable PlayerAI when charmed
-void PlayerAI::OnCharmed(bool apply)
-{
- me->IsAIEnabled = apply;
-}
-
-void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/)
-{
- Creature* charmer = me->GetCharmer()->ToCreature();
-
- //kill self if charm aura has infinite duration
- if (charmer->IsInEvadeMode())
- {
- Unit::AuraEffectList const& auras = me->GetAuraEffectsByType(SPELL_AURA_MOD_CHARM);
- for (Unit::AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
- if ((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetBase()->IsPermanent())
- {
- charmer->Kill(me);
- return;
- }
- }
-
- if (!charmer->IsInCombat())
- me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, me->GetFollowAngle());
-
- Unit* target = me->GetVictim();
- if (!target || !charmer->IsValidAttackTarget(target))
- AttackStart(charmer->SelectNearestTargetInAttackDistance());
-}
-
SpellTargetSelector::SpellTargetSelector(Unit* caster, uint32 spellId) :
_caster(caster), _spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(sSpellMgr->GetSpellInfo(spellId), caster))
{
diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h
index 5dc5946b226..766e747d998 100644
--- a/src/server/game/AI/CoreAI/UnitAI.h
+++ b/src/server/game/AI/CoreAI/UnitAI.h
@@ -268,21 +268,4 @@ class UnitAI
UnitAI& operator=(UnitAI const& right) = delete;
};
-class PlayerAI : public UnitAI
-{
- protected:
- Player* const me;
- public:
- explicit PlayerAI(Player* player) : UnitAI((Unit*)player), me(player) { }
-
- void OnCharmed(bool apply) override;
-};
-
-class SimpleCharmedAI : public PlayerAI
-{
- public:
- void UpdateAI(uint32 diff) override;
- SimpleCharmedAI(Player* player): PlayerAI(player) { }
-};
-
#endif
diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h
index 239fda577a7..e009e2ed0b6 100644
--- a/src/server/game/AI/CreatureAI.h
+++ b/src/server/game/AI/CreatureAI.h
@@ -28,6 +28,7 @@ class WorldObject;
class Unit;
class Creature;
class Player;
+class PlayerAI;
class SpellInfo;
#define TIME_INTERVAL_LOOK 5000
@@ -186,6 +187,11 @@ class CreatureAI : public UnitAI
virtual bool CanSeeAlways(WorldObject const* /*obj*/) { return false; }
+ // Called when a player is charmed by the creature
+ // If a PlayerAI* is returned, that AI is placed on the player instead of the default charm AI
+ // Object destruction is handled by Unit::RemoveCharmedBy
+ virtual PlayerAI* GetAIForCharmedPlayer(Player* /*who*/) { return nullptr; }
+
// intended for encounter design/debugging. do not use for other purposes. expensive.
int32 VisualizeBoundary(uint32 duration, Unit* owner=nullptr, bool fill=false) const;
virtual bool CheckInRoom();
diff --git a/src/server/game/AI/PlayerAI/PlayerAI.cpp b/src/server/game/AI/PlayerAI/PlayerAI.cpp
new file mode 100644
index 00000000000..bafa1a0ecf7
--- /dev/null
+++ b/src/server/game/AI/PlayerAI/PlayerAI.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2016-2016 TrinityCore <http://www.trinitycore.org/>
+ *
+ * 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/>.
+ */
+
+#include "PlayerAI.h"
+#include "SpellAuras.h"
+#include "SpellAuraEffects.h"
+
+enum Spells
+{
+ /* Generic */
+ SPELL_AUTO_SHOT = 75,
+ SPELL_SHOOT = 3018,
+ SPELL_THROW = 2764,
+ SPELL_SHOOT_WAND = 5019,
+
+ /* Paladin */
+ PASSIVE_ILLUMINATION = 20215,
+
+ /* Priest */
+ SPELL_SOUL_WARDING = 63574,
+ SPELL_SPIRIT_REDEMPTION = 20711,
+ SPELL_SHADOWFORM = 15473,
+
+ /* Shaman */
+ SPELL_TIDAL_FORCE = 582,
+ SPELL_MANA_TIDE_TOTEM = 590,
+ SPELL_SHA_NATURE_SWIFT = 591,
+ SPELL_STORMSTRIKE = 17364,
+
+ /* Druid */
+ SPELL_MOONKIN_FORM = 24858,
+ SPELL_SWIFTMEND = 18562,
+ SPELL_DRU_NATURE_SWIFT = 17116,
+ SPELL_TREE_OF_LIFE = 33891
+};
+
+bool PlayerAI::IsPlayerHealer(Player const* who)
+{
+ switch (who->getClass())
+ {
+ case CLASS_WARRIOR:
+ case CLASS_HUNTER:
+ case CLASS_ROGUE:
+ case CLASS_DEATH_KNIGHT:
+ case CLASS_MAGE:
+ case CLASS_WARLOCK:
+ default:
+ return false;
+ case CLASS_PALADIN:
+ return who->HasSpell(PASSIVE_ILLUMINATION);
+ case CLASS_PRIEST:
+ return who->HasSpell(SPELL_SOUL_WARDING) || who->HasSpell(SPELL_SPIRIT_REDEMPTION);
+ case CLASS_SHAMAN:
+ return who->HasSpell(SPELL_MANA_TIDE_TOTEM) || who->HasSpell(SPELL_SHA_NATURE_SWIFT) || who->HasSpell(SPELL_TIDAL_FORCE);
+ case CLASS_DRUID:
+ return who->HasSpell(SPELL_SWIFTMEND) || who->HasSpell(SPELL_DRU_NATURE_SWIFT) || who->HasSpell(SPELL_TREE_OF_LIFE);
+ }
+}
+
+bool PlayerAI::IsPlayerRangedAttacker(Player const* who)
+{
+ switch (who->getClass())
+ {
+ case CLASS_WARRIOR:
+ case CLASS_PALADIN:
+ case CLASS_ROGUE:
+ case CLASS_DEATH_KNIGHT:
+ default:
+ return false;
+ case CLASS_MAGE:
+ case CLASS_WARLOCK:
+ return true;
+ case CLASS_HUNTER:
+ {
+ // check if we have a ranged weapon equipped
+ Item const* rangedSlot = who->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
+ if (ItemTemplate const* rangedTemplate = rangedSlot ? rangedSlot->GetTemplate() : nullptr)
+ if ((1 << rangedTemplate->SubClass) & ITEM_SUBCLASS_MASK_WEAPON_RANGED)
+ return true;
+ return false;
+ }
+ case CLASS_PRIEST:
+ return who->HasSpell(SPELL_SHADOWFORM);
+ case CLASS_SHAMAN:
+ return !who->HasSpell(SPELL_STORMSTRIKE);
+ case CLASS_DRUID:
+ return who->HasSpell(SPELL_MOONKIN_FORM);
+ }
+}
+
+void PlayerAI::DoRangedAttackIfReady()
+{
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ if (!me->isAttackReady(RANGED_ATTACK))
+ return;
+
+ Unit* victim = me->GetVictim();
+ if (!victim)
+ return;
+
+ uint32 rangedAttackSpell = 0;
+
+ Item const* rangedItem = me->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
+ if (ItemTemplate const* rangedTemplate = rangedItem ? rangedItem->GetTemplate() : nullptr)
+ {
+ switch (rangedTemplate->SubClass)
+ {
+ case ITEM_SUBCLASS_WEAPON_BOW:
+ case ITEM_SUBCLASS_WEAPON_GUN:
+ case ITEM_SUBCLASS_WEAPON_CROSSBOW:
+ rangedAttackSpell = SPELL_SHOOT;
+ break;
+ case ITEM_SUBCLASS_WEAPON_THROWN:
+ rangedAttackSpell = SPELL_THROW;
+ break;
+ case ITEM_SUBCLASS_WEAPON_WAND:
+ rangedAttackSpell = SPELL_SHOOT_WAND;
+ break;
+ }
+ }
+
+ if (!rangedAttackSpell)
+ return;
+
+ me->CastSpell(victim, rangedAttackSpell, TRIGGERED_CAST_DIRECTLY);
+ me->resetAttackTimer(RANGED_ATTACK);
+}
+
+void PlayerAI::DoAutoAttackIfReady()
+{
+ if (IsRangedAttacker())
+ DoRangedAttackIfReady();
+ else
+ DoMeleeAttackIfReady();
+}
+
+struct UncontrolledTargetSelectPredicate : public std::unary_function<Unit*, bool>
+{
+ bool operator()(Unit const* target) const
+ {
+ return !target->HasBreakableByDamageCrowdControlAura();
+ }
+};
+Unit* SimpleCharmedPlayerAI::SelectAttackTarget() const
+{
+ if (Unit* charmer = me->GetCharmer())
+ return charmer->IsAIEnabled ? charmer->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0, UncontrolledTargetSelectPredicate()) : charmer->GetVictim();
+ return nullptr;
+}
+
+void SimpleCharmedPlayerAI::UpdateAI(const uint32 /*diff*/)
+{
+ Creature* charmer = me->GetCharmer() ? me->GetCharmer()->ToCreature() : nullptr;
+
+ //kill self if charm aura has infinite duration
+ if (charmer->IsInEvadeMode())
+ {
+ Player::AuraEffectList const& auras = me->GetAuraEffectsByType(SPELL_AURA_MOD_CHARM);
+ for (Player::AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
+ if ((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetBase()->IsPermanent())
+ {
+ me->Kill(me);
+ return;
+ }
+ }
+
+ if (charmer->IsInCombat())
+ {
+ Unit* target = me->GetVictim();
+ if (!target || !charmer->IsValidAttackTarget(target) || target->HasBreakableByDamageCrowdControlAura())
+ {
+ target = SelectAttackTarget();
+ if (!target)
+ return;
+
+ if (IsRangedAttacker())
+ AttackStartCaster(target, 28.0f);
+ else
+ AttackStart(target);
+ }
+ DoAutoAttackIfReady();
+ }
+ else
+ {
+ me->AttackStop();
+ me->CastStop();
+ me->StopMoving();
+ me->GetMotionMaster()->Clear();
+ me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
+ }
+}
+
+void SimpleCharmedPlayerAI::OnCharmed(bool apply)
+{
+ if (apply)
+ {
+ me->CastStop();
+ me->AttackStop();
+ }
+ else
+ {
+ me->CastStop();
+ me->AttackStop();
+ // @todo only voluntary movement (don't cancel stuff like death grip or charge mid-animation)
+ me->GetMotionMaster()->Clear();
+ me->StopMoving();
+ }
+}
diff --git a/src/server/game/AI/PlayerAI/PlayerAI.h b/src/server/game/AI/PlayerAI/PlayerAI.h
new file mode 100644
index 00000000000..1820bcf11c0
--- /dev/null
+++ b/src/server/game/AI/PlayerAI/PlayerAI.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016-2016 TrinityCore <http://www.trinitycore.org/>
+ *
+ * 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/>.
+ */
+
+#ifndef TRINITY_PLAYERAI_H
+#define TRINITY_PLAYERAI_H
+
+#include "UnitAI.h"
+#include "Player.h"
+#include "Creature.h"
+
+class PlayerAI : public UnitAI
+{
+ public:
+ explicit PlayerAI(Player* player) : UnitAI(static_cast<Unit*>(player)), me(player), _isSelfHealer(PlayerAI::IsPlayerHealer(player)), _isSelfRangedAttacker(PlayerAI::IsPlayerRangedAttacker(player)) { }
+
+ void OnCharmed(bool /*apply*/) override { } // charm AI application for players is handled by Unit::SetCharmedBy / Unit::RemoveCharmedBy
+
+ // helper functions to determine player info
+ static bool IsPlayerHealer(Player const* who);
+ bool IsHealer(Player const* who = nullptr) const { return (!who || who == me) ? _isSelfHealer : IsPlayerHealer(who); }
+ static bool IsPlayerRangedAttacker(Player const* who);
+ bool IsRangedAttacker(Player const* who = nullptr) const { return (!who || who == me) ? _isSelfRangedAttacker : IsPlayerRangedAttacker(who); }
+
+ protected:
+ Player* const me;
+ void SetIsRangedAttacker(bool state) { _isSelfRangedAttacker = state; } // this allows overriding of the default ranged attacker detection
+
+ virtual Unit* SelectAttackTarget() const { return me->GetCharmer() ? me->GetCharmer()->GetVictim() : nullptr; }
+ void DoRangedAttackIfReady();
+ void DoAutoAttackIfReady();
+
+ private:
+ bool _isSelfHealer;
+ bool _isSelfRangedAttacker;
+};
+
+class SimpleCharmedPlayerAI : public PlayerAI
+{
+ public:
+ SimpleCharmedPlayerAI(Player* player) : PlayerAI(player) { }
+ void UpdateAI(uint32 diff) override;
+ void OnCharmed(bool apply) override;
+ Unit* SelectAttackTarget() const override;
+};
+
+#endif
diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt
index aae5b4874d8..4d41fbc32eb 100644
--- a/src/server/game/CMakeLists.txt
+++ b/src/server/game/CMakeLists.txt
@@ -108,6 +108,7 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/Addons
${CMAKE_CURRENT_SOURCE_DIR}/AI
${CMAKE_CURRENT_SOURCE_DIR}/AI/CoreAI
+ ${CMAKE_CURRENT_SOURCE_DIR}/AI/PlayerAI
${CMAKE_CURRENT_SOURCE_DIR}/AI/ScriptedAI
${CMAKE_CURRENT_SOURCE_DIR}/AI/SmartScripts
${CMAKE_CURRENT_SOURCE_DIR}/AuctionHouse
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp
index 4215a3a5d02..81dc7894592 100644
--- a/src/server/game/Conditions/ConditionMgr.cpp
+++ b/src/server/game/Conditions/ConditionMgr.cpp
@@ -100,7 +100,8 @@ ConditionMgr::ConditionTypeInfo const ConditionMgr::StaticConditionTypeData[COND
{ "Health Value", true, true, false },
{ "Health Pct", true, true, false },
{ "Realm Achievement", true, false, false },
- { "In Water", false, false, false }
+ { "In Water", false, false, false },
+ { "Sit/stand state", true, true, false }
};
// Checks if object meets the condition
@@ -432,6 +433,19 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
condMeets = unit->IsInWater();
break;
}
+ case CONDITION_STAND_STATE:
+ {
+ if (Unit* unit = object->ToUnit())
+ {
+ if (ConditionValue1 == 0)
+ condMeets = (unit->getStandState() == ConditionValue2);
+ else if (ConditionValue2 == 0)
+ condMeets = unit->IsStandState();
+ else if (ConditionValue2 == 1)
+ condMeets = unit->IsSitState();
+ }
+ break;
+ }
default:
condMeets = false;
break;
@@ -602,6 +616,9 @@ uint32 Condition::GetSearcherTypeMaskForCondition() const
case CONDITION_IN_WATER:
mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
break;
+ case CONDITION_STAND_STATE:
+ mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
+ break;
default:
ASSERT(false && "Condition::GetSearcherTypeMaskForCondition - missing condition handling!");
break;
@@ -2090,6 +2107,28 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) const
}
case CONDITION_IN_WATER:
break;
+ case CONDITION_STAND_STATE:
+ {
+ bool valid = false;
+ switch (cond->ConditionValue1)
+ {
+ case 0:
+ valid = cond->ConditionValue2 <= UNIT_STAND_STATE_SUBMERGED;
+ break;
+ case 1:
+ valid = cond->ConditionValue2 <= 1;
+ break;
+ default:
+ valid = false;
+ break;
+ }
+ if (!valid)
+ {
+ TC_LOG_ERROR("sql.sql", "%s has non-existing stand state (%u,%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1, cond->ConditionValue2);
+ return false;
+ }
+ break;
+ }
default:
break;
}
diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h
index 35096ae18ff..3123aaca86a 100644
--- a/src/server/game/Conditions/ConditionMgr.h
+++ b/src/server/game/Conditions/ConditionMgr.h
@@ -71,7 +71,8 @@ enum ConditionTypes
CONDITION_HP_PCT = 38, // hpPct ComparisonType 0 true if unit's hp matches given pct
CONDITION_REALM_ACHIEVEMENT = 39, // achievement_id 0 0 true if realm achievement is complete
CONDITION_IN_WATER = 40, // 0 0 0 true if unit in water
- CONDITION_MAX = 41 // MAX
+ CONDITION_STAND_STATE = 41, // stateType state 0 true if unit matches specified sitstate (0,x: has exactly state x; 1,0: any standing state; 1,1: any sitting state;)
+ CONDITION_MAX = 42 // MAX
};
/*! Documentation on implementing a new ConditionSourceType:
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 49bd854ef2f..0803345f4f0 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -479,7 +479,7 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject
bool AIM_Initialize(CreatureAI* ai = NULL);
void Motion_Initialize();
- CreatureAI* AI() const { return (CreatureAI*)i_AI; }
+ CreatureAI* AI() const { return reinterpret_cast<CreatureAI*>(i_AI); }
bool SetWalk(bool enable) override;
bool SetDisableGravity(bool disable, bool packetOnly = false) override;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index a60bfb4a444..cbf29980057 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -1237,12 +1237,7 @@ void Player::Update(uint32 p_time)
UpdateAfkReport(now);
- if (IsCharmed())
- if (Unit* charmer = GetCharmer())
- if (charmer->GetTypeId() == TYPEID_UNIT && charmer->IsAlive())
- UpdateCharmedAI();
-
- if (GetAI() && IsAIEnabled)
+ if (IsAIEnabled && GetAI())
GetAI()->UpdateAI(p_time);
// Update items that have just a limited lifetime
@@ -24129,38 +24124,6 @@ bool Player::isTotalImmunity()
return false;
}
-void Player::UpdateCharmedAI()
-{
- //This should only called in Player::Update
- Creature* charmer = GetCharmer()->ToCreature();
-
- //kill self if charm aura has infinite duration
- if (charmer->IsInEvadeMode())
- {
- AuraEffectList const& auras = GetAuraEffectsByType(SPELL_AURA_MOD_CHARM);
- for (AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
- if ((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetBase()->IsPermanent())
- {
- charmer->DealDamage(this, GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
- return;
- }
- }
-
- if (!charmer->IsInCombat())
- GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
-
- Unit* target = GetVictim();
- if (!target || !charmer->IsValidAttackTarget(target))
- {
- target = charmer->SelectNearestTarget();
- if (!target)
- return;
-
- GetMotionMaster()->MoveChase(target);
- Attack(target, true);
- }
-}
-
uint32 Player::GetRuneBaseCooldown(uint8 index)
{
uint8 rune = GetBaseRune(index);
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 2388cf9d0c7..0d6d21c6b28 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -54,6 +54,7 @@ class PlayerMenu;
class PlayerSocial;
class SpellCastTargets;
class UpdateMask;
+class PlayerAI;
struct CharacterCustomizeInfo;
@@ -1022,6 +1023,8 @@ class Player : public Unit, public GridObject<Player>
explicit Player(WorldSession* session);
~Player();
+ PlayerAI* AI() const { return reinterpret_cast<PlayerAI*>(i_AI); }
+
void CleanupsBeforeDelete(bool finalCleanup = true) override;
void AddToWorld() override;
@@ -2533,8 +2536,6 @@ class Player : public Unit, public GridObject<Player>
MapReference m_mapRef;
- void UpdateCharmedAI();
-
uint32 m_lastFallTime;
float m_lastFallZ;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 80c5febdcc9..e2b0e1f01eb 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -45,6 +45,7 @@
#include "PetAI.h"
#include "Pet.h"
#include "Player.h"
+#include "PlayerAI.h"
#include "QuestDef.h"
#include "ReputationMgr.h"
#include "SpellAuraEffects.h"
@@ -3748,6 +3749,77 @@ void Unit::RemoveAura(Aura* aura, AuraRemoveMode mode)
RemoveAura(aurApp, mode);
}
+void Unit::RemoveAppliedAuras(std::function<bool(AuraApplication const*)> const& check)
+{
+ for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
+ {
+ if (check(iter->second))
+ {
+ RemoveAura(iter);
+ continue;
+ }
+ ++iter;
+ }
+}
+
+void Unit::RemoveOwnedAuras(std::function<bool(Aura const*)> const& check)
+{
+ for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
+ {
+ if (check(iter->second))
+ {
+ RemoveOwnedAura(iter);
+ continue;
+ }
+ ++iter;
+ }
+}
+
+void Unit::RemoveAppliedAuras(uint32 spellId, std::function<bool(AuraApplication const*)> const& check)
+{
+ for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
+ {
+ if (check(iter->second))
+ {
+ RemoveAura(iter);
+ continue;
+ }
+ ++iter;
+ }
+}
+
+void Unit::RemoveOwnedAuras(uint32 spellId, std::function<bool(Aura const*)> const& check)
+{
+ for (AuraMap::iterator iter = m_ownedAuras.lower_bound(spellId); iter != m_ownedAuras.upper_bound(spellId);)
+ {
+ if (check(iter->second))
+ {
+ RemoveOwnedAura(iter);
+ continue;
+ }
+ ++iter;
+ }
+}
+
+void Unit::RemoveAurasByType(AuraType auraType, std::function<bool(AuraApplication const*)> const& check)
+{
+ for (AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
+ {
+ Aura* aura = (*iter)->GetBase();
+ AuraApplication * aurApp = aura->GetApplicationOfTarget(GetGUID());
+ ASSERT(aurApp);
+
+ ++iter;
+ if (check(aurApp))
+ {
+ uint32 removedAuras = m_removedAurasCount;
+ RemoveAura(aurApp);
+ if (m_removedAurasCount > removedAuras + 1)
+ iter = m_modAuras[auraType].begin();
+ }
+ }
+}
+
void Unit::RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID, uint8 reqEffMask, AuraRemoveMode removeMode)
{
for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
@@ -15902,11 +15974,21 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
ToCreature()->AI()->OnCharmed(true);
GetMotionMaster()->MoveIdle();
}
- else
+ else if (Player* player = ToPlayer())
{
- Player* player = ToPlayer();
if (player->isAFK())
player->ToggleAFK();
+
+ if (Creature* creatureCharmer = charmer->ToCreature()) // we are charmed by a creature
+ {
+ IsAIEnabled = true;
+ i_disabledAI = i_AI;
+ // set our AI to the charmer's custom charm AI if applicable
+ if (PlayerAI* charmAI = creatureCharmer->AI()->GetAIForCharmedPlayer(player))
+ i_AI = charmAI;
+ else // otherwise use the default charmed player AI
+ i_AI = new SimpleCharmedPlayerAI(player);
+ }
player->SetClientControl(this, false);
}
@@ -16064,7 +16146,24 @@ void Unit::RemoveCharmedBy(Unit* charmer)
}
if (Player* player = ToPlayer())
+ {
+ if (charmer->GetTypeId() == TYPEID_UNIT) // charmed by a creature, this means we had PlayerAI
+ {
+ if (i_AI)
+ {
+ // allow charmed player AI to clean up
+ i_AI->OnCharmed(false);
+ // then delete it
+ delete i_AI;
+ // and restore our previous playerAI (if we had one)
+ if ((i_AI = i_disabledAI))
+ i_disabledAI = nullptr;
+ else
+ IsAIEnabled = false;
+ }
+ }
player->SetClientControl(this, true);
+ }
// a guardian should always have charminfo
if (playerCharmer && this != charmer->GetFirstControlled())
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 4565160dc93..19fd4089168 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1704,6 +1704,16 @@ class Unit : public WorldObject
void RemoveAura(AuraApplication * aurApp, AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT);
void RemoveAura(Aura* aur, AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT);
+ // Convenience methods removing auras by predicate
+ void RemoveAppliedAuras(std::function<bool(AuraApplication const*)> const& check);
+ void RemoveOwnedAuras(std::function<bool(Aura const*)> const& check);
+
+ // Optimized overloads taking advantage of map key
+ void RemoveAppliedAuras(uint32 spellId, std::function<bool(AuraApplication const*)> const& check);
+ void RemoveOwnedAuras(uint32 spellId, std::function<bool(Aura const*)> const& check);
+
+ void RemoveAurasByType(AuraType auraType, std::function<bool(AuraApplication const*)> const& check);
+
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, uint8 reqEffMask = 0, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT);
void RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT);
void RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId, ObjectGuid casterGUID, Unit* dispeller, uint8 chargesRemoved = 1);
diff --git a/src/server/game/Weather/Weather.cpp b/src/server/game/Weather/Weather.cpp
index f774916f4a5..7ef16e32031 100644
--- a/src/server/game/Weather/Weather.cpp
+++ b/src/server/game/Weather/Weather.cpp
@@ -152,7 +152,7 @@ bool Weather::ReGenerate()
uint32 chance2 = chance1+ m_weatherChances->data[season].snowChance;
uint32 chance3 = chance2+ m_weatherChances->data[season].stormChance;
- uint32 rnd = urand(0, 99);
+ uint32 rnd = urand(1, 100);
if (rnd <= chance1)
m_type = WEATHER_TYPE_RAIN;
else if (rnd <= chance2)
diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt
index 32e7421465a..ea0b058b91d 100644
--- a/src/server/scripts/CMakeLists.txt
+++ b/src/server/scripts/CMakeLists.txt
@@ -38,7 +38,6 @@ PrepareScripts(Spells scripts_STAT_SRCS)
PrepareScripts(Commands scripts_STAT_SRCS)
if(SCRIPTS)
- PrepareScripts(Commands scripts_STAT_SRCS)
PrepareScripts(Custom scripts_STAT_SRCS)
PrepareScripts(World scripts_STAT_SRCS)
PrepareScripts(OutdoorPvP scripts_STAT_SRCS)
@@ -73,6 +72,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/server/game/Addons
${CMAKE_SOURCE_DIR}/src/server/game/AI
${CMAKE_SOURCE_DIR}/src/server/game/AI/CoreAI
+ ${CMAKE_SOURCE_DIR}/src/server/game/AI/PlayerAI
${CMAKE_SOURCE_DIR}/src/server/game/AI/ScriptedAI
${CMAKE_SOURCE_DIR}/src/server/game/AI/SmartScripts
${CMAKE_SOURCE_DIR}/src/server/game/AuctionHouse
diff --git a/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp b/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp
index ce0ebf4d129..4cc72715868 100644
--- a/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp
+++ b/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp
@@ -19,7 +19,7 @@
/* ScriptData
SDName: Eastern_Plaguelands
SD%Complete: 100
-SDComment: Quest support: 5211, 5742. Special vendor Augustus the Touched
+SDComment: Quest support: 5211. Special vendor Augustus the Touched
SDCategory: Eastern Plaguelands
EndScriptData */
@@ -27,7 +27,6 @@ EndScriptData */
npc_ghoul_flayer
npc_augustus_the_touched
npc_darrowshire_spirit
-npc_tirion_fordring
EndContentData */
#include "ScriptMgr.h"
@@ -133,63 +132,9 @@ public:
};
};
-/*######
-## npc_tirion_fordring
-######*/
-
-#define GOSSIP_HELLO "I am ready to hear your tale, Tirion."
-#define GOSSIP_SELECT1 "Thank you, Tirion. What of your identity?"
-#define GOSSIP_SELECT2 "That is terrible."
-#define GOSSIP_SELECT3 "I will, Tirion."
-
-class npc_tirion_fordring : public CreatureScript
-{
-public:
- npc_tirion_fordring() : CreatureScript("npc_tirion_fordring") { }
-
- bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
- {
- player->PlayerTalkClass->ClearMenus();
- switch (action)
- {
- case GOSSIP_ACTION_INFO_DEF+1:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
- player->SEND_GOSSIP_MENU(4493, creature->GetGUID());
- break;
- case GOSSIP_ACTION_INFO_DEF+2:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
- player->SEND_GOSSIP_MENU(4494, creature->GetGUID());
- break;
- case GOSSIP_ACTION_INFO_DEF+3:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4);
- player->SEND_GOSSIP_MENU(4495, creature->GetGUID());
- break;
- case GOSSIP_ACTION_INFO_DEF+4:
- player->CLOSE_GOSSIP_MENU();
- player->AreaExploredOrEventHappens(5742);
- break;
- }
- return true;
- }
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- if (creature->IsQuestGiver())
- player->PrepareQuestMenu(creature->GetGUID());
-
- if (player->GetQuestStatus(5742) == QUEST_STATUS_INCOMPLETE && player->getStandState() == UNIT_STAND_STATE_SIT)
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
-
- player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID());
-
- return true;
- }
-};
-
void AddSC_eastern_plaguelands()
{
new npc_ghoul_flayer();
new npc_augustus_the_touched();
new npc_darrowshire_spirit();
- new npc_tirion_fordring();
}
diff --git a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp
index 96bd0aaa35e..5410f403ab9 100644
--- a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp
@@ -22,6 +22,7 @@
#include "pit_of_saron.h"
#include "Vehicle.h"
#include "Player.h"
+#include "PlayerAI.h"
enum Yells
{
@@ -438,9 +439,10 @@ class spell_tyrannus_overlord_brand : public SpellScriptLoader
if (GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
- oldAI = GetTarget()->GetAI();
- oldAIState = GetTarget()->IsAIEnabled;
- GetTarget()->SetAI(new player_overlord_brandAI(GetTarget()->ToPlayer(), GetCasterGUID()));
+ Player* pTarget = GetTarget()->ToPlayer();
+ oldAI = pTarget->AI();
+ oldAIState = pTarget->IsAIEnabled;
+ GetTarget()->SetAI(new player_overlord_brandAI(pTarget, GetCasterGUID()));
GetTarget()->IsAIEnabled = true;
}
@@ -450,7 +452,7 @@ class spell_tyrannus_overlord_brand : public SpellScriptLoader
return;
GetTarget()->IsAIEnabled = oldAIState;
- UnitAI* thisAI = GetTarget()->GetAI();
+ PlayerAI* thisAI = GetTarget()->ToPlayer()->AI();
GetTarget()->SetAI(oldAI);
delete thisAI;
}
@@ -461,7 +463,7 @@ class spell_tyrannus_overlord_brand : public SpellScriptLoader
AfterEffectRemove += AuraEffectRemoveFn(spell_tyrannus_overlord_brand_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
- UnitAI* oldAI;
+ PlayerAI* oldAI;
bool oldAIState;
};
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
index 6dfc3bf01e7..98827fb3e00 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
@@ -334,7 +334,8 @@ class boss_flame_leviathan : public CreatureScript
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
{
if (spell->Id == SPELL_START_THE_ENGINE)
- ASSERT_NOTNULL(me->GetVehicleKit())->InstallAllAccessories(false);
+ if (Vehicle* vehicleKit = me->GetVehicleKit())
+ vehicleKit->InstallAllAccessories(false);
if (spell->Id == SPELL_ELECTROSHOCK)
me->InterruptSpell(CURRENT_CHANNELED_SPELL);
diff --git a/src/server/scripts/Outland/zone_terokkar_forest.cpp b/src/server/scripts/Outland/zone_terokkar_forest.cpp
index 04ec1e4dc07..4b757544d65 100644
--- a/src/server/scripts/Outland/zone_terokkar_forest.cpp
+++ b/src/server/scripts/Outland/zone_terokkar_forest.cpp
@@ -46,13 +46,13 @@ EndContentData */
enum UnkorTheRuthless
{
- SAY_SUBMIT = 0,
-
- FACTION_HOSTILE = 45,
- FACTION_FRIENDLY = 35,
- QUEST_DONTKILLTHEFATONE = 9889,
-
- SPELL_PULVERIZE = 2676
+ SAY_SUBMIT = 0,
+ REQUIRED_KILL_COUNT = 10,
+ FACTION_FRIENDLY = 35,
+ FACTION_HOSTILE = 45,
+ SPELL_PULVERIZE = 2676,
+ QUEST_DONTKILLTHEFATONE = 9889,
+ NPC_BOULDERFIST_INVADER = 18260
};
class npc_unkor_the_ruthless : public CreatureScript
@@ -116,7 +116,7 @@ public:
Player* groupie = itr->GetSource();
if (groupie &&
groupie->GetQuestStatus(QUEST_DONTKILLTHEFATONE) == QUEST_STATUS_INCOMPLETE &&
- groupie->GetReqKillOrCastCurrentCount(QUEST_DONTKILLTHEFATONE, 18260) == 10)
+ groupie->GetReqKillOrCastCurrentCount(QUEST_DONTKILLTHEFATONE, NPC_BOULDERFIST_INVADER) == REQUIRED_KILL_COUNT)
{
groupie->AreaExploredOrEventHappens(QUEST_DONTKILLTHEFATONE);
if (!CanDoQuest)
@@ -125,7 +125,7 @@ public:
}
}
else if (player->GetQuestStatus(QUEST_DONTKILLTHEFATONE) == QUEST_STATUS_INCOMPLETE &&
- player->GetReqKillOrCastCurrentCount(QUEST_DONTKILLTHEFATONE, 18260) == 10)
+ player->GetReqKillOrCastCurrentCount(QUEST_DONTKILLTHEFATONE, NPC_BOULDERFIST_INVADER) == REQUIRED_KILL_COUNT)
{
player->AreaExploredOrEventHappens(QUEST_DONTKILLTHEFATONE);
CanDoQuest = true;
@@ -170,6 +170,11 @@ public:
## npc_infested_root_walker
######*/
+enum InfestedRootWalker
+{
+ SPELL_SUMMON_WOOD_MITES = 39130
+};
+
class npc_infested_root_walker : public CreatureScript
{
public:
@@ -193,7 +198,7 @@ public:
if (me->GetHealth() <= damage)
if (rand32() % 100 < 75)
//Summon Wood Mites
- DoCast(me, 39130, true);
+ DoCast(me, SPELL_SUMMON_WOOD_MITES, true);
}
};
};
@@ -201,6 +206,12 @@ public:
/*######
## npc_skywing
######*/
+
+enum Skywing
+{
+ QUEST_SKYWING = 10898
+};
+
class npc_skywing : public CreatureScript
{
public:
@@ -225,7 +236,7 @@ public:
switch (waypointId)
{
case 8:
- player->AreaExploredOrEventHappens(10898);
+ player->AreaExploredOrEventHappens(QUEST_SKYWING);
break;
}
}
@@ -239,7 +250,7 @@ public:
return;
Player* player = who->ToPlayer();
- if (player && player->GetQuestStatus(10898) == QUEST_STATUS_INCOMPLETE)
+ if (player && player->GetQuestStatus(QUEST_SKYWING) == QUEST_STATUS_INCOMPLETE)
if (me->IsWithinDistInMap(who, 10.0f))
Start(false, false, who->GetGUID());
}
@@ -257,6 +268,11 @@ public:
## npc_rotting_forest_rager
######*/
+enum RottingForestRager
+{
+ SPELL_SUMMON_LOTS_OF_WOOD_MITES = 39134
+};
+
class npc_rotting_forest_rager : public CreatureScript
{
public:
@@ -279,8 +295,8 @@ public:
if (done_by->GetTypeId() == TYPEID_PLAYER)
if (me->GetHealth() <= damage)
if (rand32() % 100 < 75)
- //Summon Lots of Wood Mights
- DoCast(me, 39134, true);
+ //Summon Lots of Wood Mites
+ DoCast(me, SPELL_SUMMON_LOTS_OF_WOOD_MITES, true);
}
};
};
@@ -289,19 +305,22 @@ public:
## npc_floon
######*/
-#define GOSSIP_FLOON1 "You owe Sim'salabim money. Hand them over or die!"
-#define GOSSIP_FLOON2 "Hand over the money or die...again!"
-
enum Floon
{
- SAY_FLOON_ATTACK = 0,
-
- SPELL_SILENCE = 6726,
- SPELL_FROSTBOLT = 9672,
- SPELL_FROST_NOVA = 11831,
-
- FACTION_HOSTILE_FL = 1738,
- QUEST_CRACK_SKULLS = 10009
+ SAY_FLOON_ATTACK = 0,
+ OPTION_ID_PAY_UP_OR_DIE = 0,
+ OPTION_ID_COLLECT_A_DEBT = 0,
+ FACTION_HOSTILE_FLOON = 1738,
+ MENU_ID_PAY_UP_OR_DIE = 7731,
+ MENU_ID_COLLECT_A_DEBT = 7732,
+ GOSSIP_FLOON_STRANGE_SOUNDS = 9442,
+ GOSSIP_HE_ALREADY_KILLED_ME = 9443,
+
+ SPELL_SILENCE = 6726,
+ SPELL_FROSTBOLT = 9672,
+ SPELL_FROST_NOVA = 11831,
+
+ QUEST_CRACKIN_SOME_SKULLS = 10009
};
class npc_floon : public CreatureScript
@@ -314,13 +333,13 @@ public:
player->PlayerTalkClass->ClearMenus();
if (action == GOSSIP_ACTION_INFO_DEF)
{
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_FLOON2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
- player->SEND_GOSSIP_MENU(9443, creature->GetGUID());
+ player->ADD_GOSSIP_ITEM_DB(MENU_ID_PAY_UP_OR_DIE, OPTION_ID_PAY_UP_OR_DIE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
+ player->SEND_GOSSIP_MENU(GOSSIP_HE_ALREADY_KILLED_ME, creature->GetGUID());
}
if (action == GOSSIP_ACTION_INFO_DEF+1)
{
player->CLOSE_GOSSIP_MENU();
- creature->setFaction(FACTION_HOSTILE_FL);
+ creature->setFaction(FACTION_HOSTILE_FLOON);
creature->AI()->Talk(SAY_FLOON_ATTACK, player);
creature->AI()->AttackStart(player);
}
@@ -329,10 +348,10 @@ public:
bool OnGossipHello(Player* player, Creature* creature) override
{
- if (player->GetQuestStatus(QUEST_CRACK_SKULLS) == QUEST_STATUS_INCOMPLETE)
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_FLOON1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
+ if (player->GetQuestStatus(QUEST_CRACKIN_SOME_SKULLS) == QUEST_STATUS_INCOMPLETE)
+ player->ADD_GOSSIP_ITEM_DB(MENU_ID_COLLECT_A_DEBT, OPTION_ID_COLLECT_A_DEBT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
- player->SEND_GOSSIP_MENU(9442, creature->GetGUID());
+ player->SEND_GOSSIP_MENU(GOSSIP_FLOON_STRANGE_SOUNDS, creature->GetGUID());
return true;
}
@@ -403,15 +422,16 @@ public:
######*/
enum IslaStarmaneData
{
- SAY_PROGRESS_1 = 0,
- SAY_PROGRESS_2 = 1,
- SAY_PROGRESS_3 = 2,
- SAY_PROGRESS_4 = 3,
-
- QUEST_EFTW_H = 10052,
- QUEST_EFTW_A = 10051,
- GO_CAGE = 182794,
- SPELL_CAT = 32447,
+ SAY_PROGRESS_1 = 0,
+ SAY_PROGRESS_2 = 1,
+ SAY_PROGRESS_3 = 2,
+ SAY_PROGRESS_4 = 3,
+ GO_DISTANCE = 10,
+ FACTION_ESCORTEE = 113,
+ ESCAPE_FROM_FIREWING_POINT_A = 10051,
+ ESCAPE_FROM_FIREWING_POINT_H = 10052,
+ SPELL_TRAVEL_FORM_CAT = 32447,
+ GO_CAGE = 182794
};
class npc_isla_starmane : public CreatureScript
@@ -432,7 +452,7 @@ public:
switch (waypointId)
{
case 0:
- if (GameObject* Cage = me->FindNearestGameObject(GO_CAGE, 10))
+ if (GameObject* Cage = me->FindNearestGameObject(GO_CAGE, GO_DISTANCE))
Cage->SetGoState(GO_STATE_ACTIVE);
break;
case 2:
@@ -447,16 +467,16 @@ public:
case 29:
Talk(SAY_PROGRESS_4, player);
if (player->GetTeam() == ALLIANCE)
- player->GroupEventHappens(QUEST_EFTW_A, me);
+ player->GroupEventHappens(ESCAPE_FROM_FIREWING_POINT_A, me);
else if (player->GetTeam() == HORDE)
- player->GroupEventHappens(QUEST_EFTW_H, me);
+ player->GroupEventHappens(ESCAPE_FROM_FIREWING_POINT_H, me);
me->SetInFront(player);
break;
case 30:
me->HandleEmoteCommand(EMOTE_ONESHOT_WAVE);
break;
case 31:
- DoCast(me, SPELL_CAT);
+ DoCast(me, SPELL_TRAVEL_FORM_CAT);
me->SetWalk(false);
break;
}
@@ -472,19 +492,19 @@ public:
if (Player* player = GetPlayerForEscort())
{
if (player->GetTeam() == ALLIANCE)
- player->FailQuest(QUEST_EFTW_A);
+ player->FailQuest(ESCAPE_FROM_FIREWING_POINT_A);
else if (player->GetTeam() == HORDE)
- player->FailQuest(QUEST_EFTW_H);
+ player->FailQuest(ESCAPE_FROM_FIREWING_POINT_H);
}
}
};
bool OnQuestAccept(Player* player, Creature* creature, Quest const* quest) override
{
- if (quest->GetQuestId() == QUEST_EFTW_H || quest->GetQuestId() == QUEST_EFTW_A)
+ if (quest->GetQuestId() == ESCAPE_FROM_FIREWING_POINT_H || quest->GetQuestId() == ESCAPE_FROM_FIREWING_POINT_A)
{
ENSURE_AI(npc_escortAI, (creature->AI()))->Start(true, false, player->GetGUID());
- creature->setFaction(113);
+ creature->setFaction(FACTION_ESCORTEE);
}
return true;
}
@@ -498,10 +518,20 @@ public:
/*######
## go_skull_pile
######*/
-#define GOSSIP_S_DARKSCREECHER_AKKARAI "Summon Darkscreecher Akkarai"
-#define GOSSIP_S_KARROG "Summon Karrog"
-#define GOSSIP_S_GEZZARAK_THE_HUNTRESS "Summon Gezzarak the Huntress"
-#define GOSSIP_S_VAKKIZ_THE_WINDRAGER "Summon Vakkiz the Windrager"
+
+enum SkullPile
+{
+ OPTION_ID_GEZZARAK_THE_HUNTRESS = 0,
+ OPTION_ID_DARKSCREECHER_AKKARAI = 1,
+ OPTION_ID_KARROG = 2,
+ OPTION_ID_VAKKIZ_THE_WINDRAGER = 3,
+ GOSSIP_MENU_ID_SKULL_PILE = 8660,
+ ADVERSARIAL_BLOOD = 11885,
+ SUMMON_GEZZARAK_THE_HUNTRESS = 40632,
+ SUMMON_KARROG = 40640,
+ SUMMON_DARKSCREECHER_AKKARAI = 40642,
+ SUMMON_VAKKIZ_THE_WINDRAGER = 40644
+};
class go_skull_pile : public GameObjectScript
{
@@ -520,12 +550,12 @@ public:
bool OnGossipHello(Player* player, GameObject* go) override
{
- if ((player->GetQuestStatus(11885) == QUEST_STATUS_INCOMPLETE) || player->GetQuestRewardStatus(11885))
+ if ((player->GetQuestStatus(ADVERSARIAL_BLOOD) == QUEST_STATUS_INCOMPLETE) || player->GetQuestRewardStatus(ADVERSARIAL_BLOOD))
{
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_S_DARKSCREECHER_AKKARAI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_S_KARROG, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_S_GEZZARAK_THE_HUNTRESS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_S_VAKKIZ_THE_WINDRAGER, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4);
+ player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_SKULL_PILE, OPTION_ID_GEZZARAK_THE_HUNTRESS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
+ player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_SKULL_PILE, OPTION_ID_DARKSCREECHER_AKKARAI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
+ player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_SKULL_PILE, OPTION_ID_KARROG, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
+ player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_SKULL_PILE, OPTION_ID_VAKKIZ_THE_WINDRAGER, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4);
}
player->SEND_GOSSIP_MENU(go->GetGOInfo()->questgiver.gossipID, go->GetGUID());
@@ -537,16 +567,16 @@ public:
switch (action)
{
case GOSSIP_ACTION_INFO_DEF + 1:
- player->CastSpell(player, 40642, false);
+ player->CastSpell(player, SUMMON_GEZZARAK_THE_HUNTRESS, false);
break;
case GOSSIP_ACTION_INFO_DEF + 2:
- player->CastSpell(player, 40640, false);
+ player->CastSpell(player, SUMMON_DARKSCREECHER_AKKARAI, false);
break;
case GOSSIP_ACTION_INFO_DEF + 3:
- player->CastSpell(player, 40632, false);
+ player->CastSpell(player, SUMMON_KARROG, false);
break;
case GOSSIP_ACTION_INFO_DEF + 4:
- player->CastSpell(player, 40644, false);
+ player->CastSpell(player, SUMMON_VAKKIZ_THE_WINDRAGER, false);
break;
}
}
@@ -558,7 +588,9 @@ public:
enum Slim
{
- FACTION_CONSORTIUM = 933
+ FACTION_CONSORTIUM = 933,
+ NPC_TEXT_NEITHER_SLIM_NOR_SHADY = 9895,
+ NPC_TEXT_I_SEE_YOU_ARE_A_FRIEND = 9896
};
class npc_slim : public CreatureScript
@@ -580,10 +612,10 @@ public:
if (creature->IsVendor() && player->GetReputationRank(FACTION_CONSORTIUM) >= REP_FRIENDLY)
{
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE);
- player->SEND_GOSSIP_MENU(9896, creature->GetGUID());
+ player->SEND_GOSSIP_MENU(NPC_TEXT_I_SEE_YOU_ARE_A_FRIEND, creature->GetGUID());
}
else
- player->SEND_GOSSIP_MENU(9895, creature->GetGUID());
+ player->SEND_GOSSIP_MENU(NPC_TEXT_NEITHER_SLIM_NOR_SHADY, creature->GetGUID());
return true;
}
diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp
index 3cea620559a..7c2bb0bfaa5 100644
--- a/src/server/scripts/Spells/spell_dk.cpp
+++ b/src/server/scripts/Spells/spell_dk.cpp
@@ -22,7 +22,7 @@
*/
#include "Player.h"
-#include "UnitAI.h"
+#include "PlayerAI.h"
#include "ScriptMgr.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
@@ -1909,7 +1909,7 @@ public:
if (!player || player->GetGhoulResurrectGhoulGUID().IsEmpty())
return;
- oldAI = player->GetAI();
+ oldAI = player->AI();
oldAIState = player->IsAIEnabled;
player->SetAI(new player_ghoulAI(player, player->GetGhoulResurrectGhoulGUID()));
player->IsAIEnabled = true;
@@ -1922,7 +1922,7 @@ public:
return;
player->IsAIEnabled = oldAIState;
- UnitAI* thisAI = player->GetAI();
+ PlayerAI* thisAI = player->AI();
player->SetAI(oldAI);
delete thisAI;
@@ -1943,7 +1943,7 @@ public:
AfterEffectRemove += AuraEffectRemoveFn(spell_dk_raise_ally_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
- UnitAI* oldAI;
+ PlayerAI* oldAI;
bool oldAIState;
};