aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp5
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.h1
-rw-r--r--src/server/game/Entities/Item/Item.cpp16
-rw-r--r--src/server/game/Entities/Item/Item.h2
-rw-r--r--src/server/game/Entities/Player/Player.cpp25
-rw-r--r--src/server/game/Entities/Player/Player.h2
-rw-r--r--src/server/game/Tickets/TicketMgr.cpp14
-rw-r--r--src/server/game/Tickets/TicketMgr.h16
-rw-r--r--src/server/game/World/World.cpp1
-rw-r--r--src/server/game/World/World.h1
-rw-r--r--src/server/scripts/Commands/cs_ticket.cpp4
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp209
-rw-r--r--src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp16
-rw-r--r--src/server/scripts/Northrend/Naxxramas/naxxramas.h3
-rw-r--r--src/server/scripts/Northrend/zone_sholazar_basin.cpp68
-rw-r--r--src/server/worldserver/worldserver.conf.dist10
16 files changed, 268 insertions, 125 deletions
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp
index 3e0d684a1fd..45bfee5d596 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -335,10 +335,11 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_GO_RESPAWN_BY_INSTANCE, "DELETE FROM gameobject_respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_ASYNC);
// GM Tickets
- PrepareStatement(CHAR_SEL_GM_TICKETS, "SELECT id, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp FROM gm_ticket", CONNECTION_SYNCH);
- PrepareStatement(CHAR_REP_GM_TICKET, "REPLACE INTO gm_ticket (id, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp, resolvedBy) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_GM_TICKETS, "SELECT id, type, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp FROM gm_ticket", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_REP_GM_TICKET, "REPLACE INTO gm_ticket (id, type, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp, resolvedBy) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_GM_TICKET, "DELETE FROM gm_ticket WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_PLAYER_GM_TICKETS, "DELETE FROM gm_ticket WHERE playerGuid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_UPD_PLAYER_GM_TICKETS_ON_CHAR_DELETION, "UPDATE gm_ticket SET type = 2 WHERE playerGuid = ?", CONNECTION_ASYNC);
// GM Survey/subsurvey/lag report
PrepareStatement(CHAR_INS_GM_SURVEY, "INSERT INTO gm_survey (guid, surveyId, mainSurvey, comment, createTime) VALUES (?, ?, ?, ?, UNIX_TIMESTAMP(NOW()))", CONNECTION_ASYNC);
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h
index 3382430d695..7a463c73df2 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.h
+++ b/src/server/database/Database/Implementation/CharacterDatabase.h
@@ -286,6 +286,7 @@ enum CharacterDatabaseStatements
CHAR_DEL_GM_TICKET,
CHAR_DEL_ALL_GM_TICKETS,
CHAR_DEL_PLAYER_GM_TICKETS,
+ CHAR_UPD_PLAYER_GM_TICKETS_ON_CHAR_DELETION,
CHAR_INS_GM_SURVEY,
CHAR_INS_GM_SUBSURVEY,
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp
index 9a6af376e6d..19cf9beff21 100644
--- a/src/server/game/Entities/Item/Item.cpp
+++ b/src/server/game/Entities/Item/Item.cpp
@@ -1435,3 +1435,19 @@ void Item::ItemContainerDeleteLootMoneyAndLootItemsFromDB()
ItemContainerDeleteLootMoneyFromDB();
ItemContainerDeleteLootItemsFromDB();
}
+
+void Item::SetCount(uint32 value)
+{
+ SetUInt32Value(ITEM_FIELD_STACK_COUNT, value);
+
+ if (Player* player = GetOwner())
+ {
+ if (TradeData* tradeData = player->GetTradeData())
+ {
+ TradeSlots slot = tradeData->GetTradeSlotForItem(GetGUID());
+
+ if (slot != TRADE_SLOT_INVALID)
+ tradeData->SetItem(slot, this, true);
+ }
+ }
+}
diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h
index a268334b212..1eb6530a996 100644
--- a/src/server/game/Entities/Item/Item.h
+++ b/src/server/game/Entities/Item/Item.h
@@ -262,7 +262,7 @@ class Item : public Object
bool GemsFitSockets() const;
uint32 GetCount() const { return GetUInt32Value(ITEM_FIELD_STACK_COUNT); }
- void SetCount(uint32 value) { SetUInt32Value(ITEM_FIELD_STACK_COUNT, value); }
+ void SetCount(uint32 value);
uint32 GetMaxStackCount() const { return GetTemplate()->GetMaxStackSize(); }
uint8 GetGemCountWithID(uint32 GemID) const;
uint8 GetGemCountWithLimitCategory(uint32 limitCategory) const;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 2f78280a409..97c4a78fc92 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -69,6 +69,7 @@
#include "SpellMgr.h"
#include "SpellHistory.h"
#include "Transport.h"
+#include "TicketMgr.h"
#include "UpdateData.h"
#include "UpdateFieldFlags.h"
#include "UpdateMask.h"
@@ -323,13 +324,13 @@ Item* TradeData::GetSpellCastItem() const
return m_spellCastItem ? m_player->GetItemByGuid(m_spellCastItem) : NULL;
}
-void TradeData::SetItem(TradeSlots slot, Item* item)
+void TradeData::SetItem(TradeSlots slot, Item* item, bool update /*= false*/)
{
ObjectGuid itemGuid;
if (item)
itemGuid = item->GetGUID();
- if (m_items[slot] == itemGuid)
+ if (m_items[slot] == itemGuid && !update)
return;
m_items[slot] = itemGuid;
@@ -4546,6 +4547,11 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
if (Guild* guild = sGuildMgr->GetGuildById(guildId))
guild->DeleteMember(playerguid, false, false, true);
+ // close player ticket if any
+ GmTicket* ticket = sTicketMgr->GetTicketByPlayer(playerguid);
+ if (ticket)
+ ticket->SetClosedBy(playerguid);
+
// remove from arena teams
LeaveAllArenaTeams(playerguid);
@@ -4757,9 +4763,18 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
stmt->setUInt32(0, guid);
trans->Append(stmt);
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_GM_TICKETS);
- stmt->setUInt32(0, guid);
- trans->Append(stmt);
+ if (sWorld->getBoolConfig(CONFIG_DELETE_CHARACTER_TICKET_TRACE))
+ {
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PLAYER_GM_TICKETS_ON_CHAR_DELETION);
+ stmt->setUInt32(0, guid);
+ trans->Append(stmt);
+ }
+ else
+ {
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_GM_TICKETS);
+ stmt->setUInt32(0, guid);
+ trans->Append(stmt);
+ }
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_BY_OWNER);
stmt->setUInt32(0, guid);
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 75f04cb0d7b..7c0700fa244 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1020,7 +1020,7 @@ class TradeData
Item* GetItem(TradeSlots slot) const;
bool HasItem(ObjectGuid itemGuid) const;
TradeSlots GetTradeSlotForItem(ObjectGuid itemGuid) const;
- void SetItem(TradeSlots slot, Item* item);
+ void SetItem(TradeSlots slot, Item* item, bool update = false);
uint32 GetSpell() const { return m_spell; }
void SetSpell(uint32 spell_id, Item* castItem = NULL);
diff --git a/src/server/game/Tickets/TicketMgr.cpp b/src/server/game/Tickets/TicketMgr.cpp
index dbf66c6bd71..b4b3b8267c6 100644
--- a/src/server/game/Tickets/TicketMgr.cpp
+++ b/src/server/game/Tickets/TicketMgr.cpp
@@ -32,11 +32,11 @@ inline float GetAge(uint64 t) { return float(time(NULL) - t) / DAY; }
///////////////////////////////////////////////////////////////////////////////////////////////////
// GM ticket
-GmTicket::GmTicket() : _id(0), _posX(0), _posY(0), _posZ(0), _mapId(0), _createTime(0), _lastModifiedTime(0),
+GmTicket::GmTicket() : _id(0), _type(TICKET_TYPE_OPEN), _posX(0), _posY(0), _posZ(0), _mapId(0), _createTime(0), _lastModifiedTime(0),
_completed(false), _escalatedStatus(TICKET_UNASSIGNED), _viewed(false),
_needResponse(false), _needMoreHelp(false) { }
-GmTicket::GmTicket(Player* player) : _posX(0), _posY(0), _posZ(0), _mapId(0), _createTime(time(NULL)), _lastModifiedTime(time(NULL)),
+GmTicket::GmTicket(Player* player) : _type(TICKET_TYPE_OPEN), _posX(0), _posY(0), _posZ(0), _mapId(0), _createTime(time(NULL)), _lastModifiedTime(time(NULL)),
_completed(false), _escalatedStatus(TICKET_UNASSIGNED), _viewed(false),
_needResponse(false), _needMoreHelp(false)
{
@@ -49,10 +49,11 @@ GmTicket::~GmTicket() { }
bool GmTicket::LoadFromDB(Field* fields)
{
- // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
- // ticketId, guid, name, message, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, haveTicket
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
+ // id, type, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp
uint8 index = 0;
_id = fields[ index].GetUInt32();
+ _type = TicketType(fields[++index].GetUInt8());
_playerGuid = ObjectGuid(HighGuid::Player, fields[++index].GetUInt32());
_playerName = fields[++index].GetString();
_message = fields[++index].GetString();
@@ -75,11 +76,12 @@ bool GmTicket::LoadFromDB(Field* fields)
void GmTicket::SaveToDB(SQLTransaction& trans) const
{
- // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
- // id, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp, resolvedBy
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+ // id, type, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp, resolvedBy
uint8 index = 0;
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_TICKET);
stmt->setUInt32( index, _id);
+ stmt->setUInt8 (++index, uint8(_type));
stmt->setUInt32(++index, _playerGuid.GetCounter());
stmt->setString(++index, _playerName);
stmt->setString(++index, _message);
diff --git a/src/server/game/Tickets/TicketMgr.h b/src/server/game/Tickets/TicketMgr.h
index f7d3178978f..a90a1ec0206 100644
--- a/src/server/game/Tickets/TicketMgr.h
+++ b/src/server/game/Tickets/TicketMgr.h
@@ -77,6 +77,13 @@ enum LagReportType
LAG_REPORT_TYPE_SPELL = 6
};
+enum TicketType
+{
+ TICKET_TYPE_OPEN = 0,
+ TICKET_TYPE_CLOSED = 1,
+ TICKET_TYPE_CHARACTER_DELETED = 2,
+};
+
class GmTicket
{
public:
@@ -84,7 +91,7 @@ public:
GmTicket(Player* player);
~GmTicket();
- bool IsClosed() const { return !_closedBy.IsEmpty(); }
+ bool IsClosed() const { return _type != TICKET_TYPE_OPEN; }
bool IsCompleted() const { return _completed; }
bool IsFromPlayer(ObjectGuid guid) const { return guid == _playerGuid; }
bool IsAssigned() const { return !_assignedTo.IsEmpty(); }
@@ -118,7 +125,7 @@ public:
else if (_escalatedStatus == TICKET_UNASSIGNED)
_escalatedStatus = TICKET_ASSIGNED;
}
- void SetClosedBy(ObjectGuid value) { _closedBy = value; }
+ void SetClosedBy(ObjectGuid value) { _closedBy = value; _type = TICKET_TYPE_CLOSED; }
void SetResolvedBy(ObjectGuid value) { _resolvedBy = value; }
void SetCompleted() { _completed = true; }
void SetMessage(std::string const& message)
@@ -150,6 +157,7 @@ public:
private:
uint32 _id;
+ TicketType _type; // 0 = Open, 1 = Closed, 2 = Character deleted
ObjectGuid _playerGuid;
std::string _playerName;
float _posX;
@@ -159,8 +167,8 @@ private:
std::string _message;
uint64 _createTime;
uint64 _lastModifiedTime;
- ObjectGuid _closedBy; // 0 = Open, -1 = Console, playerGuid = player abandoned ticket or read the GM response message, other = GM who closed it.
- ObjectGuid _resolvedBy; // 0 = Open, -1 = Resolved by Console, GM who resolved it by closing or completing the ticket.
+ ObjectGuid _closedBy; // 0 = Open or Closed by Console (if type = 1), playerGuid = GM who closed it or player abandoned ticket or read the GM response message.
+ ObjectGuid _resolvedBy; // 0 = Open or Resolved by Console (if type = 1), playerGuid = GM who resolved it by closing or completing the ticket.
ObjectGuid _assignedTo;
std::string _comment;
bool _completed;
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index a0dd889876c..bb4de29ad56 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -395,6 +395,7 @@ void World::LoadConfigSettings(bool reload)
///- Read ticket system setting from the config file
m_bool_configs[CONFIG_ALLOW_TICKETS] = sConfigMgr->GetBoolDefault("AllowTickets", true);
+ m_bool_configs[CONFIG_DELETE_CHARACTER_TICKET_TRACE] = sConfigMgr->GetBoolDefault("DeletedCharacterTicketTrace", false);
///- Get string for new logins (newly created characters)
SetNewCharString(sConfigMgr->GetStringDefault("PlayerStart.String", ""));
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index b8ffc946615..e3dc3b55681 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -144,6 +144,7 @@ enum WorldBoolConfigs
CONFIG_SHOW_BAN_IN_WORLD,
CONFIG_AUTOBROADCAST,
CONFIG_ALLOW_TICKETS,
+ CONFIG_DELETE_CHARACTER_TICKET_TRACE,
CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES,
CONFIG_PRESERVE_CUSTOM_CHANNELS,
CONFIG_PDUMP_NO_PATHS,
diff --git a/src/server/scripts/Commands/cs_ticket.cpp b/src/server/scripts/Commands/cs_ticket.cpp
index 9b771f734be..a9baa45f344 100644
--- a/src/server/scripts/Commands/cs_ticket.cpp
+++ b/src/server/scripts/Commands/cs_ticket.cpp
@@ -150,7 +150,7 @@ public:
return true;
}
- sTicketMgr->ResolveAndCloseTicket(ticket->GetId(), player ? player->GetGUID() : ObjectGuid(uint64(-1)));
+ sTicketMgr->ResolveAndCloseTicket(ticket->GetId(), player ? player->GetGUID() : ObjectGuid(uint64(0)));
sTicketMgr->UpdateLastChange();
std::string msg = ticket->FormatMessageString(*handler, player ? player->GetName().c_str() : "Console", NULL, NULL, NULL, NULL);
@@ -248,7 +248,7 @@ public:
Player* gm = handler->GetSession() ? handler->GetSession()->GetPlayer() : nullptr;
SQLTransaction trans = SQLTransaction(NULL);
- ticket->SetResolvedBy(gm ? gm->GetGUID() : ObjectGuid(uint64(-1)));
+ ticket->SetResolvedBy(gm ? gm->GetGUID() : ObjectGuid(uint64(0)));
ticket->SetCompleted();
ticket->SaveToDB(trans);
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp
index 733647fdb66..471a7adc9d6 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp
@@ -17,39 +17,61 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "Player.h"
#include "naxxramas.h"
-enum Says
+enum AnubSays
{
SAY_AGGRO = 0,
SAY_GREET = 1,
- SAY_SLAY = 2
+ SAY_SLAY = 2,
+
+ EMOTE_LOCUST = 3
};
-Position const GuardSummonPos = {3333.72f, -3476.30f, 287.1f, 6.2801f};
+enum GuardSays
+{
+ EMOTE_FRENZY = 0,
+ EMOTE_SPAWN = 1,
+ EMOTE_SCARAB = 2
+};
enum Events
{
- EVENT_IMPALE = 1,
- EVENT_LOCUST,
- EVENT_SPAWN_GUARDIAN_NORMAL,
- EVENT_BERSERK
+ EVENT_IMPALE = 1, // Cast Impale on a random target
+ EVENT_LOCUST, // Begin channeling Locust Swarm
+ EVENT_LOCUST_ENDS, // Locust swarm dissipates
+ EVENT_SPAWN_GUARD, // 10-man only - crypt guard has delayed spawn; also used for the locust swarm crypt guard in both modes
+ EVENT_SCARABS, // spawn corpse scarabs
+ EVENT_BERSERK // Berserk
};
enum Spells
{
- SPELL_IMPALE = 28783,
- SPELL_LOCUST_SWARM = 28785,
+ SPELL_IMPALE = 28783, // 25-man: 56090
+ SPELL_LOCUST_SWARM = 28785, // 25-man: 54021
SPELL_SUMMON_CORPSE_SCARABS_PLR = 29105, // This spawns 5 corpse scarabs on top of player
SPELL_SUMMON_CORPSE_SCARABS_MOB = 28864, // This spawns 10 corpse scarabs on top of dead guards
SPELL_BERSERK = 27680
};
+enum SpawnGroups
+{
+ GROUP_INITIAL_25M = 1,
+ GROUP_SINGLE_SPAWN = 2
+};
+
enum Misc
{
ACHIEV_TIMED_START_EVENT = 9891
};
+enum Phases
+{
+ PHASE_NORMAL = 1,
+ PHASE_SWARM
+};
+
class boss_anubrekhan : public CreatureScript
{
public:
@@ -62,46 +84,64 @@ public:
struct boss_anubrekhanAI : public BossAI
{
- boss_anubrekhanAI(Creature* creature) : BossAI(creature, BOSS_ANUBREKHAN)
+ boss_anubrekhanAI(Creature* creature) : BossAI(creature, BOSS_ANUBREKHAN) { }
+
+ void SummonGuards()
{
- Initialize();
+ if (Is25ManRaid())
+ me->SummonCreatureGroup(GROUP_INITIAL_25M);
}
- void Initialize()
+ void InitializeAI() override
{
- hasTaunted = false;
+ if (!me->isDead())
+ {
+ Reset();
+ SummonGuards();
+ }
}
- bool hasTaunted;
-
void Reset() override
{
_Reset();
+ guardCorpses.clear();
+ }
- Initialize();
+ void JustReachedHome() override
+ {
+ _JustReachedHome();
+ SummonGuards();
+ }
- if (GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL)
- {
- Position pos;
+ void JustSummoned(Creature* summon) override
+ {
+ BossAI::JustSummoned(summon);
+
+ if (me->IsInCombat())
+ if (summon->GetEntry() == NPC_CRYPT_GUARD)
+ summon->AI()->Talk(EMOTE_SPAWN, me);
+ }
- // respawn guard using home position,
- // otherwise, after a wipe, they respawn where boss was at wipe moment.
- pos = me->GetHomePosition();
- pos.m_positionY -= 10.0f;
- me->SummonCreature(NPC_CRYPT_GUARD, pos, TEMPSUMMON_CORPSE_DESPAWN);
+ void SummonedCreatureDies(Creature* summon, Unit* killer) override
+ {
+ BossAI::SummonedCreatureDies(summon, killer);
- pos = me->GetHomePosition();
- pos.m_positionY += 10.0f;
- me->SummonCreature(NPC_CRYPT_GUARD, pos, TEMPSUMMON_CORPSE_DESPAWN);
- }
+ if (summon->GetEntry() == NPC_CRYPT_GUARD)
+ guardCorpses.insert(summon->GetGUID());
+ }
+
+ void SummonedCreatureDespawn(Creature* summon) override
+ {
+ BossAI::SummonedCreatureDespawn(summon);
+
+ if (summon->GetEntry() == NPC_CRYPT_GUARD)
+ guardCorpses.erase(summon->GetGUID());
}
void KilledUnit(Unit* victim) override
{
- /// Force the player to spawn corpse scarabs via spell, @todo Check percent chance for scarabs, 20% at the moment
- if (!(rand32() % 5))
- if (victim->GetTypeId() == TYPEID_PLAYER)
- victim->CastSpell(victim, SPELL_SUMMON_CORPSE_SCARABS_PLR, true, NULL, NULL, me->GetGUID());
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ victim->CastSpell(victim, SPELL_SUMMON_CORPSE_SCARABS_PLR, true, nullptr, nullptr, me->GetGUID());
Talk(SAY_SLAY);
}
@@ -113,37 +153,22 @@ public:
// start achievement timer (kill Maexna within 20 min)
instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
}
+
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
Talk(SAY_AGGRO);
- events.ScheduleEvent(EVENT_IMPALE, urand(10000, 20000));
- events.ScheduleEvent(EVENT_LOCUST, 90000);
- events.ScheduleEvent(EVENT_BERSERK, 600000);
-
- if (GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL)
- events.ScheduleEvent(EVENT_SPAWN_GUARDIAN_NORMAL, urand(15000, 20000));
- }
- void MoveInLineOfSight(Unit* who) override
- {
- if (!hasTaunted && me->IsWithinDistInMap(who, 60.0f) && who->GetTypeId() == TYPEID_PLAYER)
- {
- Talk(SAY_GREET);
- hasTaunted = true;
- }
- ScriptedAI::MoveInLineOfSight(who);
- }
-
- void SummonedCreatureDespawn(Creature* summon) override
- {
- BossAI::SummonedCreatureDespawn(summon);
-
- // check if it is an actual killed guard
- if (!me->IsAlive() || summon->IsAlive() || summon->GetEntry() != NPC_CRYPT_GUARD)
- return;
+ summons.DoZoneInCombat();
+
+ events.SetPhase(PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_IMPALE, urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS), 0, PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_SCARABS, urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS), 0, PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_LOCUST, urand(80,120) * IN_MILLISECONDS, 0, PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS);
- summon->CastSpell(summon, SPELL_SUMMON_CORPSE_SCARABS_MOB, true, NULL, NULL, me->GetGUID());
+ if (!Is25ManRaid())
+ events.ScheduleEvent(EVENT_SPAWN_GUARD, urand(15, 20) * IN_MILLISECONDS);
}
void UpdateAI(uint32 diff) override
@@ -158,22 +183,44 @@ public:
switch (eventId)
{
case EVENT_IMPALE:
- //Cast Impale on a random target
- //Do NOT cast it when we are afflicted by locust swarm
- if (!me->HasAura(sSpellMgr->GetSpellIdForDifficulty(SPELL_LOCUST_SWARM, me)))
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
- DoCast(target, SPELL_IMPALE);
- events.ScheduleEvent(EVENT_IMPALE, urand(10000, 20000));
+ if (events.GetTimeUntilEvent(EVENT_LOCUST) < 5 * IN_MILLISECONDS) break; // don't chain impale tank -> locust swarm
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
+ DoCast(target, SPELL_IMPALE);
+ else
+ EnterEvadeMode();
+
+ events.ScheduleEvent(EVENT_IMPALE, urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS), 0, PHASE_NORMAL);
+ break;
+ case EVENT_SCARABS:
+ events.ScheduleEvent(EVENT_SCARABS, urand(40 * IN_MILLISECONDS, 60 * IN_MILLISECONDS), 0, PHASE_NORMAL);
+
+ if (!guardCorpses.empty())
+ {
+ if (ObjectGuid target = Trinity::Containers::SelectRandomContainerElement(guardCorpses))
+ if(Creature* creatureTarget = ObjectAccessor::GetCreature(*me, target))
+ {
+ creatureTarget->CastSpell(creatureTarget, SPELL_SUMMON_CORPSE_SCARABS_MOB, true, nullptr, nullptr, me->GetGUID());
+ creatureTarget->AI()->Talk(EMOTE_SCARAB);
+ creatureTarget->DespawnOrUnsummon();
+ }
+ }
break;
case EVENT_LOCUST:
- /// @todo Add Text
+ Talk(EMOTE_LOCUST);
DoCast(me, SPELL_LOCUST_SWARM);
- DoSummon(NPC_CRYPT_GUARD, GuardSummonPos, 0, TEMPSUMMON_CORPSE_DESPAWN);
+ events.ScheduleEvent(EVENT_SPAWN_GUARD, 3 * IN_MILLISECONDS);
+
+ events.ScheduleEvent(EVENT_LOCUST_ENDS, RAID_MODE(19, 23) * IN_MILLISECONDS);
events.ScheduleEvent(EVENT_LOCUST, 90000);
+ events.SetPhase(PHASE_SWARM);
+ break;
+ case EVENT_LOCUST_ENDS:
+ events.ScheduleEvent(EVENT_IMPALE, urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS), 0, PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_SCARABS, urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS), 0, PHASE_NORMAL);
+ events.SetPhase(PHASE_NORMAL);
break;
- case EVENT_SPAWN_GUARDIAN_NORMAL:
- /// @todo Add Text
- DoSummon(NPC_CRYPT_GUARD, GuardSummonPos, 0, TEMPSUMMON_CORPSE_DESPAWN);
+ case EVENT_SPAWN_GUARD:
+ me->SummonCreatureGroup(GROUP_SINGLE_SPAWN);
break;
case EVENT_BERSERK:
DoCast(me, SPELL_BERSERK, true);
@@ -182,13 +229,37 @@ public:
}
}
- DoMeleeAttackIfReady();
+ if (events.IsInPhase(PHASE_NORMAL))
+ DoMeleeAttackIfReady();
}
+ private:
+ GuidSet guardCorpses;
};
};
+class at_anubrekhan_entrance : public AreaTriggerScript
+{
+ public:
+ at_anubrekhan_entrance() : AreaTriggerScript("at_anubrekhan_entrance") { }
+
+ bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
+ {
+ InstanceScript* instance = player->GetInstanceScript();
+ if (!instance || instance->GetData(DATA_HAD_ANUBREKHAN_GREET) || instance->GetBossState(BOSS_ANUBREKHAN) != NOT_STARTED)
+ return true;
+
+ if (Creature* anub = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_ANUBREKHAN)))
+ anub->AI()->Talk(SAY_GREET);
+ instance->SetData(DATA_HAD_ANUBREKHAN_GREET, 1u);
+
+ return true;
+ }
+};
+
void AddSC_boss_anubrekhan()
{
new boss_anubrekhan();
+
+ new at_anubrekhan_entrance();
}
diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
index 37aaa639bb1..9b10fab2d62 100644
--- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
@@ -125,6 +125,7 @@ class instance_naxxramas : public InstanceMapScript
minHorsemenDiedTime = 0;
maxHorsemenDiedTime = 0;
AbominationCount = 0;
+ hadAnubRekhanGreet = false;
hadFaerlinaGreet = false;
CurrentWingTaunt = SAY_KELTHUZAD_FIRST_WING_TAUNT;
@@ -135,6 +136,9 @@ class instance_naxxramas : public InstanceMapScript
{
switch (creature->GetEntry())
{
+ case NPC_ANUBREKHAN:
+ AnubRekhanGUID = creature->GetGUID();
+ break;
case NPC_FAERLINA:
FaerlinaGUID = creature->GetGUID();
break;
@@ -319,9 +323,14 @@ class instance_naxxramas : public InstanceMapScript
case DATA_ABOMINATION_KILLED:
AbominationCount = value;
break;
+ case DATA_HAD_ANUBREKHAN_GREET:
+ hadAnubRekhanGreet = (value == 1u);
+ break;
case DATA_HAD_FAERLINA_GREET:
hadFaerlinaGreet = (value == 1u);
break;
+ default:
+ break;
}
}
@@ -331,6 +340,8 @@ class instance_naxxramas : public InstanceMapScript
{
case DATA_ABOMINATION_KILLED:
return AbominationCount;
+ case DATA_HAD_ANUBREKHAN_GREET:
+ return (uint32)hadAnubRekhanGreet;
case DATA_HAD_FAERLINA_GREET:
return (uint32)hadFaerlinaGreet;
default:
@@ -344,6 +355,8 @@ class instance_naxxramas : public InstanceMapScript
{
switch (id)
{
+ case DATA_ANUBREKHAN:
+ return AnubRekhanGUID;
case DATA_FAERLINA:
return FaerlinaGUID;
case DATA_THANE:
@@ -604,6 +617,8 @@ class instance_naxxramas : public InstanceMapScript
protected:
/* The Arachnid Quarter */
+ // Anub'rekhan
+ ObjectGuid AnubRekhanGUID;
// Grand Widow Faerlina
ObjectGuid FaerlinaGUID;
@@ -640,6 +655,7 @@ class instance_naxxramas : public InstanceMapScript
ObjectGuid KelthuzadDoorGUID;
ObjectGuid LichKingGUID;
uint8 AbominationCount;
+ bool hadAnubRekhanGreet;
bool hadFaerlinaGreet;
uint8 CurrentWingTaunt;
diff --git a/src/server/scripts/Northrend/Naxxramas/naxxramas.h b/src/server/scripts/Northrend/Naxxramas/naxxramas.h
index 6795e2cc337..6289b707411 100644
--- a/src/server/scripts/Northrend/Naxxramas/naxxramas.h
+++ b/src/server/scripts/Northrend/Naxxramas/naxxramas.h
@@ -46,6 +46,7 @@ enum Data
DATA_HEIGAN_ERUPT,
DATA_GOTHIK_GATE,
DATA_SAPPHIRON_BIRTH,
+ DATA_HAD_ANUBREKHAN_GREET,
DATA_HAD_FAERLINA_GREET,
@@ -63,6 +64,7 @@ enum Data
enum Data64
{
+ DATA_ANUBREKHAN,
DATA_FAERLINA,
DATA_THANE,
DATA_LADY,
@@ -83,6 +85,7 @@ enum Data64
enum CreaturesIds
{
+ NPC_ANUBREKHAN = 15956,
NPC_FAERLINA = 15953,
NPC_THANE = 16064,
NPC_LADY = 16065,
diff --git a/src/server/scripts/Northrend/zone_sholazar_basin.cpp b/src/server/scripts/Northrend/zone_sholazar_basin.cpp
index d5d2eebda38..6e4a8df6f25 100644
--- a/src/server/scripts/Northrend/zone_sholazar_basin.cpp
+++ b/src/server/scripts/Northrend/zone_sholazar_basin.cpp
@@ -622,17 +622,17 @@ public:
enum MiscLifewarden
{
- NPC_PRESENCE = 28563, // Freya's Presence
- NPC_SABOTEUR = 28538, // Cultist Saboteur
- NPC_SERVANT = 28320, // Servant of Freya
+ NPC_PRESENCE = 28563, // Freya's Presence
+ NPC_SABOTEUR = 28538, // Cultist Saboteur
+ NPC_SERVANT = 28320, // Servant of Freya
- WHISPER_ACTIVATE = 0,
+ WHISPER_ACTIVATE = 0,
- SPELL_FREYA_DUMMY = 51318,
- SPELL_LIFEFORCE = 51395,
- SPELL_FREYA_DUMMY_TRIGGER = 51335,
- SPELL_LASHER_EMERGE = 48195,
- SPELL_WILD_GROWTH = 52948,
+ SPELL_FREYA_DUMMY = 51318,
+ SPELL_LIFEFORCE = 51395,
+ SPELL_FREYA_DUMMY_TRIGGER = 51335,
+ SPELL_LASHER_EMERGE = 48195,
+ SPELL_WILD_GROWTH = 52948,
};
class spell_q12620_the_lifewarden_wrath : public SpellScriptLoader
@@ -702,25 +702,25 @@ public:
enum KickWhatKick
{
- NPC_LUCKY_WILHELM = 28054,
- NPC_APPLE = 28053,
- NPC_DROSTAN = 28328,
- NPC_CRUNCHY = 28346,
- NPC_THICKBIRD = 28093,
-
- SPELL_HIT_APPLE = 51331,
- SPELL_MISS_APPLE = 51332,
- SPELL_MISS_BIRD_APPLE = 51366,
- SPELL_APPLE_FALL = 51371,
- SPELL_BIRD_FALL = 51369,
-
- EVENT_MISS = 0,
- EVENT_HIT = 1,
- EVENT_MISS_BIRD = 2,
-
- SAY_WILHELM_MISS = 0,
- SAY_WILHELM_HIT = 1,
- SAY_DROSTAN_REPLY_MISS = 0,
+ NPC_LUCKY_WILHELM = 28054,
+ NPC_APPLE = 28053,
+ NPC_DROSTAN = 28328,
+ NPC_CRUNCHY = 28346,
+ NPC_THICKBIRD = 28093,
+
+ SPELL_HIT_APPLE = 51331,
+ SPELL_MISS_APPLE = 51332,
+ SPELL_MISS_BIRD_APPLE = 51366,
+ SPELL_APPLE_FALL = 51371,
+ SPELL_BIRD_FALL = 51369,
+
+ EVENT_MISS = 0,
+ EVENT_HIT = 1,
+ EVENT_MISS_BIRD = 2,
+
+ SAY_WILHELM_MISS = 0,
+ SAY_WILHELM_HIT = 1,
+ SAY_DROSTAN_REPLY_MISS = 0,
};
class spell_q12589_shoot_rjr : public SpellScriptLoader
@@ -800,8 +800,6 @@ public:
wilhelm->AI()->Talk(SAY_WILHELM_HIT);
if (Player* player = shooter->ToPlayer())
player->KilledMonsterCredit(NPC_APPLE);
- apple->DespawnOrUnsummon();
-
break;
}
}
@@ -828,11 +826,11 @@ may be easily converted to SAI when they get.*/
enum SongOfWindAndWater
{
// Spells
- SPELL_DEVOUR_WIND = 52862,
- SPELL_DEVOUR_WATER = 52864,
+ SPELL_DEVOUR_WIND = 52862,
+ SPELL_DEVOUR_WATER = 52864,
// NPCs
- NPC_HAIPHOON_WATER = 28999,
- NPC_HAIPHOON_AIR = 28985
+ NPC_HAIPHOON_WATER = 28999,
+ NPC_HAIPHOON_AIR = 28985
};
class npc_haiphoon : public CreatureScript
@@ -883,7 +881,7 @@ enum ReconnaissanceFlight
VIC_SAY_6 = 6,
PLANE_EMOTE = 0,
- SPELL_ENGINE = 52255, // Engine on Fire
+ SPELL_ENGINE = 52255, // Engine on Fire
SPELL_LAND = 52226, // Land Flying Machine
SPELL_CREDIT = 53328 // Land Flying Machine Credit
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index 13b6b22bed4..df2b2e73c1c 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -1074,6 +1074,16 @@ Command.LookupMaxResults = 0
AllowTickets = 1
#
+# DeletedCharacterTicketTrace
+# Description: Keep trace of tickets opened by deleted characters
+# gm_ticket.playerGuid will be 0, old GUID and character name
+# will be included in gm_ticket.comment
+# Default: 0 - (Disabled)
+# 1 - (Enabled)
+
+DeletedCharacterTicketTrace = 0
+
+#
# DungeonFinder.OptionsMask
# Description: Dungeon and raid finder system.
# Value is a bitmask consisting of: