aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.cpp123
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.h11
-rw-r--r--src/server/game/DataStores/DBCStructure.h2
-rw-r--r--src/server/game/DataStores/DBCfmt.h2
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp42
-rw-r--r--src/server/game/Entities/Creature/Creature.h3
-rw-r--r--src/server/game/Entities/Player/Player.cpp45
-rw-r--r--src/server/game/Entities/Player/Player.h4
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp16
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp19
-rw-r--r--src/server/game/Handlers/AuctionHouseHandler.cpp7
-rw-r--r--src/server/game/Spells/SpellMgr.cpp1
-rw-r--r--src/server/game/World/World.cpp8
-rw-r--r--src/server/game/World/World.h1
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp86
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp1
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_festergut.cpp1
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp51
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp56
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp3
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp5
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp7
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h86
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp18
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp150
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp196
-rw-r--r--src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp8
-rw-r--r--src/server/scripts/Northrend/Naxxramas/naxxramas.h2
-rw-r--r--src/server/scripts/Pet/pet_mage.cpp185
29 files changed, 867 insertions, 272 deletions
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
index 768def2ff4d..20d30704c13 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
@@ -83,12 +83,23 @@ uint32 AuctionHouseMgr::GetAuctionDeposit(AuctionHouseEntry const* entry, uint32
float multiplier = CalculatePct(float(entry->depositPercent), 3);
uint32 timeHr = (((time / 60) / 60) / 12);
- uint32 deposit = uint32(((multiplier * MSV * count / 3) * timeHr * 3) * sWorld->getRate(RATE_AUCTION_DEPOSIT));
+ uint32 deposit = uint32(MSV * multiplier * sWorld->getRate(RATE_AUCTION_DEPOSIT));
+ float remainderbase = float(MSV * multiplier * sWorld->getRate(RATE_AUCTION_DEPOSIT)) - deposit;
+
+ deposit *= timeHr * count;
+
+ int i = count;
+ while (i > 0 && (remainderbase * i) != uint32(remainderbase * i))
+ i--;
+
+ if (i)
+ deposit += remainderbase * i * timeHr;
TC_LOG_DEBUG("auctionHouse", "MSV: %u", MSV);
TC_LOG_DEBUG("auctionHouse", "Items: %u", count);
TC_LOG_DEBUG("auctionHouse", "Multiplier: %f", multiplier);
TC_LOG_DEBUG("auctionHouse", "Deposit: %u", deposit);
+ TC_LOG_DEBUG("auctionHouse", "Deposit rm: %f", remainderbase * count);
if (deposit < AH_MINIMUM_DEPOSIT * sWorld->getRate(RATE_AUCTION_DEPOSIT))
return AH_MINIMUM_DEPOSIT * sWorld->getRate(RATE_AUCTION_DEPOSIT);
@@ -389,6 +400,116 @@ bool AuctionHouseMgr::RemoveAItem(ObjectGuid::LowType id, bool deleteItem)
return true;
}
+void AuctionHouseMgr::PendingAuctionAdd(Player* player, AuctionEntry* aEntry)
+{
+ PlayerAuctions* thisAH;
+ auto itr = pendingAuctionMap.find(player->GetGUID());
+ if (itr != pendingAuctionMap.end())
+ thisAH = itr->second.first;
+ else
+ {
+ thisAH = new PlayerAuctions;
+ pendingAuctionMap[player->GetGUID()] = AuctionPair(thisAH, 0);
+ }
+ thisAH->push_back(aEntry);
+}
+
+uint32 AuctionHouseMgr::PendingAuctionCount(const Player* player) const
+{
+ auto const itr = pendingAuctionMap.find(player->GetGUID());
+ if (itr != pendingAuctionMap.end())
+ return itr->second.first->size();
+
+ return 0;
+}
+
+void AuctionHouseMgr::PendingAuctionProcess(Player* player)
+{
+ auto iterMap = pendingAuctionMap.find(player->GetGUID());
+ if (iterMap == pendingAuctionMap.end())
+ return;
+
+ PlayerAuctions* thisAH = iterMap->second.first;
+
+ SQLTransaction trans = CharacterDatabase.BeginTransaction();
+
+ uint32 totalItems = 0;
+ for (auto itrAH = thisAH->begin(); itrAH != thisAH->end(); ++itrAH)
+ {
+ AuctionEntry* AH = (*itrAH);
+ totalItems += AH->itemCount;
+ }
+
+ uint32 totaldeposit = 0;
+ auto itr = (*thisAH->begin());
+
+ if (Item* item = GetAItem(itr->itemGUIDLow))
+ totaldeposit = GetAuctionDeposit(itr->auctionHouseEntry, itr->etime, item, totalItems);
+
+ uint32 depositremain = totaldeposit;
+ for (auto itr = thisAH->begin(); itr != thisAH->end(); ++itr)
+ {
+ AuctionEntry* AH = (*itr);
+
+ if (next(itr) == thisAH->end())
+ AH->deposit = depositremain;
+ else
+ {
+ AH->deposit = totaldeposit / thisAH->size();
+ depositremain -= AH->deposit;
+ }
+
+ AH->DeleteFromDB(trans);
+ AH->SaveToDB(trans);
+ }
+
+ CharacterDatabase.CommitTransaction(trans);
+ pendingAuctionMap.erase(player->GetGUID());
+ delete thisAH;
+ player->ModifyMoney(-int32(totaldeposit));
+}
+
+void AuctionHouseMgr::UpdatePendingAuctions()
+{
+ for (auto itr = pendingAuctionMap.begin(); itr != pendingAuctionMap.end();)
+ {
+ ObjectGuid playerGUID = itr->first;
+ if (Player* player = ObjectAccessor::FindConnectedPlayer(playerGUID))
+ {
+ // Check if there were auctions since last update process if not
+ if (PendingAuctionCount(player) == itr->second.second)
+ {
+ ++itr;
+ PendingAuctionProcess(player);
+ }
+ else
+ {
+ ++itr;
+ pendingAuctionMap[playerGUID].second = PendingAuctionCount(player);
+ }
+ }
+ else
+ {
+ // Expire any auctions that we couldn't get a deposit for
+ TC_LOG_WARN("auctionHouse", "Player %s was offline, unable to retrieve deposit!", playerGUID.ToString().c_str());
+ PlayerAuctions* thisAH = itr->second.first;
+ ++itr;
+ SQLTransaction trans = CharacterDatabase.BeginTransaction();
+ for (auto AHitr = thisAH->begin(); AHitr != thisAH->end();)
+ {
+ AuctionEntry* AH = (*AHitr);
+ ++AHitr;
+ AH->expire_time = time(NULL);
+ AH->DeleteFromDB(trans);
+ AH->SaveToDB(trans);
+ }
+ CharacterDatabase.CommitTransaction(trans);
+ pendingAuctionMap.erase(playerGUID);
+ delete thisAH;
+ }
+ }
+}
+
void AuctionHouseMgr::Update()
{
mHordeAuctions.Update();
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.h b/src/server/game/AuctionHouse/AuctionHouseMgr.h
index 45cdba361f3..1f885837a44 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.h
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.h
@@ -22,6 +22,7 @@
#include "Common.h"
#include "DatabaseEnv.h"
#include "DBCStructure.h"
+#include <set>
class Item;
class Player;
@@ -82,6 +83,7 @@ struct AuctionEntry
time_t expire_time;
ObjectGuid::LowType bidder;
uint32 deposit; //deposit can be calculated only when creating auction
+ uint32 etime;
AuctionHouseEntry const* auctionHouseEntry; // in AuctionHouse.dbc
// helpers
@@ -151,6 +153,8 @@ class AuctionHouseMgr
}
typedef std::unordered_map<ObjectGuid::LowType, Item*> ItemMap;
+ typedef std::vector<AuctionEntry*> PlayerAuctions;
+ typedef std::pair<PlayerAuctions*, uint32> AuctionPair;
AuctionHouseObject* GetAuctionsMap(uint32 factionTemplateId);
AuctionHouseObject* GetAuctionsMapByHouseId(uint8 auctionHouseId);
@@ -184,7 +188,10 @@ class AuctionHouseMgr
void AddAItem(Item* it);
bool RemoveAItem(ObjectGuid::LowType id, bool deleteItem = false);
-
+ void PendingAuctionAdd(Player* player, AuctionEntry* aEntry);
+ uint32 PendingAuctionCount(const Player* player) const;
+ void PendingAuctionProcess(Player* player);
+ void UpdatePendingAuctions();
void Update();
private:
@@ -193,6 +200,8 @@ class AuctionHouseMgr
AuctionHouseObject mAllianceAuctions;
AuctionHouseObject mNeutralAuctions;
+ std::map<ObjectGuid, AuctionPair> pendingAuctionMap;
+
ItemMap mAitems;
};
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index dc4ad55d9c2..a419864a194 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -809,7 +809,7 @@ struct CreatureModelDataEntry
{
uint32 Id;
uint32 Flags;
- //char* ModelPath[16]
+ char* ModelPath;
//uint32 Unk1;
float Scale; // Used in calculation of unit collision data
//int32 Unk2
diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h
index c75c0fff625..e81db5924f6 100644
--- a/src/server/game/DataStores/DBCfmt.h
+++ b/src/server/game/DataStores/DBCfmt.h
@@ -42,7 +42,7 @@ char const CinematicSequencesEntryfmt[] = "nxxxxxxxxx";
char const CreatureDisplayInfofmt[] = "nixifxxxxxxxxxxx";
char const CreatureDisplayInfoExtrafmt[] = "diixxxxxxxxxxxxxxxxxx";
char const CreatureFamilyfmt[] = "nfifiiiiixssssssssssssssssxx";
-char const CreatureModelDatafmt[] = "nixxfxxxxxxxxxxffxxxxxxxxxxx";
+char const CreatureModelDatafmt[] = "nisxfxxxxxxxxxxffxxxxxxxxxxx";
char const CreatureSpellDatafmt[] = "niiiixxxx";
char const CreatureTypefmt[] = "nxxxxxxxxxxxxxxxxxx";
char const CurrencyTypesfmt[] = "xnxi";
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index ea10ce7988b..6ba8fb44e09 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -103,6 +103,48 @@ uint32 CreatureTemplate::GetFirstValidModelId() const
return 0;
}
+uint32 CreatureTemplate::GetFirstInvisibleModel() const
+{
+ CreatureModelInfo const* modelInfo = sObjectMgr->GetCreatureModelInfo(Modelid1);
+ if (modelInfo && modelInfo->is_trigger)
+ return Modelid1;
+
+ modelInfo = sObjectMgr->GetCreatureModelInfo(Modelid2);
+ if (modelInfo && modelInfo->is_trigger)
+ return Modelid2;
+
+ modelInfo = sObjectMgr->GetCreatureModelInfo(Modelid3);
+ if (modelInfo && modelInfo->is_trigger)
+ return Modelid3;
+
+ modelInfo = sObjectMgr->GetCreatureModelInfo(Modelid4);
+ if (modelInfo && modelInfo->is_trigger)
+ return Modelid4;
+
+ return 11686;
+}
+
+uint32 CreatureTemplate::GetFirstVisibleModel() const
+{
+ CreatureModelInfo const* modelInfo = sObjectMgr->GetCreatureModelInfo(Modelid1);
+ if (modelInfo && !modelInfo->is_trigger)
+ return Modelid1;
+
+ modelInfo = sObjectMgr->GetCreatureModelInfo(Modelid2);
+ if (modelInfo && !modelInfo->is_trigger)
+ return Modelid2;
+
+ modelInfo = sObjectMgr->GetCreatureModelInfo(Modelid3);
+ if (modelInfo && !modelInfo->is_trigger)
+ return Modelid3;
+
+ modelInfo = sObjectMgr->GetCreatureModelInfo(Modelid4);
+ if (modelInfo && !modelInfo->is_trigger)
+ return Modelid4;
+
+ return 17519;
+}
+
bool AssistDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
{
if (Unit* victim = ObjectAccessor::GetUnit(m_owner, m_victim))
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 9a41c8570ed..966944e099f 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -137,6 +137,8 @@ struct CreatureTemplate
uint32 ScriptID;
uint32 GetRandomValidModelId() const;
uint32 GetFirstValidModelId() const;
+ uint32 GetFirstInvisibleModel() const;
+ uint32 GetFirstVisibleModel() const;
// helpers
SkillType GetRequiredLootSkill() const
@@ -278,6 +280,7 @@ struct CreatureModelInfo
float combat_reach;
uint8 gender;
uint32 modelid_other_gender;
+ bool is_trigger;
};
// Benchmarked: Faster than std::map (insert/find)
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 58a9626776b..ceab7d06c96 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -1535,6 +1535,7 @@ void Player::Update(uint32 p_time)
//because we don't want player's ghost teleported from graveyard
if (IsHasDelayedTeleport() && IsAlive())
TeleportTo(m_teleport_dest, m_teleport_options);
+
}
void Player::setDeathState(DeathState s)
@@ -2149,6 +2150,17 @@ void Player::RemoveFromWorld()
}
}
+bool Player::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const
+{
+ // players are immune to taunt (the aura and the spell effect)
+ if (spellInfo->Effects[index].IsAura(SPELL_AURA_MOD_TAUNT))
+ return true;
+ if (spellInfo->Effects[index].IsEffect(SPELL_EFFECT_ATTACK_ME))
+ return true;
+
+ return Unit::IsImmunedToSpellEffect(spellInfo, index);
+}
+
void Player::RegenerateAll()
{
//if (m_regenTimer <= 500)
@@ -5825,8 +5837,6 @@ void Player::UpdateCombatSkills(Unit* victim, WeaponAttackType attType, bool def
uint8 plevel = getLevel(); // if defense than victim == attacker
uint8 greylevel = Trinity::XP::GetGrayLevel(plevel);
uint8 moblevel = victim->getLevelForTarget(this);
- if (moblevel < greylevel)
- return;
if (moblevel > plevel + 5)
moblevel = plevel + 5;
@@ -13230,36 +13240,25 @@ void Player::TradeCancel(bool sendback)
void Player::UpdateSoulboundTradeItems()
{
- if (m_itemSoulboundTradeable.empty())
- return;
-
// also checks for garbage data
- for (ItemDurationList::iterator itr = m_itemSoulboundTradeable.begin(); itr != m_itemSoulboundTradeable.end();)
+ for (GuidUnorderedSet::iterator itr = m_itemSoulboundTradeable.begin(); itr != m_itemSoulboundTradeable.end();)
{
- ASSERT(*itr);
- if ((*itr)->GetOwnerGUID() != GetGUID())
- {
- m_itemSoulboundTradeable.erase(itr++);
- continue;
- }
- if ((*itr)->CheckSoulboundTradeExpire())
- {
- m_itemSoulboundTradeable.erase(itr++);
- continue;
- }
- ++itr;
+ Item* item = GetItemByGuid(*itr);
+ if (!item || item->GetOwnerGUID() != GetGUID() || item->CheckSoulboundTradeExpire())
+ itr = m_itemSoulboundTradeable.erase(itr);
+ else
+ ++itr;
}
}
void Player::AddTradeableItem(Item* item)
{
- m_itemSoulboundTradeable.push_back(item);
+ m_itemSoulboundTradeable.insert(item->GetGUID());
}
-/// @todo should never allow an item to be added to m_itemSoulboundTradeable twice
void Player::RemoveTradeableItem(Item* item)
{
- m_itemSoulboundTradeable.remove(item);
+ m_itemSoulboundTradeable.erase(item->GetGUID());
}
void Player::UpdateItemDuration(uint32 time, bool realtimeonly)
@@ -23833,7 +23832,7 @@ void Player::SetViewpoint(WorldObject* target, bool apply)
// farsight dynobj or puppet may be very far away
UpdateVisibilityOf(target);
- if (target->isType(TYPEMASK_UNIT) && !GetVehicle())
+ if (target->isType(TYPEMASK_UNIT) && target != GetVehicleBase())
((Unit*)target)->AddPlayerToVision(this);
}
else
@@ -23846,7 +23845,7 @@ void Player::SetViewpoint(WorldObject* target, bool apply)
return;
}
- if (target->isType(TYPEMASK_UNIT) && !GetVehicle())
+ if (target->isType(TYPEMASK_UNIT) && target != GetVehicleBase())
((Unit*)target)->RemovePlayerFromVision(this);
//must immediately set seer back otherwise may crash
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 8057a4ee54d..26944de9770 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1034,6 +1034,8 @@ class Player : public Unit, public GridObject<Player>
static bool BuildEnumData(PreparedQueryResult result, WorldPacket* data);
+ bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const override;
+
void SetInWater(bool apply);
bool IsInWater() const override { return m_isInWater; }
@@ -2392,7 +2394,7 @@ class Player : public Unit, public GridObject<Player>
EnchantDurationList m_enchantDuration;
ItemDurationList m_itemDuration;
- ItemDurationList m_itemSoulboundTradeable;
+ GuidUnorderedSet m_itemSoulboundTradeable;
void ResetTimeSync();
void SendTimeSync();
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 277ead92df7..27f6d5f614d 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -17791,22 +17791,8 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target)
}
if (cinfo->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER)
- {
if (target->IsGameMaster())
- {
- if (cinfo->Modelid1)
- displayId = cinfo->Modelid1; // Modelid1 is a visible model for gms
- else
- displayId = 17519; // world visible trigger's model
- }
- else
- {
- if (cinfo->Modelid2)
- displayId = cinfo->Modelid2; // Modelid2 is an invisible model for players
- else
- displayId = 11686; // world invisible trigger's model
- }
- }
+ displayId = cinfo->GetFirstVisibleModel();
}
fieldBuffer << uint32(displayId);
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index b2be5c49b91..6f5368ed150 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -1236,7 +1236,11 @@ uint32 ObjectMgr::ChooseDisplayId(CreatureTemplate const* cinfo, CreatureData co
if (data && data->displayid)
return data->displayid;
- return cinfo->GetRandomValidModelId();
+ if (!(cinfo->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER))
+ return cinfo->GetRandomValidModelId();
+
+ // Triggers by default receive the invisible model
+ return cinfo->GetFirstInvisibleModel();
}
void ObjectMgr::ChooseCreatureFlags(const CreatureTemplate* cinfo, uint32& npcflag, uint32& unit_flags, uint32& dynamicflags, const CreatureData* data /*= NULL*/)
@@ -1301,6 +1305,12 @@ void ObjectMgr::LoadCreatureModelInfo()
Field* fields = result->Fetch();
uint32 modelId = fields[0].GetUInt32();
+ CreatureDisplayInfoEntry const* creatureDisplay = sCreatureDisplayInfoStore.LookupEntry(modelId);
+ if (!creatureDisplay)
+ {
+ TC_LOG_ERROR("sql.sql", "Table `creature_model_info` has model for nonexistent display id (%u).", modelId);
+ continue;
+ }
CreatureModelInfo& modelInfo = _creatureModelStore[modelId];
@@ -1308,12 +1318,10 @@ void ObjectMgr::LoadCreatureModelInfo()
modelInfo.combat_reach = fields[2].GetFloat();
modelInfo.gender = fields[3].GetUInt8();
modelInfo.modelid_other_gender = fields[4].GetUInt32();
+ modelInfo.is_trigger = false;
// Checks
- if (!sCreatureDisplayInfoStore.LookupEntry(modelId))
- TC_LOG_ERROR("sql.sql", "Table `creature_model_info` has model for nonexistent display id (%u).", modelId);
-
if (modelInfo.gender > GENDER_NONE)
{
TC_LOG_ERROR("sql.sql", "Table `creature_model_info` has wrong gender (%u) for display id (%u).", uint32(modelInfo.gender), modelId);
@@ -1329,6 +1337,9 @@ void ObjectMgr::LoadCreatureModelInfo()
if (modelInfo.combat_reach < 0.1f)
modelInfo.combat_reach = DEFAULT_COMBAT_REACH;
+ if (CreatureModelDataEntry const* modelData = sCreatureModelDataStore.LookupEntry(creatureDisplay->ModelId))
+ modelInfo.is_trigger = strstr(modelData->ModelPath, "InvisibleStalker") != nullptr;
+
++count;
}
while (result->NextRow());
diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp
index 8ecf86680ca..a9680ff69bb 100644
--- a/src/server/game/Handlers/AuctionHouseHandler.cpp
+++ b/src/server/game/Handlers/AuctionHouseHandler.cpp
@@ -303,18 +303,21 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData)
AH->buyout = buyout;
AH->expire_time = time(NULL) + auctionTime;
AH->deposit = deposit;
+ AH->etime = etime;
AH->auctionHouseEntry = auctionHouseEntry;
TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) with count %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u",
_player->GetName().c_str(), _player->GetGUID().GetCounter(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetGUID().GetCounter(), item->GetCount(), bid, buyout, auctionTime, AH->GetHouseId());
sAuctionMgr->AddAItem(item);
auctionHouse->AddAuction(AH);
+ sAuctionMgr->PendingAuctionAdd(_player, AH);
_player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true);
SQLTransaction trans = CharacterDatabase.BeginTransaction();
item->DeleteFromInventoryDB(trans);
item->SaveToDB(trans);
+
AH->SaveToDB(trans);
_player->SaveInventoryAndGoldToDB(trans);
CharacterDatabase.CommitTransaction(trans);
@@ -351,12 +354,14 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData)
AH->buyout = buyout;
AH->expire_time = time(NULL) + auctionTime;
AH->deposit = deposit;
+ AH->etime = etime;
AH->auctionHouseEntry = auctionHouseEntry;
TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) with count %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u",
_player->GetName().c_str(), _player->GetGUID().GetCounter(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetGUID().GetCounter(), newItem->GetCount(), bid, buyout, auctionTime, AH->GetHouseId());
sAuctionMgr->AddAItem(newItem);
auctionHouse->AddAuction(AH);
+ sAuctionMgr->PendingAuctionAdd(_player, AH);
for (uint32 j = 0; j < itemsCount; ++j)
{
@@ -396,8 +401,6 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData)
GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1);
}
-
- _player->ModifyMoney(-int32(deposit));
}
//this function is called when client bids or buys out auction
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 2d990ad3ed2..debe4ac3cbf 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3053,6 +3053,7 @@ void SpellMgr::LoadSpellInfoCorrections()
case 52479: // Gift of the Harvester
case 48246: // Ball of Flame
case 36327: // Shoot Arcane Explosion Arrow
+ case 55479: // Force Obedience
spellInfo->MaxAffectedTargets = 1;
break;
case 36384: // Skartax Purple Beam
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index c41caa8f955..bcfd105f3c6 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1782,6 +1782,7 @@ void World::SetInitialWorldSettings()
m_timers[WUPDATE_WEATHERS].SetInterval(1*IN_MILLISECONDS);
m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*IN_MILLISECONDS);
+ m_timers[WUPDATE_AUCTIONS_PENDING].SetInterval(250);
m_timers[WUPDATE_UPTIME].SetInterval(m_int_configs[CONFIG_UPTIME_UPDATE]*MINUTE*IN_MILLISECONDS);
//Update "uptime" table based on configuration entry in minutes.
m_timers[WUPDATE_CORPSES].SetInterval(20 * MINUTE * IN_MILLISECONDS);
@@ -2052,6 +2053,13 @@ void World::Update(uint32 diff)
sAuctionMgr->Update();
}
+ if (m_timers[WUPDATE_AUCTIONS_PENDING].Passed())
+ {
+ m_timers[WUPDATE_AUCTIONS_PENDING].Reset();
+
+ sAuctionMgr->UpdatePendingAuctions();
+ }
+
/// <li> Handle AHBot operations
if (m_timers[WUPDATE_AHBOT].Passed())
{
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 133ac3f2386..c76b11276cc 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -69,6 +69,7 @@ enum ShutdownExitCode
enum WorldTimers
{
WUPDATE_AUCTIONS,
+ WUPDATE_AUCTIONS_PENDING,
WUPDATE_WEATHERS,
WUPDATE_UPTIME,
WUPDATE_CORPSES,
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 aeaf8a70ba5..cfeb31d5526 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp
@@ -136,11 +136,12 @@ enum Events
enum Actions
{
- ACTION_STAND_UP = 1,
- ACTION_CAST_INVOCATION = 2,
- ACTION_REMOVE_INVOCATION = 3,
- ACTION_KINETIC_BOMB_JUMP = 4,
- ACTION_FLAME_BALL_CHASE = 5,
+ ACTION_START_INTRO = 1,
+ ACTION_STAND_UP = 2,
+ ACTION_CAST_INVOCATION = 3,
+ ACTION_REMOVE_INVOCATION = 4,
+ ACTION_KINETIC_BOMB_JUMP = 5,
+ ACTION_FLAME_BALL_CHASE = 6,
};
enum Points
@@ -162,6 +163,7 @@ class StandUpEvent : public BasicEvent
bool Execute(uint64 /*eventTime*/, uint32 /*diff*/)
{
_owner.HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
+ _owner.SetReactState(REACT_AGGRESSIVE);
return true;
}
@@ -382,8 +384,6 @@ class boss_prince_keleseth_icc : public CreatureScript
if (!me->isDead())
JustRespawned();
-
- me->SetReactState(REACT_DEFENSIVE);
}
void Reset() override
@@ -395,7 +395,6 @@ class boss_prince_keleseth_icc : public CreatureScript
_isEmpowered = false;
me->SetHealth(_spawnHealth);
instance->SetData(DATA_ORB_WHISPERER_ACHIEVEMENT, uint32(true));
- me->SetReactState(REACT_DEFENSIVE);
}
void EnterCombat(Unit* /*who*/) override
@@ -597,8 +596,6 @@ class boss_prince_taldaram_icc : public CreatureScript
if (!me->isDead())
JustRespawned();
-
- me->SetReactState(REACT_DEFENSIVE);
}
void Reset() override
@@ -610,12 +607,6 @@ class boss_prince_taldaram_icc : public CreatureScript
_isEmpowered = false;
me->SetHealth(_spawnHealth);
instance->SetData(DATA_ORB_WHISPERER_ACHIEVEMENT, uint32(true));
- me->SetReactState(REACT_DEFENSIVE);
- }
-
- void MoveInLineOfSight(Unit* /*who*/) override
-
- {
}
void EnterCombat(Unit* /*who*/) override
@@ -821,8 +812,6 @@ class boss_prince_valanar_icc : public CreatureScript
if (!me->isDead())
JustRespawned();
-
- me->SetReactState(REACT_DEFENSIVE);
}
void Reset() override
@@ -834,12 +823,6 @@ class boss_prince_valanar_icc : public CreatureScript
_isEmpowered = false;
me->SetHealth(me->GetMaxHealth());
instance->SetData(DATA_ORB_WHISPERER_ACHIEVEMENT, uint32(true));
- me->SetReactState(REACT_DEFENSIVE);
- }
-
- void MoveInLineOfSight(Unit* /*who*/) override
-
- {
}
void EnterCombat(Unit* /*who*/) override
@@ -905,6 +888,7 @@ class boss_prince_valanar_icc : public CreatureScript
default:
break;
}
+
summons.Summon(summon);
if (me->IsInCombat())
DoZoneInCombat(summon);
@@ -1070,25 +1054,28 @@ class npc_blood_queen_lana_thel : public CreatureScript
me->SetVisible(true);
}
- void MoveInLineOfSight(Unit* who) override
-
+ void DoAction(int32 action) override
{
- if (_introDone)
- return;
-
- if (!me->IsWithinDistInMap(who, 35.0f, false))
- return;
-
- _introDone = true;
- Talk(SAY_INTRO_1);
- _events.SetPhase(1);
- _events.ScheduleEvent(EVENT_INTRO_1, 14000);
- // summon a visual trigger
- if (Creature* summon = DoSummon(NPC_FLOATING_TRIGGER, triggerPos, 15000, TEMPSUMMON_TIMED_DESPAWN))
+ switch (action)
{
- summon->CastSpell(summon, SPELL_OOC_INVOCATION_VISUAL, true);
- summon->SetSpeed(MOVE_FLIGHT, 0.15f, true);
- summon->GetMotionMaster()->MovePoint(0, triggerEndPos);
+ case ACTION_START_INTRO:
+ if (!_introDone)
+ {
+ _introDone = true;
+ Talk(SAY_INTRO_1);
+ _events.SetPhase(1);
+ _events.ScheduleEvent(EVENT_INTRO_1, 14000);
+ // summon a visual trigger
+ if (Creature* summon = DoSummon(NPC_FLOATING_TRIGGER, triggerPos, 15000, TEMPSUMMON_TIMED_DESPAWN))
+ {
+ summon->CastSpell(summon, SPELL_OOC_INVOCATION_VISUAL, true);
+ summon->SetSpeed(MOVE_FLIGHT, 0.15f, true); // todo: creature is swimming, check if this is blizzlike or not.
+ summon->GetMotionMaster()->MovePoint(0, triggerEndPos);
+ }
+ }
+ break;
+ default:
+ break;
}
}
@@ -1328,7 +1315,6 @@ class npc_dark_nucleus : public CreatureScript
}
void MoveInLineOfSight(Unit* who) override
-
{
ScriptedAI::MoveInLineOfSight(who);
}
@@ -1670,6 +1656,21 @@ class spell_blood_council_shadow_prison_damage : public SpellScriptLoader
}
};
+class at_blood_prince_council_start_intro : public AreaTriggerScript
+{
+ public:
+ at_blood_prince_council_start_intro() : AreaTriggerScript("at_blood_prince_council_start_intro") { }
+
+ bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
+ {
+ if (InstanceScript* instance = player->GetInstanceScript())
+ if (Creature* bloodQueen = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_BLOOD_QUEEN_LANA_THEL_COUNCIL)))
+ bloodQueen->AI()->DoAction(ACTION_START_INTRO);
+
+ return true;
+ }
+};
+
void AddSC_boss_blood_prince_council()
{
new boss_blood_council_controller();
@@ -1689,4 +1690,5 @@ void AddSC_boss_blood_prince_council()
new spell_valanar_kinetic_bomb_absorb();
new spell_blood_council_shadow_prison();
new spell_blood_council_shadow_prison_damage();
+ new at_blood_prince_council_start_intro();
}
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp
index 365e0a1588d..54c24769246 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp
@@ -268,7 +268,6 @@ class boss_deathbringer_saurfang : public CreatureScript
void Reset() override
{
_Reset();
- me->SetReactState(REACT_DEFENSIVE);
events.SetPhase(PHASE_COMBAT);
Initialize();
me->SetPower(POWER_ENERGY, 0);
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_festergut.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_festergut.cpp
index e3e89d865ff..f76c415ab92 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_festergut.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_festergut.cpp
@@ -93,7 +93,6 @@ class boss_festergut : public CreatureScript
void Reset() override
{
_Reset();
- me->SetReactState(REACT_DEFENSIVE);
events.ScheduleEvent(EVENT_BERSERK, 300000);
events.ScheduleEvent(EVENT_INHALE_BLIGHT, urand(25000, 30000));
events.ScheduleEvent(EVENT_GAS_SPORE, urand(20000, 25000));
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp
index 3a745e2c98c..78a279b94fd 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp
@@ -174,6 +174,11 @@ enum DeprogrammingData
POINT_DESPAWN = 384721,
};
+enum Actions
+{
+ ACTION_START_INTRO
+};
+
#define NPC_DARNAVAN RAID_MODE<uint32>(NPC_DARNAVAN_10, NPC_DARNAVAN_25, NPC_DARNAVAN_10, NPC_DARNAVAN_25)
#define NPC_DARNAVAN_CREDIT RAID_MODE<uint32>(NPC_DARNAVAN_CREDIT_10, NPC_DARNAVAN_CREDIT_25, NPC_DARNAVAN_CREDIT_10, NPC_DARNAVAN_CREDIT_25)
#define QUEST_DEPROGRAMMING RAID_MODE<uint32>(QUEST_DEPROGRAMMING_10, QUEST_DEPROGRAMMING_25, QUEST_DEPROGRAMMING_10, QUEST_DEPROGRAMMING_25)
@@ -241,20 +246,26 @@ class boss_lady_deathwhisper : public CreatureScript
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, false);
}
- void MoveInLineOfSight(Unit* who) override
-
+ void DoAction(int32 action) override
{
- if (!_introDone && me->IsWithinDistInMap(who, 110.0f))
+ switch (action)
{
- _introDone = true;
- Talk(SAY_INTRO_1);
- events.SetPhase(PHASE_INTRO);
- events.ScheduleEvent(EVENT_INTRO_2, 11000, 0, PHASE_INTRO);
- events.ScheduleEvent(EVENT_INTRO_3, 21000, 0, PHASE_INTRO);
- events.ScheduleEvent(EVENT_INTRO_4, 31500, 0, PHASE_INTRO);
- events.ScheduleEvent(EVENT_INTRO_5, 39500, 0, PHASE_INTRO);
- events.ScheduleEvent(EVENT_INTRO_6, 48500, 0, PHASE_INTRO);
- events.ScheduleEvent(EVENT_INTRO_7, 58000, 0, PHASE_INTRO);
+ case ACTION_START_INTRO:
+ if (!_introDone)
+ {
+ _introDone = true;
+ Talk(SAY_INTRO_1);
+ events.SetPhase(PHASE_INTRO);
+ events.ScheduleEvent(EVENT_INTRO_2, 11000, 0, PHASE_INTRO);
+ events.ScheduleEvent(EVENT_INTRO_3, 21000, 0, PHASE_INTRO);
+ events.ScheduleEvent(EVENT_INTRO_4, 31500, 0, PHASE_INTRO);
+ events.ScheduleEvent(EVENT_INTRO_5, 39500, 0, PHASE_INTRO);
+ events.ScheduleEvent(EVENT_INTRO_6, 48500, 0, PHASE_INTRO);
+ events.ScheduleEvent(EVENT_INTRO_7, 58000, 0, PHASE_INTRO);
+ }
+ break;
+ default:
+ break;
}
}
@@ -1024,6 +1035,21 @@ class spell_cultist_dark_martyrdom : public SpellScriptLoader
}
};
+class at_lady_deathwhisper_entrance : public AreaTriggerScript
+{
+ public:
+ at_lady_deathwhisper_entrance() : AreaTriggerScript("at_lady_deathwhisper_entrance") { }
+
+ bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
+ {
+ if (InstanceScript* instance = player->GetInstanceScript())
+ if (Creature* ladyDeathwhisper = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_LADY_DEATHWHISPER)))
+ ladyDeathwhisper->AI()->DoAction(ACTION_START_INTRO);
+
+ return true;
+ }
+};
+
void AddSC_boss_lady_deathwhisper()
{
new boss_lady_deathwhisper();
@@ -1033,4 +1059,5 @@ void AddSC_boss_lady_deathwhisper()
new npc_darnavan();
new spell_deathwhisper_mana_barrier();
new spell_cultist_dark_martyrdom();
+ new at_lady_deathwhisper_entrance();
}
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp
index 2fbd1293891..993fc75fcde 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp
@@ -89,11 +89,15 @@ enum MiscInfo
//DATA_SPIKE_IMMUNE_1, = 2, // Reserved & used
//DATA_SPIKE_IMMUNE_2, = 3, // Reserved & used
- ACTION_CLEAR_SPIKE_IMMUNITIES = 1,
-
MAX_BONE_SPIKE_IMMUNE = 3,
};
+enum Actions
+{
+ ACTION_CLEAR_SPIKE_IMMUNITIES = 1,
+ ACTION_TALK_ENTER_ZONE = 2
+};
+
class BoneSpikeTargetSelector : public std::unary_function<Unit*, bool>
{
public:
@@ -131,7 +135,6 @@ class boss_lord_marrowgar : public CreatureScript
_boneStormDuration = RAID_MODE<uint32>(20000, 30000, 20000, 30000);
_baseSpeed = creature->GetSpeedRate(MOVE_RUN);
_coldflameLastPos.Relocate(creature);
- _introDone = false;
_boneSlice = false;
}
@@ -146,6 +149,7 @@ class boss_lord_marrowgar : public CreatureScript
events.ScheduleEvent(EVENT_COLDFLAME, 5000, EVENT_GROUP_SPECIAL);
events.ScheduleEvent(EVENT_WARN_BONE_STORM, urand(45000, 50000));
events.ScheduleEvent(EVENT_ENRAGE, 600000);
+ _introDone = false;
_boneSlice = false;
_boneSpikeImmune.clear();
}
@@ -179,16 +183,6 @@ class boss_lord_marrowgar : public CreatureScript
Talk(SAY_KILL);
}
- void MoveInLineOfSight(Unit* who) override
-
- {
- if (!_introDone && me->IsWithinDistInMap(who, 70.0f))
- {
- Talk(SAY_ENTER_ZONE);
- _introDone = true;
- }
- }
-
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim() || !CheckInRoom())
@@ -324,10 +318,21 @@ class boss_lord_marrowgar : public CreatureScript
void DoAction(int32 action) override
{
- if (action != ACTION_CLEAR_SPIKE_IMMUNITIES)
- return;
-
- _boneSpikeImmune.clear();
+ switch (action)
+ {
+ case ACTION_CLEAR_SPIKE_IMMUNITIES:
+ _boneSpikeImmune.clear();
+ break;
+ case ACTION_TALK_ENTER_ZONE:
+ if (!_introDone)
+ {
+ Talk(SAY_ENTER_ZONE);
+ _introDone = true;
+ }
+ break;
+ default:
+ break;
+ }
}
private:
@@ -742,6 +747,22 @@ class spell_marrowgar_bone_slice : public SpellScriptLoader
}
};
+class at_lord_marrowgar_entrance : public AreaTriggerScript
+{
+ public:
+ at_lord_marrowgar_entrance() : AreaTriggerScript("at_lord_marrowgar_entrance") { }
+
+ bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
+ {
+ if (InstanceScript* instance = player->GetInstanceScript())
+ if (Creature* lordMarrowgar = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_LORD_MARROWGAR)))
+ lordMarrowgar->AI()->DoAction(ACTION_TALK_ENTER_ZONE);
+
+ return true;
+ }
+
+};
+
void AddSC_boss_lord_marrowgar()
{
new boss_lord_marrowgar();
@@ -753,4 +774,5 @@ void AddSC_boss_lord_marrowgar()
new spell_marrowgar_bone_spike_graveyard();
new spell_marrowgar_bone_storm();
new spell_marrowgar_bone_slice();
+ new at_lord_marrowgar_entrance();
}
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp
index be134a06173..4c67c0a7163 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp
@@ -236,7 +236,6 @@ class boss_professor_putricide : public CreatureScript
summons.DespawnAll();
SetPhase(PHASE_COMBAT_1);
_experimentState = EXPERIMENT_STATE_OOZE;
- me->SetReactState(REACT_DEFENSIVE);
me->SetWalk(false);
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE)
me->GetMotionMaster()->MovementExpired();
@@ -616,7 +615,7 @@ class boss_professor_putricide : public CreatureScript
DoCast(me, SPELL_TEAR_GAS_PERIODIC_TRIGGER, true);
break;
case EVENT_RESUME_ATTACK:
- me->SetReactState(REACT_DEFENSIVE);
+ me->SetReactState(REACT_AGGRESSIVE);
AttackStart(me->GetVictim());
// remove Tear Gas
me->RemoveAurasDueToSpell(SPELL_TEAR_GAS_PERIODIC_TRIGGER);
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp
index 1a2ebd179fe..d03925f734a 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp
@@ -168,11 +168,6 @@ class boss_rotface : public CreatureScript
Talk(SAY_SLIME_SPRAY);
}
- void MoveInLineOfSight(Unit* /*who*/) override
- {
- // don't enter combat
- }
-
void JustSummoned(Creature* summon) override
{
if (summon->GetEntry() == NPC_VILE_GAS_STALKER)
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
index 65d99b022dc..8917af0038f 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
@@ -234,7 +234,6 @@ class boss_sindragosa : public CreatureScript
void Reset() override
{
BossAI::Reset();
- me->SetReactState(REACT_DEFENSIVE);
DoCast(me, SPELL_TANK_MARKER, true);
events.ScheduleEvent(EVENT_BERSERK, 600000);
events.ScheduleEvent(EVENT_CLEAVE, 10000, EVENT_GROUP_LAND_PHASE);
@@ -659,7 +658,6 @@ class npc_spinestalker : public CreatureScript
_events.ScheduleEvent(EVENT_BELLOWING_ROAR, urand(20000, 25000));
_events.ScheduleEvent(EVENT_CLEAVE_SPINESTALKER, urand(10000, 15000));
_events.ScheduleEvent(EVENT_TAIL_SWEEP, urand(8000, 12000));
- me->SetReactState(REACT_DEFENSIVE);
if (!_summoned)
{
@@ -699,6 +697,7 @@ class npc_spinestalker : public CreatureScript
me->GetMotionMaster()->MoveIdle();
me->StopMoving();
me->GetMotionMaster()->MovePoint(POINT_FROSTWYRM_FLY_IN, SpinestalkerFlyPos);
+ me->SetReactState(REACT_DEFENSIVE);
}
}
@@ -714,6 +713,7 @@ class npc_spinestalker : public CreatureScript
me->SetHomePosition(SpinestalkerLandPos);
me->SetFacingTo(SpinestalkerLandPos.GetOrientation());
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ me->SetReactState(REACT_AGGRESSIVE);
}
void UpdateAI(uint32 diff) override
@@ -794,7 +794,6 @@ class npc_rimefang : public CreatureScript
_events.Reset();
_events.ScheduleEvent(EVENT_FROST_BREATH_RIMEFANG, urand(12000, 15000));
_events.ScheduleEvent(EVENT_ICY_BLAST, urand(30000, 35000));
- me->SetReactState(REACT_DEFENSIVE);
Initialize();
if (!_summoned)
@@ -835,6 +834,7 @@ class npc_rimefang : public CreatureScript
me->GetMotionMaster()->MoveIdle();
me->StopMoving();
me->GetMotionMaster()->MovePoint(POINT_FROSTWYRM_FLY_IN, RimefangFlyPos);
+ me->SetReactState(REACT_DEFENSIVE);
}
}
@@ -850,6 +850,7 @@ class npc_rimefang : public CreatureScript
me->SetHomePosition(RimefangLandPos);
me->SetFacingTo(RimefangLandPos.GetOrientation());
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
+ me->SetReactState(REACT_AGGRESSIVE);
}
void EnterCombat(Unit* /*victim*/) override
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
index e739f5a5036..224aa6cda45 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
+++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
@@ -72,50 +72,51 @@ enum TeleporterSpells
enum DataTypes
{
// Encounter States/Boss GUIDs
- DATA_LORD_MARROWGAR = 0,
- DATA_LADY_DEATHWHISPER = 1,
- DATA_ICECROWN_GUNSHIP_BATTLE = 2,
- DATA_DEATHBRINGER_SAURFANG = 3,
- DATA_FESTERGUT = 4,
- DATA_ROTFACE = 5,
- DATA_PROFESSOR_PUTRICIDE = 6,
- DATA_BLOOD_PRINCE_COUNCIL = 7,
- DATA_BLOOD_QUEEN_LANA_THEL = 8,
- DATA_SISTER_SVALNA = 9,
- DATA_VALITHRIA_DREAMWALKER = 10,
- DATA_SINDRAGOSA = 11,
- DATA_THE_LICH_KING = 12,
+ DATA_LORD_MARROWGAR = 0,
+ DATA_LADY_DEATHWHISPER = 1,
+ DATA_ICECROWN_GUNSHIP_BATTLE = 2,
+ DATA_DEATHBRINGER_SAURFANG = 3,
+ DATA_FESTERGUT = 4,
+ DATA_ROTFACE = 5,
+ DATA_PROFESSOR_PUTRICIDE = 6,
+ DATA_BLOOD_PRINCE_COUNCIL = 7,
+ DATA_BLOOD_QUEEN_LANA_THEL = 8,
+ DATA_SISTER_SVALNA = 9,
+ DATA_VALITHRIA_DREAMWALKER = 10,
+ DATA_SINDRAGOSA = 11,
+ DATA_THE_LICH_KING = 12,
// Additional data
- DATA_SAURFANG_EVENT_NPC = 13,
- DATA_BONED_ACHIEVEMENT = 14,
- DATA_OOZE_DANCE_ACHIEVEMENT = 15,
- DATA_PUTRICIDE_TABLE = 16,
- DATA_NAUSEA_ACHIEVEMENT = 17,
- DATA_ORB_WHISPERER_ACHIEVEMENT = 18,
- DATA_PRINCE_KELESETH_GUID = 19,
- DATA_PRINCE_TALDARAM_GUID = 20,
- DATA_PRINCE_VALANAR_GUID = 21,
- DATA_BLOOD_PRINCES_CONTROL = 22,
- DATA_SINDRAGOSA_FROSTWYRMS = 23,
- DATA_SPINESTALKER = 24,
- DATA_RIMEFANG = 25,
- DATA_COLDFLAME_JETS = 26,
- DATA_TEAM_IN_INSTANCE = 27,
- DATA_BLOOD_QUICKENING_STATE = 28,
- DATA_HEROIC_ATTEMPTS = 29,
- DATA_CROK_SCOURGEBANE = 30,
- DATA_CAPTAIN_ARNATH = 31,
- DATA_CAPTAIN_BRANDON = 32,
- DATA_CAPTAIN_GRONDEL = 33,
- DATA_CAPTAIN_RUPERT = 34,
- DATA_VALITHRIA_TRIGGER = 35,
- DATA_VALITHRIA_LICH_KING = 36,
- DATA_HIGHLORD_TIRION_FORDRING = 37,
- DATA_ARTHAS_PLATFORM = 38,
- DATA_TERENAS_MENETHIL = 39,
- DATA_ENEMY_GUNSHIP = 40,
- DATA_UPPERSPIRE_TELE_ACT = 41,
+ DATA_SAURFANG_EVENT_NPC = 13,
+ DATA_BONED_ACHIEVEMENT = 14,
+ DATA_OOZE_DANCE_ACHIEVEMENT = 15,
+ DATA_PUTRICIDE_TABLE = 16,
+ DATA_NAUSEA_ACHIEVEMENT = 17,
+ DATA_ORB_WHISPERER_ACHIEVEMENT = 18,
+ DATA_PRINCE_KELESETH_GUID = 19,
+ DATA_PRINCE_TALDARAM_GUID = 20,
+ DATA_PRINCE_VALANAR_GUID = 21,
+ DATA_BLOOD_PRINCES_CONTROL = 22,
+ DATA_SINDRAGOSA_FROSTWYRMS = 23,
+ DATA_SPINESTALKER = 24,
+ DATA_RIMEFANG = 25,
+ DATA_COLDFLAME_JETS = 26,
+ DATA_TEAM_IN_INSTANCE = 27,
+ DATA_BLOOD_QUICKENING_STATE = 28,
+ DATA_HEROIC_ATTEMPTS = 29,
+ DATA_CROK_SCOURGEBANE = 30,
+ DATA_CAPTAIN_ARNATH = 31,
+ DATA_CAPTAIN_BRANDON = 32,
+ DATA_CAPTAIN_GRONDEL = 33,
+ DATA_CAPTAIN_RUPERT = 34,
+ DATA_VALITHRIA_TRIGGER = 35,
+ DATA_VALITHRIA_LICH_KING = 36,
+ DATA_HIGHLORD_TIRION_FORDRING = 37,
+ DATA_ARTHAS_PLATFORM = 38,
+ DATA_TERENAS_MENETHIL = 39,
+ DATA_ENEMY_GUNSHIP = 40,
+ DATA_UPPERSPIRE_TELE_ACT = 41,
+ DATA_BLOOD_QUEEN_LANA_THEL_COUNCIL = 42
};
enum CreaturesIds
@@ -247,6 +248,7 @@ enum CreaturesIds
NPC_KINETIC_BOMB_TARGET = 38458,
NPC_KINETIC_BOMB = 38454,
NPC_SHOCK_VORTEX = 38422,
+ NPC_BLOOD_QUEEN_LANA_THEL_COUNCIL = 38004,
// Blood-Queen Lana'thel
NPC_BLOOD_QUEEN_LANA_THEL = 37955,
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
index 5354d1772b6..718c0ebe231 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
@@ -173,6 +173,12 @@ class instance_icecrown_citadel : public InstanceMapScript
switch (creature->GetEntry())
{
+ case NPC_LORD_MARROWGAR:
+ LordMarrowgarGUID = creature->GetGUID();
+ break;
+ case NPC_LADY_DEATHWHISPER:
+ LadyDeahtwhisperGUID = creature->GetGUID();
+ break;
case NPC_KOR_KRON_GENERAL:
if (TeamInInstance == ALLIANCE)
creature->UpdateEntry(NPC_ALLIANCE_COMMANDER);
@@ -249,6 +255,9 @@ class instance_icecrown_citadel : public InstanceMapScript
case NPC_BLOOD_ORB_CONTROLLER:
BloodCouncilControllerGUID = creature->GetGUID();
break;
+ case NPC_BLOOD_QUEEN_LANA_THEL_COUNCIL:
+ BloodQueenLanaThelCouncilGUID = creature->GetGUID();
+ break;
case NPC_BLOOD_QUEEN_LANA_THEL:
BloodQueenLanaThelGUID = creature->GetGUID();
break;
@@ -712,6 +721,10 @@ class instance_icecrown_citadel : public InstanceMapScript
{
switch (type)
{
+ case DATA_LORD_MARROWGAR:
+ return LordMarrowgarGUID;
+ case DATA_LADY_DEATHWHISPER:
+ return LadyDeahtwhisperGUID;
case DATA_ICECROWN_GUNSHIP_BATTLE:
return GunshipGUID;
case DATA_ENEMY_GUNSHIP:
@@ -738,6 +751,8 @@ class instance_icecrown_citadel : public InstanceMapScript
return BloodCouncilGUIDs[2];
case DATA_BLOOD_PRINCES_CONTROL:
return BloodCouncilControllerGUID;
+ case DATA_BLOOD_QUEEN_LANA_THEL_COUNCIL:
+ return BloodQueenLanaThelCouncilGUID;
case DATA_BLOOD_QUEEN_LANA_THEL:
return BloodQueenLanaThelGUID;
case DATA_CROK_SCOURGEBANE:
@@ -1425,6 +1440,8 @@ class instance_icecrown_citadel : public InstanceMapScript
protected:
EventMap Events;
+ ObjectGuid LordMarrowgarGUID;
+ ObjectGuid LadyDeahtwhisperGUID;
ObjectGuid LadyDeathwisperElevatorGUID;
ObjectGuid GunshipGUID;
ObjectGuid EnemyGunshipGUID;
@@ -1452,6 +1469,7 @@ class instance_icecrown_citadel : public InstanceMapScript
ObjectGuid PutricideTableGUID;
ObjectGuid BloodCouncilGUIDs[3];
ObjectGuid BloodCouncilControllerGUID;
+ ObjectGuid BloodQueenLanaThelCouncilGUID;
ObjectGuid BloodQueenLanaThelGUID;
ObjectGuid CrokScourgebaneGUID;
ObjectGuid CrokCaptainGUIDs[4];
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp
index e52731d003e..0d938122f28 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp
@@ -18,6 +18,7 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "PassiveAI.h"
+#include "SpellScript.h"
#include "naxxramas.h"
enum Spells
@@ -28,6 +29,14 @@ enum Spells
SPELL_NECROTIC_POISON = 28776,
SPELL_FRENZY = 54123
};
+#define SPELL_FRENZY_HELPER RAID_MODE(54123,54124)
+
+enum Emotes
+{
+ EMOTE_SPIDERS = 0,
+ EMOTE_WEB_WRAP = 1,
+ EMOTE_WEB_SPRAY = 2
+};
enum Creatures
{
@@ -35,12 +44,16 @@ enum Creatures
NPC_SPIDERLING = 17055,
};
-#define MAX_POS_WRAP 3
-const Position PosWrap[MAX_POS_WRAP] =
+#define MAX_WRAP_POSITION 7
+const Position WrapPositions[MAX_WRAP_POSITION] =
{
- {3546.796f, -3869.082f, 296.450f, 0.0f},
- {3531.271f, -3847.424f, 299.450f, 0.0f},
- {3497.067f, -3843.384f, 302.384f, 0.0f},
+ {3453.818f, -3854.651f, 308.7581f, 4.362833f},
+ {3535.042f, -3842.383f, 300.795f, 3.179324f},
+ {3538.399f, -3846.088f, 299.964f, 4.310297f},
+ {3548.464f, -3854.676f, 298.6075f, 4.546609f},
+ {3557.663f, -3870.123f, 297.5027f, 3.756433f},
+ {3560.546f, -3879.353f, 297.4843f, 2.508937f},
+ {3562.535f, -3892.507f, 298.532f, 6.022466f},
};
enum Events
@@ -51,7 +64,24 @@ enum Events
EVENT_POISON,
EVENT_WRAP,
EVENT_SUMMON,
- EVENT_FRENZY,
+};
+
+const float WEB_WRAP_MOVE_SPEED = 20.0f;
+
+struct WebTargetSelector : public std::unary_function<Unit*, bool>
+{
+ WebTargetSelector(Unit* maexxna) : _maexxna(maexxna) {}
+ bool operator()(Unit const* target) const
+ {
+ if (_maexxna->GetVictim() == target) // never target tank
+ return false;
+ if (target->HasAura(SPELL_WEB_WRAP)) // never target targets that are already webbed
+ return false;
+ return true;
+ }
+
+ private:
+ const Unit* _maexxna;
};
class boss_maexxna : public CreatureScript
@@ -66,27 +96,22 @@ public:
struct boss_maexxnaAI : public BossAI
{
- boss_maexxnaAI(Creature* creature) : BossAI(creature, BOSS_MAEXXNA)
- {
- Initialize();
- }
+ boss_maexxnaAI(Creature* creature) : BossAI(creature, BOSS_MAEXXNA) { }
- void Initialize()
+ void EnterCombat(Unit* /*who*/) override
{
- enraged = false;
+ _EnterCombat();
+ events.ScheduleEvent(EVENT_WRAP, 20 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_SPRAY, 40 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_SHOCK, urandms(5, 10));
+ events.ScheduleEvent(EVENT_POISON, urandms(10, 15));
+ events.ScheduleEvent(EVENT_SUMMON, 30 * IN_MILLISECONDS);
}
- bool enraged;
-
- void EnterCombat(Unit* /*who*/) override
+ void Reset() override
{
- _EnterCombat();
- Initialize();
- events.ScheduleEvent(EVENT_WRAP, 20000);
- events.ScheduleEvent(EVENT_SPRAY, 40000);
- events.ScheduleEvent(EVENT_SHOCK, urand(5000, 10000));
- events.ScheduleEvent(EVENT_POISON, urand(10000, 15000));
- events.ScheduleEvent(EVENT_SUMMON, 30000);
+ _Reset();
+ instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_WEB_WRAP);
}
void UpdateAI(uint32 diff) override
@@ -94,10 +119,9 @@ public:
if (!UpdateVictim() || !CheckInRoom())
return;
- if (!enraged && HealthBelowPct(30))
+ if (HealthBelowPct(30) && !me->HasAura(SPELL_FRENZY_HELPER))
{
- enraged = true;
- events.ScheduleEvent(EVENT_FRENZY, 0); // will be cast immediately
+ DoCast(SPELL_FRENZY);
}
events.Update(diff);
@@ -107,41 +131,49 @@ public:
switch (eventId)
{
case EVENT_WRAP:
- /// @todo Add missing text
- for (uint8 i = 0; i < RAID_MODE(1, 2); ++i)
+ {
+ std::list<Unit*> targets;
+ SelectTargetList(targets, WebTargetSelector(me), RAID_MODE(1, 2), SELECT_TARGET_RANDOM);
+ if (!targets.empty())
{
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0, true, -SPELL_WEB_WRAP))
+ Talk(EMOTE_WEB_WRAP);
+ int8 wrapPos = -1;
+ for (Unit* target : targets)
{
+ if (wrapPos == -1) // allow all positions on the first target
+ wrapPos = urand(0, MAX_WRAP_POSITION - 1);
+ else // on subsequent iterations, only allow positions that are not equal to the previous one (this is sufficient since we should only have two targets at most, ever)
+ wrapPos = (wrapPos + urand(1, MAX_WRAP_POSITION - 1)) % MAX_WRAP_POSITION;
+
target->RemoveAura(sSpellMgr->GetSpellIdForDifficulty(SPELL_WEB_SPRAY, me));
- uint8 pos = rand32() % MAX_POS_WRAP;
- target->GetMotionMaster()->MoveJump(PosWrap[pos].GetPositionX(), PosWrap[pos].GetPositionY(), PosWrap[pos].GetPositionZ(), 20, 20);
- if (Creature* wrap = DoSummon(NPC_WEB_WRAP, PosWrap[pos], 0, TEMPSUMMON_CORPSE_DESPAWN))
- wrap->AI()->SetGUID(target->GetGUID());
+ if (Creature* wrap = DoSummon(NPC_WEB_WRAP, WrapPositions[wrapPos], 70 * IN_MILLISECONDS, TEMPSUMMON_TIMED_DESPAWN))
+ {
+ wrap->AI()->SetGUID(target->GetGUID()); // handles application of debuff
+ target->GetMotionMaster()->MoveJump(WrapPositions[wrapPos], WEB_WRAP_MOVE_SPEED, WEB_WRAP_MOVE_SPEED); // move after stun to avoid stun cancelling move
+ }
}
}
events.ScheduleEvent(EVENT_WRAP, 40000);
break;
+ }
case EVENT_SPRAY:
+ Talk(EMOTE_WEB_SPRAY);
DoCastAOE(SPELL_WEB_SPRAY);
events.ScheduleEvent(EVENT_SPRAY, 40000);
break;
case EVENT_SHOCK:
DoCastAOE(SPELL_POISON_SHOCK);
- events.ScheduleEvent(EVENT_SHOCK, urand(10000, 20000));
+ events.ScheduleEvent(EVENT_SHOCK, urandms(10, 20));
break;
case EVENT_POISON:
DoCastVictim(SPELL_NECROTIC_POISON);
- events.ScheduleEvent(EVENT_POISON, urand(10000, 20000));
- break;
- case EVENT_FRENZY:
- DoCast(me, SPELL_FRENZY, true);
- events.ScheduleEvent(EVENT_FRENZY, 600000);
+ events.ScheduleEvent(EVENT_POISON, urandms(10, 20));
break;
case EVENT_SUMMON:
- /// @todo Add missing text
+ Talk(EMOTE_SPIDERS);
uint8 amount = urand(8, 10);
for (uint8 i = 0; i < amount; ++i)
- DoSummon(NPC_SPIDERLING, me, 0, TEMPSUMMON_CORPSE_DESPAWN);
+ DoSummon(NPC_SPIDERLING, me, 4.0f, 5 * IN_MILLISECONDS, TEMPSUMMON_CORPSE_TIMED_DESPAWN);
events.ScheduleEvent(EVENT_SUMMON, 40000);
break;
}
@@ -165,23 +197,49 @@ public:
struct npc_webwrapAI : public NullCreatureAI
{
- npc_webwrapAI(Creature* creature) : NullCreatureAI(creature) { }
+ npc_webwrapAI(Creature* creature) : NullCreatureAI(creature), visibleTimer(0) { }
ObjectGuid victimGUID;
+ uint32 visibleTimer;
+
+ void InitializeAI() override
+ {
+ me->SetVisible(false);
+ }
void SetGUID(ObjectGuid guid, int32 /*param*/) override
{
+ if (!guid)
+ return;
victimGUID = guid;
- if (me->m_spells[0] && victimGUID)
- if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID))
- victim->CastSpell(victim, me->m_spells[0], true, NULL, NULL, me->GetGUID());
+ if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID))
+ {
+ visibleTimer = (me->GetDistance2d(victim)/WEB_WRAP_MOVE_SPEED + 0.5f) * IN_MILLISECONDS;
+ victim->CastSpell(victim, SPELL_WEB_WRAP, true, NULL, NULL, me->GetGUID());
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!visibleTimer)
+ return;
+
+ if (diff >= visibleTimer)
+ {
+ visibleTimer = 0;
+ me->SetVisible(true);
+ }
+ else
+ visibleTimer -= diff;
}
void JustDied(Unit* /*killer*/) override
{
- if (me->m_spells[0] && victimGUID)
+ if (victimGUID)
if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID))
- victim->RemoveAurasDueToSpell(me->m_spells[0], me->GetGUID());
+ victim->RemoveAurasDueToSpell(SPELL_WEB_WRAP, me->GetGUID());
+
+ me->DespawnOrUnsummon(5 * IN_MILLISECONDS);
}
};
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp
index 1683667a02a..f94f7b227bf 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp
@@ -17,43 +17,40 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "SpellInfo.h"
#include "naxxramas.h"
-//Razuvious - NO TEXT sound only
-//8852 aggro01 - Hah hah, I'm just getting warmed up!
-//8853 aggro02 Stand and fight!
-//8854 aggro03 Show me what you've got!
-//8861 slay1 - You should've stayed home!
-//8863 slay2-
-//8858 cmmnd3 - You disappoint me, students!
-//8855 cmmnd1 - Do as I taught you!
-//8856 cmmnd2 - Show them no mercy!
-//8859 cmmnd4 - The time for practice is over! Show me what you've learned!
-//8861 Sweep the leg! Do you have a problem with that?
-//8860 death - An honorable... death...
-//8947 - Aggro Mixed? - ?
-
-#define SOUND_AGGRO RAND(8852, 8853, 8854)
-#define SOUND_SLAY RAND(8861, 8863)
-#define SOUND_COMMND RAND(8855, 8856, 8858, 8859, 8861)
-#define SOUND_DEATH 8860
-#define SOUND_AGGROMIX 8847
+enum Yells
+{
+ SAY_AGGRO = 0,
+ SAY_SLAY = 1,
+ SAY_TAUNTED = 2,
+ SAY_DEATH = 3
+};
enum Spells
{
- SPELL_UNBALANCING_STRIKE = 26613,
- SPELL_DISRUPTING_SHOUT = 29107,
- SPELL_JAGGED_KNIFE = 55550,
- SPELL_HOPELESS = 29125
+ SPELL_UNBALANCING_STRIKE = 26613,
+ SPELL_DISRUPTING_SHOUT = 29107,
+ SPELL_JAGGED_KNIFE = 55550,
+ SPELL_HOPELESS = 29125,
+ SPELL_UNDERSTUDY_TAUNT = 29060,
+ SPELL_UNDERSTUDY_BLOOD_STRIKE = 61696,
+ SPELL_FORCE_OBEDIENCE = 55479
};
enum Events
{
- EVENT_NONE,
+ EVENT_ATTACK = 1,
EVENT_STRIKE,
EVENT_SHOUT,
- EVENT_KNIFE,
- EVENT_COMMAND,
+ EVENT_KNIFE
+};
+
+enum SummonGroups
+{
+ SUMMON_GROUP_10MAN = 1,
+ SUMMON_GROUP_25MAN = 2
};
class boss_razuvious : public CreatureScript
@@ -70,36 +67,60 @@ public:
{
boss_razuviousAI(Creature* creature) : BossAI(creature, BOSS_RAZUVIOUS) { }
- void KilledUnit(Unit* /*victim*/) override
+ void SummonAdds()
{
- if (!(rand32() % 3))
- DoPlaySoundToSet(me, SOUND_SLAY);
+ me->SummonCreatureGroup(SUMMON_GROUP_10MAN);
+ if (Is25ManRaid())
+ me->SummonCreatureGroup(SUMMON_GROUP_25MAN);
}
- void DamageTaken(Unit* pDone_by, uint32& uiDamage) override
+ void InitializeAI() override
{
- // Damage done by the controlled Death Knight understudies should also count toward damage done by players
- if (pDone_by->GetTypeId() == TYPEID_UNIT && (pDone_by->GetEntry() == 16803 || pDone_by->GetEntry() == 29941))
+ if (!me->isDead())
{
- me->LowerPlayerDamageReq(uiDamage);
+ Reset();
+ SummonAdds();
}
}
+ void JustReachedHome() override
+ {
+ _JustReachedHome();
+ SummonAdds();
+ me->GetMotionMaster()->Initialize();
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetTypeId() == TYPEID_PLAYER || (victim->GetTypeId() == TYPEID_UNIT && victim->GetEntry() == NPC_DK_UNDERSTUDY))
+ Talk(SAY_SLAY);
+ }
+
+ void SpellHit(Unit* caster, SpellInfo const* spell) override
+ {
+ if (spell->Id == SPELL_UNDERSTUDY_TAUNT)
+ Talk(SAY_TAUNTED, caster);
+ }
+
void JustDied(Unit* /*killer*/) override
{
- _JustDied();
- DoPlaySoundToSet(me, SOUND_DEATH);
- me->CastSpell(me, SPELL_HOPELESS, true); /// @todo this may affect other creatures
+ Talk(SAY_DEATH);
+ DoCastAOE(SPELL_HOPELESS, true);
+
+ events.Reset();
+ instance->SetBossState(BOSS_RAZUVIOUS, DONE);
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
- DoPlaySoundToSet(me, SOUND_AGGRO);
- events.ScheduleEvent(EVENT_STRIKE, 30000);
- events.ScheduleEvent(EVENT_SHOUT, 25000);
- events.ScheduleEvent(EVENT_COMMAND, 40000);
- events.ScheduleEvent(EVENT_KNIFE, 10000);
+ me->StopMoving();
+ summons.DoZoneInCombat();
+ Talk(SAY_AGGRO);
+ events.ScheduleEvent(EVENT_ATTACK, 7 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_STRIKE, 21 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_SHOUT, 16 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_KNIFE, 10 * IN_MILLISECONDS);
}
void UpdateAI(uint32 diff) override
@@ -113,33 +134,112 @@ public:
{
switch (eventId)
{
+ case EVENT_ATTACK:
+ SetCombatMovement(true);
+ if (Unit* victim = me->GetVictim())
+ me->GetMotionMaster()->MoveChase(victim);
+ break;
case EVENT_STRIKE:
DoCastVictim(SPELL_UNBALANCING_STRIKE);
- events.ScheduleEvent(EVENT_STRIKE, 30000);
+ events.ScheduleEvent(EVENT_STRIKE, 6 * IN_MILLISECONDS);
return;
case EVENT_SHOUT:
DoCastAOE(SPELL_DISRUPTING_SHOUT);
- events.ScheduleEvent(EVENT_SHOUT, 25000);
+ events.ScheduleEvent(EVENT_SHOUT, 16 * IN_MILLISECONDS);
return;
case EVENT_KNIFE:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f))
DoCast(target, SPELL_JAGGED_KNIFE);
- events.ScheduleEvent(EVENT_KNIFE, 10000);
- return;
- case EVENT_COMMAND:
- DoPlaySoundToSet(me, SOUND_COMMND);
- events.ScheduleEvent(EVENT_COMMAND, 40000);
+ events.ScheduleEvent(EVENT_KNIFE, urandms(10,15));
return;
}
}
DoMeleeAttackIfReady();
}
+
+ void Reset() override
+ {
+ SetCombatMovement(false);
+ _Reset();
+ }
};
};
+class npc_dk_understudy : public CreatureScript
+{
+ public:
+ npc_dk_understudy() : CreatureScript("npc_dk_understudy") { }
+
+ struct npc_dk_understudyAI : public ScriptedAI
+ {
+ npc_dk_understudyAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), bloodStrikeTimer(0) { }
+
+ void EnterCombat(Unit* /*who*/) override
+ {
+ me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
+ if (Creature* razuvious = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_RAZUVIOUS)))
+ razuvious->AI()->DoZoneInCombat(nullptr, 250.0f);
+ }
+
+ void JustReachedHome() override
+ {
+ if (_instance->GetBossState(BOSS_RAZUVIOUS) == DONE)
+ me->DespawnOrUnsummon();
+ else
+ ScriptedAI::JustReachedHome();
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!me->isPossessedByPlayer() && !UpdateVictim())
+ return;
+
+ if (!me->isPossessedByPlayer())
+ {
+ if (diff < bloodStrikeTimer)
+ bloodStrikeTimer -= diff;
+ else
+ DoCastVictim(SPELL_UNDERSTUDY_BLOOD_STRIKE);
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ void OnCharmed(bool apply) override
+ {
+ ScriptedAI::OnCharmed(apply);
+ if (apply)
+ {
+ if (!me->IsInCombat())
+ EnterCombat(nullptr);
+ me->StopMoving();
+ me->SetReactState(REACT_PASSIVE);
+ _charmer = me->GetCharmerGUID();
+ }
+ else
+ {
+ me->SetReactState(REACT_AGGRESSIVE);
+ if (Unit* charmer = ObjectAccessor::GetUnit(*me, _charmer))
+ me->AddThreat(charmer, 100000.0f);
+ DoZoneInCombat(nullptr, 250.0f);
+ }
+ }
+ private:
+ InstanceScript* const _instance;
+ ObjectGuid _charmer;
+ uint32 bloodStrikeTimer;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_dk_understudyAI>(creature);
+ }
+};
+
void AddSC_boss_razuvious()
{
new boss_razuvious();
+ new npc_dk_understudy();
}
diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
index 53ce68d3efc..0e572835a51 100644
--- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
@@ -60,7 +60,6 @@ DoorData const doorData[] =
MinionData const minionData[] =
{
- { NPC_DK_UNDERSTUDY, BOSS_RAZUVIOUS },
{ NPC_SIR, BOSS_HORSEMEN },
{ NPC_THANE, BOSS_HORSEMEN },
{ NPC_LADY, BOSS_HORSEMEN },
@@ -143,6 +142,9 @@ class instance_naxxramas : public InstanceMapScript
case NPC_FAERLINA:
FaerlinaGUID = creature->GetGUID();
break;
+ case NPC_RAZUVIOUS:
+ RazuviousGUID = creature->GetGUID();
+ break;
case NPC_THANE:
ThaneGUID = creature->GetGUID();
break;
@@ -378,6 +380,8 @@ class instance_naxxramas : public InstanceMapScript
return AnubRekhanGUID;
case DATA_FAERLINA:
return FaerlinaGUID;
+ case DATA_RAZUVIOUS:
+ return RazuviousGUID;
case DATA_THANE:
return ThaneGUID;
case DATA_LADY:
@@ -652,6 +656,8 @@ class instance_naxxramas : public InstanceMapScript
ObjectGuid HeiganGUID;
/* The Military Quarter */
+ // Instructor Razuvious
+ ObjectGuid RazuviousGUID;
// Gothik the Harvester
ObjectGuid GothikGateGUID;
// The Four Horsemen
diff --git a/src/server/scripts/Northrend/Naxxramas/naxxramas.h b/src/server/scripts/Northrend/Naxxramas/naxxramas.h
index d2b99784953..e4d15cf84ba 100644
--- a/src/server/scripts/Northrend/Naxxramas/naxxramas.h
+++ b/src/server/scripts/Northrend/Naxxramas/naxxramas.h
@@ -66,6 +66,7 @@ enum Data64
{
DATA_ANUBREKHAN,
DATA_FAERLINA,
+ DATA_RAZUVIOUS,
DATA_THANE,
DATA_LADY,
DATA_BARON,
@@ -87,6 +88,7 @@ enum CreaturesIds
{
NPC_ANUBREKHAN = 15956,
NPC_FAERLINA = 15953,
+ NPC_RAZUVIOUS = 16061,
NPC_THANE = 16064,
NPC_LADY = 16065,
NPC_BARON = 30549,
diff --git a/src/server/scripts/Pet/pet_mage.cpp b/src/server/scripts/Pet/pet_mage.cpp
index 0d6353cfb86..14d2687c298 100644
--- a/src/server/scripts/Pet/pet_mage.cpp
+++ b/src/server/scripts/Pet/pet_mage.cpp
@@ -24,11 +24,25 @@
#include "ScriptedCreature.h"
#include "CombatAI.h"
#include "Pet.h"
+#include "PetAI.h"
+#include "Cell.h"
+#include "CellImpl.h"
+#include "GridNotifiers.h"
+#include "GridNotifiersImpl.h"
enum MageSpells
{
SPELL_MAGE_CLONE_ME = 45204,
- SPELL_MAGE_MASTERS_THREAT_LIST = 58838
+ SPELL_MAGE_MASTERS_THREAT_LIST = 58838,
+ SPELL_MAGE_FROST_BOLT = 59638,
+ SPELL_MAGE_FIRE_BLAST = 59637
+};
+
+enum MirrorImageTimers
+{
+ TIMER_MIRROR_IMAGE_INIT = 0,
+ TIMER_MIRROR_IMAGE_FROST_BOLT = 4000,
+ TIMER_MIRROR_IMAGE_FIRE_BLAST = 6000
};
class npc_pet_mage_mirror_image : public CreatureScript
@@ -40,20 +54,184 @@ class npc_pet_mage_mirror_image : public CreatureScript
{
npc_pet_mage_mirror_imageAI(Creature* creature) : CasterAI(creature) { }
+ void Init()
+ {
+ Unit* owner = me->GetCharmerOrOwner();
+
+ std::list<Unit*> targets;
+ Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(me, me, 30.0f);
+ Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(me, targets, u_check);
+ me->VisitNearbyObject(40.0f, searcher);
+
+ Unit* highestThreatUnit = nullptr;
+ float highestThreat = 0.0f;
+ Unit* nearestPlayer = nullptr;
+ for (std::list<Unit*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter)
+ {
+ // Consider only units without CC
+ if (!(*iter)->HasBreakableByDamageCrowdControlAura((*iter)))
+ {
+ // Take first found unit
+ if (!highestThreatUnit && (*iter)->GetTypeId() != TYPEID_PLAYER)
+ {
+ highestThreatUnit = (*iter);
+ continue;
+ }
+ if (!nearestPlayer && ((*iter)->GetTypeId() == TYPEID_PLAYER))
+ {
+ nearestPlayer = (*iter);
+ continue;
+ }
+ // else compare best fit unit with current unit
+ ThreatContainer::StorageType triggers = (*iter)->getThreatManager().getThreatList();
+ for (ThreatContainer::StorageType::const_iterator trig_citr = triggers.begin(); trig_citr != triggers.end(); ++trig_citr)
+ {
+ // Try to find threat referenced to owner
+ if ((*trig_citr)->getTarget() == owner)
+ {
+ // Check if best fit hostile unit hs lower threat than this current unit
+ if (highestThreat < (*trig_citr)->getThreat())
+ {
+ // If so, update best fit unit
+ highestThreat = (*trig_citr)->getThreat();
+ highestThreatUnit = (*iter);
+ break;
+ }
+ }
+ }
+ // In case no unit with threat was found so far, always check for nearest unit (only for players)
+ if ((*iter)->GetTypeId() == TYPEID_PLAYER)
+ {
+ // If this player is closer than the previous one, update it
+ if (me->GetDistance((*iter)->GetPosition()) < me->GetDistance(nearestPlayer->GetPosition()))
+ nearestPlayer = (*iter);
+ }
+ }
+ }
+ // Prioritize units with threat referenced to owner
+ if (highestThreat > 0.0f && highestThreatUnit)
+ me->Attack(highestThreatUnit, false);
+ // If there is no such target, try to attack nearest hostile unit if such exists
+ else if (nearestPlayer)
+ me->Attack(nearestPlayer, false);
+ }
+
+ bool IsInThreatList(Unit* target)
+ {
+ Unit* owner = me->GetCharmerOrOwner();
+
+ std::list<Unit*> targets;
+ Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(me, me, 30.0f);
+ Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(me, targets, u_check);
+ me->VisitNearbyObject(40.0f, searcher);
+
+ for (std::list<Unit*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter)
+ {
+ if ((*iter) == target)
+ {
+ // Consider only units without CC
+ if (!(*iter)->HasBreakableByDamageCrowdControlAura((*iter)))
+ {
+ ThreatContainer::StorageType triggers = (*iter)->getThreatManager().getThreatList();
+ for (ThreatContainer::StorageType::const_iterator trig_citr = triggers.begin(); trig_citr != triggers.end(); ++trig_citr)
+ {
+ // Try to find threat referenced to owner
+ if ((*trig_citr)->getTarget() == owner)
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
void InitializeAI() override
{
CasterAI::InitializeAI();
Unit* owner = me->GetOwner();
if (!owner)
return;
- // Inherit Master's Threat List (not yet implemented)
- owner->CastSpell((Unit*)NULL, SPELL_MAGE_MASTERS_THREAT_LIST, true);
+
// here mirror image casts on summoner spell (not present in client dbc) 49866
// here should be auras (not present in client dbc): 35657, 35658, 35659, 35660 selfcast by mirror images (stats related?)
// Clone Me!
owner->CastSpell(me, SPELL_MAGE_CLONE_ME, false);
}
+ void EnterCombat(Unit* who) override
+ {
+ if (me->GetVictim() && !me->GetVictim()->HasBreakableByDamageCrowdControlAura(me))
+ {
+ me->CastSpell(who, SPELL_MAGE_FIRE_BLAST, false);
+ events.ScheduleEvent(SPELL_MAGE_FROST_BOLT, TIMER_MIRROR_IMAGE_INIT);
+ events.ScheduleEvent(SPELL_MAGE_FIRE_BLAST, TIMER_MIRROR_IMAGE_FIRE_BLAST);
+ }
+ else
+ EnterEvadeMode();
+ }
+
+ void Reset() override
+ {
+ events.Reset();
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ Unit* owner = me->GetCharmerOrOwner();
+ Unit* target = owner->getAttackerForHelper();
+
+ events.Update(diff);
+
+ // prevent CC interrupts by images
+ if (me->GetVictim() && me->EnsureVictim()->HasBreakableByDamageCrowdControlAura(me))
+ {
+ me->InterruptNonMeleeSpells(false);
+ return;
+ }
+
+ 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)
+ {
+ Unit* ownerTarget = nullptr;
+ if (Player* owner = me->GetCharmerOrOwner()->ToPlayer())
+ ownerTarget = owner->GetSelectedUnit();
+
+ // recognize which victim will be choosen
+ if (ownerTarget && ownerTarget->GetTypeId() == TYPEID_PLAYER)
+ {
+ if (!ownerTarget->HasBreakableByDamageCrowdControlAura(ownerTarget))
+ me->Attack(ownerTarget, false);
+ }
+ else if (ownerTarget && (ownerTarget->GetTypeId() != TYPEID_PLAYER) && IsInThreatList(ownerTarget))
+ {
+ if (!ownerTarget->HasBreakableByDamageCrowdControlAura(ownerTarget))
+ me->Attack(ownerTarget, false);
+ }
+ else
+ Init();
+ }
+
+ if (uint32 spellId = events.ExecuteEvent())
+ {
+ if (spellId == SPELL_MAGE_FROST_BOLT)
+ {
+ events.ScheduleEvent(SPELL_MAGE_FROST_BOLT, TIMER_MIRROR_IMAGE_FROST_BOLT);
+ DoCastVictim(spellId);
+ }
+ else if (spellId == SPELL_MAGE_FIRE_BLAST)
+ {
+ DoCastVictim(spellId);
+ events.ScheduleEvent(SPELL_MAGE_FIRE_BLAST, TIMER_MIRROR_IMAGE_FIRE_BLAST);
+ }
+ }
+ }
+
// Do not reload Creature templates on evade mode enter - prevent visual lost
void EnterEvadeMode() override
{
@@ -68,6 +246,7 @@ class npc_pet_mage_mirror_image : public CreatureScript
me->GetMotionMaster()->Clear(false);
me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), MOTION_SLOT_ACTIVE);
}
+ Init();
}
};