aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVincent-Michael <Vincent_Michael@gmx.de>2013-08-30 23:46:24 +0200
committerVincent-Michael <Vincent_Michael@gmx.de>2013-08-30 23:46:24 +0200
commit38bb6fe8e7935d91cc9e487c73a966689146d8f2 (patch)
tree348d72809628705ca88e05c29927de12fbba9870 /src
parent224c5c5d3d4876f6cf05c37d7183205b1b9b565f (diff)
parent3f6296b65ebd63849f67895f7ab6280b8828da28 (diff)
Merge branch 'master' of github.com:TrinityCore/TrinityCore into 4.3.4
Conflicts: src/server/game/AI/EventAI/CreatureEventAIMgr.cpp src/server/game/Entities/Creature/Creature.h src/server/game/Entities/Player/Player.cpp src/server/game/Globals/ObjectMgr.cpp src/server/game/Handlers/CharacterHandler.cpp src/server/game/Quests/QuestDef.cpp src/server/game/Quests/QuestDef.h
Diffstat (limited to 'src')
-rw-r--r--src/server/collision/Maps/MapTree.cpp5
-rw-r--r--src/server/game/Entities/Creature/Creature.h6
-rw-r--r--src/server/game/Entities/Player/Player.cpp10
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp12
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp6
-rw-r--r--src/server/game/Movement/Spline/Spline.h4
-rw-r--r--src/server/game/Quests/QuestDef.cpp26
-rw-r--r--src/server/game/Quests/QuestDef.h39
-rw-r--r--src/server/game/Spells/SpellEffects.cpp3
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_festergut.cpp26
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp24
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp98
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h2
13 files changed, 186 insertions, 75 deletions
diff --git a/src/server/collision/Maps/MapTree.cpp b/src/server/collision/Maps/MapTree.cpp
index dc12bb68e0d..436f30eed10 100644
--- a/src/server/collision/Maps/MapTree.cpp
+++ b/src/server/collision/Maps/MapTree.cpp
@@ -156,6 +156,11 @@ namespace VMAP
bool StaticMapTree::isInLineOfSight(const Vector3& pos1, const Vector3& pos2) const
{
float maxDist = (pos2 - pos1).magnitude();
+ // return false if distance is over max float, in case of cheater teleporting to the end of the universe
+ if (maxDist == std::numeric_limits<float>::max() ||
+ maxDist == std::numeric_limits<float>::infinity())
+ return false;
+
// valid map coords should *never ever* produce float overflow, but this would produce NaNs too
ASSERT(maxDist < std::numeric_limits<float>::max());
// prevent NaN values which can cause BIH intersection to enter infinite loop
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 13ed277eda3..365bb05444e 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -193,7 +193,7 @@ struct CreatureBaseStats
uint32 GenerateHealth(CreatureTemplate const* info) const
{
- return uint32((BaseHealth[info->expansion] * info->ModHealth) + 0.5f);
+ return uint32(ceil(BaseHealth[info->expansion] * info->ModHealth));
}
uint32 GenerateMana(CreatureTemplate const* info) const
@@ -202,12 +202,12 @@ struct CreatureBaseStats
if (!BaseMana)
return 0;
- return uint32((BaseMana * info->ModMana * info->ModManaExtra) + 0.5f);
+ return uint32(ceil(BaseMana * info->ModMana * info->ModManaExtra));
}
uint32 GenerateArmor(CreatureTemplate const* info) const
{
- return uint32((BaseArmor * info->ModArmor) + 0.5f);
+ return uint32(ceil(BaseArmor * info->ModArmor));
}
static CreatureBaseStats const* GetBaseStats(uint8 level, uint8 unitClass);
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 02e95fd3975..fcdc59da9c6 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -15000,7 +15000,7 @@ bool Player::CanCompleteQuest(uint32 quest_id)
}
}
- if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_KILL | QUEST_SPECIAL_FLAGS_SPEAKTO))
+ if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_KILL | QUEST_SPECIAL_FLAGS_CAST | QUEST_SPECIAL_FLAGS_SPEAKTO))
{
for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
{
@@ -15159,7 +15159,7 @@ void Player::AddQuest(Quest const* quest, Object* questGiver)
questStatusData.ItemCount[i] = 0;
}
- if (quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_KILL | QUEST_SPECIAL_FLAGS_SPEAKTO))
+ if (quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_KILL | QUEST_SPECIAL_FLAGS_CAST | QUEST_SPECIAL_FLAGS_SPEAKTO))
{
for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
questStatusData.CreatureOrGOCount[i] = 0;
@@ -16359,7 +16359,7 @@ void Player::KilledMonsterCredit(uint32 entry, uint64 guid /*= 0*/)
QuestStatusData& q_status = m_QuestStatus[questid];
if (q_status.Status == QUEST_STATUS_INCOMPLETE && (!GetGroup() || !GetGroup()->isRaidGroup() || qInfo->IsAllowedInRaid(GetMap()->GetDifficulty())))
{
- if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_KILL))
+ if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_KILL) /*&& !qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_CAST)*/)
{
for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j)
{
@@ -16450,7 +16450,7 @@ void Player::KillCreditGO(uint32 entry, uint64 guid)
if (q_status.Status == QUEST_STATUS_INCOMPLETE)
{
- if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_KILL))
+ if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_CAST) /*&& !qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_KILL)*/)
{
for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j)
{
@@ -16504,7 +16504,7 @@ void Player::TalkedToCreature(uint32 entry, uint64 guid)
if (q_status.Status == QUEST_STATUS_INCOMPLETE)
{
- if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_KILL | QUEST_SPECIAL_FLAGS_SPEAKTO))
+ if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_KILL | QUEST_SPECIAL_FLAGS_CAST | QUEST_SPECIAL_FLAGS_SPEAKTO))
{
for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j)
{
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 1cd6125cc95..81a07e2620d 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -3627,12 +3627,12 @@ void ObjectMgr::LoadQuests()
}
}
- if (qinfo->Flags & QUEST_SPECIAL_FLAGS_MONTHLY)
+ if (qinfo->SpecialFlags & QUEST_SPECIAL_FLAGS_MONTHLY)
{
- if (!(qinfo->Flags & QUEST_SPECIAL_FLAGS_REPEATABLE))
+ if (!(qinfo->SpecialFlags & QUEST_SPECIAL_FLAGS_REPEATABLE))
{
TC_LOG_ERROR(LOG_FILTER_SQL, "Monthly quest %u not marked as repeatable in `SpecialFlags`, added.", qinfo->GetQuestId());
- qinfo->Flags |= QUEST_SPECIAL_FLAGS_REPEATABLE;
+ qinfo->SpecialFlags |= QUEST_SPECIAL_FLAGS_REPEATABLE;
}
}
@@ -3699,13 +3699,13 @@ void ObjectMgr::LoadQuests()
}
// RequiredRaces, can be 0/RACEMASK_ALL_PLAYABLE to allow any race
if (qinfo->RequiredRaces)
- {
+ {
if (!(qinfo->RequiredRaces & RACEMASK_ALL_PLAYABLE))
{
TC_LOG_ERROR(LOG_FILTER_SQL, "Quest %u does not contain any playable races in `RequiredRaces` (%u), value set to 0 (all races).", qinfo->GetQuestId(), qinfo->RequiredRaces);
qinfo->RequiredRaces = 0;
}
- }
+ }
// RequiredSkillId, can be 0
if (qinfo->RequiredSkillId)
{
@@ -3917,7 +3917,7 @@ void ObjectMgr::LoadQuests()
{
// In fact SpeakTo and Kill are quite same: either you can speak to mob:SpeakTo or you can't:Kill/Cast
- qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_KILL | QUEST_SPECIAL_FLAGS_SPEAKTO);
+ qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_KILL | QUEST_SPECIAL_FLAGS_CAST | QUEST_SPECIAL_FLAGS_SPEAKTO);
if (!qinfo->RequiredNpcOrGoCount[j])
{
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index 1cf197aeb69..341a1a89403 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -1279,6 +1279,7 @@ void WorldSession::HandleCharRenameOpcode(WorldPacket& recvData)
void WorldSession::HandleChangePlayerNameOpcodeCallBack(PreparedQueryResult result, std::string const& newName)
{
+ AntiDOS.AllowOpcode(CMSG_CHAR_ENUM, true);
if (!result)
{
WorldPacket data(SMSG_CHAR_RENAME, 1);
@@ -1528,6 +1529,9 @@ void WorldSession::HandleCharCustomize(WorldPacket& recvData)
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_AT_LOGIN);
stmt->setUInt32(0, GUID_LOPART(guid));
+ // TODO: Make async with callback
+ // TODO 2: Allow opcode at end of callback
+ AntiDOS.AllowOpcode(CMSG_CHAR_ENUM, true);
PreparedQueryResult result = CharacterDatabase.Query(stmt);
if (!result)
@@ -1781,6 +1785,8 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData)
uint8 playerClass = nameData->m_class;
uint8 level = nameData->m_level;
+ // TO Do: Make async and allow opcode on callback
+ AntiDOS.AllowOpcode(CMSG_CHAR_ENUM, true);
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_AT_LOGIN_TITLES);
stmt->setUInt32(0, lowGuid);
PreparedQueryResult result = CharacterDatabase.Query(stmt);
diff --git a/src/server/game/Movement/Spline/Spline.h b/src/server/game/Movement/Spline/Spline.h
index 42090cae71b..d4b100ee46e 100644
--- a/src/server/game/Movement/Spline/Spline.h
+++ b/src/server/game/Movement/Spline/Spline.h
@@ -21,6 +21,7 @@
#include "MovementTypedefs.h"
#include <G3D/Vector3.h>
+#include <limits>
namespace Movement {
@@ -184,6 +185,9 @@ public:
while (i < index_hi)
{
new_length = cacher(*this, i);
+ // length overflowed, assign to max positive value
+ if (new_length < 0)
+ new_length = std::numeric_limits<length_type>::max();
lengths[++i] = new_length;
ASSERT(prev_length <= new_length);
diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp
index 9f374dec8e4..d377aa0a197 100644
--- a/src/server/game/Quests/QuestDef.cpp
+++ b/src/server/game/Quests/QuestDef.cpp
@@ -72,7 +72,6 @@ Quest::Quest(Field* questRecord)
RewardReputationMask = questRecord[46].GetUInt8();
QuestGiverPortrait = questRecord[47].GetUInt32();
QuestTurnInPortrait = questRecord[48].GetUInt32();
-
for (int i = 0; i < QUEST_REWARDS_COUNT; ++i)
RewardItemId[i] = questRecord[49+i].GetUInt32();
@@ -168,37 +167,36 @@ Quest::Quest(Field* questRecord)
if (SpecialFlags & QUEST_SPECIAL_FLAGS_AUTO_ACCEPT)
Flags |= QUEST_FLAGS_AUTO_ACCEPT;
- m_reqItemsCount = 0;
- m_reqNpcOrGoCount = 0;
- m_rewItemsCount = 0;
- m_rewChoiceItemsCount = 0;
- m_rewCurrencyCount = 0;
- m_reqCurrencyCount = 0;
+ _reqItemsCount = 0;
+ _reqNpcOrGoCount = 0;
+ _rewItemsCount = 0;
+ _rewChoiceItemsCount = 0;
+ _rewCurrencyCount = 0;
+ _reqCurrencyCount = 0;
for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
if (RequiredItemId[i])
- ++m_reqItemsCount;
+ ++_reqItemsCount;
for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
if (RequiredNpcOrGo[i])
- ++m_reqNpcOrGoCount;
+ ++_reqNpcOrGoCount;
for (int i = 0; i < QUEST_REWARDS_COUNT; ++i)
if (RewardItemId[i])
- ++m_rewItemsCount;
+ ++_rewItemsCount;
for (int i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
if (RewardChoiceItemId[i])
- ++m_rewChoiceItemsCount;
+ ++_rewChoiceItemsCount;
for (int i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i)
if (RewardCurrencyId[i])
- ++m_rewCurrencyCount;
+ ++_rewCurrencyCount;
for (int i = 0; i < QUEST_REQUIRED_CURRENCY_COUNT; ++i)
if (RequiredCurrencyId[i])
- ++m_reqCurrencyCount;
-
+ ++_reqCurrencyCount;
}
uint32 Quest::XPValue(Player* player) const
diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h
index ee7c47ded91..599780d5cbe 100644
--- a/src/server/game/Quests/QuestDef.h
+++ b/src/server/game/Quests/QuestDef.h
@@ -160,14 +160,15 @@ enum QuestSpecialFlags
{
QUEST_SPECIAL_FLAGS_NONE = 0x000,
// Trinity flags for set SpecialFlags in DB if required but used only at server
- QUEST_SPECIAL_FLAGS_REPEATABLE = 0x001,
- QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT = 0x002, // if required area explore, spell SPELL_EFFECT_QUEST_COMPLETE casting, table `*_script` command SCRIPT_COMMAND_QUEST_EXPLORED use, set from script)
- QUEST_SPECIAL_FLAGS_AUTO_ACCEPT = 0x004, // quest is to be auto-accepted.
- QUEST_SPECIAL_FLAGS_DF_QUEST = 0x008, // quest is used by Dungeon Finder.
- QUEST_SPECIAL_FLAGS_MONTHLY = 0x010, // quest is reset at the begining of the month
+ QUEST_SPECIAL_FLAGS_REPEATABLE = 0x001, // Set by 1 in SpecialFlags from DB
+ QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT = 0x002, // Set by 2 in SpecialFlags from DB (if required area explore, spell SPELL_EFFECT_QUEST_COMPLETE casting, table `FECT_QUEST_COMPLETE casting, table `*_script` command SCRIPT_COMMAND_QUEST_EXPLORED use, set from script)
+ QUEST_SPECIAL_FLAGS_AUTO_ACCEPT = 0x004, // Set by 4 in SpecialFlags in DB if the quest is to be auto-accepted.
+ QUEST_SPECIAL_FLAGS_DF_QUEST = 0x008, // Set by 8 in SpecialFlags in DB if the quest is used by Dungeon Finder.
+ QUEST_SPECIAL_FLAGS_MONTHLY = 0x010, // Set by 16 in SpecialFlags in DB if the quest is reset at the begining of the month
+ QUEST_SPECIAL_FLAGS_CAST = 0x020, // Set by 32 in SpecialFlags in DB if the quest requires RequiredOrNpcGo killcredit but NOT kill (a spell cast)
// room for more custom flags
- QUEST_SPECIAL_FLAGS_DB_ALLOWED = QUEST_SPECIAL_FLAGS_REPEATABLE | QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT | QUEST_SPECIAL_FLAGS_AUTO_ACCEPT | QUEST_SPECIAL_FLAGS_DF_QUEST | QUEST_SPECIAL_FLAGS_MONTHLY,
+ QUEST_SPECIAL_FLAGS_DB_ALLOWED = QUEST_SPECIAL_FLAGS_REPEATABLE | QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT | QUEST_SPECIAL_FLAGS_AUTO_ACCEPT | QUEST_SPECIAL_FLAGS_DF_QUEST | QUEST_SPECIAL_FLAGS_MONTHLY | QUEST_SPECIAL_FLAGS_CAST,
QUEST_SPECIAL_FLAGS_DELIVER = 0x080, // Internal flag computed only
QUEST_SPECIAL_FLAGS_SPEAKTO = 0x100, // Internal flag computed only
@@ -286,7 +287,7 @@ class Quest
uint32 GetQuestTurnInPortrait() const { return QuestTurnInPortrait; }
bool IsDaily() const { return Flags & QUEST_FLAGS_DAILY; }
bool IsWeekly() const { return Flags & QUEST_FLAGS_WEEKLY; }
- bool IsMonthly() const { return Flags & QUEST_SPECIAL_FLAGS_MONTHLY; }
+ bool IsMonthly() const { return SpecialFlags & QUEST_SPECIAL_FLAGS_MONTHLY; }
bool IsSeasonal() const { return (ZoneOrSort == -QUEST_SORT_SEASONAL || ZoneOrSort == -QUEST_SORT_SPECIAL || ZoneOrSort == -QUEST_SORT_LUNAR_FESTIVAL || ZoneOrSort == -QUEST_SORT_MIDSUMMER || ZoneOrSort == -QUEST_SORT_BREWFEST || ZoneOrSort == -QUEST_SORT_LOVE_IS_IN_THE_AIR || ZoneOrSort == -QUEST_SORT_NOBLEGARDEN) && !IsRepeatable(); }
bool IsDailyOrWeekly() const { return Flags & (QUEST_FLAGS_DAILY | QUEST_FLAGS_WEEKLY); }
bool IsRaidQuest(Difficulty difficulty) const;
@@ -319,12 +320,12 @@ class Quest
uint32 RequiredCurrencyId[QUEST_REQUIRED_CURRENCY_COUNT];
uint32 RequiredCurrencyCount[QUEST_REQUIRED_CURRENCY_COUNT];
- uint32 GetReqItemsCount() const { return m_reqItemsCount; }
- uint32 GetReqCreatureOrGOcount() const { return m_reqNpcOrGoCount; }
- uint32 GetRewChoiceItemsCount() const { return m_rewChoiceItemsCount; }
- uint32 GetRewItemsCount() const { return m_rewItemsCount; }
- uint32 GetRewCurrencyCount() const { return m_rewCurrencyCount; }
- uint32 GetReqCurrencyCount() const { return m_reqCurrencyCount; }
+ uint32 GetReqItemsCount() const { return _reqItemsCount; }
+ uint32 GetReqCreatureOrGOcount() const { return _reqNpcOrGoCount; }
+ uint32 GetRewChoiceItemsCount() const { return _rewChoiceItemsCount; }
+ uint32 GetRewItemsCount() const { return _rewItemsCount; }
+ uint32 GetRewCurrencyCount() const { return _rewCurrencyCount; }
+ uint32 GetReqCurrencyCount() const { return _reqCurrencyCount; }
void BuildExtraQuestInfo(WorldPacket& data, Player* player) const;
@@ -335,12 +336,12 @@ class Quest
// cached data
private:
- uint32 m_reqItemsCount;
- uint32 m_reqNpcOrGoCount;
- uint32 m_rewChoiceItemsCount;
- uint32 m_rewItemsCount;
- uint32 m_rewCurrencyCount;
- uint32 m_reqCurrencyCount;
+ uint32 _reqItemsCount;
+ uint32 _reqNpcOrGoCount;
+ uint32 _rewChoiceItemsCount;
+ uint32 _rewItemsCount;
+ uint32 _rewCurrencyCount;
+ uint32 _reqCurrencyCount;
// table data
protected:
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index cc6a584847d..db7e8b35f2f 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -898,6 +898,9 @@ void Spell::EffectForceCast(SpellEffIndex effIndex)
case 52349: // Overtake
unitTarget->CastCustomSpell(unitTarget, spellInfo->Id, &damage, NULL, NULL, true, NULL, NULL, m_originalCasterGUID);
return;
+ case 72299: // Malleable Goo Summon Trigger
+ unitTarget->CastSpell(unitTarget, spellInfo->Id, true, NULL, NULL, m_originalCasterGUID);
+ return;
}
}
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_festergut.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_festergut.cpp
index bf85fe455c7..68df37f0fdd 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_festergut.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_festergut.cpp
@@ -206,15 +206,27 @@ class boss_festergut : public CreatureScript
}
case EVENT_VILE_GAS:
{
- std::list<Unit*> targets;
+ std::list<Unit*> ranged, melee;
uint32 minTargets = RAID_MODE<uint32>(3, 8, 3, 8);
- SelectTargetList(targets, minTargets, SELECT_TARGET_RANDOM, -5.0f, true);
- float minDist = 0.0f;
- if (targets.size() >= minTargets)
- minDist = -5.0f;
+ SelectTargetList(ranged, 25, SELECT_TARGET_RANDOM, -5.0f, true);
+ SelectTargetList(melee, 25, SELECT_TARGET_RANDOM, 5.0f, true);
+ while (ranged.size() < minTargets)
+ {
+ if (melee.empty())
+ break;
+
+ Unit* target = Trinity::Containers::SelectRandomContainerElement(melee);
+ ranged.push_back(target);
+ melee.remove(target);
+ }
+
+ if (!ranged.empty())
+ {
+ Trinity::Containers::RandomResizeList(ranged, RAID_MODE<uint32>(1, 3, 1, 3));
+ for (std::list<Unit*>::iterator itr = ranged.begin(); itr != ranged.end(); ++itr)
+ DoCast(*itr, SPELL_VILE_GAS);
+ }
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, minDist, true))
- DoCast(target, SPELL_VILE_GAS);
events.ScheduleEvent(EVENT_VILE_GAS, urand(28000, 35000));
break;
}
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp
index 927b3dfe467..96627548848 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp
@@ -55,10 +55,8 @@ enum Spells
SPELL_GASEOUS_BLIGHT_LARGE = 69157,
SPELL_GASEOUS_BLIGHT_MEDIUM = 69162,
SPELL_GASEOUS_BLIGHT_SMALL = 69164,
- SPELL_MALLABLE_GOO_H = 70852,
-
- // Rotface
- SPELL_VILE_GAS_H = 69240,
+ SPELL_MALLEABLE_GOO_H = 72296,
+ SPELL_MALLEABLE_GOO_SUMMON = 72299,
// Professor Putricide
SPELL_SLIME_PUDDLE_TRIGGER = 70341,
@@ -122,7 +120,6 @@ enum Events
// Rotface
EVENT_ROTFACE_DIES = 3,
- EVENT_ROTFACE_VILE_GAS = 4,
EVENT_ROTFACE_OOZE_FLOOD = 5,
// Professor Putricide
@@ -305,6 +302,9 @@ class boss_professor_putricide : public CreatureScript
summons.Summon(summon);
switch (summon->GetEntry())
{
+ case NPC_MALLEABLE_OOZE_STALKER:
+ DoCast(summon, SPELL_MALLEABLE_GOO_H);
+ return;
case NPC_GROWING_OOZE_PUDDLE:
summon->CastSpell(summon, SPELL_GROW_STACKER, true);
summon->CastSpell(summon, SPELL_SLIME_PUDDLE_AURA, true);
@@ -424,7 +424,7 @@ class boss_professor_putricide : public CreatureScript
me->SetReactState(REACT_PASSIVE);
DoZoneInCombat(me);
if (IsHeroic())
- events.ScheduleEvent(EVENT_FESTERGUT_GOO, urand(15000, 20000), 0, PHASE_FESTERGUT);
+ events.ScheduleEvent(EVENT_FESTERGUT_GOO, urand(13000, 18000), 0, PHASE_FESTERGUT);
break;
case ACTION_FESTERGUT_GAS:
Talk(SAY_FESTERGUT_GASEOUS_BLIGHT);
@@ -441,8 +441,6 @@ class boss_professor_putricide : public CreatureScript
me->SetReactState(REACT_PASSIVE);
_oozeFloodStage = 0;
DoZoneInCombat(me);
- if (IsHeroic())
- events.ScheduleEvent(EVENT_ROTFACE_VILE_GAS, urand(15000, 20000), 0, PHASE_ROTFACE);
// init random sequence of floods
if (Creature* rotface = Unit::GetCreature(*me, instance->GetData64(DATA_ROTFACE)))
{
@@ -582,19 +580,13 @@ class boss_professor_putricide : public CreatureScript
EnterEvadeMode();
break;
case EVENT_FESTERGUT_GOO:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(me)))
- DoCast(target, SPELL_MALLABLE_GOO_H, true); // triggered, to skip LoS check
- events.ScheduleEvent(EVENT_FESTERGUT_GOO, urand(15000, 20000), 0, PHASE_FESTERGUT);
+ me->CastCustomSpell(SPELL_MALLEABLE_GOO_SUMMON, SPELLVALUE_MAX_TARGETS, 1, NULL, true);
+ events.ScheduleEvent(EVENT_FESTERGUT_GOO, (Is25ManRaid() ? 10000 : 30000) + urand(0, 5000), 0, PHASE_FESTERGUT);
break;
case EVENT_ROTFACE_DIES:
Talk(SAY_ROTFACE_DEATH);
EnterEvadeMode();
break;
- case EVENT_ROTFACE_VILE_GAS:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(me)))
- DoCast(target, SPELL_VILE_GAS_H, true); // triggered, to skip LoS check
- events.ScheduleEvent(EVENT_ROTFACE_VILE_GAS, urand(15000, 20000), 0, PHASE_ROTFACE);
- break;
case EVENT_ROTFACE_OOZE_FLOOD:
DoAction(ACTION_ROTFACE_OOZE);
events.ScheduleEvent(EVENT_ROTFACE_OOZE_FLOOD, 25000, 0, PHASE_ROTFACE);
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp
index 97385b108b6..eddc67b5f5e 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp
@@ -46,6 +46,7 @@ enum Spells
// Rotface
SPELL_SLIME_SPRAY = 69508, // every 20 seconds
SPELL_MUTATED_INFECTION = 69674, // hastens every 1:30
+ SPELL_VILE_GAS_TRIGGER_SUMMON = 72287,
// Oozes
SPELL_LITTLE_OOZE_COMBINE = 69537, // combine 2 Small Oozes
@@ -64,6 +65,10 @@ enum Spells
SPELL_MORTAL_WOUND = 71127,
SPELL_DECIMATE = 71123,
SPELL_AWAKEN_PLAGUED_ZOMBIES = 71159,
+
+ // Professor Putricide
+ SPELL_VILE_GAS_H = 72272,
+ SPELL_VILE_GAS_TRIGGER = 72285,
};
#define MUTATED_INFECTION RAID_MODE<int32>(69674, 71224, 73022, 73023)
@@ -74,13 +79,14 @@ enum Events
EVENT_SLIME_SPRAY = 1,
EVENT_HASTEN_INFECTIONS = 2,
EVENT_MUTATED_INFECTION = 3,
+ EVENT_VILE_GAS = 4,
// Precious
- EVENT_DECIMATE = 4,
- EVENT_MORTAL_WOUND = 5,
- EVENT_SUMMON_ZOMBIES = 6,
+ EVENT_DECIMATE = 5,
+ EVENT_MORTAL_WOUND = 6,
+ EVENT_SUMMON_ZOMBIES = 7,
- EVENT_STICKY_OOZE = 7,
+ EVENT_STICKY_OOZE = 8,
};
class boss_rotface : public CreatureScript
@@ -102,6 +108,9 @@ class boss_rotface : public CreatureScript
events.ScheduleEvent(EVENT_SLIME_SPRAY, 20000);
events.ScheduleEvent(EVENT_HASTEN_INFECTIONS, 90000);
events.ScheduleEvent(EVENT_MUTATED_INFECTION, 14000);
+ if (IsHeroic())
+ events.ScheduleEvent(EVENT_VILE_GAS, urand(22000, 27000));
+
infectionStage = 0;
infectionCooldown = 14000;
}
@@ -119,7 +128,9 @@ class boss_rotface : public CreatureScript
Talk(SAY_AGGRO);
if (Creature* professor = Unit::GetCreature(*me, instance->GetData64(DATA_PROFESSOR_PUTRICIDE)))
professor->AI()->DoAction(ACTION_ROTFACE_COMBAT);
+
DoZoneInCombat();
+ DoCast(me, SPELL_GREEN_ABOMINATION_HITTIN__YA_PROC, true);
}
void JustDied(Unit* /*killer*/) OVERRIDE
@@ -158,11 +169,17 @@ class boss_rotface : public CreatureScript
}
void MoveInLineOfSight(Unit* /*who*/) OVERRIDE
-
{
// don't enter combat
}
+ void JustSummoned(Creature* summon) OVERRIDE
+ {
+ if (summon->GetEntry() == NPC_VILE_GAS_STALKER)
+ if (Creature* professor = Unit::GetCreature(*me, instance->GetData64(DATA_PROFESSOR_PUTRICIDE)))
+ professor->CastSpell(summon, SPELL_VILE_GAS_H, true);
+ }
+
void UpdateAI(uint32 diff) OVERRIDE
{
if (!UpdateVictim() || !CheckInRoom())
@@ -197,6 +214,10 @@ class boss_rotface : public CreatureScript
me->CastCustomSpell(SPELL_MUTATED_INFECTION, SPELLVALUE_MAX_TARGETS, 1, NULL, false);
events.ScheduleEvent(EVENT_MUTATED_INFECTION, infectionCooldown);
break;
+ case EVENT_VILE_GAS:
+ DoCastAOE(SPELL_VILE_GAS_TRIGGER);
+ events.ScheduleEvent(EVENT_VILE_GAS, urand(30000, 35000));
+ break;
default:
break;
}
@@ -231,6 +252,7 @@ class npc_little_ooze : public CreatureScript
{
DoCast(me, SPELL_LITTLE_OOZE_COMBINE, true);
DoCast(me, SPELL_WEAK_RADIATING_OOZE, true);
+ DoCast(me, SPELL_GREEN_ABOMINATION_HITTIN__YA_PROC, true);
events.ScheduleEvent(EVENT_STICKY_OOZE, 5000);
me->AddThreat(summoner, 500000.0f);
}
@@ -775,6 +797,71 @@ class spell_rotface_unstable_ooze_explosion_suicide : public SpellScriptLoader
}
};
+class spell_rotface_vile_gas_trigger : public SpellScriptLoader
+{
+ public:
+ spell_rotface_vile_gas_trigger() : SpellScriptLoader("spell_rotface_vile_gas_trigger") { }
+
+ class spell_rotface_vile_gas_trigger_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_rotface_vile_gas_trigger_SpellScript);
+
+ void FilterTargets(std::list<WorldObject*>& targets)
+ {
+ targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster()));
+ if (targets.empty())
+ return;
+
+ std::list<WorldObject*> ranged, melee;
+ std::list<WorldObject*>::iterator itr = targets.begin();
+ while (itr != targets.end() && (*itr)->GetDistance(GetCaster()) < 5.0f)
+ {
+ melee.push_back((*itr)->ToUnit());
+ ++itr;
+ }
+
+ while (itr != targets.end())
+ {
+ ranged.push_back((*itr)->ToUnit());
+ ++itr;
+ }
+
+ uint32 minTargets = GetCaster()->GetMap()->Is25ManRaid() ? 8 : 3;
+ while (ranged.size() < minTargets)
+ {
+ if (melee.empty())
+ break;
+
+ WorldObject* target = Trinity::Containers::SelectRandomContainerElement(melee);
+ ranged.push_back(target);
+ melee.remove(target);
+ }
+
+ if (!ranged.empty())
+ Trinity::Containers::RandomResizeList(ranged, GetCaster()->GetMap()->Is25ManRaid() ? 3 : 1);
+
+ targets.swap(ranged);
+ }
+
+ void HandleDummy(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+ GetCaster()->CastSpell(GetHitUnit(), SPELL_VILE_GAS_TRIGGER_SUMMON);
+ }
+
+ void Register()
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_rotface_vile_gas_trigger_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ OnEffectHitTarget += SpellEffectFn(spell_rotface_vile_gas_trigger_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_rotface_vile_gas_trigger_SpellScript();
+ }
+};
+
void AddSC_boss_rotface()
{
new boss_rotface();
@@ -789,4 +876,5 @@ void AddSC_boss_rotface()
new spell_rotface_unstable_ooze_explosion_init();
new spell_rotface_unstable_ooze_explosion();
new spell_rotface_unstable_ooze_explosion_suicide();
+ new spell_rotface_vile_gas_trigger();
}
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
index e328658b9af..6090d4b8368 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
+++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
@@ -183,12 +183,14 @@ enum CreaturesIds
// Festergut
NPC_FESTERGUT = 36626,
NPC_GAS_DUMMY = 36659,
+ NPC_MALLEABLE_OOZE_STALKER = 38556,
// Rotface
NPC_ROTFACE = 36627,
NPC_OOZE_SPRAY_STALKER = 37986,
NPC_PUDDLE_STALKER = 37013,
NPC_UNSTABLE_EXPLOSION_STALKER = 38107,
+ NPC_VILE_GAS_STALKER = 38548,
// Professor Putricide
NPC_PROFESSOR_PUTRICIDE = 36678,