diff options
Diffstat (limited to 'src')
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; }; |