diff options
Diffstat (limited to 'src')
30 files changed, 331 insertions, 189 deletions
diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h index f72c1430370..1f3b78a8d56 100644 --- a/src/common/Utilities/Util.h +++ b/src/common/Utilities/Util.h @@ -27,6 +27,7 @@ #include <vector> #include <list> #include <map> +#include <ctime> // Searcher for map of structs template<typename T, class S> struct Finder diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 69a0f684a84..808491495a9 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -2305,6 +2305,31 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } break; } + case SMART_ACTION_RANDOM_SOUND: + { + std::vector<uint32> sounds; + std::copy_if(e.action.randomSound.sounds.begin(), e.action.randomSound.sounds.end(), + std::back_inserter(sounds), [](uint32 sound) { return sound != 0; }); + + bool onlySelf = e.action.randomSound.onlySelf != 0; + + if (ObjectList* targets = GetTargets(e, unit)) + { + for (WorldObject* const obj : *targets) + { + if (IsUnit(obj)) + { + uint32 sound = Trinity::Containers::SelectRandomContainerElement(sounds); + obj->PlayDirectSound(sound, onlySelf ? obj->ToPlayer() : nullptr); + TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_RANDOM_SOUND: target: %s (%s), sound: %u, onlyself: %s", + obj->GetName().c_str(), obj->GetGUID().ToString().c_str(), sound, onlySelf ? "true" : "false"); + } + } + + delete targets; + break; + } + } default: TC_LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry %d SourceType %u, Event %u, Unhandled Action type %u", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); break; diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index d56983924b4..977847e60c9 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -827,6 +827,21 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) if (e.action.randomEmote.emote6 && !IsEmoteValid(e, e.action.randomEmote.emote6)) return false; break; + case SMART_ACTION_RANDOM_SOUND: + { + if (std::all_of(e.action.randomSound.sounds.begin(), e.action.randomSound.sounds.end(), [](uint32 sound) { return sound == 0; })) + { + TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u does not have any non-zero sound", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); + return false; + } + + for (uint32 sound : e.action.randomSound.sounds) + if (sound && !IsSoundValid(e, sound)) + return false; + + break; + } case SMART_ACTION_CAST: { if (!IsSpellValid(e, e.action.cast.spell)) diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index 91ee0a1d1e0..c0ea648462d 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -43,6 +43,16 @@ struct WayPoint float z; }; +enum eSmartAI +{ + SMART_EVENT_PARAM_COUNT = 4, + SMART_ACTION_PARAM_COUNT = 6, + SMART_SUMMON_COUNTER = 0xFFFFFF, + SMART_ESCORT_LAST_OOC_POINT = 0xFFFFFF, + SMART_RANDOM_POINT = 0xFFFFFE, + SMART_ESCORT_TARGETS = 0xFFFFFF +}; + enum SMART_EVENT_PHASE { SMART_EVENT_PHASE_ALWAYS = 0, @@ -540,8 +550,9 @@ enum SMART_ACTION SMART_ACTION_GAME_EVENT_START = 112, // GameEventId SMART_ACTION_START_CLOSEST_WAYPOINT = 113, // wp1, wp2, wp3, wp4, wp5, wp6, wp7 SMART_ACTION_RISE_UP = 114, // distance + SMART_ACTION_RANDOM_SOUND = 115, // soundId1, soundId2, soundId3, soundId4, soundId5, onlySelf - SMART_ACTION_END = 115 + SMART_ACTION_END = 116 }; struct SmartAction @@ -1017,6 +1028,12 @@ struct SmartAction uint32 wp6; } closestWaypointFromList; + struct + { + std::array<uint32, SMART_ACTION_PARAM_COUNT - 1> sounds; + uint32 onlySelf; + } randomSound; + //! Note for any new future actions //! All parameters must have type uint32 @@ -1180,16 +1197,6 @@ struct SmartTarget }; }; -enum eSmartAI -{ - SMART_EVENT_PARAM_COUNT = 4, - SMART_ACTION_PARAM_COUNT = 6, - SMART_SUMMON_COUNTER = 0xFFFFFF, - SMART_ESCORT_LAST_OOC_POINT = 0xFFFFFF, - SMART_RANDOM_POINT = 0xFFFFFE, - SMART_ESCORT_TARGETS = 0xFFFFFF -}; - enum SmartScriptType { SMART_SCRIPT_TYPE_CREATURE = 0, //done diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 3ee1ba7db7b..d0b25971358 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -39,23 +39,24 @@ class WorldSession; enum CreatureFlagsExtra { - CREATURE_FLAG_EXTRA_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group - CREATURE_FLAG_EXTRA_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility) - CREATURE_FLAG_EXTRA_NO_PARRY = 0x00000004, // creature can't parry - CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry - CREATURE_FLAG_EXTRA_NO_BLOCK = 0x00000010, // creature can't block - CREATURE_FLAG_EXTRA_NO_CRUSH = 0x00000020, // creature can't do crush attacks - CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP - 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_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 - CREATURE_FLAG_EXTRA_ALL_DIMINISH = 0x00100000, // Creature is subject to all diminishing returns as player are - CREATURE_FLAG_EXTRA_DUNGEON_BOSS = 0x10000000, // creature is a dungeon boss (SET DYNAMICALLY, DO NOT ADD IN DB) - CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING = 0x20000000 // creature ignore pathfinding + CREATURE_FLAG_EXTRA_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group + CREATURE_FLAG_EXTRA_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility) + CREATURE_FLAG_EXTRA_NO_PARRY = 0x00000004, // creature can't parry + CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry + CREATURE_FLAG_EXTRA_NO_BLOCK = 0x00000010, // creature can't block + CREATURE_FLAG_EXTRA_NO_CRUSH = 0x00000020, // creature can't do crush attacks + CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP + 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_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 + CREATURE_FLAG_EXTRA_ALL_DIMINISH = 0x00100000, // creature is subject to all diminishing returns as player are + CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ = 0x00200000, // creature does not need to take player damage for kill credit + CREATURE_FLAG_EXTRA_DUNGEON_BOSS = 0x10000000, // creature is a dungeon boss (SET DYNAMICALLY, DO NOT ADD IN DB) + CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING = 0x20000000 // creature ignore pathfinding }; #define CREATURE_FLAG_EXTRA_DB_ALLOWED (CREATURE_FLAG_EXTRA_INSTANCE_BIND | CREATURE_FLAG_EXTRA_CIVILIAN | \ @@ -63,7 +64,7 @@ enum CreatureFlagsExtra 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_GUARD | CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING) + CREATURE_FLAG_EXTRA_GUARD | CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING | CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ) #define CREATURE_REGEN_INTERVAL 2 * IN_MILLISECONDS @@ -656,7 +657,7 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject void SetDisableReputationGain(bool disable) { DisableReputationGain = disable; } bool IsReputationGainDisabled() const { return DisableReputationGain; } - bool IsDamageEnoughForLootingAndReward() const { return m_PlayerDamageReq == 0; } + bool IsDamageEnoughForLootingAndReward() const { return (m_creatureInfo->flags_extra & CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ) || (m_PlayerDamageReq == 0); } void LowerPlayerDamageReq(uint32 unDamage); void ResetPlayerDamageReq() { m_PlayerDamageReq = GetHealth() / 2; } uint32 m_PlayerDamageReq; diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 6f0b9f89e44..b030f42bef7 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1353,7 +1353,15 @@ void GameObject::Use(Unit* user) break; } - player->KillCreditGO(info->entry, GetGUID()); + if (Group* group = player->GetGroup()) + { + for (GroupReference const* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) + if (Player* member = itr->GetSource()) + if (member->IsAtGroupRewardDistance(this)) + member->KillCreditGO(info->entry, GetGUID()); + } + else + player->KillCreditGO(info->entry, GetGUID()); } if (uint32 trapEntry = info->goober.linkedTrapId) diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index a826f841058..3aed5fde7b3 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -1692,6 +1692,9 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe RoundToInterval(auraAbsorbMod, 0.0f, 100.0f); + int32 absorbIgnoringDamage = CalculatePct(dmgInfo.GetDamage(), auraAbsorbMod); + dmgInfo.ModifyDamage(-absorbIgnoringDamage); + // We're going to call functions which can modify content of the list during iteration over it's elements // Let's copy the list so we can prevent iterator invalidation AuraEffectList vSchoolAbsorbCopy(victim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_ABSORB)); @@ -1724,9 +1727,6 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe if (defaultPrevented) continue; - // Apply absorb mod auras - AddPct(currentAbsorb, -auraAbsorbMod); - // absorb must be smaller than the damage itself currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(dmgInfo.GetDamage())); @@ -1775,8 +1775,6 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe if (defaultPrevented) continue; - AddPct(currentAbsorb, -auraAbsorbMod); - // absorb must be smaller than the damage itself currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(dmgInfo.GetDamage())); @@ -1805,6 +1803,8 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe } } + dmgInfo.ModifyDamage(absorbIgnoringDamage); + // split damage auras - only when not damaging self if (victim != this) { @@ -7099,9 +7099,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere float chance = 100.0f / procSpell->Effects[effIndex].ChainTarget; if (!roll_chance_f(chance)) return false; - - // Remove cooldown (Chain Lightning - has Category Recovery time) - GetSpellHistory()->ResetCooldown(spellId); } CastSpell(victim, spellId, true, castItem, triggeredByAura); diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 8ebc71b0146..43159828a3c 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -2274,6 +2274,8 @@ LootMethod Group::GetLootMethod() const ObjectGuid Group::GetLooterGuid() const { + if (GetLootMethod() == FREE_FOR_ALL) + return ObjectGuid::Empty; return m_looterGuid; } diff --git a/src/server/game/Miscellaneous/Formulas.h b/src/server/game/Miscellaneous/Formulas.h index 52b80ce92ab..6f987b8adb3 100644 --- a/src/server/game/Miscellaneous/Formulas.h +++ b/src/server/game/Miscellaneous/Formulas.h @@ -185,6 +185,9 @@ namespace Trinity } xpMod *= isBattleGround ? sWorld->getRate(RATE_XP_BG_KILL) : sWorld->getRate(RATE_XP_KILL); + if (creature->m_PlayerDamageReq) // if players dealt less than 50% of the damage and were credited anyway (due to CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ), scale XP gained appropriately (linear scaling) + xpMod *= 1.0f - 2.0f*creature->m_PlayerDamageReq / creature->GetMaxHealth(); + gain = uint32(gain * xpMod); } diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index a4e7f61d83c..6a10d113553 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -1103,18 +1103,11 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const if (apply) { - // Remove cooldown of spells triggered on stance change - they may share cooldown with stance spell if (spellId) - { - target->GetSpellHistory()->ResetCooldown(spellId); target->CastSpell(target, spellId, true, NULL, this); - } if (spellId2) - { - target->GetSpellHistory()->ResetCooldown(spellId2); target->CastSpell(target, spellId2, true, NULL, this); - } if (target->GetTypeId() == TYPEID_PLAYER) { diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 84bff4a69d6..63fe148dd93 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -4701,7 +4701,7 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_FAILED_NOT_READY; } - if (!m_caster->GetSpellHistory()->IsReady(m_spellInfo, m_castItemEntry)) + if (!m_caster->GetSpellHistory()->IsReady(m_spellInfo, m_castItemEntry, IsIgnoringCooldowns())) { if (m_triggeredByAuraSpell) return SPELL_FAILED_DONT_REPORT; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 40bd4e3c263..f961654f279 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -877,11 +877,6 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex) values.AddSpellMod(SPELLVALUE_BASE_POINT2, damage); } - // Remove spell cooldown (not category) if spell triggering spell with cooldown and same category - if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->CategoryRecoveryTime && spellInfo->CategoryRecoveryTime - && m_spellInfo->GetCategory() == spellInfo->GetCategory()) - m_caster->GetSpellHistory()->ResetCooldown(spellInfo->Id); - // original caster guid only for GO cast m_caster->CastSpell(targets, spellInfo, &values, TRIGGERED_FULL_MASK, NULL, NULL, m_originalCasterGUID); } @@ -930,11 +925,6 @@ void Spell::EffectTriggerMissileSpell(SpellEffIndex effIndex) values.AddSpellMod(SPELLVALUE_BASE_POINT2, damage); } - // Remove spell cooldown (not category) if spell triggering spell with cooldown and same category - if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->CategoryRecoveryTime && spellInfo->CategoryRecoveryTime - && m_spellInfo->GetCategory() == spellInfo->GetCategory()) - m_caster->GetSpellHistory()->ResetCooldown(spellInfo->Id); - // original caster guid only for GO cast m_caster->CastSpell(targets, spellInfo, &values, TRIGGERED_FULL_MASK, NULL, NULL, m_originalCasterGUID); } diff --git a/src/server/game/Spells/SpellHistory.cpp b/src/server/game/Spells/SpellHistory.cpp index ac08f681933..adf5fc47c77 100644 --- a/src/server/game/Spells/SpellHistory.cpp +++ b/src/server/game/Spells/SpellHistory.cpp @@ -182,13 +182,13 @@ void SpellHistory::HandleCooldowns(SpellInfo const* spellInfo, uint32 itemID, Sp StartCooldown(spellInfo, itemID, spell); } -bool SpellHistory::IsReady(SpellInfo const* spellInfo, uint32 itemId /*= 0*/) const +bool SpellHistory::IsReady(SpellInfo const* spellInfo, uint32 itemId /*= 0*/, bool ignoreCategoryCooldown /*= false*/) const { if (spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE) if (IsSchoolLocked(spellInfo->GetSchoolMask())) return false; - if (HasCooldown(spellInfo->Id, itemId)) + if (HasCooldown(spellInfo->Id, itemId, ignoreCategoryCooldown)) return false; return true; @@ -465,11 +465,14 @@ void SpellHistory::ResetAllCooldowns() _spellCooldowns.clear(); } -bool SpellHistory::HasCooldown(SpellInfo const* spellInfo, uint32 itemId /*= 0*/) const +bool SpellHistory::HasCooldown(SpellInfo const* spellInfo, uint32 itemId /*= 0*/, bool ignoreCategoryCooldown /*= false*/) const { if (_spellCooldowns.count(spellInfo->Id) != 0) return true; + if (ignoreCategoryCooldown) + return false; + uint32 category = 0; GetCooldownDurations(spellInfo, itemId, nullptr, &category, nullptr); if (!category) @@ -478,9 +481,9 @@ bool SpellHistory::HasCooldown(SpellInfo const* spellInfo, uint32 itemId /*= 0*/ return _categoryCooldowns.count(category) != 0; } -bool SpellHistory::HasCooldown(uint32 spellId, uint32 itemId /*= 0*/) const +bool SpellHistory::HasCooldown(uint32 spellId, uint32 itemId /*= 0*/, bool ignoreCategoryCooldown /*= false*/) const { - return HasCooldown(sSpellMgr->EnsureSpellInfo(spellId), itemId); + return HasCooldown(sSpellMgr->EnsureSpellInfo(spellId), itemId, ignoreCategoryCooldown); } uint32 SpellHistory::GetRemainingCooldown(SpellInfo const* spellInfo) const diff --git a/src/server/game/Spells/SpellHistory.h b/src/server/game/Spells/SpellHistory.h index 00c790a670d..f0a53fe130d 100644 --- a/src/server/game/Spells/SpellHistory.h +++ b/src/server/game/Spells/SpellHistory.h @@ -62,7 +62,7 @@ public: void HandleCooldowns(SpellInfo const* spellInfo, Item const* item, Spell* spell = nullptr); void HandleCooldowns(SpellInfo const* spellInfo, uint32 itemID, Spell* spell = nullptr); - bool IsReady(SpellInfo const* spellInfo, uint32 itemId = 0) const; + bool IsReady(SpellInfo const* spellInfo, uint32 itemId = 0, bool ignoreCategoryCooldown = false) const; template<class OwnerType> void WritePacket(WorldPacket& packet) const; @@ -105,8 +105,8 @@ public: } void ResetAllCooldowns(); - bool HasCooldown(SpellInfo const* spellInfo, uint32 itemId = 0) const; - bool HasCooldown(uint32 spellId, uint32 itemId = 0) const; + bool HasCooldown(SpellInfo const* spellInfo, uint32 itemId = 0, bool ignoreCategoryCooldown = false) const; + bool HasCooldown(uint32 spellId, uint32 itemId = 0, bool ignoreCategoryCooldown = false) const; uint32 GetRemainingCooldown(SpellInfo const* spellInfo) const; // School lockouts diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index e0b9bf53b63..ff8fc4539ff 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -2944,6 +2944,7 @@ void SpellMgr::LoadSpellInfoCorrections() case 53096: // Quetz'lun's Judgment case 70743: // AoD Special case 70614: // AoD Special - Vegard + case 4020: // Safirdrang's Chill spellInfo->MaxAffectedTargets = 1; break; case 42436: // Drink! (Brewfest) diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index daf4fe5866a..7580e9a07d3 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -43,7 +43,7 @@ struct EnumName #define CREATE_NAMED_ENUM(VALUE) { VALUE, STRINGIZE(VALUE) } #define NPCFLAG_COUNT 24 -#define FLAGS_EXTRA_COUNT 16 +#define FLAGS_EXTRA_COUNT 18 EnumName<NPCFlags, int32> const npcFlagTexts[NPCFLAG_COUNT] = { @@ -162,7 +162,9 @@ EnumName<CreatureFlagsExtra> const flagsExtra[FLAGS_EXTRA_COUNT] = CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_SKILLGAIN), CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_TAUNT_DIMINISH), CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_ALL_DIMINISH), - CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_DUNGEON_BOSS) + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_DUNGEON_BOSS), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING) }; class npc_commandscript : public CommandScript diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h index 39c9d9a79a7..9fce132ea7e 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h @@ -59,7 +59,7 @@ enum CreatureIds enum GameObjectIds { GO_BLACK_DRAGON_EGG = 177807, - GO_BOSSGATE01 = 175946, + GO_PORTCULLIS = 176965, GO_DRAKE_RIDER_PORTCULLIS = 175185, GO_ALTERAC_VALLEY_GATE = 180424, GO_GATE = 185483, diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp index 83b2b45851c..a4241b16f8d 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp @@ -22,7 +22,7 @@ DoorData const doorData[] = { - { GO_BOSSGATE01, DATA_RAZORGORE_THE_UNTAMED, DOOR_TYPE_PASSAGE }, + { GO_PORTCULLIS, DATA_RAZORGORE_THE_UNTAMED, DOOR_TYPE_PASSAGE }, { GO_DRAKE_RIDER_PORTCULLIS, DATA_VAELASTRAZ_THE_CORRUPT, DOOR_TYPE_PASSAGE }, { GO_ALTERAC_VALLEY_GATE, DATA_BROODLORD_LASHLAYER, DOOR_TYPE_PASSAGE }, { GO_GATE, DATA_FIREMAW, DOOR_TYPE_PASSAGE }, diff --git a/src/server/scripts/EasternKingdoms/Deadmines/instance_deadmines.cpp b/src/server/scripts/EasternKingdoms/Deadmines/instance_deadmines.cpp index 80391ab2873..6714b243765 100644 --- a/src/server/scripts/EasternKingdoms/Deadmines/instance_deadmines.cpp +++ b/src/server/scripts/EasternKingdoms/Deadmines/instance_deadmines.cpp @@ -61,6 +61,8 @@ class instance_deadmines : public InstanceMapScript SetHeaders(DataHeader); State = CANNON_NOT_USED; + CannonBlast_Timer = 0; + PiratesDelay_Timer = 0; } ObjectGuid FactoryDoorGUID; diff --git a/src/server/scripts/EasternKingdoms/Uldaman/uldaman.cpp b/src/server/scripts/EasternKingdoms/Uldaman/uldaman.cpp index 622c8f0de01..447dbcd67f9 100644 --- a/src/server/scripts/EasternKingdoms/Uldaman/uldaman.cpp +++ b/src/server/scripts/EasternKingdoms/Uldaman/uldaman.cpp @@ -132,7 +132,10 @@ public: ## at_map_chamber ######*/ -#define QUEST_HIDDEN_CHAMBER 2240 +enum MapChamber +{ + QUEST_HIDDEN_CHAMBER = 2240 +}; class AreaTrigger_at_map_chamber : public AreaTriggerScript { diff --git a/src/server/scripts/EasternKingdoms/zone_undercity.cpp b/src/server/scripts/EasternKingdoms/zone_undercity.cpp index 43143748661..c0b4e06cfff 100644 --- a/src/server/scripts/EasternKingdoms/zone_undercity.cpp +++ b/src/server/scripts/EasternKingdoms/zone_undercity.cpp @@ -317,59 +317,6 @@ public: }; /*###### -## npc_parqual_fintallas -######*/ - -enum ParqualFintallas -{ - SPELL_MARK_OF_SHAME = 6767 -}; - -#define GOSSIP_HPF1 "Gul'dan" -#define GOSSIP_HPF2 "Kel'Thuzad" -#define GOSSIP_HPF3 "Ner'zhul" - -class npc_parqual_fintallas : public CreatureScript -{ -public: - npc_parqual_fintallas() : CreatureScript("npc_parqual_fintallas") { } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - player->CLOSE_GOSSIP_MENU(); - creature->CastSpell(player, SPELL_MARK_OF_SHAME, false); - } - if (action == GOSSIP_ACTION_INFO_DEF+2) - { - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(6628); - } - return true; - } - - bool OnGossipHello(Player* player, Creature* creature) override - { - if (creature->IsQuestGiver()) - player->PrepareQuestMenu(creature->GetGUID()); - - if (player->GetQuestStatus(6628) == QUEST_STATUS_INCOMPLETE && !player->HasAura(SPELL_MARK_OF_SHAME)) - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HPF1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HPF2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HPF3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->SEND_GOSSIP_MENU(5822, creature->GetGUID()); - } - else - player->SEND_GOSSIP_MENU(5821, creature->GetGUID()); - - return true; - } -}; - -/*###### ## AddSC ######*/ @@ -377,5 +324,4 @@ void AddSC_undercity() { new npc_lady_sylvanas_windrunner(); new npc_highborne_lamenter(); - new npc_parqual_fintallas(); } diff --git a/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp b/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp index 6cf86c3069f..b1a00f35bb5 100644 --- a/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp +++ b/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp @@ -41,12 +41,23 @@ EndContentData */ ## npcs_dithers_and_arbington ######*/ -#define GOSSIP_HDA1 "What does the Felstone Field Cauldron need?" -#define GOSSIP_HDA2 "What does the Dalson's Tears Cauldron need?" -#define GOSSIP_HDA3 "What does the Writhing Haunt Cauldron need?" -#define GOSSIP_HDA4 "What does the Gahrron's Withering Cauldron need?" - -#define GOSSIP_SDA1 "Thanks, i need a Vitreous Focuser" +enum DithersAndArbington +{ + GOSSIP_ITEM_ID_FELSTONE_FIELD = 0, + GOSSIP_ITEM_ID_DALSON_S_TEARS = 1, + GOSSIP_ITEM_ID_WRITHING_HAUNT = 2, + GOSSIP_ITEM_ID_GAHRRON_S_WITH = 3, + GOSSIP_MENU_ID_LETS_GET_TO_WORK = 3223, + GOSSIP_MENU_ID_VITREOUS_FOCUSER = 3229, + NPC_TEXT_OSSEOUS_AGITATORS = 3980, + NPC_TEXT_SOMATIC_INTENSIFIERS_1 = 3981, + NPC_TEXT_SOMATIC_INTENSIFIERS_2 = 3982, + NPC_TEXT_ECTOPLASMIC_RESONATORS = 3983, + NPC_TEXT_LET_S_GET_TO_WORK = 3985, + QUEST_MISSION_ACCOMPLISHED_H = 5237, + QUEST_MISSION_ACCOMPLISHED_A = 5238, + CREATE_ITEM_VITREOUS_FOCUSER = 17529 +}; class npcs_dithers_and_arbington : public CreatureScript { @@ -62,24 +73,24 @@ public: player->GetSession()->SendListInventory(creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SDA1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - player->SEND_GOSSIP_MENU(3980, creature->GetGUID()); + player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_VITREOUS_FOCUSER, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + player->SEND_GOSSIP_MENU(NPC_TEXT_OSSEOUS_AGITATORS, creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SDA1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - player->SEND_GOSSIP_MENU(3981, creature->GetGUID()); + player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_VITREOUS_FOCUSER, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + player->SEND_GOSSIP_MENU(NPC_TEXT_SOMATIC_INTENSIFIERS_1, creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SDA1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - player->SEND_GOSSIP_MENU(3982, creature->GetGUID()); + player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_VITREOUS_FOCUSER, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + player->SEND_GOSSIP_MENU(NPC_TEXT_SOMATIC_INTENSIFIERS_2, creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF+4: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SDA1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - player->SEND_GOSSIP_MENU(3983, creature->GetGUID()); + player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_VITREOUS_FOCUSER, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + player->SEND_GOSSIP_MENU(NPC_TEXT_ECTOPLASMIC_RESONATORS, creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF+5: player->CLOSE_GOSSIP_MENU(); - creature->CastSpell(player, 17529, false); + creature->CastSpell(player, CREATE_ITEM_VITREOUS_FOCUSER, false); break; } return true; @@ -93,13 +104,13 @@ public: if (creature->IsVendor()) player->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - if (player->GetQuestRewardStatus(5237) || player->GetQuestRewardStatus(5238)) + if (player->GetQuestRewardStatus(QUEST_MISSION_ACCOMPLISHED_H) || player->GetQuestRewardStatus(QUEST_MISSION_ACCOMPLISHED_A)) { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HDA1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HDA2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HDA3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HDA4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - player->SEND_GOSSIP_MENU(3985, creature->GetGUID()); + player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_LETS_GET_TO_WORK, GOSSIP_ITEM_ID_FELSTONE_FIELD, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_LETS_GET_TO_WORK, GOSSIP_ITEM_ID_DALSON_S_TEARS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_LETS_GET_TO_WORK, GOSSIP_ITEM_ID_WRITHING_HAUNT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_LETS_GET_TO_WORK, GOSSIP_ITEM_ID_GAHRRON_S_WITH, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); + player->SEND_GOSSIP_MENU(NPC_TEXT_LET_S_GET_TO_WORK, creature->GetGUID()); } else player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); diff --git a/src/server/scripts/Kalimdor/WailingCaverns/wailing_caverns.cpp b/src/server/scripts/Kalimdor/WailingCaverns/wailing_caverns.cpp index 63c56e29414..29a754d5895 100644 --- a/src/server/scripts/Kalimdor/WailingCaverns/wailing_caverns.cpp +++ b/src/server/scripts/Kalimdor/WailingCaverns/wailing_caverns.cpp @@ -58,6 +58,10 @@ enum Enums SAY_FAREWELL = 5, SAY_ATTACKED = 11, + GOSSIP_OPTION_LET_EVENT_BEGIN = 201, + NPC_TEXT_NARALEX_SLEEPS_AGAIN = 698, + NPC_TEXT_FANGLORDS_ARE_DEAD = 699, + SPELL_MARK_OF_THE_WILD_RANK_2 = 5232, SPELL_SERPENTINE_CLEANSING = 6270, SPELL_NARALEXS_AWAKENING = 6271, @@ -70,10 +74,6 @@ enum Enums NPC_MUTANUS_THE_DEVOURER = 3654, }; -#define GOSSIP_ID_START_1 698 //Naralex sleeps again! -#define GOSSIP_ID_START_2 699 //The fanglords are dead! -#define GOSSIP_ITEM_NARALEX "Let the event begin!" - class npc_disciple_of_naralex : public CreatureScript { public: @@ -116,8 +116,8 @@ public: if ((instance->GetData(TYPE_LORD_COBRAHN) == DONE) && (instance->GetData(TYPE_LORD_PYTHAS) == DONE) && (instance->GetData(TYPE_LADY_ANACONDRA) == DONE) && (instance->GetData(TYPE_LORD_SERPENTIS) == DONE)) { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NARALEX, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(GOSSIP_ID_START_2, creature->GetGUID()); + player->ADD_GOSSIP_ITEM_DB(GOSSIP_OPTION_LET_EVENT_BEGIN, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->SEND_GOSSIP_MENU(NPC_TEXT_FANGLORDS_ARE_DEAD, creature->GetGUID()); if (!instance->GetData(TYPE_NARALEX_YELLED)) { @@ -127,7 +127,7 @@ public: } else { - player->SEND_GOSSIP_MENU(GOSSIP_ID_START_1, creature->GetGUID()); + player->SEND_GOSSIP_MENU(NPC_TEXT_NARALEX_SLEEPS_AGAIN, creature->GetGUID()); } } return true; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp index f59701b9c25..b8e7dcc91d5 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp @@ -1222,6 +1222,7 @@ class npc_kinetic_bomb : public CreatureScript _x = 0.f; _y = 0.f; _groundZ = 0.f; + me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); } void Reset() override diff --git a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp b/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp index 869a3ec3921..a7a89f44d81 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp @@ -67,7 +67,8 @@ enum Actions enum HorsemenData { - DATA_MOVEMENT_FINISHED = DATA_HORSEMEN_CHECK_ACHIEVEMENT_CREDIT + 1, // make sure we don't conflict with the one from naxxramas.h + DATA_HORSEMEN_IS_TIMED_KILL = Data::DATA_HORSEMEN_CHECK_ACHIEVEMENT_CREDIT, // inherit from naxxramas.h - this needs to be the first entry to ensure that there are no conflicts + DATA_MOVEMENT_FINISHED, DATA_DEATH_TIME }; @@ -130,7 +131,7 @@ struct boss_four_horsemen_baseAI : public BossAI return _myMovementFinished ? 1 : 0; case DATA_DEATH_TIME: return _timeDied; - case DATA_HORSEMEN_CHECK_ACHIEVEMENT_CREDIT: + case DATA_HORSEMEN_IS_TIMED_KILL: { uint32 minTime = 0, maxTime = 0; for (Horseman boss : horsemen) diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp index b72bcbecdac..86a4a9caf3a 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp @@ -110,30 +110,24 @@ class boss_ingvar_the_plunderer : public CreatureScript { if (me->GetEntry() != NPC_INGVAR) me->UpdateEntry(NPC_INGVAR); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE); _Reset(); - events.SetPhase(PHASE_HUMAN); - - events.ScheduleEvent(EVENT_CLEAVE, urand(6, 12)*IN_MILLISECONDS, 0, PHASE_HUMAN); - events.ScheduleEvent(EVENT_STAGGERING_ROAR, urand(18, 21)*IN_MILLISECONDS, 0, PHASE_HUMAN); - events.ScheduleEvent(EVENT_ENRAGE, urand(7, 14)*IN_MILLISECONDS, 0, PHASE_HUMAN); - events.ScheduleEvent(EVENT_SMASH, urand(12, 17)*IN_MILLISECONDS, 0, PHASE_HUMAN); } void DamageTaken(Unit* /*doneBy*/, uint32& damage) override { if (damage >= me->GetHealth() && events.IsInPhase(PHASE_HUMAN)) { + events.SetPhase(PHASE_EVENT); + events.ScheduleEvent(EVENT_SUMMON_BANSHEE, 3 * IN_MILLISECONDS, 0, PHASE_EVENT); + me->RemoveAllAuras(); + me->StopMoving(); DoCast(me, SPELL_INGVAR_FEIGN_DEATH, true); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE); - events.SetPhase(PHASE_EVENT); - events.ScheduleEvent(EVENT_SUMMON_BANSHEE, 3 * IN_MILLISECONDS, 0, PHASE_EVENT); - Talk(SAY_DEATH); } @@ -152,13 +146,28 @@ class boss_ingvar_the_plunderer : public CreatureScript me->RemoveAura(SPELL_INGVAR_FEIGN_DEATH); DoCast(me, SPELL_INGVAR_TRANSFORM, true); me->UpdateEntry(NPC_INGVAR_UNDEAD); - events.ScheduleEvent(EVENT_JUST_TRANSFORMED, 2 * IN_MILLISECONDS, 0, PHASE_EVENT); + events.ScheduleEvent(EVENT_JUST_TRANSFORMED, IN_MILLISECONDS / 2, 0, PHASE_EVENT); } void EnterCombat(Unit* /*who*/) override { + if (events.IsInPhase(PHASE_EVENT) || events.IsInPhase(PHASE_UNDEAD)) // ingvar gets multiple EnterCombat calls + return; _EnterCombat(); + Talk(SAY_AGGRO); + events.SetPhase(PHASE_HUMAN); + events.ScheduleEvent(EVENT_CLEAVE, urand(6, 12)*IN_MILLISECONDS, 0, PHASE_HUMAN); + events.ScheduleEvent(EVENT_STAGGERING_ROAR, urand(18, 21)*IN_MILLISECONDS, 0, PHASE_HUMAN); + events.ScheduleEvent(EVENT_ENRAGE, urand(7, 14)*IN_MILLISECONDS, 0, PHASE_HUMAN); + events.ScheduleEvent(EVENT_SMASH, urand(12, 17)*IN_MILLISECONDS, 0, PHASE_HUMAN); + } + + void AttackStart(Unit* who) override + { + if (events.IsInPhase(PHASE_EVENT)) // prevent ingvar from beginning to attack/chase during transition + return; + BossAI::AttackStart(who); } void JustDied(Unit* /*killer*/) override @@ -171,7 +180,7 @@ class boss_ingvar_the_plunderer : public CreatureScript { events.SetPhase(PHASE_UNDEAD); events.ScheduleEvent(EVENT_DARK_SMASH, urand(14, 18)*IN_MILLISECONDS, 0, PHASE_UNDEAD); - events.ScheduleEvent(EVENT_DREADFUL_ROAR, urand(18, 22)*IN_MILLISECONDS, 0, PHASE_UNDEAD); + events.ScheduleEvent(EVENT_DREADFUL_ROAR, 0, 0, PHASE_UNDEAD); events.ScheduleEvent(EVENT_WOE_STRIKE, urand(10, 14)*IN_MILLISECONDS, 0, PHASE_UNDEAD); events.ScheduleEvent(EVENT_SHADOW_AXE, 30*IN_MILLISECONDS, 0, PHASE_UNDEAD); } @@ -214,9 +223,17 @@ class boss_ingvar_the_plunderer : public CreatureScript events.ScheduleEvent(EVENT_SMASH, urand(12, 16)*IN_MILLISECONDS, 0, PHASE_HUMAN); break; case EVENT_JUST_TRANSFORMED: + ScheduleSecondPhase(); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE); + if (Unit* target = me->getThreatManager().getHostilTarget()) + AttackStart(target); + else + { + EnterEvadeMode(EVADE_REASON_NO_HOSTILES); + return; + } + Talk(SAY_AGGRO); DoZoneInCombat(); - ScheduleSecondPhase(); return; case EVENT_SUMMON_BANSHEE: DoCast(me, SPELL_SUMMON_BANSHEE); diff --git a/src/server/scripts/Pet/pet_mage.cpp b/src/server/scripts/Pet/pet_mage.cpp index fee47aa1fa2..37584bda2ae 100644 --- a/src/server/scripts/Pet/pet_mage.cpp +++ b/src/server/scripts/Pet/pet_mage.cpp @@ -178,6 +178,9 @@ class npc_pet_mage_mirror_image : public CreatureScript void UpdateAI(uint32 diff) override { Unit* owner = me->GetCharmerOrOwner(); + if (!owner) + return; + Unit* target = owner->getAttackerForHelper(); events.Update(diff); @@ -192,9 +195,6 @@ class npc_pet_mage_mirror_image : public CreatureScript if (me->HasUnitState(UNIT_STATE_CASTING)) return; - if (!owner) - return; - // assign target if image doesnt have any or the target is not actual if (!target || me->GetVictim() != target) { diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp index 13e7697910b..8bd4b3eb070 100644 --- a/src/server/scripts/Spells/spell_paladin.cpp +++ b/src/server/scripts/Spells/spell_paladin.cpp @@ -1195,7 +1195,7 @@ class spell_pal_light_s_beacon : public SpellScriptLoader if (!procSpell) return; - uint32 healSpellId = procSpell->IsRankOf(sSpellMgr->GetSpellInfo(SPELL_PALADIN_HOLY_LIGHT)) ? SPELL_PALADIN_BEACON_OF_LIGHT_HEAL_1 : SPELL_PALADIN_BEACON_OF_LIGHT_HEAL_3; + uint32 healSpellId = procSpell->IsRankOf(sSpellMgr->EnsureSpellInfo(SPELL_PALADIN_HOLY_LIGHT)) ? SPELL_PALADIN_BEACON_OF_LIGHT_HEAL_1 : SPELL_PALADIN_BEACON_OF_LIGHT_HEAL_3; uint32 heal = CalculatePct(eventInfo.GetHealInfo()->GetHeal(), aurEff->GetAmount()); Unit* beaconTarget = GetCaster(); diff --git a/src/server/scripts/World/duel_reset.cpp b/src/server/scripts/World/duel_reset.cpp index c5b53368bc8..3c46255a1bf 100644 --- a/src/server/scripts/World/duel_reset.cpp +++ b/src/server/scripts/World/duel_reset.cpp @@ -34,9 +34,8 @@ class DuelResetScript : public PlayerScript player1->GetSpellHistory()->SaveCooldownStateBeforeDuel(); player2->GetSpellHistory()->SaveCooldownStateBeforeDuel(); - - ResetSpellCooldowns(player1); - ResetSpellCooldowns(player2); + ResetSpellCooldowns(player1, true); + ResetSpellCooldowns(player2, true); } // Health and mana reset @@ -73,9 +72,8 @@ class DuelResetScript : public PlayerScript // Cooldown restore if (sWorld->getBoolConfig(CONFIG_RESET_DUEL_COOLDOWNS)) { - - ResetSpellCooldowns(winner); - ResetSpellCooldowns(loser); + ResetSpellCooldowns(winner, false); + ResetSpellCooldowns(loser, false); winner->GetSpellHistory()->RestoreCooldownStateAfterDuel(); loser->GetSpellHistory()->RestoreCooldownStateAfterDuel(); @@ -98,14 +96,35 @@ class DuelResetScript : public PlayerScript } } - static void ResetSpellCooldowns(Player* player) + static void ResetSpellCooldowns(Player* player, bool onStartDuel) { - // remove cooldowns on spells that have < 10 min CD and has no onHold - player->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool + if (onStartDuel) { - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); - return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS && !itr->second.OnHold; - }, true); + // remove cooldowns on spells that have < 10 min CD > 30 sec and has no onHold + player->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool + { + SpellHistory::Clock::time_point now = SpellHistory::Clock::now(); + uint32 cooldownDuration = itr->second.CooldownEnd > now ? std::chrono::duration_cast<std::chrono::milliseconds>(itr->second.CooldownEnd - now).count() : 0; + SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); + return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS + && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS + && !itr->second.OnHold + && cooldownDuration > 0 + && ( spellInfo->RecoveryTime - cooldownDuration ) > (MINUTE / 2) * IN_MILLISECONDS + && ( spellInfo->CategoryRecoveryTime - cooldownDuration ) > (MINUTE / 2) * IN_MILLISECONDS; + }, true); + } + else + { + // remove cooldowns on spells that have < 10 min CD and has no onHold + player->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool + { + SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); + return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS + && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS + && !itr->second.OnHold; + }, true); + } // pet cooldowns if (Pet* pet = player->GetPet()) diff --git a/src/server/scripts/World/npc_professions.cpp b/src/server/scripts/World/npc_professions.cpp index 4dca55d562d..867ebafe32b 100644 --- a/src/server/scripts/World/npc_professions.cpp +++ b/src/server/scripts/World/npc_professions.cpp @@ -18,27 +18,26 @@ /* ScriptData SDName: Npc_Professions -SD%Complete: 80 -SDComment: Provides learn/unlearn/relearn-options for professions. Not supported: Unlearn engineering, re-learn engineering, re-learn leatherworking. -SDCategory: NPCs +SD%Complete: 100 +SDComment: Provides learn/unlearn/relearn-options for professions. +SDCategory: NPCs/GOBs EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" +#include "GameObjectAI.h" #include "Player.h" #include "SpellInfo.h" #include "WorldSession.h" /* A few notes for future developement: -- A full implementation of gossip for GO's is required. They must have the same scripting capabilities as creatures. Basically, -there is no difference here (except that default text is chosen with `gameobject_template`.`data3` (for GO type2, different dataN for a few others) - It's possible blacksmithing still require some tweaks and adjustments due to the way we _have_ to use reputation. */ /*### -# to be removed from here (->ncp_text). This is data for database projects. +# to be removed from here (->npc_text). This is data for database projects. ###*/ #define TALK_MUST_UNLEARN_WEAPON "You must forget your weapon type specialty before I can help you. Go to Everlook in Winterspring and seek help there." @@ -153,6 +152,9 @@ enum ProfessionSpells S_LEARN_GOBLIN = 20221, S_LEARN_GNOMISH = 20220, + S_UNLEARN_GOBLIN = 68334, + S_UNLEARN_GNOMISH = 68333, + S_SPELLFIRE = 26797, S_MOONCLOTH = 26798, S_SHADOWEAVE = 26801, @@ -376,6 +378,27 @@ void ProfessionUnlearnSpells(Player* player, uint32 type) player->RemoveSpell(36075); // Wildfeather Leggings player->RemoveSpell(36078); // Living Crystal Breastplate break; + case S_UNLEARN_GOBLIN: // S_UNLEARN_GOBLIN + player->RemoveSpell(30565); // Foreman's Enchanted Helmet + player->RemoveSpell(30566); // Foreman's Reinforced Helmet + player->RemoveSpell(30563); // Goblin Rocket Launcher + player->RemoveSpell(56514); // Global Thermal Sapper Charge + player->RemoveSpell(36954); // Dimensional Ripper - Area 52 + player->RemoveSpell(23486); // Dimensional Ripper - Everlook + player->RemoveSpell(23078); // Goblin Jumper Cables XL + player->RemoveSpell(72952); // Shatter Rounds + break; + case S_UNLEARN_GNOMISH: // S_UNLEARN_GNOMISH + player->RemoveSpell(30575); // Gnomish Battle Goggles + player->RemoveSpell(30574); // Gnomish Power Goggles + player->RemoveSpell(56473); // Gnomish X-Ray Specs + player->RemoveSpell(30569); // Gnomish Poultryizer + player->RemoveSpell(30563); // Ultrasafe Transporter - Toshley's Station + player->RemoveSpell(23489); // Ultrasafe Transporter - Gadgetzan + player->RemoveSpell(23129); // World Enlarger + player->RemoveSpell(23096); // Gnomish Alarm-o-Bot + player->RemoveSpell(72953); // Iceblade Arrow + break; case S_UNLEARN_SPELLFIRE: // S_UNLEARN_SPELLFIRE player->RemoveSpell(26752); // Spellfire Belt player->RemoveSpell(26753); // Spellfire Gloves @@ -923,6 +946,76 @@ public: } }; +// Object ID - 177226 +// Book "Soothsaying for dummies" +enum SoothsayingForDummies +{ + GOSSIP_ID = 7058, + + // Engineering + OPTION_UNLEARN_GNOMISH = 0, + OPTION_UNLEARN_GOBLIN = 1, + OPTION_LEARN_GNOMISH = 2, + OPTION_LEARN_GOBLIN = 3, + + // Leatherworking + OPTION_LEARN_DRAGONSCALE = 4, + OPTION_LEARN_ELEMENTAL = 5, + OPTION_LEARN_TRIBAL = 6 +}; + +class go_soothsaying_for_dummies : public GameObjectScript +{ + public: + go_soothsaying_for_dummies() : GameObjectScript("go_soothsaying_for_dummies") { } + + struct go_soothsaying_for_dummiesAI : public GameObjectAI + { + go_soothsaying_for_dummiesAI(GameObject* go) : GameObjectAI(go) { } + + bool GossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override + { + if (menuId != GOSSIP_ID) + return false; + + switch (gossipListId) + { + case OPTION_UNLEARN_GNOMISH: + ProcessUnlearnAction(player, nullptr, S_UNLEARN_GNOMISH, 0, 0); // cost is handled by gossip code + break; + case OPTION_UNLEARN_GOBLIN: + ProcessUnlearnAction(player, nullptr, S_UNLEARN_GOBLIN, 0, 0); + break; + case OPTION_LEARN_GNOMISH: + player->CastSpell(player, S_LEARN_GNOMISH, true); + break; + case OPTION_LEARN_GOBLIN: + player->CastSpell(player, S_LEARN_GOBLIN, true); + break; + case OPTION_LEARN_DRAGONSCALE: + player->CastSpell(player, S_LEARN_DRAGON, true); + break; + case OPTION_LEARN_ELEMENTAL: + player->CastSpell(player, S_LEARN_ELEMENTAL, true); + break; + case OPTION_LEARN_TRIBAL: + player->CastSpell(player, S_LEARN_TRIBAL, true); + break; + default: + return false; + } + + player->CLOSE_GOSSIP_MENU(); + return true; // prevent further processing + } + }; + + GameObjectAI* GetAI(GameObject* go) const override + { + return new go_soothsaying_for_dummiesAI(go); + } +}; + /*### # start menues leatherworking ###*/ @@ -1212,6 +1305,7 @@ void AddSC_npc_professions() new npc_prof_alchemy(); new npc_prof_blacksmith(); new npc_engineering_tele_trinket(); + new go_soothsaying_for_dummies(); new npc_prof_leather(); new npc_prof_tailor(); } |