aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/Utilities/Util.h1
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp25
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp15
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h29
-rw-r--r--src/server/game/Entities/Creature/Creature.h39
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp10
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp13
-rw-r--r--src/server/game/Groups/Group.cpp2
-rw-r--r--src/server/game/Miscellaneous/Formulas.h3
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp7
-rw-r--r--src/server/game/Spells/Spell.cpp2
-rw-r--r--src/server/game/Spells/SpellEffects.cpp10
-rw-r--r--src/server/game/Spells/SpellHistory.cpp13
-rw-r--r--src/server/game/Spells/SpellHistory.h6
-rw-r--r--src/server/game/Spells/SpellMgr.cpp1
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp6
-rw-r--r--src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h2
-rw-r--r--src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/Deadmines/instance_deadmines.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/Uldaman/uldaman.cpp5
-rw-r--r--src/server/scripts/EasternKingdoms/zone_undercity.cpp54
-rw-r--r--src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp53
-rw-r--r--src/server/scripts/Kalimdor/WailingCaverns/wailing_caverns.cpp14
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp1
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp5
-rw-r--r--src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp43
-rw-r--r--src/server/scripts/Pet/pet_mage.cpp6
-rw-r--r--src/server/scripts/Spells/spell_paladin.cpp2
-rw-r--r--src/server/scripts/World/duel_reset.cpp43
-rw-r--r--src/server/scripts/World/npc_professions.cpp106
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();
}