Merge commit '32d9a71a4219ea353950979a2491e7879b7fa79a' into 4.3.4
Conflicts: README.md sql/base/auth_database.sql sql/updates/world/2014_12_27_01_world_335.sql src/server/game/Conditions/ConditionMgr.cpp src/server/game/Globals/ObjectMgr.cpp src/server/game/Server/WorldSession.cpp src/server/scripts/Commands/cs_misc.cpp src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/instance_hyjal.cpp src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp src/server/scripts/Spells/spell_hunter.cpp
This commit is contained in:
commit
79eb80dcba
71 files changed
+1652
-1862
No files matched your search
@@ -2,12 +2,9 @@
|
||||
|
||||
[](http://www.issuestats.com/github/TrinityCore/TrinityCore) [](http://www.issuestats.com/github/TrinityCore/TrinityCore) [](https://www.bountysource.com/trackers/1310-trinity-core?utm_source=1310&utm_medium=shield&utm_campaign=TRACKER_BADGE)
|
||||
|
||||
## Build Status
|
||||
|
||||
6.x | 4.3.4 | 3.3.5
|
||||
:------------: | :------------: | :------------:
|
||||
[](https://travis-ci.org/TrinityCore/TrinityCore) | [](https://travis-ci.org/TrinityCore/TrinityCore) | [](https://travis-ci.org/TrinityCore/TrinityCore)
|
||||
[](https://scan.coverity.com/projects/435) | | [](https://scan.coverity.com/projects/4656)
|
||||
`6.x`: [](https://travis-ci.org/TrinityCore/TrinityCore)
|
||||
`4.3.4`: [](https://travis-ci.org/TrinityCore/TrinityCore)
|
||||
`3.3.5`: [](https://travis-ci.org/TrinityCore/TrinityCore)
|
||||
|
||||
## Introduction
|
||||
|
||||
@@ -40,8 +37,10 @@ website at [TrinityCore.org](http://www.trinitycore.org).
|
||||
|
||||
## Install
|
||||
|
||||
Detailed installation guides are available in the [wiki](http://collab.kpsn.org/display/tc/Installation+Guide) for
|
||||
Windows, Linux and Mac OSX.
|
||||
Detailed installation guides are available in the wiki for
|
||||
[Windows](http://collab.kpsn.org/display/tc/Win),
|
||||
[Linux](http://collab.kpsn.org/display/tc/Linux) and
|
||||
[Mac OSX](http://collab.kpsn.org/display/tc/Mac).
|
||||
|
||||
|
||||
## Reporting issues
|
||||
|
||||
@@ -341,9 +341,9 @@ endfunction()
|
||||
# Guesses Boost's compiler prefix used in built library names
|
||||
# Returns the guess by setting the variable pointed to by _ret
|
||||
function(_Boost_GUESS_COMPILER_PREFIX _ret)
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel"
|
||||
OR "${CMAKE_CXX_COMPILER}" MATCHES "icl"
|
||||
OR "${CMAKE_CXX_COMPILER}" MATCHES "icpc")
|
||||
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel"
|
||||
OR ${CMAKE_CXX_COMPILER} MATCHES "icl"
|
||||
OR ${CMAKE_CXX_COMPILER} MATCHES "icpc")
|
||||
if(WIN32)
|
||||
set (_boost_COMPILER "-iw")
|
||||
else()
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ utf8-cpp (UTF-8 with C++ in a Portable Way)
|
||||
|
||||
zlib (A Massively Spiffy Yet Delicately Unobtrusive Compression Library)
|
||||
http://www.zlib.net/
|
||||
Version: 1.2.7
|
||||
Version: 1.2.8
|
||||
|
||||
gSOAP (a portable development toolkit for C and C++ XML Web services and XML data bindings)
|
||||
http://gsoap2.sourceforge.net/
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
-- MySQL dump 10.15 Distrib 10.0.13-MariaDB, for Win64 (x86)
|
||||
-- MySQL dump 10.15 Distrib 10.0.15-MariaDB, for Win64 (x86)
|
||||
--
|
||||
-- Host: localhost Database: auth_4x
|
||||
-- ------------------------------------------------------
|
||||
-- Server version 10.0.13-MariaDB
|
||||
-- Server version 10.0.15-MariaDB
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
@@ -496,7 +496,8 @@ DROP TABLE IF EXISTS `rbac_default_permissions`;
|
||||
CREATE TABLE `rbac_default_permissions` (
|
||||
`secId` int(10) unsigned NOT NULL COMMENT 'Security Level id',
|
||||
`permissionId` int(10) unsigned NOT NULL COMMENT 'permission id',
|
||||
PRIMARY KEY (`secId`,`permissionId`),
|
||||
`realmId` int(11) NOT NULL DEFAULT '-1' COMMENT 'Realm Id, -1 means all',
|
||||
PRIMARY KEY (`secId`,`permissionId`,`realmId`),
|
||||
KEY `fk__rbac_default_permissions__rbac_permissions` (`permissionId`),
|
||||
CONSTRAINT `fk__rbac_default_permissions__rbac_permissions` FOREIGN KEY (`permissionId`) REFERENCES `rbac_permissions` (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Default permission to assign to different account security levels';
|
||||
@@ -508,7 +509,7 @@ CREATE TABLE `rbac_default_permissions` (
|
||||
|
||||
LOCK TABLES `rbac_default_permissions` WRITE;
|
||||
/*!40000 ALTER TABLE `rbac_default_permissions` DISABLE KEYS */;
|
||||
INSERT INTO `rbac_default_permissions` VALUES (3,192),(2,193),(1,194),(0,195);
|
||||
INSERT INTO `rbac_default_permissions` VALUES (0,195,-1),(1,194,-1),(2,193,-1),(3,192,-1);
|
||||
/*!40000 ALTER TABLE `rbac_default_permissions` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
@@ -661,4 +662,4 @@ UNLOCK TABLES;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2014-11-11 0:38:41
|
||||
-- Dump completed on 2014-12-21 20:42:33
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE `rbac_default_permissions`
|
||||
ADD COLUMN `realmId` INT(11) NOT NULL DEFAULT '-1' COMMENT 'Realm Id, -1 means all',
|
||||
DROP PRIMARY KEY, ADD PRIMARY KEY (`secId`, `permissionId`, `realmId`);
|
||||
@@ -0,0 +1,9 @@
|
||||
-- Add rbac_permissions
|
||||
DELETE FROM `rbac_permissions` WHERE `id` = 51;
|
||||
INSERT INTO `rbac_permissions` (`id`,`name`) VALUES
|
||||
(51, 'Allow trading between factions');
|
||||
|
||||
-- Add rbac_linked_permissions
|
||||
DELETE FROM `rbac_linked_permissions` WHERE `linkedId` = 51;
|
||||
INSERT INTO `rbac_linked_permissions` (`id`,`linkedId`) VALUES
|
||||
(194, 51);
|
||||
@@ -446,7 +446,7 @@ void AccountMgr::LoadRBAC()
|
||||
while (result->NextRow());
|
||||
|
||||
TC_LOG_DEBUG("rbac", "AccountMgr::LoadRBAC: Loading default permissions");
|
||||
result = LoginDatabase.Query("SELECT secId, permissionId FROM rbac_default_permissions ORDER BY secId ASC");
|
||||
result = LoginDatabase.PQuery("SELECT secId, permissionId FROM rbac_default_permissions WHERE (realmId = %u OR realmId = -1) ORDER BY secId ASC", realmID);
|
||||
if (!result)
|
||||
{
|
||||
TC_LOG_INFO("server.loading", ">> Loaded 0 default permission definitions. DB table `rbac_default_permissions` is empty.");
|
||||
|
||||
@@ -100,6 +100,7 @@ enum RBACPermissions
|
||||
RBAC_PERM_COMMANDS_PINFO_CHECK_PERSONAL_DATA = 48,
|
||||
RBAC_PERM_EMAIL_CONFIRM_FOR_PASS_CHANGE = 49,
|
||||
RBAC_PERM_MAY_CHECK_OWN_EMAIL = 50,
|
||||
RBAC_PERM_ALLOW_TWO_SIDE_TRADE = 51,
|
||||
|
||||
// Free space for core permissions (till 149)
|
||||
// Roles (Permissions with delegated permissions) use 199 and descending
|
||||
|
||||
@@ -1000,7 +1000,7 @@ uint32 ChatHandler::extractSpellIdFromLink(char* text)
|
||||
if (!idS)
|
||||
return 0;
|
||||
|
||||
uint32 id = (uint32)atol(idS);
|
||||
uint32 id = atoul(idS);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
@@ -1013,13 +1013,10 @@ uint32 ChatHandler::extractSpellIdFromLink(char* text)
|
||||
if (!talentEntry)
|
||||
return 0;
|
||||
|
||||
int32 rank = param1_str ? (uint32)atol(param1_str) : 0;
|
||||
uint32 rank = param1_str ? atol(param1_str) : 0u;
|
||||
if (rank >= MAX_TALENT_RANK)
|
||||
return 0;
|
||||
|
||||
if (rank < 0)
|
||||
rank = 0;
|
||||
|
||||
return talentEntry->RankID[rank];
|
||||
}
|
||||
case SPELL_LINK_ENCHANT:
|
||||
@@ -1027,7 +1024,7 @@ uint32 ChatHandler::extractSpellIdFromLink(char* text)
|
||||
return id;
|
||||
case SPELL_LINK_GLYPH:
|
||||
{
|
||||
uint32 glyph_prop_id = param1_str ? (uint32)atol(param1_str) : 0;
|
||||
uint32 glyph_prop_id = param1_str ? atoul(param1_str) : 0;
|
||||
|
||||
GlyphPropertiesEntry const* glyphPropEntry = sGlyphPropertiesStore.LookupEntry(glyph_prop_id);
|
||||
if (!glyphPropEntry)
|
||||
@@ -1100,7 +1097,7 @@ ObjectGuid ChatHandler::extractGuidFromLink(char* text)
|
||||
}
|
||||
case SPELL_LINK_CREATURE:
|
||||
{
|
||||
uint32 lowguid = (uint32)atol(idS);
|
||||
uint32 lowguid = atoul(idS);
|
||||
|
||||
if (CreatureData const* data = sObjectMgr->GetCreatureData(lowguid))
|
||||
return ObjectGuid(HIGHGUID_UNIT, data->id, lowguid);
|
||||
@@ -1109,7 +1106,7 @@ ObjectGuid ChatHandler::extractGuidFromLink(char* text)
|
||||
}
|
||||
case SPELL_LINK_GAMEOBJECT:
|
||||
{
|
||||
uint32 lowguid = (uint32)atol(idS);
|
||||
uint32 lowguid = atoul(idS);
|
||||
|
||||
if (GameObjectData const* data = sObjectMgr->GetGOData(lowguid))
|
||||
return ObjectGuid(HIGHGUID_GAMEOBJECT, data->id, lowguid);
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -212,6 +212,8 @@ struct Condition
|
||||
uint32 GetSearcherTypeMaskForCondition();
|
||||
bool isLoaded() const { return ConditionType > CONDITION_NONE || ReferenceId; }
|
||||
uint32 GetMaxAvailableConditionTargets();
|
||||
|
||||
std::string ToString(bool ext = false) const; /// For logging purpose
|
||||
};
|
||||
|
||||
typedef std::list<Condition*> ConditionList;
|
||||
@@ -230,7 +232,6 @@ class ConditionMgr
|
||||
~ConditionMgr();
|
||||
|
||||
public:
|
||||
|
||||
static ConditionMgr* instance()
|
||||
{
|
||||
static ConditionMgr instance;
|
||||
@@ -245,14 +246,24 @@ class ConditionMgr
|
||||
bool IsObjectMeetToConditions(WorldObject* object, ConditionList const& conditions);
|
||||
bool IsObjectMeetToConditions(WorldObject* object1, WorldObject* object2, ConditionList const& conditions);
|
||||
bool IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, ConditionList const& conditions);
|
||||
bool CanHaveSourceGroupSet(ConditionSourceType sourceType) const;
|
||||
bool CanHaveSourceIdSet(ConditionSourceType sourceType) const;
|
||||
static bool CanHaveSourceGroupSet(ConditionSourceType sourceType);
|
||||
static bool CanHaveSourceIdSet(ConditionSourceType sourceType);
|
||||
ConditionList GetConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry);
|
||||
ConditionList GetConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId);
|
||||
ConditionList GetConditionsForSmartEvent(int32 entryOrGuid, uint32 eventId, uint32 sourceType);
|
||||
ConditionList GetConditionsForVehicleSpell(uint32 creatureId, uint32 spellId);
|
||||
ConditionList GetConditionsForNpcVendorEvent(uint32 creatureId, uint32 itemId);
|
||||
|
||||
struct ConditionTypeInfo
|
||||
{
|
||||
char const* Name;
|
||||
bool HasConditionValue1;
|
||||
bool HasConditionValue2;
|
||||
bool HasConditionValue3;
|
||||
};
|
||||
static char const* StaticSourceTypeData[CONDITION_SOURCE_TYPE_MAX];
|
||||
static ConditionTypeInfo const StaticConditionTypeData[CONDITION_MAX];
|
||||
|
||||
private:
|
||||
bool isSourceTypeValid(Condition* cond);
|
||||
bool addToLootTemplate(Condition* cond, LootTemplate* loot);
|
||||
@@ -261,6 +272,8 @@ class ConditionMgr
|
||||
bool addToSpellImplicitTargetConditions(Condition* cond);
|
||||
bool IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, ConditionList const& conditions);
|
||||
|
||||
static void LogUselessConditionValue(Condition* cond, uint8 index, uint32 value);
|
||||
|
||||
void Clean(); // free up resources
|
||||
std::list<Condition*> AllocatedMemoryStore; // some garbage collection :)
|
||||
|
||||
|
||||
@@ -785,7 +785,7 @@ void Object::_LoadIntoDataField(std::string const& data, uint32 startOffset, uin
|
||||
|
||||
for (uint32 index = 0; index < count; ++index)
|
||||
{
|
||||
m_uint32Values[startOffset + index] = atol(tokens[index]);
|
||||
m_uint32Values[startOffset + index] = atoul(tokens[index]);
|
||||
_changesMask.SetBit(startOffset + index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ void PlayerTaxi::LoadTaxiMask(std::string const &data)
|
||||
for (Tokenizer::const_iterator iter = tokens.begin(); index < TaxiMaskSize && iter != tokens.end(); ++iter, ++index)
|
||||
{
|
||||
// load and set bits only for existing taxi nodes
|
||||
m_taximask[index] = sTaxiNodesMask[index] & uint32(atol(*iter));
|
||||
m_taximask[index] = sTaxiNodesMask[index] & atoul(*iter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, uint3
|
||||
|
||||
for (Tokenizer::const_iterator iter = Tokenizer.begin(); iter != Tokenizer.end(); ++iter)
|
||||
{
|
||||
uint32 node = uint32(atol(*iter));
|
||||
uint32 node = atoul(*iter);
|
||||
AddTaxiDestination(node);
|
||||
}
|
||||
|
||||
@@ -15555,12 +15555,13 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
|
||||
|
||||
void Player::FailQuest(uint32 questId)
|
||||
{
|
||||
// Already complete quests shouldn't turn failed.
|
||||
if (GetQuestStatus(questId) == QUEST_STATUS_COMPLETE)
|
||||
return;
|
||||
|
||||
if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId))
|
||||
{
|
||||
// Already complete quests shouldn't turn failed.
|
||||
if (GetQuestStatus(questId) == QUEST_STATUS_COMPLETE && !quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED))
|
||||
return;
|
||||
|
||||
SetQuestStatus(questId, QUEST_STATUS_FAILED);
|
||||
|
||||
uint16 log_slot = FindQuestSlot(questId);
|
||||
@@ -21550,12 +21551,15 @@ void Player::SetRestBonus(float rest_bonus_new)
|
||||
m_rest_bonus = rest_bonus_new;
|
||||
|
||||
// update data for client
|
||||
if (GetSession()->IsARecruiter() || (GetSession()->GetRecruiterId() != 0))
|
||||
if ((GetsRecruitAFriendBonus(true) && (GetSession()->IsARecruiter() || GetSession()->GetRecruiterId() != 0)))
|
||||
SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_RAF_LINKED);
|
||||
else if (m_rest_bonus > 10)
|
||||
SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_RESTED); // Set Reststate = Rested
|
||||
else if (m_rest_bonus <= 1)
|
||||
SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_NOT_RAF_LINKED); // Set Reststate = Normal
|
||||
else
|
||||
{
|
||||
if (m_rest_bonus > 10)
|
||||
SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_RESTED);
|
||||
else if (m_rest_bonus <= 1)
|
||||
SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_NOT_RAF_LINKED);
|
||||
}
|
||||
|
||||
//RestTickUpdate
|
||||
SetUInt32Value(PLAYER_REST_STATE_EXPERIENCE, uint32(m_rest_bonus));
|
||||
|
||||
@@ -12232,7 +12232,7 @@ void CharmInfo::LoadPetActionBar(const std::string& data)
|
||||
// use unsigned cast to avoid sign negative format use at long-> ActiveStates (int) conversion
|
||||
ActiveStates type = ActiveStates(atol(*iter));
|
||||
++iter;
|
||||
uint32 action = uint32(atol(*iter));
|
||||
uint32 action = atoul(*iter);
|
||||
|
||||
PetActionBar[index].SetActionAndType(action, type);
|
||||
|
||||
|
||||
@@ -596,17 +596,17 @@ void ObjectMgr::LoadCreatureTemplateAddons()
|
||||
creatureAddon.auras.resize(tokens.size());
|
||||
for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr)
|
||||
{
|
||||
SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(uint32(atol(*itr)));
|
||||
SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(atoul(*itr));
|
||||
if (!AdditionalSpellInfo)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong spell %u defined in `auras` field in `creature_template_addon`.", entry, uint32(atol(*itr)));
|
||||
TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong spell %lu defined in `auras` field in `creature_template_addon`.", entry, atoul(*itr));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (AdditionalSpellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE))
|
||||
TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has SPELL_AURA_CONTROL_VEHICLE aura %u defined in `auras` field in `creature_template_addon`.", entry, uint32(atol(*itr)));
|
||||
TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has SPELL_AURA_CONTROL_VEHICLE aura %lu defined in `auras` field in `creature_template_addon`.", entry, atoul(*itr));
|
||||
|
||||
creatureAddon.auras[i++] = uint32(atol(*itr));
|
||||
creatureAddon.auras[i++] = atoul(*itr);
|
||||
}
|
||||
|
||||
if (creatureAddon.mount)
|
||||
@@ -1044,17 +1044,17 @@ void ObjectMgr::LoadCreatureAddons()
|
||||
creatureAddon.auras.resize(tokens.size());
|
||||
for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr)
|
||||
{
|
||||
SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(uint32(atol(*itr)));
|
||||
SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(atoul(*itr));
|
||||
if (!AdditionalSpellInfo)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "Creature (GUID: %u) has wrong spell %u defined in `auras` field in `creature_addon`.", guid, uint32(atol(*itr)));
|
||||
TC_LOG_ERROR("sql.sql", "Creature (GUID: %u) has wrong spell %lu defined in `auras` field in `creature_addon`.", guid, atoul(*itr));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (AdditionalSpellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE))
|
||||
TC_LOG_ERROR("sql.sql", "Creature (GUID: %u) has SPELL_AURA_CONTROL_VEHICLE aura %u defined in `auras` field in `creature_addon`.", guid, uint32(atol(*itr)));
|
||||
TC_LOG_ERROR("sql.sql", "Creature (GUID: %u) has SPELL_AURA_CONTROL_VEHICLE aura %lu defined in `auras` field in `creature_addon`.", guid, atoul(*itr));
|
||||
|
||||
creatureAddon.auras[i++] = uint32(atol(*itr));
|
||||
creatureAddon.auras[i++] = atoul(*itr);
|
||||
}
|
||||
|
||||
if (creatureAddon.mount)
|
||||
@@ -5757,35 +5757,32 @@ void ObjectMgr::LoadAreaTriggerScripts()
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
_areaTriggerScriptStore.clear(); // need for reload case
|
||||
QueryResult result = WorldDatabase.Query("SELECT entry, ScriptName FROM areatrigger_scripts");
|
||||
|
||||
QueryResult result = WorldDatabase.Query("SELECT entry, ScriptName FROM areatrigger_scripts");
|
||||
if (!result)
|
||||
{
|
||||
TC_LOG_INFO("server.loading", ">> Loaded 0 areatrigger scripts. DB table `areatrigger_scripts` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
++count;
|
||||
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint32 Trigger_ID = fields[0].GetUInt32();
|
||||
const char *scriptName = fields[1].GetCString();
|
||||
uint32 triggerId = fields[0].GetUInt32();
|
||||
char const* scriptName = fields[1].GetCString();
|
||||
|
||||
AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
|
||||
AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(triggerId);
|
||||
if (!atEntry)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.", Trigger_ID);
|
||||
TC_LOG_ERROR("sql.sql", "AreaTrigger (ID: %u) does not exist in `AreaTrigger.dbc`.", triggerId);
|
||||
continue;
|
||||
}
|
||||
_areaTriggerScriptStore[Trigger_ID] = GetScriptId(scriptName);
|
||||
} while (result->NextRow());
|
||||
_areaTriggerScriptStore[triggerId] = GetScriptId(scriptName);
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u areatrigger scripts in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " areatrigger scripts in %u ms", _areaTriggerScriptStore.size(), GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
uint32 ObjectMgr::GetNearestTaxiNode(float x, float y, float z, uint32 mapid, uint32 team)
|
||||
@@ -8690,31 +8687,32 @@ void ObjectMgr::LoadScriptNames()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
_scriptNamesStore.push_back("");
|
||||
_scriptNamesStore.emplace_back("");
|
||||
|
||||
QueryResult result = WorldDatabase.Query(
|
||||
"SELECT DISTINCT(ScriptName) FROM achievement_criteria_data WHERE ScriptName <> '' AND type = 11 "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM battleground_template WHERE ScriptName <> '' "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM creature_template WHERE ScriptName <> '' "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM gameobject_template WHERE ScriptName <> '' "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM achievement_criteria_data WHERE ScriptName <> '' AND type = 11 "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM battleground_template WHERE ScriptName <> '' "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM creature_template WHERE ScriptName <> '' "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM gameobject_template WHERE ScriptName <> '' "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM item_script_names WHERE ScriptName <> '' "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM areatrigger_scripts WHERE ScriptName <> '' "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM spell_script_names WHERE ScriptName <> '' "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM transports WHERE ScriptName <> '' "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM game_weather WHERE ScriptName <> '' "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM conditions WHERE ScriptName <> '' "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM outdoorpvp_template WHERE ScriptName <> '' "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(script) FROM instance_template WHERE script <> ''");
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM areatrigger_scripts WHERE ScriptName <> '' "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM spell_script_names WHERE ScriptName <> '' "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM transports WHERE ScriptName <> '' "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM game_weather WHERE ScriptName <> '' "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM conditions WHERE ScriptName <> '' "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(ScriptName) FROM outdoorpvp_template WHERE ScriptName <> '' "
|
||||
"UNION "
|
||||
"SELECT DISTINCT(script) FROM instance_template WHERE script <> ''");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
@@ -8722,20 +8720,23 @@ void ObjectMgr::LoadScriptNames()
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 1;
|
||||
|
||||
do
|
||||
{
|
||||
_scriptNamesStore.push_back((*result)[0].GetString());
|
||||
++count;
|
||||
_scriptNamesStore.emplace_back((*result)[0].GetCString());
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
std::sort(_scriptNamesStore.begin(), _scriptNamesStore.end());
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %d Script Names in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
|
||||
#ifdef SCRIPTS
|
||||
for (size_t i = 1; i < _scriptNamesStore.size(); ++i)
|
||||
UnusedScriptNames.push_back(_scriptNamesStore[i]);
|
||||
#endif
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " ScriptNames in %u ms", _scriptNamesStore.size(), GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
uint32 ObjectMgr::GetScriptId(const char *name)
|
||||
uint32 ObjectMgr::GetScriptId(char const* name)
|
||||
{
|
||||
// use binary search to find the script name in the sorted vector
|
||||
// assume "" is the first element
|
||||
|
||||
@@ -1261,9 +1261,8 @@ class ObjectMgr
|
||||
bool IsVendorItemValid(uint32 vendor_entry, uint32 id, int32 maxcount, uint32 ptime, uint32 ExtendedCost, uint8 type, Player* player = NULL, std::set<uint32>* skip_vendors = NULL, uint32 ORnpcflag = 0) const;
|
||||
|
||||
void LoadScriptNames();
|
||||
ScriptNameContainer &GetScriptNames() { return _scriptNamesStore; }
|
||||
const char * GetScriptName(uint32 id) const { return id < _scriptNamesStore.size() ? _scriptNamesStore[id].c_str() : ""; }
|
||||
uint32 GetScriptId(const char *name);
|
||||
char const* GetScriptName(uint32 id) const { return id < _scriptNamesStore.size() ? _scriptNamesStore[id].c_str() : ""; }
|
||||
uint32 GetScriptId(char const* name);
|
||||
|
||||
SpellClickInfoMapBounds GetSpellClickInfoMapBounds(uint32 creature_id) const
|
||||
{
|
||||
|
||||
@@ -2110,7 +2110,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData)
|
||||
}
|
||||
|
||||
for (uint32 index = 0; index < ktcount; ++index)
|
||||
knownTitles[index] = atol(tokens[index]);
|
||||
knownTitles[index] = atoul(tokens[index]);
|
||||
|
||||
for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChangeTitles.begin(); it != sObjectMgr->FactionChangeTitles.end(); ++it)
|
||||
{
|
||||
|
||||
@@ -42,14 +42,6 @@ enum CharterItemIDs
|
||||
ARENA_TEAM_CHARTER_5v5 = 23562
|
||||
};
|
||||
|
||||
enum CharterCosts
|
||||
{
|
||||
GUILD_CHARTER_COST = 1000,
|
||||
ARENA_TEAM_CHARTER_2v2_COST = 800000,
|
||||
ARENA_TEAM_CHARTER_3v3_COST = 1200000,
|
||||
ARENA_TEAM_CHARTER_5v5_COST = 2000000
|
||||
};
|
||||
|
||||
void WorldSession::HandlePetitionBuyOpcode(WorldPacket& recvData)
|
||||
{
|
||||
TC_LOG_DEBUG("network", "Received opcode CMSG_PETITION_BUY");
|
||||
@@ -106,7 +98,7 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket& recvData)
|
||||
return;
|
||||
|
||||
charterid = GUILD_CHARTER;
|
||||
cost = GUILD_CHARTER_COST;
|
||||
cost = sWorld->getIntConfig(CONFIG_CHARTER_COST_GUILD);
|
||||
type = GUILD_CHARTER_TYPE;
|
||||
}
|
||||
else
|
||||
@@ -122,17 +114,17 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket& recvData)
|
||||
{
|
||||
case 1:
|
||||
charterid = ARENA_TEAM_CHARTER_2v2;
|
||||
cost = ARENA_TEAM_CHARTER_2v2_COST;
|
||||
cost = sWorld->getIntConfig(CONFIG_CHARTER_COST_ARENA_2v2);
|
||||
type = ARENA_TEAM_CHARTER_2v2_TYPE;
|
||||
break;
|
||||
case 2:
|
||||
charterid = ARENA_TEAM_CHARTER_3v3;
|
||||
cost = ARENA_TEAM_CHARTER_3v3_COST;
|
||||
cost = sWorld->getIntConfig(CONFIG_CHARTER_COST_ARENA_3v3);
|
||||
type = ARENA_TEAM_CHARTER_3v3_TYPE;
|
||||
break;
|
||||
case 3:
|
||||
charterid = ARENA_TEAM_CHARTER_5v5;
|
||||
cost = ARENA_TEAM_CHARTER_5v5_COST;
|
||||
cost = sWorld->getIntConfig(CONFIG_CHARTER_COST_ARENA_5v5);
|
||||
type = ARENA_TEAM_CHARTER_5v5_TYPE;
|
||||
break;
|
||||
default:
|
||||
@@ -941,7 +933,7 @@ void WorldSession::SendPetitionShowList(ObjectGuid guid)
|
||||
data << uint32(1); // index
|
||||
data << uint32(GUILD_CHARTER); // charter entry
|
||||
data << uint32(CHARTER_DISPLAY_ID); // charter display id
|
||||
data << uint32(GUILD_CHARTER_COST); // charter cost
|
||||
data << uint32(sWorld->getIntConfig(CONFIG_CHARTER_COST_GUILD)); // charter cost
|
||||
data << uint32(0); // unknown
|
||||
data << uint32(sWorld->getIntConfig(CONFIG_MIN_PETITION_SIGNS)); // required signs
|
||||
}
|
||||
@@ -952,21 +944,21 @@ void WorldSession::SendPetitionShowList(ObjectGuid guid)
|
||||
data << uint32(1); // index
|
||||
data << uint32(ARENA_TEAM_CHARTER_2v2); // charter entry
|
||||
data << uint32(CHARTER_DISPLAY_ID); // charter display id
|
||||
data << uint32(ARENA_TEAM_CHARTER_2v2_COST); // charter cost
|
||||
data << uint32(sWorld->getIntConfig(CONFIG_CHARTER_COST_ARENA_2v2)); // charter cost
|
||||
data << uint32(2); // unknown
|
||||
data << uint32(2); // required signs?
|
||||
// 3v3
|
||||
data << uint32(2); // index
|
||||
data << uint32(ARENA_TEAM_CHARTER_3v3); // charter entry
|
||||
data << uint32(CHARTER_DISPLAY_ID); // charter display id
|
||||
data << uint32(ARENA_TEAM_CHARTER_3v3_COST); // charter cost
|
||||
data << uint32(sWorld->getIntConfig(CONFIG_CHARTER_COST_ARENA_3v3)); // charter cost
|
||||
data << uint32(3); // unknown
|
||||
data << uint32(3); // required signs?
|
||||
// 5v5
|
||||
data << uint32(3); // index
|
||||
data << uint32(ARENA_TEAM_CHARTER_5v5); // charter entry
|
||||
data << uint32(CHARTER_DISPLAY_ID); // charter display id
|
||||
data << uint32(ARENA_TEAM_CHARTER_5v5_COST); // charter cost
|
||||
data << uint32(sWorld->getIntConfig(CONFIG_CHARTER_COST_ARENA_5v5)); // charter cost
|
||||
data << uint32(5); // unknown
|
||||
data << uint32(5); // required signs?
|
||||
}
|
||||
|
||||
@@ -775,7 +775,9 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) && pOther->GetTeam() !=_player->GetTeam())
|
||||
if (pOther->GetTeam() != _player->GetTeam() &&
|
||||
(!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) &&
|
||||
!GetPlayer()->GetSession()->HasPermission(rbac::RBAC_PERM_ALLOW_TWO_SIDE_TRADE)))
|
||||
{
|
||||
info.Status = TRADE_STATUS_WRONG_FACTION;
|
||||
SendTradeStatus(info);
|
||||
|
||||
@@ -128,7 +128,7 @@ void InstanceScript::LoadObjectData(ObjectData const* creatureData, ObjectData c
|
||||
if (gameObjectData)
|
||||
LoadObjectData(gameObjectData, _gameObjectInfo);
|
||||
|
||||
TC_LOG_ERROR("scripts", "InstanceScript::LoadObjectData: " SZFMTD " objects loaded.", _creatureInfo.size() + _gameObjectInfo.size());
|
||||
TC_LOG_DEBUG("scripts", "InstanceScript::LoadObjectData: " SZFMTD " objects loaded.", _creatureInfo.size() + _gameObjectInfo.size());
|
||||
}
|
||||
|
||||
void InstanceScript::LoadObjectData(ObjectData const* data, ObjectInfoMap& objectInfo)
|
||||
|
||||
@@ -56,12 +56,12 @@ void RandomMovementGenerator<Creature>::_setRandomLocation(Creature* creature)
|
||||
Trinity::NormalizeMapCoord(destX);
|
||||
Trinity::NormalizeMapCoord(destY);
|
||||
|
||||
travelDistZ = distanceX*distanceX + distanceY*distanceY;
|
||||
travelDistZ = range; // sin^2+cos^2=1, so travelDistZ=range^2; no need for sqrt below
|
||||
|
||||
if (is_air_ok) // 3D system above ground and above water (flying mode)
|
||||
{
|
||||
// Limit height change
|
||||
const float distanceZ = float(rand_norm()) * std::sqrt(travelDistZ)/2.0f;
|
||||
const float distanceZ = float(rand_norm()) * travelDistZ/2.0f;
|
||||
destZ = respZ + distanceZ;
|
||||
float levelZ = map->GetWaterOrGroundLevel(destX, destY, destZ-2.0f);
|
||||
|
||||
@@ -73,7 +73,7 @@ void RandomMovementGenerator<Creature>::_setRandomLocation(Creature* creature)
|
||||
else // 2D only
|
||||
{
|
||||
// 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE)
|
||||
travelDistZ = travelDistZ >= 100.0f ? 10.0f : std::sqrt(travelDistZ);
|
||||
travelDistZ = travelDistZ >= 10.0f ? 10.0f : travelDistZ;
|
||||
|
||||
// The fastest way to get an accurate result 90% of the time.
|
||||
// Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long.
|
||||
|
||||
@@ -34,6 +34,12 @@
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
// namespace
|
||||
// {
|
||||
UnusedScriptContainer UnusedScripts;
|
||||
UnusedScriptNamesContainer UnusedScriptNames;
|
||||
// }
|
||||
|
||||
// This is the global static registry of scripts.
|
||||
template<class TScript>
|
||||
class ScriptRegistry
|
||||
@@ -89,6 +95,12 @@ class ScriptRegistry
|
||||
{
|
||||
ScriptPointerList[id] = script;
|
||||
sScriptMgr->IncrementScriptCount();
|
||||
|
||||
#ifdef SCRIPTS
|
||||
UnusedScriptNamesContainer::iterator itr = std::lower_bound(UnusedScriptNames.begin(), UnusedScriptNames.end(), script->GetName());
|
||||
if (itr != UnusedScriptNames.end() && *itr == script->GetName())
|
||||
UnusedScriptNames.erase(itr);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -106,8 +118,7 @@ class ScriptRegistry
|
||||
|
||||
// Avoid calling "delete script;" because we are currently in the script constructor
|
||||
// In a valid scenario this will not happen because every script has a name assigned in the database
|
||||
// If that happens, it's acceptable to just leak a few bytes
|
||||
|
||||
UnusedScripts.push_back(script);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -189,6 +200,15 @@ void ScriptMgr::Initialize()
|
||||
FillSpellSummary();
|
||||
AddScripts();
|
||||
|
||||
#ifdef SCRIPTS
|
||||
for (std::string const& scriptName : UnusedScriptNames)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "ScriptName '%s' exists in database, but no core script found!", scriptName.c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
UnloadUnusedScripts();
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u C++ scripts in %u ms", GetScriptCount(), GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
@@ -229,10 +249,19 @@ void ScriptMgr::Unload()
|
||||
|
||||
#undef SCR_CLEAR
|
||||
|
||||
UnloadUnusedScripts();
|
||||
|
||||
delete[] SpellSummary;
|
||||
delete[] UnitAI::AISpellInfo;
|
||||
}
|
||||
|
||||
void ScriptMgr::UnloadUnusedScripts()
|
||||
{
|
||||
for (size_t i = 0; i < UnusedScripts.size(); ++i)
|
||||
delete UnusedScripts[i];
|
||||
UnusedScripts.clear();
|
||||
}
|
||||
|
||||
void ScriptMgr::LoadDatabase()
|
||||
{
|
||||
sScriptSystemMgr->LoadScriptWaypoints();
|
||||
|
||||
@@ -872,6 +872,15 @@ class GroupScript : public ScriptObject
|
||||
// Placed here due to ScriptRegistry::AddScript dependency.
|
||||
#define sScriptMgr ScriptMgr::instance()
|
||||
|
||||
// namespace
|
||||
// {
|
||||
typedef std::vector<ScriptObject*> UnusedScriptContainer;
|
||||
typedef std::list<std::string> UnusedScriptNamesContainer;
|
||||
|
||||
extern UnusedScriptContainer UnusedScripts;
|
||||
extern UnusedScriptNamesContainer UnusedScriptNames;
|
||||
// }
|
||||
|
||||
// Manages registration, loading, and execution of scripts.
|
||||
class ScriptMgr
|
||||
{
|
||||
@@ -900,6 +909,7 @@ class ScriptMgr
|
||||
public: /* Unloading */
|
||||
|
||||
void Unload();
|
||||
void UnloadUnusedScripts();
|
||||
|
||||
public: /* SpellScriptLoader */
|
||||
|
||||
|
||||
@@ -324,46 +324,51 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
|
||||
while (m_Socket && !_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket && _recvQueue.next(packet, updater))
|
||||
{
|
||||
if (!AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||
KickPlayer();
|
||||
|
||||
OpcodeHandler const* opHandle = opcodeTable[packet->GetOpcode()];
|
||||
try
|
||||
if (packet->GetOpcode() >= NUM_MSG_TYPES)
|
||||
{
|
||||
switch (opHandle->Status)
|
||||
TC_LOG_ERROR("network.opcode", "Received non-existed opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str()
|
||||
, GetPlayerInfo().c_str());
|
||||
sScriptMgr->OnUnknownPacketReceive(this, *packet);
|
||||
}
|
||||
else
|
||||
{
|
||||
OpcodeHandler& opHandle = opcodeTable[packet->GetOpcode()];
|
||||
try
|
||||
{
|
||||
case STATUS_LOGGEDIN:
|
||||
if (!_player)
|
||||
{
|
||||
// skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets
|
||||
//! If player didn't log out a while ago, it means packets are being sent while the server does not recognize
|
||||
//! the client to be in world yet. We will re-add the packets to the bottom of the queue and process them later.
|
||||
if (!m_playerRecentlyLogout)
|
||||
switch (opHandle->Status)
|
||||
{
|
||||
case STATUS_LOGGEDIN:
|
||||
if (!_player)
|
||||
{
|
||||
//! Prevent infinite loop
|
||||
if (!firstDelayedPacket)
|
||||
firstDelayedPacket = packet;
|
||||
//! Because checking a bool is faster than reallocating memory
|
||||
deletePacket = false;
|
||||
QueuePacket(packet);
|
||||
//! Log
|
||||
// skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets
|
||||
//! If player didn't log out a while ago, it means packets are being sent while the server does not recognize
|
||||
//! the client to be in world yet. We will re-add the packets to the bottom of the queue and process them later.
|
||||
if (!m_playerRecentlyLogout)
|
||||
{
|
||||
//! Prevent infinite loop
|
||||
if (!firstDelayedPacket)
|
||||
firstDelayedPacket = packet;
|
||||
//! Because checking a bool is faster than reallocating memory
|
||||
deletePacket = false;
|
||||
QueuePacket(packet);
|
||||
//! Log
|
||||
TC_LOG_DEBUG("network", "Re-enqueueing packet with opcode %s with with status STATUS_LOGGEDIN. "
|
||||
"Player is currently not in world yet.", GetOpcodeNameForLogging(packet->GetOpcode()).c_str());
|
||||
}
|
||||
}
|
||||
else if (_player->IsInWorld())
|
||||
{
|
||||
sScriptMgr->OnPacketReceive(this, *packet);
|
||||
(this->*opHandle->Handler)(*packet);
|
||||
LogUnprocessedTail(packet);
|
||||
}
|
||||
// lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer
|
||||
break;
|
||||
case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT:
|
||||
if (!_player && !m_playerRecentlyLogout && !m_playerLogout) // There's a short delay between _player = null and m_playerRecentlyLogout = true during logout
|
||||
LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT",
|
||||
"the player has not logged in yet and not recently logout");
|
||||
else
|
||||
else if (_player->IsInWorld() && AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||
{
|
||||
sScriptMgr->OnPacketReceive(this, *packet);
|
||||
(this->*opHandle.handler)(*packet);
|
||||
LogUnprocessedTail(packet);
|
||||
}
|
||||
// lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer
|
||||
break;
|
||||
case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT:
|
||||
if (!_player && !m_playerRecentlyLogout && !m_playerLogout) // There's a short delay between _player = null and m_playerRecentlyLogout = true during logout
|
||||
LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT",
|
||||
"the player has not logged in yet and not recently logout");
|
||||
else if (AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||
{
|
||||
// not expected _player or must checked in packet hanlder
|
||||
sScriptMgr->OnPacketReceive(this, *packet);
|
||||
@@ -376,7 +381,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player has not logged in yet");
|
||||
else if (_player->IsInWorld())
|
||||
LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player is still in world");
|
||||
else
|
||||
else if(AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||
{
|
||||
sScriptMgr->OnPacketReceive(this, *packet);
|
||||
(this->*opHandle->Handler)(*packet);
|
||||
@@ -396,25 +401,29 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
if (packet->GetOpcode() == CMSG_CHAR_ENUM)
|
||||
m_playerRecentlyLogout = false;
|
||||
|
||||
sScriptMgr->OnPacketReceive(this, *packet);
|
||||
if (AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||
{
|
||||
sScriptMgr->OnPacketReceive(this, *packet);
|
||||
(this->*opHandle->Handler)(*packet);
|
||||
LogUnprocessedTail(packet);
|
||||
LogUnprocessedTail(packet);
|
||||
}
|
||||
break;
|
||||
case STATUS_NEVER:
|
||||
TC_LOG_ERROR("network.opcode", "Received not allowed opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str()
|
||||
, GetPlayerInfo().c_str());
|
||||
break;
|
||||
case STATUS_UNHANDLED:
|
||||
TC_LOG_ERROR("network.opcode", "Received not handled opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str()
|
||||
break;
|
||||
case STATUS_UNHANDLED:
|
||||
TC_LOG_DEBUG("network.opcode", "Received not handled opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str()
|
||||
, GetPlayerInfo().c_str());
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (ByteBufferException const&)
|
||||
{
|
||||
TC_LOG_ERROR("misc", "WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.",
|
||||
packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId());
|
||||
packet->hexlike();
|
||||
}
|
||||
}
|
||||
catch (ByteBufferException const&)
|
||||
{
|
||||
TC_LOG_ERROR("network", "WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.",
|
||||
packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId());
|
||||
packet->hexlike();
|
||||
}
|
||||
|
||||
if (deletePacket)
|
||||
@@ -1208,8 +1217,11 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) co
|
||||
case POLICY_LOG:
|
||||
return true;
|
||||
case POLICY_KICK:
|
||||
{
|
||||
TC_LOG_INFO("network", "AntiDOS: Player kicked!");
|
||||
Session->KickPlayer();
|
||||
return false;
|
||||
}
|
||||
case POLICY_BAN:
|
||||
{
|
||||
BanMode bm = (BanMode)sWorld->getIntConfig(CONFIG_PACKET_SPOOF_BANMODE);
|
||||
@@ -1223,7 +1235,7 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) co
|
||||
}
|
||||
sWorld->BanAccount(bm, nameOrIp, duration, "DOS (Packet Flooding/Spoofing", "Server: AutoDOS");
|
||||
TC_LOG_INFO("network", "AntiDOS: Player automatically banned for %u seconds.", duration);
|
||||
|
||||
Session->KickPlayer();
|
||||
return false;
|
||||
}
|
||||
default: // invalid policy
|
||||
|
||||
@@ -3450,7 +3450,7 @@ void Spell::SendSpellCooldown()
|
||||
{
|
||||
// Handle pet cooldowns here if needed instead of in PetAI to avoid hidden cooldown restarts
|
||||
Creature* _creature = m_caster->ToCreature();
|
||||
if (_creature && _creature->IsPet())
|
||||
if (_creature && (_creature->IsPet() || _creature->IsGuardian()))
|
||||
_creature->AddCreatureSpellCooldown(m_spellInfo->Id);
|
||||
|
||||
return;
|
||||
@@ -7096,6 +7096,19 @@ bool Spell::CallScriptEffectHandlers(SpellEffIndex effIndex, SpellEffectHandleMo
|
||||
return preventDefault;
|
||||
}
|
||||
|
||||
void Spell::CallScriptSuccessfulDispel(SpellEffIndex effIndex)
|
||||
{
|
||||
for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
|
||||
{
|
||||
(*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_EFFECT_SUCCESSFUL_DISPEL);
|
||||
std::list<SpellScript::EffectHandler>::iterator hookItrEnd = (*scritr)->OnEffectSuccessfulDispel.end(), hookItr = (*scritr)->OnEffectSuccessfulDispel.begin();
|
||||
for (; hookItr != hookItrEnd; ++hookItr)
|
||||
hookItr->Call(*scritr, effIndex);
|
||||
|
||||
(*scritr)->_FinishScriptCall();
|
||||
}
|
||||
}
|
||||
|
||||
void Spell::CallScriptBeforeHitHandlers()
|
||||
{
|
||||
for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
|
||||
|
||||
@@ -649,6 +649,7 @@ class Spell
|
||||
SpellCastResult CallScriptCheckCastHandlers();
|
||||
void PrepareScriptHitHandlers();
|
||||
bool CallScriptEffectHandlers(SpellEffIndex effIndex, SpellEffectHandleMode mode);
|
||||
void CallScriptSuccessfulDispel(SpellEffIndex effIndex);
|
||||
void CallScriptBeforeHitHandlers();
|
||||
void CallScriptOnHitHandlers();
|
||||
void CallScriptAfterHitHandlers();
|
||||
|
||||
@@ -310,6 +310,10 @@ bool SpellScript::_Validate(SpellInfo const* entry)
|
||||
if (!(*itr).GetAffectedEffectsMask(entry))
|
||||
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnEffectHitTarget` of SpellScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
|
||||
|
||||
for (std::list<EffectHandler>::iterator itr = OnEffectSuccessfulDispel.begin(); itr != OnEffectSuccessfulDispel.end(); ++itr)
|
||||
if (!(*itr).GetAffectedEffectsMask(entry))
|
||||
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnEffectSuccessfulDispel` of SpellScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
|
||||
|
||||
for (std::list<ObjectAreaTargetSelectHandler>::iterator itr = OnObjectAreaTargetSelect.begin(); itr != OnObjectAreaTargetSelect.end(); ++itr)
|
||||
if (!(*itr).GetAffectedEffectsMask(entry))
|
||||
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnObjectAreaTargetSelect` of SpellScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
|
||||
|
||||
@@ -130,6 +130,7 @@ enum SpellScriptHookType
|
||||
SPELL_SCRIPT_HOOK_EFFECT_LAUNCH_TARGET,
|
||||
SPELL_SCRIPT_HOOK_EFFECT_HIT,
|
||||
SPELL_SCRIPT_HOOK_EFFECT_HIT_TARGET,
|
||||
SPELL_SCRIPT_HOOK_EFFECT_SUCCESSFUL_DISPEL,
|
||||
SPELL_SCRIPT_HOOK_BEFORE_HIT,
|
||||
SPELL_SCRIPT_HOOK_HIT,
|
||||
SPELL_SCRIPT_HOOK_AFTER_HIT,
|
||||
@@ -292,6 +293,7 @@ class SpellScript : public _SpellScript
|
||||
HookList<EffectHandler> OnEffectLaunchTarget;
|
||||
HookList<EffectHandler> OnEffectHit;
|
||||
HookList<EffectHandler> OnEffectHitTarget;
|
||||
HookList<EffectHandler> OnEffectSuccessfulDispel;
|
||||
#define SpellEffectFn(F, I, N) EffectHandlerFunction(&F, I, N)
|
||||
|
||||
// example: BeforeHit += SpellHitFn(class::function);
|
||||
@@ -334,6 +336,9 @@ class SpellScript : public _SpellScript
|
||||
// 11. OnHit - executed just before spell deals damage and procs auras - when spell hits target - called for each target from spell target map
|
||||
// 12. AfterHit - executed just after spell finishes all it's jobs for target - called for each target from spell target map
|
||||
|
||||
// this hook is only executed after a successful dispel of any aura
|
||||
// OnEffectSuccessfulDispel - executed just after effect successfully dispelled aura(s)
|
||||
|
||||
//
|
||||
// methods allowing interaction with Spell object
|
||||
//
|
||||
|
||||
@@ -532,10 +532,10 @@ DumpReturn PlayerDumpReader::LoadDump(std::string const& file, uint32 account, s
|
||||
if (!changenth(line, 2, chraccount)) // characters.account update
|
||||
ROLLBACK(DUMP_FILE_BROKEN);
|
||||
|
||||
race = uint8(atol(getnth(line, 4).c_str()));
|
||||
playerClass = uint8(atol(getnth(line, 5).c_str()));
|
||||
gender = uint8(atol(getnth(line, 6).c_str()));
|
||||
level = uint8(atol(getnth(line, 7).c_str()));
|
||||
race = uint8(atoul(getnth(line, 4).c_str()));
|
||||
playerClass = uint8(atoul(getnth(line, 5).c_str()));
|
||||
gender = uint8(atoul(getnth(line, 6).c_str()));
|
||||
level = uint8(atoul(getnth(line, 7).c_str()));
|
||||
if (name.empty())
|
||||
{
|
||||
// check if the original name already exists
|
||||
|
||||
@@ -703,6 +703,11 @@ void World::LoadConfigSettings(bool reload)
|
||||
m_int_configs[CONFIG_MIN_PET_NAME] = 2;
|
||||
}
|
||||
|
||||
m_int_configs[CONFIG_CHARTER_COST_GUILD] = sConfigMgr->GetIntDefault("Guild.CharterCost", 1000);
|
||||
m_int_configs[CONFIG_CHARTER_COST_ARENA_2v2] = sConfigMgr->GetIntDefault("ArenaTeam.CharterCost.2v2", 800000);
|
||||
m_int_configs[CONFIG_CHARTER_COST_ARENA_3v3] = sConfigMgr->GetIntDefault("ArenaTeam.CharterCost.3v3", 1200000);
|
||||
m_int_configs[CONFIG_CHARTER_COST_ARENA_5v5] = sConfigMgr->GetIntDefault("ArenaTeam.CharterCost.5v5", 2000000);
|
||||
|
||||
m_int_configs[CONFIG_CHARACTER_CREATING_DISABLED] = sConfigMgr->GetIntDefault("CharacterCreating.Disabled", 0);
|
||||
m_int_configs[CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK] = sConfigMgr->GetIntDefault("CharacterCreating.Disabled.RaceMask", 0);
|
||||
m_int_configs[CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK] = sConfigMgr->GetIntDefault("CharacterCreating.Disabled.ClassMask", 0);
|
||||
|
||||
@@ -358,6 +358,10 @@ enum WorldIntConfigs
|
||||
CONFIG_BG_REWARD_WINNER_CONQUEST_LAST,
|
||||
CONFIG_CREATURE_PICKPOCKET_REFILL,
|
||||
CONFIG_AHBOT_UPDATE_INTERVAL,
|
||||
CONFIG_CHARTER_COST_GUILD,
|
||||
CONFIG_CHARTER_COST_ARENA_2v2,
|
||||
CONFIG_CHARTER_COST_ARENA_3v3,
|
||||
CONFIG_CHARTER_COST_ARENA_5v5,
|
||||
INT_CONFIG_VALUE_COUNT
|
||||
};
|
||||
|
||||
|
||||
@@ -489,7 +489,7 @@ public:
|
||||
|
||||
static bool HandleDebugSendQuestPartyMsgCommand(ChatHandler* handler, char const* args)
|
||||
{
|
||||
uint32 msg = atol((char*)args);
|
||||
uint32 msg = atoul(args);
|
||||
handler->GetSession()->GetPlayer()->SendPushToPartyResponse(handler->GetSession()->GetPlayer(), msg);
|
||||
return true;
|
||||
}
|
||||
@@ -508,7 +508,7 @@ public:
|
||||
|
||||
static bool HandleDebugSendQuestInvalidMsgCommand(ChatHandler* handler, char const* args)
|
||||
{
|
||||
QuestFailedReason msg = static_cast<QuestFailedReason>(atol((char*)args));
|
||||
QuestFailedReason msg = static_cast<QuestFailedReason>(atoul(args));
|
||||
handler->GetSession()->GetPlayer()->SendCanTakeQuestResponse(msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ public:
|
||||
if (!id)
|
||||
return false;
|
||||
|
||||
uint32 objectId = atol(id);
|
||||
uint32 objectId = atoul(id);
|
||||
if (!objectId)
|
||||
return false;
|
||||
|
||||
@@ -240,7 +240,7 @@ public:
|
||||
if (!id)
|
||||
return false;
|
||||
|
||||
uint32 objectId = atol(id);
|
||||
uint32 objectId = atoul(id);
|
||||
|
||||
if (objectId)
|
||||
result = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, orientation, map, phaseMask, (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ FROM gameobject WHERE map = '%i' AND id = '%u' ORDER BY order_ ASC LIMIT 1",
|
||||
|
||||
@@ -269,7 +269,7 @@ public:
|
||||
const char* onlineState = "";
|
||||
|
||||
// Parse the guid to uint32...
|
||||
ObjectGuid parseGUID(HIGHGUID_PLAYER, uint32(atol((char*)args)));
|
||||
ObjectGuid parseGUID(HIGHGUID_PLAYER, uint32(atoul(args)));
|
||||
|
||||
// ... and try to extract a player out of it.
|
||||
if (sObjectMgr->GetPlayerNameByGUID(parseGUID, nameTarget))
|
||||
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
if (!id)
|
||||
return false;
|
||||
|
||||
uint32 creatureId = atol(id);
|
||||
uint32 creatureId = atoul(id);
|
||||
if (!creatureId)
|
||||
{
|
||||
handler->PSendSysMessage(LANG_COMMAND_INVALIDCREATUREID, creatureId);
|
||||
@@ -82,7 +82,7 @@ public:
|
||||
}
|
||||
|
||||
char* countStr = strtok(NULL, " ");
|
||||
uint32 count = countStr ? atol(countStr) : 10;
|
||||
uint32 count = countStr ? atoul(countStr) : 10;
|
||||
|
||||
if (count == 0)
|
||||
return false;
|
||||
@@ -133,11 +133,11 @@ public:
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
char* id = handler->extractKeyFromLink((char*)args, "Hitem");
|
||||
char const* id = handler->extractKeyFromLink((char*)args, "Hitem");
|
||||
if (!id)
|
||||
return false;
|
||||
|
||||
uint32 itemId = atol(id);
|
||||
uint32 itemId = atoul(id);
|
||||
if (!itemId)
|
||||
{
|
||||
handler->PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, itemId);
|
||||
@@ -154,7 +154,7 @@ public:
|
||||
}
|
||||
|
||||
char* countStr = strtok(NULL, " ");
|
||||
uint32 count = countStr ? atol(countStr) : 10;
|
||||
uint32 count = countStr ? atoul(countStr) : 10;
|
||||
|
||||
if (count == 0)
|
||||
return false;
|
||||
@@ -354,7 +354,7 @@ public:
|
||||
if (!id)
|
||||
return false;
|
||||
|
||||
uint32 gameObjectId = atol(id);
|
||||
uint32 gameObjectId = atoul(id);
|
||||
if (!gameObjectId)
|
||||
{
|
||||
handler->PSendSysMessage(LANG_COMMAND_LISTOBJINVALIDID, gameObjectId);
|
||||
@@ -371,7 +371,7 @@ public:
|
||||
}
|
||||
|
||||
char* countStr = strtok(NULL, " ");
|
||||
uint32 count = countStr ? atol(countStr) : 10;
|
||||
uint32 count = countStr ? atoul(countStr) : 10;
|
||||
|
||||
if (count == 0)
|
||||
return false;
|
||||
@@ -476,7 +476,7 @@ public:
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
ObjectGuid parseGUID(HIGHGUID_PLAYER, uint32(atol((char*)args)));
|
||||
ObjectGuid parseGUID(HIGHGUID_PLAYER, uint32(atoul(args)));
|
||||
|
||||
if (sObjectMgr->GetPlayerNameByGUID(parseGUID, targetName))
|
||||
{
|
||||
|
||||
@@ -1149,7 +1149,7 @@ public:
|
||||
char const* id = handler->extractKeyFromLink((char*)args, "Hitem");
|
||||
if (!id)
|
||||
return false;
|
||||
itemId = uint32(atol(id));
|
||||
itemId = atoul(id);
|
||||
}
|
||||
|
||||
char const* ccount = strtok(NULL, " ");
|
||||
@@ -1231,7 +1231,7 @@ public:
|
||||
if (!id)
|
||||
return false;
|
||||
|
||||
uint32 itemSetId = atol(id);
|
||||
uint32 itemSetId = atoul(id);
|
||||
|
||||
// prevent generation all items with itemset field value '0'
|
||||
if (itemSetId == 0)
|
||||
@@ -1372,7 +1372,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 level = uint32(atol(levelStr));
|
||||
int32 level = atol(levelStr);
|
||||
|
||||
Player* target = handler->getSelectedPlayer();
|
||||
if (!target)
|
||||
@@ -1394,7 +1394,7 @@ public:
|
||||
|
||||
// If our target does not yet have the skill they are trying to add to them, the chosen level also becomes
|
||||
// the max level of the new profession.
|
||||
uint16 max = maxPureSkill ? atol(maxPureSkill) : targetHasSkill ? target->GetPureMaxSkillValue(skill) : uint16(level);
|
||||
uint16 max = maxPureSkill ? atoul(maxPureSkill) : targetHasSkill ? target->GetPureMaxSkillValue(skill) : uint16(level);
|
||||
|
||||
if (level <= 0 || level > max || max <= 0)
|
||||
return false;
|
||||
@@ -1434,7 +1434,7 @@ public:
|
||||
PreparedStatement* stmt = NULL;
|
||||
|
||||
// To make sure we get a target, we convert our guid to an omniversal...
|
||||
ObjectGuid parseGUID(HIGHGUID_PLAYER, uint32(atol((char*)args)));
|
||||
ObjectGuid parseGUID(HIGHGUID_PLAYER, uint32(atoul(args)));
|
||||
|
||||
// ... and make sure we get a target, somehow.
|
||||
if (sObjectMgr->GetPlayerNameByGUID(parseGUID, targetName))
|
||||
@@ -1795,7 +1795,7 @@ public:
|
||||
uint32 totalmail = uint32(fields[1].GetUInt64());
|
||||
|
||||
// ... we have to convert it from Char to int. We can use totalmail as it is
|
||||
rmailint = atol(readmail.c_str());
|
||||
rmailint = atoul(readmail.c_str());
|
||||
|
||||
// Output XXI. LANG_INFO_CHR_MAILS if at least one mail is given
|
||||
if (totalmail >= 1)
|
||||
@@ -1993,7 +1993,7 @@ public:
|
||||
static bool HandleMuteInfoHelper(uint32 accountId, char const* accountName, ChatHandler *handler)
|
||||
{
|
||||
PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_MUTE_INFO);
|
||||
stmt->setUInt16(0, accountId);
|
||||
stmt->setUInt32(0, accountId);
|
||||
PreparedQueryResult result = LoginDatabase.Query(stmt);
|
||||
|
||||
if (!result)
|
||||
|
||||
@@ -334,15 +334,15 @@ public:
|
||||
char* fmaxcount = strtok(NULL, " "); //add maxcount, default: 0
|
||||
uint32 maxcount = 0;
|
||||
if (fmaxcount)
|
||||
maxcount = atol(fmaxcount);
|
||||
maxcount = atoul(fmaxcount);
|
||||
|
||||
char* fincrtime = strtok(NULL, " "); //add incrtime, default: 0
|
||||
uint32 incrtime = 0;
|
||||
if (fincrtime)
|
||||
incrtime = atol(fincrtime);
|
||||
incrtime = atoul(fincrtime);
|
||||
|
||||
char* fextendedcost = strtok(NULL, " "); //add ExtendedCost, default: 0
|
||||
uint32 extendedcost = fextendedcost ? atol(fextendedcost) : 0;
|
||||
uint32 extendedcost = fextendedcost ? atoul(fextendedcost) : 0;
|
||||
Creature* vendor = handler->getSelectedCreature();
|
||||
if (!vendor)
|
||||
{
|
||||
@@ -572,7 +572,7 @@ public:
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
uint32 itemId = atol(pitem);
|
||||
uint32 itemId = atoul(pitem);
|
||||
|
||||
const uint8 type = 1; // FIXME: make type (1 item, 2 currency) an argument
|
||||
|
||||
@@ -1356,7 +1356,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectGuid receiver_guid(HIGHGUID_PLAYER, uint32(atol(receiver_str)));
|
||||
ObjectGuid receiver_guid(HIGHGUID_PLAYER, uint32(atoul(receiver_str)));
|
||||
|
||||
// check online security
|
||||
Player* receiver = ObjectAccessor::FindPlayer(receiver_guid);
|
||||
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
if (!cId)
|
||||
return false;
|
||||
|
||||
uint32 entry = atol(cId);
|
||||
uint32 entry = atoul(cId);
|
||||
|
||||
Quest const* quest = sObjectMgr->GetQuestTemplate(entry);
|
||||
|
||||
@@ -112,7 +112,7 @@ public:
|
||||
if (!cId)
|
||||
return false;
|
||||
|
||||
uint32 entry = atol(cId);
|
||||
uint32 entry = atoul(cId);
|
||||
|
||||
Quest const* quest = sObjectMgr->GetQuestTemplate(entry);
|
||||
|
||||
@@ -165,7 +165,7 @@ public:
|
||||
if (!cId)
|
||||
return false;
|
||||
|
||||
uint32 entry = atol(cId);
|
||||
uint32 entry = atoul(cId);
|
||||
|
||||
Quest const* quest = sObjectMgr->GetQuestTemplate(entry);
|
||||
|
||||
@@ -269,7 +269,7 @@ public:
|
||||
if (!cId)
|
||||
return false;
|
||||
|
||||
uint32 entry = atol(cId);
|
||||
uint32 entry = atoul(cId);
|
||||
|
||||
Quest const* quest = sObjectMgr->GetQuestTemplate(entry);
|
||||
|
||||
|
||||
@@ -225,7 +225,7 @@ class boss_ragnaros : public CreatureScript
|
||||
events.ScheduleEvent(EVENT_ELEMENTAL_FIRE, urand(10000, 14000));
|
||||
break;
|
||||
case EVENT_MAGMA_BLAST:
|
||||
if (me->IsWithinMeleeRange(me->GetVictim()))
|
||||
if (!me->IsWithinMeleeRange(me->GetVictim()))
|
||||
{
|
||||
DoCastVictim(SPELL_MAGMA_BLAST);
|
||||
if (!_hasYelledMagmaBurst)
|
||||
|
||||
+287
-371
@@ -25,10 +25,9 @@ EndScriptData */
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "hyjal.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "hyjal_trash.h"
|
||||
#include "SpellScript.h"
|
||||
#include "Player.h"
|
||||
#include "hyjal.h"
|
||||
|
||||
enum Texts
|
||||
{
|
||||
@@ -39,42 +38,59 @@ enum Texts
|
||||
SAY_ENRAGE = 5,
|
||||
SAY_DEATH = 6,
|
||||
SAY_SOUL_CHARGE = 7,
|
||||
// YELL_ARCHIMONDE_INTRO = 8
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_DENOUEMENT_WISP = 32124,
|
||||
SPELL_ANCIENT_SPARK = 39349,
|
||||
SPELL_PROTECTION_OF_ELUNE = 38528,
|
||||
SPELL_DENOUEMENT_WISP = 32124,
|
||||
SPELL_ANCIENT_SPARK = 39349,
|
||||
SPELL_PROTECTION_OF_ELUNE = 38528,
|
||||
|
||||
SPELL_DRAIN_WORLD_TREE = 39140,
|
||||
SPELL_DRAIN_WORLD_TREE_2 = 39141,
|
||||
SPELL_DRAIN_WORLD_TREE = 39140,
|
||||
SPELL_DRAIN_WORLD_TREE_TRIGGERED = 39141,
|
||||
|
||||
SPELL_FINGER_OF_DEATH = 31984,
|
||||
SPELL_HAND_OF_DEATH = 35354,
|
||||
SPELL_AIR_BURST = 32014,
|
||||
SPELL_GRIP_OF_THE_LEGION = 31972,
|
||||
SPELL_DOOMFIRE_STRIKE = 31903, //summons two creatures
|
||||
SPELL_DOOMFIRE_SPAWN = 32074,
|
||||
SPELL_DOOMFIRE = 31945,
|
||||
SPELL_SOUL_CHARGE_YELLOW = 32045,
|
||||
SPELL_SOUL_CHARGE_GREEN = 32051,
|
||||
SPELL_SOUL_CHARGE_RED = 32052,
|
||||
SPELL_UNLEASH_SOUL_YELLOW = 32054,
|
||||
SPELL_UNLEASH_SOUL_GREEN = 32057,
|
||||
SPELL_UNLEASH_SOUL_RED = 32053,
|
||||
SPELL_FEAR = 31970,
|
||||
SPELL_FINGER_OF_DEATH = 31984,
|
||||
SPELL_HAND_OF_DEATH = 35354,
|
||||
SPELL_AIR_BURST = 32014,
|
||||
SPELL_GRIP_OF_THE_LEGION = 31972,
|
||||
SPELL_DOOMFIRE_STRIKE = 31903, // summons two creatures
|
||||
SPELL_DOOMFIRE_SPAWN = 32074,
|
||||
SPELL_DOOMFIRE = 31945,
|
||||
SPELL_SOUL_CHARGE_YELLOW = 32045,
|
||||
SPELL_SOUL_CHARGE_GREEN = 32051,
|
||||
SPELL_SOUL_CHARGE_RED = 32052,
|
||||
SPELL_UNLEASH_SOUL_YELLOW = 32054,
|
||||
SPELL_UNLEASH_SOUL_GREEN = 32057,
|
||||
SPELL_UNLEASH_SOUL_RED = 32053,
|
||||
SPELL_FEAR = 31970
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_HAND_OF_DEATH = 1, // Raid wiper
|
||||
EVENT_UNLEASH_SOUL_CHARGE,
|
||||
EVENT_FINGER_OF_DEATH,
|
||||
EVENT_GRIP_OF_THE_LEGION,
|
||||
EVENT_FEAR,
|
||||
EVENT_AIR_BURST,
|
||||
EVENT_DOOMFIRE,
|
||||
EVENT_DISTANCE_CHECK, // This checks if he's too close to the World Tree (75 yards from a point on the tree), if true then he will enrage
|
||||
EVENT_SUMMON_WHISP
|
||||
};
|
||||
|
||||
enum Summons
|
||||
{
|
||||
CREATURE_DOOMFIRE = 18095,
|
||||
CREATURE_DOOMFIRE_SPIRIT = 18104,
|
||||
CREATURE_ANCIENT_WISP = 17946,
|
||||
CREATURE_CHANNEL_TARGET = 22418,
|
||||
NPC_DOOMFIRE = 18095,
|
||||
NPC_DOOMFIRE_SPIRIT = 18104,
|
||||
NPC_ANCIENT_WISP = 17946
|
||||
};
|
||||
|
||||
Position const NordrassilLoc = {5503.713f, -3523.436f, 1608.781f, 0.0f};
|
||||
enum Actions
|
||||
{
|
||||
ACTION_ENRAGE,
|
||||
ACTION_CHANNEL_WORLD_TREE
|
||||
};
|
||||
|
||||
class npc_ancient_wisp : public CreatureScript
|
||||
{
|
||||
@@ -200,7 +216,6 @@ public:
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
|
||||
{
|
||||
//will update once TargetGUID is 0. In case noone actually moves(not likely) and this is 0
|
||||
//when UpdateAI needs it, it will be forced to select randomPoint
|
||||
@@ -249,409 +264,309 @@ class boss_archimonde : public CreatureScript
|
||||
public:
|
||||
boss_archimonde() : CreatureScript("boss_archimonde") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
struct boss_archimondeAI : public BossAI
|
||||
{
|
||||
return GetInstanceAI<boss_archimondeAI>(creature);
|
||||
}
|
||||
|
||||
struct boss_archimondeAI : public hyjal_trashAI
|
||||
{
|
||||
boss_archimondeAI(Creature* creature) : hyjal_trashAI(creature)
|
||||
boss_archimondeAI(Creature* creature) : BossAI(creature, DATA_ARCHIMONDE)
|
||||
{
|
||||
Initialize();
|
||||
instance = creature->GetInstanceScript();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
DoomfireSpiritGUID.Clear();
|
||||
damageTaken = 0;
|
||||
WorldTreeGUID.Clear();
|
||||
|
||||
DrainNordrassilTimer = 0;
|
||||
FearTimer = 42000;
|
||||
AirBurstTimer = 30000;
|
||||
GripOfTheLegionTimer = urand(5000, 25000);
|
||||
DoomfireTimer = 20000;
|
||||
SoulChargeTimer = urand(2000, 30000);
|
||||
SoulChargeCount = 0;
|
||||
MeleeRangeCheckTimer = 15000;
|
||||
HandOfDeathTimer = 2000;
|
||||
WispCount = 0; // When ~30 wisps are summoned, Archimonde dies
|
||||
EnrageTimer = 600000; // 10 minutes
|
||||
CheckDistanceTimer = 30000; // This checks if he's too close to the World Tree (75 yards from a point on the tree), if true then he will enrage
|
||||
SummonWispTimer = 0;
|
||||
_unleashSpell = 0;
|
||||
_chargeSpell = 0;
|
||||
|
||||
Enraged = false;
|
||||
BelowTenPercent = false;
|
||||
HasProtected = false;
|
||||
IsChanneling = false;
|
||||
}
|
||||
|
||||
InstanceScript* instance;
|
||||
|
||||
ObjectGuid DoomfireSpiritGUID;
|
||||
ObjectGuid WorldTreeGUID;
|
||||
|
||||
uint32 DrainNordrassilTimer;
|
||||
uint32 FearTimer;
|
||||
uint32 AirBurstTimer;
|
||||
uint32 GripOfTheLegionTimer;
|
||||
uint32 DoomfireTimer;
|
||||
uint32 SoulChargeTimer;
|
||||
uint8 SoulChargeCount;
|
||||
uint32 MeleeRangeCheckTimer;
|
||||
uint32 HandOfDeathTimer;
|
||||
uint32 SummonWispTimer;
|
||||
uint8 WispCount;
|
||||
uint32 EnrageTimer;
|
||||
uint32 CheckDistanceTimer;
|
||||
|
||||
bool Enraged;
|
||||
bool BelowTenPercent;
|
||||
bool HasProtected;
|
||||
bool IsChanneling;
|
||||
void InitializeAI() override
|
||||
{
|
||||
BossAI::InitializeAI();
|
||||
DoAction(ACTION_CHANNEL_WORLD_TREE);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
instance->SetData(DATA_ARCHIMONDEEVENT, NOT_STARTED);
|
||||
|
||||
Initialize();
|
||||
_Reset();
|
||||
me->RemoveAllAuras(); // Reset Soul Charge auras.
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
me->InterruptSpell(CURRENT_CHANNELED_SPELL);
|
||||
Talk(SAY_AGGRO);
|
||||
DoZoneInCombat();
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_FEAR, 42000);
|
||||
events.ScheduleEvent(EVENT_AIR_BURST, 30000);
|
||||
events.ScheduleEvent(EVENT_GRIP_OF_THE_LEGION, urand(5000, 25000));
|
||||
events.ScheduleEvent(EVENT_DOOMFIRE, 20000);
|
||||
events.ScheduleEvent(EVENT_UNLEASH_SOUL_CHARGE, urand(2000, 30000));
|
||||
events.ScheduleEvent(EVENT_FINGER_OF_DEATH, 15000);
|
||||
events.ScheduleEvent(EVENT_HAND_OF_DEATH, 600000);
|
||||
events.ScheduleEvent(EVENT_DISTANCE_CHECK, 30000);
|
||||
}
|
||||
|
||||
instance->SetData(DATA_ARCHIMONDEEVENT, IN_PROGRESS);
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_HAND_OF_DEATH:
|
||||
DoCastAOE(SPELL_HAND_OF_DEATH);
|
||||
events.ScheduleEvent(EVENT_HAND_OF_DEATH, 2000);
|
||||
break;
|
||||
case EVENT_UNLEASH_SOUL_CHARGE:
|
||||
_chargeSpell = 0;
|
||||
_unleashSpell = 0;
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
switch (urand(0, 2))
|
||||
{
|
||||
case 0:
|
||||
_chargeSpell = SPELL_SOUL_CHARGE_RED;
|
||||
_unleashSpell = SPELL_UNLEASH_SOUL_RED;
|
||||
break;
|
||||
case 1:
|
||||
_chargeSpell = SPELL_SOUL_CHARGE_YELLOW;
|
||||
_unleashSpell = SPELL_UNLEASH_SOUL_YELLOW;
|
||||
break;
|
||||
case 2:
|
||||
_chargeSpell = SPELL_SOUL_CHARGE_GREEN;
|
||||
_unleashSpell = SPELL_UNLEASH_SOUL_GREEN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (me->HasAura(_chargeSpell))
|
||||
{
|
||||
me->RemoveAuraFromStack(_chargeSpell);
|
||||
DoCastVictim(_unleashSpell);
|
||||
SoulChargeCount--;
|
||||
events.ScheduleEvent(EVENT_UNLEASH_SOUL_CHARGE, urand(2000, 30000));
|
||||
}
|
||||
break;
|
||||
case EVENT_FINGER_OF_DEATH:
|
||||
if (!SelectTarget(SELECT_TARGET_RANDOM, 0, 5.0f)) // Checks if there are no targets in melee range
|
||||
{
|
||||
DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0), SPELL_FINGER_OF_DEATH);
|
||||
events.ScheduleEvent(EVENT_FINGER_OF_DEATH, 1000);
|
||||
}
|
||||
else
|
||||
events.ScheduleEvent(EVENT_FINGER_OF_DEATH, 5000);
|
||||
break;
|
||||
case EVENT_GRIP_OF_THE_LEGION:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
|
||||
DoCast(target, SPELL_GRIP_OF_THE_LEGION);
|
||||
events.ScheduleEvent(EVENT_GRIP_OF_THE_LEGION, urand(5000, 25000));
|
||||
break;
|
||||
case EVENT_AIR_BURST:
|
||||
Talk(SAY_AIR_BURST);
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1))
|
||||
DoCast(target, SPELL_AIR_BURST); //not on tank
|
||||
events.ScheduleEvent(EVENT_AIR_BURST, urand(25000, 40000));
|
||||
break;
|
||||
case EVENT_FEAR:
|
||||
DoCastAOE(SPELL_FEAR);
|
||||
events.ScheduleEvent(EVENT_FEAR, 42000);
|
||||
break;
|
||||
case EVENT_DOOMFIRE:
|
||||
Talk(SAY_DOOMFIRE);
|
||||
if (Unit* temp = SelectTarget(SELECT_TARGET_RANDOM, 1))
|
||||
SummonDoomfire(temp);
|
||||
else
|
||||
SummonDoomfire(me->GetVictim());
|
||||
events.ScheduleEvent(EVENT_DOOMFIRE, 20000);
|
||||
break;
|
||||
case EVENT_DISTANCE_CHECK:
|
||||
if (Creature* channelTrigger = instance->GetCreature(DATA_CHANNEL_TARGET))
|
||||
if (me->IsWithinDistInMap(channelTrigger, 75.0f))
|
||||
DoAction(ACTION_ENRAGE);
|
||||
events.ScheduleEvent(EVENT_DISTANCE_CHECK, 5000);
|
||||
break;
|
||||
case EVENT_SUMMON_WHISP:
|
||||
DoSpawnCreature(NPC_ANCIENT_WISP, float(rand32() % 40), float(rand32() % 40), 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
++WispCount;
|
||||
if (WispCount >= 30)
|
||||
me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
|
||||
events.ScheduleEvent(EVENT_SUMMON_WHISP, 1500);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32 &damage) override
|
||||
{
|
||||
if (me->HealthBelowPctDamaged(10, damage))
|
||||
{
|
||||
if (!Enraged)
|
||||
DoAction(ACTION_ENRAGE);
|
||||
|
||||
if (!HasProtected)
|
||||
{
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
|
||||
// All members of raid must get this buff
|
||||
DoCastAOE(SPELL_PROTECTION_OF_ELUNE, true);
|
||||
HasProtected = true;
|
||||
events.ScheduleEvent(EVENT_SUMMON_WHISP, 1500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
|
||||
if (victim && victim->GetTypeId() == TYPEID_PLAYER)
|
||||
GainSoulCharge(victim->ToPlayer());
|
||||
}
|
||||
|
||||
void GainSoulCharge(Player* victim)
|
||||
{
|
||||
switch (victim->getClass())
|
||||
if (victim->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
case CLASS_PRIEST:
|
||||
case CLASS_PALADIN:
|
||||
case CLASS_WARLOCK:
|
||||
victim->CastSpell(me, SPELL_SOUL_CHARGE_RED, true);
|
||||
break;
|
||||
case CLASS_MAGE:
|
||||
case CLASS_ROGUE:
|
||||
case CLASS_WARRIOR:
|
||||
victim->CastSpell(me, SPELL_SOUL_CHARGE_YELLOW, true);
|
||||
break;
|
||||
case CLASS_DRUID:
|
||||
case CLASS_SHAMAN:
|
||||
case CLASS_HUNTER:
|
||||
victim->CastSpell(me, SPELL_SOUL_CHARGE_GREEN, true);
|
||||
break;
|
||||
}
|
||||
switch (victim->getClass())
|
||||
{
|
||||
case CLASS_PRIEST:
|
||||
case CLASS_PALADIN:
|
||||
case CLASS_WARLOCK:
|
||||
victim->CastSpell(me, SPELL_SOUL_CHARGE_RED, true);
|
||||
break;
|
||||
case CLASS_MAGE:
|
||||
case CLASS_ROGUE:
|
||||
case CLASS_WARRIOR:
|
||||
victim->CastSpell(me, SPELL_SOUL_CHARGE_YELLOW, true);
|
||||
break;
|
||||
case CLASS_DRUID:
|
||||
case CLASS_SHAMAN:
|
||||
case CLASS_HUNTER:
|
||||
victim->CastSpell(me, SPELL_SOUL_CHARGE_GREEN, true);
|
||||
break;
|
||||
}
|
||||
|
||||
SoulChargeTimer = urand(2000, 30000);
|
||||
++SoulChargeCount;
|
||||
events.ScheduleEvent(EVENT_UNLEASH_SOUL_CHARGE, urand(2000, 30000));
|
||||
++SoulChargeCount;
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
void JustReachedHome() override
|
||||
{
|
||||
DoAction(ACTION_CHANNEL_WORLD_TREE);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
hyjal_trashAI::JustDied(killer);
|
||||
Talk(SAY_DEATH);
|
||||
|
||||
instance->SetData(DATA_ARCHIMONDEEVENT, DONE);
|
||||
}
|
||||
|
||||
bool CanUseFingerOfDeath()
|
||||
{
|
||||
// First we check if our current victim is in melee range or not.
|
||||
Unit* victim = me->GetVictim();
|
||||
if (victim && me->IsWithinDistInMap(victim, me->GetAttackDistance(victim)))
|
||||
return false;
|
||||
|
||||
ThreatContainer::StorageType const &threatlist = me->getThreatManager().getThreatList();
|
||||
if (threatlist.empty())
|
||||
return false;
|
||||
|
||||
std::list<Unit*> targets;
|
||||
ThreatContainer::StorageType::const_iterator itr = threatlist.begin();
|
||||
for (; itr != threatlist.end(); ++itr)
|
||||
{
|
||||
Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid());
|
||||
if (unit && unit->IsAlive())
|
||||
targets.push_back(unit);
|
||||
}
|
||||
|
||||
if (targets.empty())
|
||||
return false;
|
||||
|
||||
targets.sort(Trinity::ObjectDistanceOrderPred(me));
|
||||
Unit* target = targets.front();
|
||||
if (target)
|
||||
{
|
||||
if (!me->IsWithinDistInMap(target, me->GetAttackDistance(target)))
|
||||
return true; // Cast Finger of Death
|
||||
else // This target is closest, he is our new tank
|
||||
me->AddThreat(target, me->getThreatManager().getThreat(me->GetVictim()));
|
||||
}
|
||||
|
||||
return false;
|
||||
_JustDied();
|
||||
// @todo: remove this when instance script gets updated, kept for compatibility only
|
||||
instance->SetData(DATA_ARCHIMONDE, DONE);
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summoned) override
|
||||
{
|
||||
if (summoned->GetEntry() == CREATURE_ANCIENT_WISP)
|
||||
summoned->AI()->AttackStart(me);
|
||||
else
|
||||
switch (summoned->GetEntry())
|
||||
{
|
||||
summoned->setFaction(me->getFaction());
|
||||
summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
|
||||
summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
case NPC_ANCIENT_WISP:
|
||||
summoned->AI()->AttackStart(me);
|
||||
break;
|
||||
case NPC_DOOMFIRE_SPIRIT:
|
||||
DoomfireSpiritGUID = summoned->GetGUID();
|
||||
break;
|
||||
case NPC_DOOMFIRE:
|
||||
summoned->CastSpell(summoned, SPELL_DOOMFIRE_SPAWN, false);
|
||||
summoned->CastSpell(summoned, SPELL_DOOMFIRE, true, 0, 0, me->GetGUID());
|
||||
|
||||
if (Unit* DoomfireSpirit = ObjectAccessor::GetUnit(*me, DoomfireSpiritGUID))
|
||||
{
|
||||
summoned->GetMotionMaster()->MoveFollow(DoomfireSpirit, 0.0f, 0.0f);
|
||||
DoomfireSpiritGUID.Clear();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (summoned->GetEntry() == CREATURE_DOOMFIRE_SPIRIT)
|
||||
void DoAction(int32 actionId) override
|
||||
{
|
||||
switch (actionId)
|
||||
{
|
||||
DoomfireSpiritGUID = summoned->GetGUID();
|
||||
}
|
||||
|
||||
if (summoned->GetEntry() == CREATURE_DOOMFIRE)
|
||||
{
|
||||
summoned->CastSpell(summoned, SPELL_DOOMFIRE_SPAWN, false);
|
||||
summoned->CastSpell(summoned, SPELL_DOOMFIRE, true, 0, 0, me->GetGUID());
|
||||
|
||||
if (Unit* DoomfireSpirit = ObjectAccessor::GetUnit(*me, DoomfireSpiritGUID))
|
||||
{
|
||||
summoned->GetMotionMaster()->MoveFollow(DoomfireSpirit, 0.0f, 0.0f);
|
||||
DoomfireSpiritGUID.Clear();
|
||||
}
|
||||
case ACTION_ENRAGE:
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
Enraged = true;
|
||||
Talk(SAY_ENRAGE);
|
||||
break;
|
||||
case ACTION_CHANNEL_WORLD_TREE:
|
||||
DoCastAOE(SPELL_DRAIN_WORLD_TREE, true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//this is code doing close to what the summoning spell would do (spell 31903)
|
||||
void SummonDoomfire(Unit* target)
|
||||
{
|
||||
me->SummonCreature(CREATURE_DOOMFIRE_SPIRIT,
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
me->SummonCreature(NPC_DOOMFIRE_SPIRIT,
|
||||
target->GetPositionX()+15.0f, target->GetPositionY()+15.0f, target->GetPositionZ(), 0,
|
||||
TEMPSUMMON_TIMED_DESPAWN, 27000);
|
||||
|
||||
me->SummonCreature(CREATURE_DOOMFIRE,
|
||||
me->SummonCreature(NPC_DOOMFIRE,
|
||||
target->GetPositionX()-15.0f, target->GetPositionY()-15.0f, target->GetPositionZ(), 0,
|
||||
TEMPSUMMON_TIMED_DESPAWN, 27000);
|
||||
}
|
||||
|
||||
void UnleashSoulCharge()
|
||||
{
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
|
||||
bool HasCast = false;
|
||||
uint32 chargeSpell = 0;
|
||||
uint32 unleashSpell = 0;
|
||||
|
||||
switch (urand(0, 2))
|
||||
{
|
||||
case 0:
|
||||
chargeSpell = SPELL_SOUL_CHARGE_RED;
|
||||
unleashSpell = SPELL_UNLEASH_SOUL_RED;
|
||||
break;
|
||||
case 1:
|
||||
chargeSpell = SPELL_SOUL_CHARGE_YELLOW;
|
||||
unleashSpell = SPELL_UNLEASH_SOUL_YELLOW;
|
||||
break;
|
||||
case 2:
|
||||
chargeSpell = SPELL_SOUL_CHARGE_GREEN;
|
||||
unleashSpell = SPELL_UNLEASH_SOUL_GREEN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (me->HasAura(chargeSpell))
|
||||
{
|
||||
me->RemoveAuraFromStack(chargeSpell);
|
||||
DoCastVictim(unleashSpell);
|
||||
HasCast = true;
|
||||
SoulChargeCount--;
|
||||
}
|
||||
|
||||
if (HasCast)
|
||||
SoulChargeTimer = urand(2000, 30000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!me->IsInCombat())
|
||||
{
|
||||
// Do not let the raid skip straight to Archimonde. Visible and hostile ONLY if Azagalor is finished.
|
||||
if ((instance->GetData(DATA_AZGALOREVENT) < DONE) && (me->IsVisible() || (me->getFaction() != 35)))
|
||||
{
|
||||
me->SetVisible(false);
|
||||
me->setFaction(35);
|
||||
}
|
||||
else if ((instance->GetData(DATA_AZGALOREVENT) >= DONE) && (!me->IsVisible() || (me->getFaction() == 35)))
|
||||
{
|
||||
me->setFaction(1720);
|
||||
me->SetVisible(true);
|
||||
}
|
||||
|
||||
if (DrainNordrassilTimer <= diff)
|
||||
{
|
||||
if (!IsChanneling)
|
||||
{
|
||||
Creature* temp = me->SummonCreature(CREATURE_CHANNEL_TARGET, NordrassilLoc, TEMPSUMMON_TIMED_DESPAWN, 1200000);
|
||||
|
||||
if (temp)
|
||||
WorldTreeGUID = temp->GetGUID();
|
||||
|
||||
if (Unit* Nordrassil = ObjectAccessor::GetUnit(*me, WorldTreeGUID))
|
||||
{
|
||||
Nordrassil->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
Nordrassil->SetDisplayId(11686);
|
||||
DoCast(Nordrassil, SPELL_DRAIN_WORLD_TREE);
|
||||
IsChanneling = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Unit* Nordrassil = ObjectAccessor::GetUnit(*me, WorldTreeGUID))
|
||||
{
|
||||
Nordrassil->CastSpell(me, SPELL_DRAIN_WORLD_TREE_2, true);
|
||||
DrainNordrassilTimer = 1000;
|
||||
}
|
||||
} else DrainNordrassilTimer -= diff;
|
||||
}
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (me->HealthBelowPct(10) && !BelowTenPercent && !Enraged)
|
||||
BelowTenPercent = true;
|
||||
|
||||
if (!Enraged)
|
||||
{
|
||||
if (EnrageTimer <= diff)
|
||||
{
|
||||
if (HealthAbovePct(10))
|
||||
{
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
Enraged = true;
|
||||
Talk(SAY_ENRAGE);
|
||||
}
|
||||
} else EnrageTimer -= diff;
|
||||
|
||||
if (CheckDistanceTimer <= diff)
|
||||
{
|
||||
// To simplify the check, we simply summon a Creature in the location and then check how far we are from the creature
|
||||
Creature* Check = me->SummonCreature(CREATURE_CHANNEL_TARGET, NordrassilLoc, TEMPSUMMON_TIMED_DESPAWN, 2000);
|
||||
if (Check)
|
||||
{
|
||||
Check->SetVisible(false);
|
||||
|
||||
if (me->IsWithinDistInMap(Check, 75))
|
||||
{
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
Enraged = true;
|
||||
Talk(SAY_ENRAGE);
|
||||
}
|
||||
}
|
||||
CheckDistanceTimer = 5000;
|
||||
} else CheckDistanceTimer -= diff;
|
||||
}
|
||||
|
||||
if (BelowTenPercent)
|
||||
{
|
||||
if (!HasProtected)
|
||||
{
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
|
||||
//all members of raid must get this buff
|
||||
DoCastVictim(SPELL_PROTECTION_OF_ELUNE, true);
|
||||
HasProtected = true;
|
||||
Enraged = true;
|
||||
}
|
||||
|
||||
if (SummonWispTimer <= diff)
|
||||
{
|
||||
DoSpawnCreature(CREATURE_ANCIENT_WISP, float(rand32() % 40), float(rand32() % 40), 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
SummonWispTimer = 1500;
|
||||
++WispCount;
|
||||
} else SummonWispTimer -= diff;
|
||||
|
||||
if (WispCount >= 30)
|
||||
me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
|
||||
}
|
||||
|
||||
if (Enraged)
|
||||
{
|
||||
if (HandOfDeathTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_HAND_OF_DEATH);
|
||||
HandOfDeathTimer = 2000;
|
||||
} else HandOfDeathTimer -= diff;
|
||||
return; // Don't do anything after this point.
|
||||
}
|
||||
|
||||
if (SoulChargeCount)
|
||||
{
|
||||
if (SoulChargeTimer <= diff)
|
||||
UnleashSoulCharge();
|
||||
else SoulChargeTimer -= diff;
|
||||
}
|
||||
|
||||
if (GripOfTheLegionTimer <= diff)
|
||||
{
|
||||
DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0), SPELL_GRIP_OF_THE_LEGION);
|
||||
GripOfTheLegionTimer = urand(5000, 25000);
|
||||
} else GripOfTheLegionTimer -= diff;
|
||||
|
||||
if (AirBurstTimer <= diff)
|
||||
{
|
||||
Talk(SAY_AIR_BURST);
|
||||
DoCast(SelectTarget(SELECT_TARGET_RANDOM, 1), SPELL_AIR_BURST);//not on tank
|
||||
AirBurstTimer = urand(25000, 40000);
|
||||
} else AirBurstTimer -= diff;
|
||||
|
||||
if (FearTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_FEAR);
|
||||
FearTimer = 42000;
|
||||
} else FearTimer -= diff;
|
||||
|
||||
if (DoomfireTimer <= diff)
|
||||
{
|
||||
Talk(SAY_DOOMFIRE);
|
||||
Unit* temp = SelectTarget(SELECT_TARGET_RANDOM, 1);
|
||||
if (!temp)
|
||||
temp = me->GetVictim();
|
||||
|
||||
//replace with spell cast 31903 once implicitTarget 73 implemented
|
||||
SummonDoomfire(temp);
|
||||
|
||||
//supposedly three doomfire can be up at the same time
|
||||
DoomfireTimer = 20000;
|
||||
} else DoomfireTimer -= diff;
|
||||
|
||||
if (MeleeRangeCheckTimer <= diff)
|
||||
{
|
||||
if (CanUseFingerOfDeath())
|
||||
{
|
||||
DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0), SPELL_FINGER_OF_DEATH);
|
||||
MeleeRangeCheckTimer = 1000;
|
||||
}
|
||||
|
||||
MeleeRangeCheckTimer = 5000;
|
||||
} else MeleeRangeCheckTimer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
void WaypointReached(uint32 /*waypointId*/) override { }
|
||||
private:
|
||||
ObjectGuid DoomfireSpiritGUID;
|
||||
uint8 SoulChargeCount;
|
||||
uint8 WispCount;
|
||||
uint32 _chargeSpell;
|
||||
uint32 _unleashSpell;
|
||||
bool Enraged;
|
||||
bool HasProtected;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetInstanceAI<boss_archimondeAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
// 39142 - Drain World Tree Dummy
|
||||
class spell_archimonde_drain_world_tree_dummy : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_archimonde_drain_world_tree_dummy() : SpellScriptLoader("spell_archimonde_drain_world_tree_dummy") { }
|
||||
|
||||
class spell_archimonde_drain_world_tree_dummy_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_archimonde_drain_world_tree_dummy_SpellScript);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
if (!sSpellMgr->GetSpellInfo(SPELL_DRAIN_WORLD_TREE_TRIGGERED))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Unit* target = GetHitUnit())
|
||||
target->CastSpell(GetCaster(), SPELL_DRAIN_WORLD_TREE_TRIGGERED, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_archimonde_drain_world_tree_dummy_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_archimonde_drain_world_tree_dummy_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_archimonde()
|
||||
@@ -660,4 +575,5 @@ void AddSC_boss_archimonde()
|
||||
new npc_doomfire();
|
||||
new npc_doomfire_targetting();
|
||||
new npc_ancient_wisp();
|
||||
new spell_archimonde_drain_world_tree_dummy();
|
||||
}
|
||||
@@ -44,7 +44,8 @@ enum DataTypes
|
||||
DATA_HORDE_RETREAT = 17,
|
||||
DATA_RAIDDAMAGE = 18,
|
||||
DATA_RESET_RAIDDAMAGE = 19,
|
||||
TYPE_RETREAT = 20
|
||||
TYPE_RETREAT = 20,
|
||||
DATA_CHANNEL_TARGET = 21
|
||||
};
|
||||
|
||||
enum WorldStateIds
|
||||
@@ -77,7 +78,8 @@ enum CreaturesIds
|
||||
KAZROGAL = 17888,
|
||||
AZGALOR = 17842,
|
||||
ARCHIMONDE = 17968,
|
||||
NPC_WORLD_TRIGGER_TINY = 21987
|
||||
NPC_WORLD_TRIGGER_TINY = 21987,
|
||||
NPC_CHANNEL_TARGET = 22418
|
||||
};
|
||||
|
||||
enum GameobjectIds
|
||||
@@ -89,5 +91,6 @@ enum GameobjectIds
|
||||
GO_ROARING_FLAME = 182592
|
||||
};
|
||||
|
||||
#endif
|
||||
#define MINRAIDDAMAGE 700000 // minimal damage before trash can drop loot and reputation, resets if faction leader dies
|
||||
|
||||
#endif
|
||||
@@ -26,7 +26,6 @@ enum Spells
|
||||
SPELL_METEOR = 33814, //infernal visual
|
||||
SPELL_IMMOLATION = 37059,
|
||||
SPELL_FLAME_BUFFET = 31724,
|
||||
NPC_TRIGGER = 21987, //World Trigger (Tiny)
|
||||
MODEL_INVIS = 11686, //invisible model
|
||||
SPELL_DISEASE_CLOUD = 31607,
|
||||
SPELL_KNOCKDOWN = 31610,
|
||||
@@ -465,10 +464,7 @@ public:
|
||||
}
|
||||
if (!meteor)
|
||||
{
|
||||
float x, y, z;
|
||||
me->GetPosition(x, y, z);
|
||||
Creature* trigger = me->SummonCreature(NPC_TRIGGER, x + 8, y + 8, z + 25 + rand32() % 10, me->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 1000);
|
||||
if (trigger)
|
||||
if (Creature* trigger = me->SummonCreature(NPC_WORLD_TRIGGER_TINY, me->GetPositionWithOffset({ 8.0f, 8.0f, frand(25.0f, 35.0f), 0.0f }), TEMPSUMMON_TIMED_DESPAWN, 1000))
|
||||
{
|
||||
trigger->SetVisible(false);
|
||||
trigger->setFaction(me->getFaction());
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#include "hyjal.h"
|
||||
#include "ScriptedEscortAI.h"
|
||||
|
||||
#define MINRAIDDAMAGE 700000//minimal damage before trash can drop loot and reputation, resets if faction leader dies
|
||||
|
||||
struct hyjal_trashAI : public npc_escortAI
|
||||
{
|
||||
hyjal_trashAI(Creature* creature);
|
||||
|
||||
@@ -40,8 +40,16 @@ EndScriptData */
|
||||
4 - Archimonde event
|
||||
*/
|
||||
|
||||
#define YELL_EFFORTS "All of your efforts have been in vain, for the draining of the World Tree has already begun. Soon the heart of your world will beat no more."
|
||||
#define YELL_EFFORTS_NAME "Archimonde"
|
||||
enum Yells
|
||||
{
|
||||
YELL_ARCHIMONDE_INTRO = 8
|
||||
};
|
||||
|
||||
ObjectData const creatureData[] =
|
||||
{
|
||||
{ NPC_CHANNEL_TARGET, DATA_CHANNEL_TARGET },
|
||||
{ 0, 0 } // END
|
||||
};
|
||||
|
||||
class instance_hyjal : public InstanceMapScript
|
||||
{
|
||||
@@ -58,6 +66,7 @@ public:
|
||||
instance_mount_hyjal_InstanceMapScript(Map* map) : InstanceScript(map)
|
||||
{
|
||||
SetHeaders(DataHeader);
|
||||
LoadObjectData(creatureData, nullptr);
|
||||
memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));
|
||||
|
||||
RaidDamage = 0;
|
||||
@@ -105,15 +114,35 @@ public:
|
||||
{
|
||||
switch (creature->GetEntry())
|
||||
{
|
||||
case RAGE_WINTERCHILL: RageWinterchill = creature->GetGUID(); break;
|
||||
case ANETHERON: Anetheron = creature->GetGUID(); break;
|
||||
case KAZROGAL: Kazrogal = creature->GetGUID(); break;
|
||||
case AZGALOR: Azgalor = creature->GetGUID(); break;
|
||||
case ARCHIMONDE: Archimonde = creature->GetGUID(); break;
|
||||
case JAINA: JainaProudmoore = creature->GetGUID(); break;
|
||||
case THRALL: Thrall = creature->GetGUID(); break;
|
||||
case TYRANDE: TyrandeWhisperwind = creature->GetGUID(); break;
|
||||
case RAGE_WINTERCHILL:
|
||||
RageWinterchill = creature->GetGUID();
|
||||
break;
|
||||
case ANETHERON:
|
||||
Anetheron = creature->GetGUID();
|
||||
break;
|
||||
case KAZROGAL:
|
||||
Kazrogal = creature->GetGUID();
|
||||
break;
|
||||
case AZGALOR:
|
||||
Azgalor = creature->GetGUID();
|
||||
break;
|
||||
case ARCHIMONDE:
|
||||
Archimonde = creature->GetGUID();
|
||||
if (GetData(DATA_AZGALOREVENT) != DONE)
|
||||
creature->SetVisible(false);
|
||||
break;
|
||||
case JAINA:
|
||||
JainaProudmoore = creature->GetGUID();
|
||||
break;
|
||||
case THRALL:
|
||||
Thrall = creature->GetGUID();
|
||||
break;
|
||||
case TYRANDE:
|
||||
TyrandeWhisperwind = creature->GetGUID();
|
||||
break;
|
||||
}
|
||||
|
||||
InstanceScript::OnCreatureCreate(creature);
|
||||
}
|
||||
|
||||
ObjectGuid GetGuidData(uint32 identifier) const override
|
||||
@@ -147,40 +176,19 @@ public:
|
||||
m_auiEncounter[2] = data;
|
||||
break;
|
||||
case DATA_AZGALOREVENT:
|
||||
m_auiEncounter[3] = data;
|
||||
if (data == DONE)
|
||||
{
|
||||
m_auiEncounter[3] = data;
|
||||
if (data == DONE)
|
||||
instance->LoadGrid(5581.49f, -3445.63f);
|
||||
if (Creature* archimonde = instance->GetCreature(Archimonde))
|
||||
{
|
||||
if (ArchiYell)
|
||||
break;
|
||||
archimonde->SetVisible(true);
|
||||
|
||||
ArchiYell = true;
|
||||
|
||||
Creature* creature = instance->GetCreature(Azgalor);
|
||||
if (creature)
|
||||
if (!ArchiYell)
|
||||
{
|
||||
Creature* unit = creature->SummonCreature(NPC_WORLD_TRIGGER_TINY, creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000);
|
||||
ArchiYell = true;
|
||||
archimonde->AI()->Talk(YELL_ARCHIMONDE_INTRO);
|
||||
|
||||
Map* map = creature->GetMap();
|
||||
if (map->IsDungeon() && unit)
|
||||
{
|
||||
unit->SetVisible(false);
|
||||
Map::PlayerList const &PlayerList = map->GetPlayers();
|
||||
if (PlayerList.isEmpty())
|
||||
return;
|
||||
|
||||
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
|
||||
{
|
||||
if (Player* player = i->GetSource())
|
||||
{
|
||||
WorldPacket packet;
|
||||
|
||||
ChatHandler::BuildChatPacket(packet, CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, unit, player, YELL_EFFORTS);
|
||||
player->SendDirectMessage(&packet);
|
||||
player->PlayDirectSound(10986, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -292,6 +292,7 @@ public:
|
||||
break;
|
||||
}
|
||||
player->CLOSE_GOSSIP_MENU();
|
||||
ai->SetDespawnAtFar(false);
|
||||
creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -19,13 +19,15 @@
|
||||
/* ScriptData
|
||||
SDName: Dustwallow_Marsh
|
||||
SD%Complete: 95
|
||||
SDComment: Quest support: 1270, 1222, 27245
|
||||
SDComment: Quest support: 558, 11126, 11142, 11174, Vendor Nat Pagle
|
||||
SDCategory: Dustwallow Marsh
|
||||
EndScriptData */
|
||||
|
||||
/* ContentData
|
||||
npc_stinky
|
||||
go_blackhoof_cage
|
||||
npc_lady_jaina_proudmoore
|
||||
npc_nat_pagle
|
||||
npc_private_hendel
|
||||
npc_cassa_crimsonwing - handled by npc_taxi
|
||||
EndContentData */
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
@@ -36,99 +38,6 @@ EndContentData */
|
||||
#include "Player.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
/*######
|
||||
## npc_risen_husk_spirit
|
||||
######*/
|
||||
|
||||
enum HauntingWitchHill
|
||||
{
|
||||
// Quest
|
||||
QUEST_WHATS_HAUNTING_WITCH_HILL = 11180,
|
||||
|
||||
// General spells
|
||||
SPELL_SUMMON_RESTLESS_APPARITION = 42511,
|
||||
SPELL_WITCH_HILL_INFORMATION_CREDIT = 42512,
|
||||
|
||||
// Risen Husk specific
|
||||
SPELL_CONSUME_FLESH = 37933,
|
||||
NPC_RISEN_HUSK = 23555,
|
||||
|
||||
// Risen Spirit specific
|
||||
SPELL_INTANGIBLE_PRESENCE = 43127,
|
||||
NPC_RISEN_SPIRIT = 23554,
|
||||
|
||||
// Events
|
||||
EVENT_CONSUME_FLESH = 1,
|
||||
EVENT_INTANGIBLE_PRESENCE = 2,
|
||||
};
|
||||
|
||||
class npc_risen_husk_spirit : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_risen_husk_spirit() : CreatureScript("npc_risen_husk_spirit") { }
|
||||
|
||||
struct npc_risen_husk_spiritAI : public ScriptedAI
|
||||
{
|
||||
npc_risen_husk_spiritAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
events.Reset();
|
||||
if (me->GetEntry() == NPC_RISEN_HUSK)
|
||||
events.ScheduleEvent(EVENT_CONSUME_FLESH, 5000);
|
||||
else if (me->GetEntry() == NPC_RISEN_SPIRIT)
|
||||
events.ScheduleEvent(EVENT_INTANGIBLE_PRESENCE, 5000);
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
if (killer->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
if (killer->ToPlayer()->GetQuestStatus(QUEST_WHATS_HAUNTING_WITCH_HILL) == QUEST_STATUS_INCOMPLETE)
|
||||
{
|
||||
DoCast(me, SPELL_SUMMON_RESTLESS_APPARITION, true);
|
||||
DoCast(killer, SPELL_WITCH_HILL_INFORMATION_CREDIT, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_CONSUME_FLESH:
|
||||
DoCastVictim(SPELL_CONSUME_FLESH);
|
||||
events.ScheduleEvent(EVENT_CONSUME_FLESH, 15000);
|
||||
break;
|
||||
case EVENT_INTANGIBLE_PRESENCE:
|
||||
DoCastVictim(SPELL_INTANGIBLE_PRESENCE);
|
||||
events.ScheduleEvent(EVENT_INTANGIBLE_PRESENCE, 15000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap events;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_risen_husk_spiritAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
/*######
|
||||
## npc_lady_jaina_proudmoore
|
||||
######*/
|
||||
@@ -366,131 +275,6 @@ public:
|
||||
|
||||
};
|
||||
|
||||
/*######
|
||||
## npc_stinky
|
||||
######*/
|
||||
|
||||
enum Stinky
|
||||
{
|
||||
QUEST_STINKYS_ESCAPE_H = 1270,
|
||||
QUEST_STINKYS_ESCAPE_A = 1222,
|
||||
SAY_QUEST_ACCEPTED = 0,
|
||||
SAY_STAY_1 = 1,
|
||||
SAY_STAY_2 = 2,
|
||||
SAY_STAY_3 = 3,
|
||||
SAY_STAY_4 = 4,
|
||||
SAY_STAY_5 = 5,
|
||||
SAY_STAY_6 = 6,
|
||||
SAY_QUEST_COMPLETE = 7,
|
||||
SAY_ATTACKED_1 = 8,
|
||||
EMOTE_DISAPPEAR = 9
|
||||
};
|
||||
|
||||
class npc_stinky : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_stinky() : CreatureScript("npc_stinky") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_stinkyAI(creature);
|
||||
}
|
||||
|
||||
bool OnQuestAccept(Player* player, Creature* creature, Quest const* quest) override
|
||||
{
|
||||
if (quest->GetQuestId() == QUEST_STINKYS_ESCAPE_H || quest->GetQuestId() == QUEST_STINKYS_ESCAPE_A)
|
||||
{
|
||||
if (npc_stinkyAI* pEscortAI = CAST_AI(npc_stinky::npc_stinkyAI, creature->AI()))
|
||||
{
|
||||
creature->setFaction(FACTION_ESCORT_N_NEUTRAL_ACTIVE);
|
||||
creature->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
creature->AI()->Talk(SAY_QUEST_ACCEPTED);
|
||||
pEscortAI->Start(false, false, player->GetGUID());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct npc_stinkyAI : public npc_escortAI
|
||||
{
|
||||
npc_stinkyAI(Creature* creature) : npc_escortAI(creature) { }
|
||||
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
switch (waypointId)
|
||||
{
|
||||
case 7:
|
||||
Talk(SAY_STAY_1, player);
|
||||
break;
|
||||
case 11:
|
||||
Talk(SAY_STAY_2, player);
|
||||
break;
|
||||
case 25:
|
||||
Talk(SAY_STAY_3, player);
|
||||
break;
|
||||
case 26:
|
||||
Talk(SAY_STAY_4, player);
|
||||
break;
|
||||
case 27:
|
||||
Talk(SAY_STAY_5, player);
|
||||
break;
|
||||
case 28:
|
||||
Talk(SAY_STAY_6, player);
|
||||
me->SetStandState(UNIT_STAND_STATE_KNEEL);
|
||||
break;
|
||||
case 29:
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
break;
|
||||
case 37:
|
||||
Talk(SAY_QUEST_COMPLETE, player);
|
||||
me->SetSpeed(MOVE_RUN, 1.2f, true);
|
||||
me->SetWalk(false);
|
||||
if (player->GetQuestStatus(QUEST_STINKYS_ESCAPE_H))
|
||||
player->GroupEventHappens(QUEST_STINKYS_ESCAPE_H, me);
|
||||
if (player->GetQuestStatus(QUEST_STINKYS_ESCAPE_A))
|
||||
player->GroupEventHappens(QUEST_STINKYS_ESCAPE_A, me);
|
||||
break;
|
||||
case 39:
|
||||
Talk(EMOTE_DISAPPEAR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* who) override
|
||||
{
|
||||
Talk(SAY_ATTACKED_1, who);
|
||||
}
|
||||
|
||||
void Reset() override { }
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Player* player = GetPlayerForEscort();
|
||||
if (player && HasEscortState(STATE_ESCORT_ESCORTING))
|
||||
{
|
||||
if (player->GetQuestStatus(QUEST_STINKYS_ESCAPE_H))
|
||||
player->FailQuest(QUEST_STINKYS_ESCAPE_H);
|
||||
|
||||
if (player->GetQuestStatus(QUEST_STINKYS_ESCAPE_A))
|
||||
player->FailQuest(QUEST_STINKYS_ESCAPE_A);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 uiDiff) override
|
||||
{
|
||||
npc_escortAI::UpdateAI(uiDiff);
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
enum SpellScripts
|
||||
{
|
||||
@@ -631,41 +415,13 @@ class spell_energize_aoe : public SpellScriptLoader
|
||||
}
|
||||
};
|
||||
|
||||
/*######
|
||||
## go_blackhoof_cage
|
||||
######*/
|
||||
|
||||
enum PrisonersOfTheGrimTotems
|
||||
{
|
||||
NPC_THERAMORE_PRISONER = 23720,
|
||||
SAY_FREE = 0,
|
||||
};
|
||||
|
||||
class go_blackhoof_cage : public GameObjectScript
|
||||
{
|
||||
public:
|
||||
go_blackhoof_cage() : GameObjectScript("go_blackhoof_cage") { }
|
||||
|
||||
bool OnGossipHello(Player* player, GameObject* go) override
|
||||
{
|
||||
go->UseDoorOrButton();
|
||||
if (Creature* prisoner = go->FindNearestCreature(NPC_THERAMORE_PRISONER, 1.0f))
|
||||
{
|
||||
if (player)
|
||||
player->KilledMonsterCredit(NPC_THERAMORE_PRISONER);
|
||||
|
||||
prisoner->AI()->Talk(SAY_FREE); // We also emote cry here (handled in creature_text.emote)
|
||||
prisoner->DespawnOrUnsummon(6000);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_dustwallow_marsh()
|
||||
{
|
||||
new npc_stinky();
|
||||
new npc_lady_jaina_proudmoore();
|
||||
new npc_nat_pagle();
|
||||
new npc_private_hendel();
|
||||
new npc_zelfrax();
|
||||
new spell_ooze_zap();
|
||||
new spell_ooze_zap_channel_end();
|
||||
new spell_energize_aoe();
|
||||
new go_blackhoof_cage();
|
||||
}
|
||||
@@ -362,7 +362,7 @@ class NecroticPlagueTargetCheck : public std::unary_function<Unit*, bool>
|
||||
|
||||
bool operator()(Unit* unit) const
|
||||
{
|
||||
if (!unit || unit == _sourceObj || !unit->isTargetableForAttack() || unit->IsTotem() || unit->HasAura(SPELL_PLAGUE_AVOIDANCE))
|
||||
if (!unit || unit == _sourceObj || !unit->isTargetableForAttack() || unit->GetTypeId() != TYPEID_PLAYER || unit->HasAura(SPELL_PLAGUE_AVOIDANCE))
|
||||
return false;
|
||||
if ((_notAura1 && unit->HasAura(_notAura1)) || (_notAura2 && unit->HasAura(_notAura2)))
|
||||
return false;
|
||||
|
||||
@@ -30,26 +30,23 @@ EndScriptData */
|
||||
#include "naxxramas.h"
|
||||
#include "Player.h"
|
||||
|
||||
enum Yells
|
||||
enum Texts
|
||||
{
|
||||
//when shappiron dies. dialog between kel and lich king (in this order)
|
||||
SAY_SAPP_DIALOG1 = 0, //not used
|
||||
SAY_SAPP_DIALOG2_LICH = 1, //not used
|
||||
SAY_SAPP_DIALOG3 = 2, //not used
|
||||
SAY_SAPP_DIALOG4_LICH = 3, //not used
|
||||
SAY_SAPP_DIALOG5 = 4, //not used
|
||||
SAY_CAT_DIED = 5, //when cat dies, not used
|
||||
//when each of the 4 wing bosses dies
|
||||
SAY_TAUNT = 6,
|
||||
SAY_AGGRO = 7,
|
||||
SAY_SLAY = 8,
|
||||
SAY_DEATH = 9,
|
||||
SAY_CHAIN = 10,
|
||||
SAY_FROST_BLAST = 11,
|
||||
SAY_REQUEST_AID = 12, //start of phase 3
|
||||
SAY_ANSWER_REQUEST = 13, //lich king answer
|
||||
EMOTE_PHASE_TWO = 13,
|
||||
SAY_SUMMON_MINIONS = 14, //start of phase 1
|
||||
SAY_SPECIAL = 15
|
||||
SAY_SPECIAL = 15,
|
||||
|
||||
// The Lich King
|
||||
SAY_ANSWER_REQUEST = 3,
|
||||
|
||||
// Old World Trigger
|
||||
SAY_GUARDIAN_SPAWNED = 0
|
||||
};
|
||||
|
||||
enum Events
|
||||
@@ -70,7 +67,10 @@ enum Events
|
||||
EVENT_TRIGGER,
|
||||
|
||||
EVENT_PHASE,
|
||||
EVENT_MORTAL_WOUND
|
||||
EVENT_MORTAL_WOUND,
|
||||
|
||||
EVENT_ANSWER_REQUEST,
|
||||
EVENT_SUMMON_GUARDIANS
|
||||
};
|
||||
|
||||
enum Spells
|
||||
@@ -123,6 +123,13 @@ enum Spells
|
||||
SPELL_MORTAL_WOUND = 28467
|
||||
};
|
||||
|
||||
enum Phases
|
||||
{
|
||||
PHASE_ONE = 1, // Players move in the circle and Kel'Thuzad spawns his minions.
|
||||
PHASE_TWO = 2, // Starts on a timer.
|
||||
PHASE_THREE = 3 // At 45% health.
|
||||
};
|
||||
|
||||
enum Creatures
|
||||
{
|
||||
NPC_WASTE = 16427, // Soldiers of the Frozen Wastes
|
||||
@@ -270,15 +277,11 @@ public:
|
||||
void Initialize()
|
||||
{
|
||||
nGuardiansOfIcecrownCount = 0;
|
||||
uiGuardiansOfIcecrownTimer = 5000; // 5 seconds for summoning each Guardian of Icecrown in phase 3
|
||||
|
||||
Phase = 0;
|
||||
nAbomination = 0;
|
||||
nWeaver = 0;
|
||||
}
|
||||
|
||||
uint32 Phase;
|
||||
uint32 uiGuardiansOfIcecrownTimer;
|
||||
uint32 uiFaction;
|
||||
|
||||
uint8 nGuardiansOfIcecrownCount;
|
||||
@@ -345,7 +348,6 @@ public:
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
me->setFaction(uiFaction);
|
||||
|
||||
_EnterCombat();
|
||||
for (uint8 i = 0; i <= 3; ++i)
|
||||
{
|
||||
@@ -354,10 +356,10 @@ public:
|
||||
}
|
||||
DoCast(me, SPELL_KELTHUZAD_CHANNEL, false);
|
||||
Talk(SAY_SUMMON_MINIONS);
|
||||
Phase = 1;
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetFloatValue(UNIT_FIELD_COMBATREACH, 4);
|
||||
me->SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, 4);
|
||||
events.SetPhase(PHASE_ONE);
|
||||
events.ScheduleEvent(EVENT_TRIGGER, 5000);
|
||||
events.ScheduleEvent(EVENT_WASTE, 15000);
|
||||
events.ScheduleEvent(EVENT_ABOMIN, 30000);
|
||||
@@ -365,6 +367,23 @@ public:
|
||||
events.ScheduleEvent(EVENT_PHASE, 228000);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
|
||||
{
|
||||
if (events.IsInPhase(PHASE_TWO) && me->HealthBelowPctDamaged(45, damage))
|
||||
{
|
||||
Talk(SAY_REQUEST_AID);
|
||||
events.SetPhase(PHASE_THREE);
|
||||
events.ScheduleEvent(EVENT_ANSWER_REQUEST, 4000);
|
||||
|
||||
for (uint8 i = 0; i <= 3; ++i)
|
||||
{
|
||||
if (GameObject* portal = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_KELTHUZAD_PORTAL01 + i)))
|
||||
if (portal->getLootState() == GO_READY)
|
||||
portal->UseDoorOrButton();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
@@ -372,7 +391,7 @@ public:
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (Phase == 1)
|
||||
if (events.IsInPhase(PHASE_ONE))
|
||||
{
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
@@ -405,6 +424,7 @@ public:
|
||||
case EVENT_PHASE:
|
||||
events.Reset();
|
||||
Talk(SAY_AGGRO);
|
||||
Talk(EMOTE_PHASE_TWO);
|
||||
spawns.DespawnAll();
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->CastStop();
|
||||
@@ -417,7 +437,7 @@ public:
|
||||
events.ScheduleEvent(EVENT_BLAST, urand(60000, 120000));
|
||||
if (GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL)
|
||||
events.ScheduleEvent(EVENT_CHAIN, urand(30000, 60000));
|
||||
Phase = 2;
|
||||
events.SetPhase(PHASE_TWO);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -426,38 +446,6 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
//start phase 3 when we are 45% health
|
||||
if (Phase != 3)
|
||||
{
|
||||
if (HealthBelowPct(45))
|
||||
{
|
||||
Phase = 3;
|
||||
Talk(SAY_REQUEST_AID);
|
||||
//here Lich King should respond to KelThuzad but I don't know which Creature to make talk
|
||||
//so for now just make Kelthuzad says it.
|
||||
Talk(SAY_ANSWER_REQUEST);
|
||||
|
||||
for (uint8 i = 0; i <= 3; ++i)
|
||||
{
|
||||
if (GameObject* portal = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_KELTHUZAD_PORTAL01 + i)))
|
||||
if (portal->getLootState() == GO_READY)
|
||||
portal->UseDoorOrButton();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (nGuardiansOfIcecrownCount < RAID_MODE(2, 4))
|
||||
{
|
||||
if (uiGuardiansOfIcecrownTimer <= diff)
|
||||
{
|
||||
/// @todo Add missing text
|
||||
if (Creature* guardian = DoSummon(NPC_ICECROWN, Pos[RAND(2, 5, 8, 11)]))
|
||||
guardian->SetFloatValue(UNIT_FIELD_COMBATREACH, 2);
|
||||
++nGuardiansOfIcecrownCount;
|
||||
uiGuardiansOfIcecrownTimer = 5000;
|
||||
}
|
||||
else uiGuardiansOfIcecrownTimer -= diff;
|
||||
}
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
@@ -609,6 +597,18 @@ public:
|
||||
Talk(SAY_FROST_BLAST);
|
||||
events.Repeat(30000, 90000);
|
||||
break;
|
||||
case EVENT_ANSWER_REQUEST:
|
||||
if (Creature* lichKing = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_LICH_KING)))
|
||||
lichKing->AI()->Talk(SAY_ANSWER_REQUEST);
|
||||
events.ScheduleEvent(EVENT_SUMMON_GUARDIANS, 5000);
|
||||
break;
|
||||
case EVENT_SUMMON_GUARDIANS:
|
||||
if (Creature* guardian = DoSummon(NPC_ICECROWN, Pos[RAND(2, 5, 8, 11)]))
|
||||
guardian->SetFloatValue(UNIT_FIELD_COMBATREACH, 2);
|
||||
++nGuardiansOfIcecrownCount;
|
||||
if (nGuardiansOfIcecrownCount < RAID_MODE(2, 4))
|
||||
events.ScheduleEvent(EVENT_SUMMON_GUARDIANS, 5000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -69,6 +69,15 @@ MinionData const minionData[] =
|
||||
{ 0, 0, }
|
||||
};
|
||||
|
||||
ObjectData const objectData[] =
|
||||
{
|
||||
{ GO_NAXX_PORTAL_ARACHNID, DATA_NAXX_PORTAL_ARACHNID },
|
||||
{ GO_NAXX_PORTAL_CONSTRUCT, DATA_NAXX_PORTAL_CONSTRUCT },
|
||||
{ GO_NAXX_PORTAL_PLAGUE, DATA_NAXX_PORTAL_PLAGUE },
|
||||
{ GO_NAXX_PORTAL_MILITARY, DATA_NAXX_PORTAL_MILITARY },
|
||||
{ 0, 0, }
|
||||
};
|
||||
|
||||
float const HeiganPos[2] = { 2796.0f, -3707.0f };
|
||||
float const HeiganEruptionSlope[3] =
|
||||
{
|
||||
@@ -111,10 +120,12 @@ class instance_naxxramas : public InstanceMapScript
|
||||
SetBossNumber(EncounterCount);
|
||||
LoadDoorData(doorData);
|
||||
LoadMinionData(minionData);
|
||||
LoadObjectData(nullptr, objectData);
|
||||
|
||||
minHorsemenDiedTime = 0;
|
||||
maxHorsemenDiedTime = 0;
|
||||
AbominationCount = 0;
|
||||
CurrentWingTaunt = SAY_KELTHUZAD_FIRST_WING_TAUNT;
|
||||
|
||||
playerDied = 0;
|
||||
}
|
||||
@@ -156,6 +167,9 @@ class instance_naxxramas : public InstanceMapScript
|
||||
case NPC_KEL_THUZAD:
|
||||
KelthuzadGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_LICH_KING:
|
||||
LichKingGUID = creature->GetGUID();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -201,11 +215,30 @@ class instance_naxxramas : public InstanceMapScript
|
||||
case GO_KELTHUZAD_TRIGGER:
|
||||
KelthuzadTriggerGUID = go->GetGUID();
|
||||
break;
|
||||
case GO_ROOM_KELTHUZAD:
|
||||
KelthuzadDoorGUID = go->GetGUID();
|
||||
break;
|
||||
case GO_NAXX_PORTAL_ARACHNID:
|
||||
if (GetBossState(BOSS_MAEXXNA) == DONE)
|
||||
go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
break;
|
||||
case GO_NAXX_PORTAL_CONSTRUCT:
|
||||
if (GetBossState(BOSS_THADDIUS) == DONE)
|
||||
go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
break;
|
||||
case GO_NAXX_PORTAL_PLAGUE:
|
||||
if (GetBossState(BOSS_LOATHEB) == DONE)
|
||||
go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
break;
|
||||
case GO_NAXX_PORTAL_MILITARY:
|
||||
if (GetBossState(BOSS_HORSEMEN) == DONE)
|
||||
go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
AddDoor(go, true);
|
||||
InstanceScript::OnGameObjectCreate(go);
|
||||
}
|
||||
|
||||
void OnGameObjectRemove(GameObject* go) override
|
||||
@@ -232,7 +265,7 @@ class instance_naxxramas : public InstanceMapScript
|
||||
break;
|
||||
}
|
||||
|
||||
AddDoor(go, false);
|
||||
InstanceScript::OnGameObjectRemove(go);
|
||||
}
|
||||
|
||||
void OnUnitDeath(Unit* unit) override
|
||||
@@ -242,6 +275,15 @@ class instance_naxxramas : public InstanceMapScript
|
||||
playerDied = 1;
|
||||
SaveToDB();
|
||||
}
|
||||
|
||||
if (Creature* creature = unit->ToCreature())
|
||||
if (creature->GetEntry() == NPC_BIGGLESWORTH)
|
||||
{
|
||||
// Loads Kel'Thuzad's grid. We need this as he must be active in order for his texts to work.
|
||||
instance->LoadGrid(3749.67f, -5114.06f);
|
||||
if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID))
|
||||
kelthuzad->AI()->Talk(SAY_KELTHUZAD_CAT_DIED);
|
||||
}
|
||||
}
|
||||
|
||||
void SetData(uint32 id, uint32 value) override
|
||||
@@ -327,6 +369,8 @@ class instance_naxxramas : public InstanceMapScript
|
||||
return PortalsGUID[3];
|
||||
case DATA_KELTHUZAD_TRIGGER:
|
||||
return KelthuzadTriggerGUID;
|
||||
case DATA_LICH_KING:
|
||||
return LichKingGUID;
|
||||
}
|
||||
|
||||
return ObjectGuid::Empty;
|
||||
@@ -337,18 +381,156 @@ class instance_naxxramas : public InstanceMapScript
|
||||
if (!InstanceScript::SetBossState(id, state))
|
||||
return false;
|
||||
|
||||
if (id == BOSS_HORSEMEN && state == DONE)
|
||||
switch (id)
|
||||
{
|
||||
if (GameObject* horsemenChest = instance->GetGameObject(HorsemenChestGUID))
|
||||
{
|
||||
horsemenChest->SetRespawnTime(horsemenChest->GetRespawnDelay());
|
||||
horsemenChest->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
}
|
||||
case BOSS_MAEXXNA:
|
||||
if (state == DONE)
|
||||
{
|
||||
if (GameObject* teleporter = GetGameObject(DATA_NAXX_PORTAL_ARACHNID))
|
||||
teleporter->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
|
||||
events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000);
|
||||
}
|
||||
break;
|
||||
case BOSS_LOATHEB:
|
||||
if (state == DONE)
|
||||
{
|
||||
if (GameObject* teleporter = GetGameObject(DATA_NAXX_PORTAL_PLAGUE))
|
||||
teleporter->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
|
||||
events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000);
|
||||
}
|
||||
break;
|
||||
case BOSS_THADDIUS:
|
||||
if (state == DONE)
|
||||
{
|
||||
if (GameObject* teleporter = GetGameObject(DATA_NAXX_PORTAL_CONSTRUCT))
|
||||
teleporter->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
|
||||
events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000);
|
||||
}
|
||||
break;
|
||||
case BOSS_GOTHIK:
|
||||
if (state == DONE)
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_KORTHAZZ, 10000);
|
||||
break;
|
||||
case BOSS_HORSEMEN:
|
||||
if (state == DONE)
|
||||
{
|
||||
if (GameObject* horsemenChest = instance->GetGameObject(HorsemenChestGUID))
|
||||
{
|
||||
horsemenChest->SetRespawnTime(horsemenChest->GetRespawnDelay());
|
||||
horsemenChest->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
}
|
||||
|
||||
if (GameObject* teleporter = GetGameObject(DATA_NAXX_PORTAL_MILITARY))
|
||||
teleporter->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
|
||||
events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000);
|
||||
}
|
||||
break;
|
||||
case BOSS_SAPPHIRON:
|
||||
if (state == DONE)
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD, 6000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Update(uint32 diff) override
|
||||
{
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_DIALOGUE_GOTHIK_KORTHAZZ:
|
||||
if (Creature* korthazz = instance->GetCreature(ThaneGUID))
|
||||
korthazz->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_ZELIEK, 5000);
|
||||
break;
|
||||
case EVENT_DIALOGUE_GOTHIK_ZELIEK:
|
||||
if (Creature* zeliek = instance->GetCreature(SirGUID))
|
||||
zeliek->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_BLAUMEUX, 6000);
|
||||
break;
|
||||
case EVENT_DIALOGUE_GOTHIK_BLAUMEUX:
|
||||
if (Creature* blaumeux = instance->GetCreature(LadyGUID))
|
||||
blaumeux->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_RIVENDARE, 6000);
|
||||
break;
|
||||
case EVENT_DIALOGUE_GOTHIK_RIVENDARE:
|
||||
if (Creature* rivendare = instance->GetCreature(BaronGUID))
|
||||
rivendare->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_BLAUMEUX2, 6000);
|
||||
break;
|
||||
case EVENT_DIALOGUE_GOTHIK_BLAUMEUX2:
|
||||
if (Creature* blaumeux = instance->GetCreature(LadyGUID))
|
||||
blaumeux->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN2);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_ZELIEK2, 6000);
|
||||
break;
|
||||
case EVENT_DIALOGUE_GOTHIK_ZELIEK2:
|
||||
if (Creature* zeliek = instance->GetCreature(SirGUID))
|
||||
zeliek->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN2);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_KORTHAZZ2, 6000);
|
||||
break;
|
||||
case EVENT_DIALOGUE_GOTHIK_KORTHAZZ2:
|
||||
if (Creature* korthazz = instance->GetCreature(ThaneGUID))
|
||||
korthazz->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN2);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_RIVENDARE2, 6000);
|
||||
break;
|
||||
case EVENT_DIALOGUE_GOTHIK_RIVENDARE2:
|
||||
if (Creature* rivendare = instance->GetCreature(BaronGUID))
|
||||
rivendare->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN2);
|
||||
break;
|
||||
case EVENT_KELTHUZAD_WING_TAUNT:
|
||||
// Loads Kel'Thuzad's grid. We need this as he must be active in order for his texts to work.
|
||||
instance->LoadGrid(3749.67f, -5114.06f);
|
||||
if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID))
|
||||
kelthuzad->AI()->Talk(CurrentWingTaunt);
|
||||
++CurrentWingTaunt;
|
||||
break;
|
||||
case EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD:
|
||||
if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID))
|
||||
kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD);
|
||||
HandleGameObject(KelthuzadDoorGUID, false);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_LICHKING, 6000);
|
||||
break;
|
||||
case EVENT_DIALOGUE_SAPPHIRON_LICHKING:
|
||||
if (Creature* lichKing = instance->GetCreature(LichKingGUID))
|
||||
lichKing->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_LICH_KING);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD2, 16000);
|
||||
break;
|
||||
case EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD2:
|
||||
if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID))
|
||||
kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD2);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_LICHKING2, 9000);
|
||||
break;
|
||||
case EVENT_DIALOGUE_SAPPHIRON_LICHKING2:
|
||||
if (Creature* lichKing = instance->GetCreature(LichKingGUID))
|
||||
lichKing->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_LICH_KING2);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD3, 12000);
|
||||
break;
|
||||
case EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD3:
|
||||
if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID))
|
||||
kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD3);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD4, 6000);
|
||||
break;
|
||||
case EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD4:
|
||||
if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID))
|
||||
kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD4);
|
||||
HandleGameObject(KelthuzadDoorGUID, true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HeiganErupt(uint32 section)
|
||||
{
|
||||
for (uint32 i = 0; i < 4; ++i)
|
||||
@@ -450,10 +632,15 @@ class instance_naxxramas : public InstanceMapScript
|
||||
ObjectGuid KelthuzadGUID;
|
||||
ObjectGuid KelthuzadTriggerGUID;
|
||||
ObjectGuid PortalsGUID[4];
|
||||
ObjectGuid KelthuzadDoorGUID;
|
||||
ObjectGuid LichKingGUID;
|
||||
uint8 AbominationCount;
|
||||
uint8 CurrentWingTaunt;
|
||||
|
||||
/* The Immortal / The Undying */
|
||||
uint32 playerDied;
|
||||
|
||||
EventMap events;
|
||||
};
|
||||
|
||||
InstanceScript* GetInstanceScript(InstanceMap* map) const override
|
||||
|
||||
@@ -52,6 +52,11 @@ enum Data
|
||||
DATA_HORSEMEN2,
|
||||
DATA_HORSEMEN3,
|
||||
DATA_ABOMINATION_KILLED,
|
||||
|
||||
DATA_NAXX_PORTAL_ARACHNID,
|
||||
DATA_NAXX_PORTAL_CONSTRUCT,
|
||||
DATA_NAXX_PORTAL_PLAGUE,
|
||||
DATA_NAXX_PORTAL_MILITARY
|
||||
};
|
||||
|
||||
enum Data64
|
||||
@@ -71,6 +76,7 @@ enum Data64
|
||||
DATA_KELTHUZAD_PORTAL03,
|
||||
DATA_KELTHUZAD_PORTAL04,
|
||||
DATA_KELTHUZAD_TRIGGER,
|
||||
DATA_LICH_KING
|
||||
};
|
||||
|
||||
enum CreaturesIds
|
||||
@@ -89,7 +95,10 @@ enum CreaturesIds
|
||||
NPC_CRYPT_GUARD = 16573,
|
||||
NPC_NAXXRAMAS_FOLLOWER = 16505,
|
||||
NPC_FOLLOWER_WORSHIPPER = 16506,
|
||||
NPC_DK_UNDERSTUDY = 16803
|
||||
NPC_DK_UNDERSTUDY = 16803,
|
||||
NPC_BIGGLESWORTH = 16998,
|
||||
NPC_LICH_KING = 16980,
|
||||
NPC_OLD_WORLD_TRIGGER = 15384
|
||||
};
|
||||
|
||||
enum GameObjectsIds
|
||||
@@ -133,7 +142,13 @@ enum GameObjectsIds
|
||||
GO_CONS_EYE_RAMP_BOSS = 181232,
|
||||
GO_CONS_NOX_TESLA_FEUGEN = 181477,
|
||||
GO_CONS_NOX_TESLA_STALAGG = 181478,
|
||||
GO_BIRTH = 181356
|
||||
GO_BIRTH = 181356,
|
||||
|
||||
// Teleporting pads spawned by the end of every quarter.
|
||||
GO_NAXX_PORTAL_ARACHNID = 181575,
|
||||
GO_NAXX_PORTAL_CONSTRUCT = 181576,
|
||||
GO_NAXX_PORTAL_PLAGUE = 181577,
|
||||
GO_NAXX_PORTAL_MILITARY = 181578
|
||||
};
|
||||
|
||||
enum SpellIds
|
||||
@@ -142,6 +157,50 @@ enum SpellIds
|
||||
SPELL_SLIME = 28801
|
||||
};
|
||||
|
||||
enum InstanceEvents
|
||||
{
|
||||
// Dialogue that happens after Gothik's death.
|
||||
EVENT_DIALOGUE_GOTHIK_KORTHAZZ = 1,
|
||||
EVENT_DIALOGUE_GOTHIK_ZELIEK,
|
||||
EVENT_DIALOGUE_GOTHIK_BLAUMEUX,
|
||||
EVENT_DIALOGUE_GOTHIK_RIVENDARE,
|
||||
EVENT_DIALOGUE_GOTHIK_BLAUMEUX2,
|
||||
EVENT_DIALOGUE_GOTHIK_ZELIEK2,
|
||||
EVENT_DIALOGUE_GOTHIK_KORTHAZZ2,
|
||||
EVENT_DIALOGUE_GOTHIK_RIVENDARE2,
|
||||
|
||||
// Dialogue that happens after each wing.
|
||||
EVENT_KELTHUZAD_WING_TAUNT,
|
||||
|
||||
// Dialogue that happens after Sapphiron's death.
|
||||
EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD,
|
||||
EVENT_DIALOGUE_SAPPHIRON_LICHKING,
|
||||
EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD2,
|
||||
EVENT_DIALOGUE_SAPPHIRON_LICHKING2,
|
||||
EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD3,
|
||||
EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD4
|
||||
};
|
||||
|
||||
enum InstanceTexts
|
||||
{
|
||||
// The Four Horsemen
|
||||
SAY_DIALOGUE_GOTHIK_HORSEMAN = 5,
|
||||
SAY_DIALOGUE_GOTHIK_HORSEMAN2 = 6,
|
||||
|
||||
// Kel'Thuzad
|
||||
SAY_DIALOGUE_SAPPHIRON_KELTHUZAD = 0,
|
||||
SAY_DIALOGUE_SAPPHIRON_KELTHUZAD2 = 2,
|
||||
SAY_DIALOGUE_SAPPHIRON_KELTHUZAD3 = 4,
|
||||
SAY_DIALOGUE_SAPPHIRON_KELTHUZAD4 = 20,
|
||||
|
||||
SAY_KELTHUZAD_CAT_DIED = 5,
|
||||
SAY_KELTHUZAD_FIRST_WING_TAUNT = 16,
|
||||
|
||||
// Lich King
|
||||
SAY_DIALOGUE_SAPPHIRON_LICH_KING = 1,
|
||||
SAY_DIALOGUE_SAPPHIRON_LICH_KING2 = 2
|
||||
};
|
||||
|
||||
/*
|
||||
template<class AI>
|
||||
CreatureAI* GetNaxxramasAI(Creature* creature)
|
||||
|
||||
@@ -100,21 +100,21 @@ class boss_anomalus : public CreatureScript
|
||||
{
|
||||
Initialize();
|
||||
|
||||
instance->SetData(DATA_ANOMALUS_EVENT, NOT_STARTED);
|
||||
instance->SetBossState(DATA_ANOMALUS, NOT_STARTED);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
instance->SetData(DATA_ANOMALUS_EVENT, IN_PROGRESS);
|
||||
instance->SetBossState(DATA_ANOMALUS, IN_PROGRESS);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
|
||||
instance->SetData(DATA_ANOMALUS_EVENT, DONE);
|
||||
instance->SetBossState(DATA_ANOMALUS, DONE);
|
||||
}
|
||||
|
||||
uint32 GetData(uint32 type) const override
|
||||
|
||||
@@ -101,7 +101,7 @@ public:
|
||||
|
||||
RemovePrison(CheckContainmentSpheres());
|
||||
|
||||
instance->SetData(DATA_KERISTRASZA_EVENT, NOT_STARTED);
|
||||
instance->SetBossState(DATA_KERISTRASZA, NOT_STARTED);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
@@ -109,14 +109,14 @@ public:
|
||||
Talk(SAY_AGGRO);
|
||||
DoCastAOE(SPELL_INTENSE_COLD);
|
||||
|
||||
instance->SetData(DATA_KERISTRASZA_EVENT, IN_PROGRESS);
|
||||
instance->SetBossState(DATA_KERISTRASZA, IN_PROGRESS);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
|
||||
instance->SetData(DATA_KERISTRASZA_EVENT, DONE);
|
||||
instance->SetBossState(DATA_KERISTRASZA, DONE);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* who) override
|
||||
|
||||
@@ -31,7 +31,9 @@ enum Spells
|
||||
|
||||
SPELL_FIRE_MAGUS_VISUAL = 47705,
|
||||
SPELL_FROST_MAGUS_VISUAL = 47706,
|
||||
SPELL_ARCANE_MAGUS_VISUAL = 47704
|
||||
SPELL_ARCANE_MAGUS_VISUAL = 47704,
|
||||
|
||||
SPELL_WEAR_CHRISTMAS_HAT = 61400
|
||||
};
|
||||
|
||||
enum Creatures
|
||||
@@ -53,7 +55,9 @@ enum Yells
|
||||
enum Misc
|
||||
{
|
||||
ACTION_MAGUS_DEAD = 1,
|
||||
DATA_SPLIT_PERSONALITY = 2
|
||||
DATA_SPLIT_PERSONALITY = 2,
|
||||
|
||||
GAME_EVENT_WINTER_VEIL = 2,
|
||||
};
|
||||
|
||||
const Position CenterOfRoom = {504.80f, 89.07f, -16.12f, 6.27f};
|
||||
@@ -128,21 +132,24 @@ public:
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetVisible(true);
|
||||
|
||||
instance->SetData(DATA_MAGUS_TELESTRA_EVENT, NOT_STARTED);
|
||||
instance->SetBossState(DATA_MAGUS_TELESTRA, NOT_STARTED);
|
||||
|
||||
if (IsHeroic() && sGameEventMgr->IsActiveEvent(GAME_EVENT_WINTER_VEIL) && !me->HasAura(SPELL_WEAR_CHRISTMAS_HAT))
|
||||
me->AddAura(SPELL_WEAR_CHRISTMAS_HAT, me);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
instance->SetData(DATA_MAGUS_TELESTRA_EVENT, IN_PROGRESS);
|
||||
instance->SetBossState(DATA_MAGUS_TELESTRA, IN_PROGRESS);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
|
||||
instance->SetData(DATA_MAGUS_TELESTRA_EVENT, DONE);
|
||||
instance->SetBossState(DATA_MAGUS_TELESTRA, DONE);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* who) override
|
||||
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
|
||||
struct boss_ormorokAI : public BossAI
|
||||
{
|
||||
boss_ormorokAI(Creature* creature) : BossAI(creature, DATA_ORMOROK_EVENT)
|
||||
boss_ormorokAI(Creature* creature) : BossAI(creature, DATA_ORMOROK)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
@@ -95,8 +95,6 @@ public:
|
||||
events.ScheduleEvent(EVENT_CRYSTALLINE_TANGLER, 17000);
|
||||
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
instance->SetData(DATA_ORMOROK_EVENT, IN_PROGRESS);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) override
|
||||
@@ -112,10 +110,7 @@ public:
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
_JustDied();
|
||||
|
||||
Talk(SAY_DEATH);
|
||||
|
||||
instance->SetData(DATA_ORMOROK_EVENT, DONE);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* who) override
|
||||
@@ -138,27 +133,27 @@ public:
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_TRAMPLE:
|
||||
DoCast(me, SPELL_TRAMPLE);
|
||||
events.ScheduleEvent(EVENT_TRAMPLE, 10000);
|
||||
break;
|
||||
case EVENT_SPELL_REFLECTION:
|
||||
Talk(SAY_REFLECT);
|
||||
DoCast(me, SPELL_SPELL_REFLECTION);
|
||||
events.ScheduleEvent(EVENT_SPELL_REFLECTION, 30000);
|
||||
break;
|
||||
case EVENT_CRYSTAL_SPIKES:
|
||||
Talk(SAY_CRYSTAL_SPIKES);
|
||||
DoCast(SPELL_CRYSTAL_SPIKES);
|
||||
events.ScheduleEvent(EVENT_CRYSTAL_SPIKES, 12000);
|
||||
break;
|
||||
case EVENT_CRYSTALLINE_TANGLER:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, OrmorokTanglerPredicate(me)))
|
||||
DoCast(target, SPELL_SUMMON_CRYSTALLINE_TANGLER);
|
||||
events.ScheduleEvent(EVENT_CRYSTALLINE_TANGLER, 17000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case EVENT_TRAMPLE:
|
||||
DoCast(me, SPELL_TRAMPLE);
|
||||
events.ScheduleEvent(EVENT_TRAMPLE, 10000);
|
||||
break;
|
||||
case EVENT_SPELL_REFLECTION:
|
||||
Talk(SAY_REFLECT);
|
||||
DoCast(me, SPELL_SPELL_REFLECTION);
|
||||
events.ScheduleEvent(EVENT_SPELL_REFLECTION, 30000);
|
||||
break;
|
||||
case EVENT_CRYSTAL_SPIKES:
|
||||
Talk(SAY_CRYSTAL_SPIKES);
|
||||
DoCast(SPELL_CRYSTAL_SPIKES);
|
||||
events.ScheduleEvent(EVENT_CRYSTAL_SPIKES, 12000);
|
||||
break;
|
||||
case EVENT_CRYSTALLINE_TANGLER:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, OrmorokTanglerPredicate(me)))
|
||||
DoCast(target, SPELL_SUMMON_CRYSTALLINE_TANGLER);
|
||||
events.ScheduleEvent(EVENT_CRYSTALLINE_TANGLER, 17000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,8 @@
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "nexus.h"
|
||||
#include "Player.h"
|
||||
|
||||
#define NUMBER_OF_ENCOUNTERS 4
|
||||
#include "nexus.h"
|
||||
|
||||
enum Factions
|
||||
{
|
||||
@@ -30,229 +28,163 @@ enum Factions
|
||||
|
||||
class instance_nexus : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
instance_nexus() : InstanceMapScript("instance_nexus", 576) { }
|
||||
public:
|
||||
instance_nexus() : InstanceMapScript(NexusScriptName, 576) { }
|
||||
|
||||
InstanceScript* GetInstanceScript(InstanceMap* map) const override
|
||||
{
|
||||
return new instance_nexus_InstanceMapScript(map);
|
||||
}
|
||||
|
||||
struct instance_nexus_InstanceMapScript : public InstanceScript
|
||||
{
|
||||
instance_nexus_InstanceMapScript(Map* map) : InstanceScript(map)
|
||||
struct instance_nexus_InstanceMapScript : public InstanceScript
|
||||
{
|
||||
SetHeaders(DataHeader);
|
||||
memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));
|
||||
}
|
||||
|
||||
uint32 m_auiEncounter[NUMBER_OF_ENCOUNTERS];
|
||||
|
||||
ObjectGuid Anomalus;
|
||||
ObjectGuid Keristrasza;
|
||||
|
||||
ObjectGuid AnomalusContainmentSphere;
|
||||
ObjectGuid OrmoroksContainmentSphere;
|
||||
ObjectGuid TelestrasContainmentSphere;
|
||||
|
||||
std::string strInstData;
|
||||
|
||||
void OnCreatureCreate(Creature* creature) override
|
||||
{
|
||||
Map::PlayerList const &players = instance->GetPlayers();
|
||||
uint32 TeamInInstance = 0;
|
||||
|
||||
if (!players.isEmpty())
|
||||
instance_nexus_InstanceMapScript(Map* map) : InstanceScript(map)
|
||||
{
|
||||
if (Player* player = players.begin()->GetSource())
|
||||
TeamInInstance = player->GetTeam();
|
||||
}
|
||||
switch (creature->GetEntry())
|
||||
{
|
||||
case 26763:
|
||||
Anomalus = creature->GetGUID();
|
||||
break;
|
||||
case 26723:
|
||||
Keristrasza = creature->GetGUID();
|
||||
break;
|
||||
// Alliance npcs are spawned by default, if you are alliance, you will fight against horde npcs.
|
||||
case 26800:
|
||||
{
|
||||
if (ServerAllowsTwoSideGroups())
|
||||
creature->setFaction(FACTION_HOSTILE_FOR_ALL);
|
||||
if (TeamInInstance == ALLIANCE)
|
||||
creature->UpdateEntry(26799);
|
||||
break;
|
||||
}
|
||||
case 26802:
|
||||
{
|
||||
if (ServerAllowsTwoSideGroups())
|
||||
creature->setFaction(FACTION_HOSTILE_FOR_ALL);
|
||||
if (TeamInInstance == ALLIANCE)
|
||||
creature->UpdateEntry(26801);
|
||||
break;
|
||||
}
|
||||
case 26805:
|
||||
{
|
||||
if (ServerAllowsTwoSideGroups())
|
||||
creature->setFaction(FACTION_HOSTILE_FOR_ALL);
|
||||
if (TeamInInstance == ALLIANCE)
|
||||
creature->UpdateEntry(26803);
|
||||
break;
|
||||
}
|
||||
case 27949:
|
||||
{
|
||||
if (ServerAllowsTwoSideGroups())
|
||||
creature->setFaction(FACTION_HOSTILE_FOR_ALL);
|
||||
if (TeamInInstance == ALLIANCE)
|
||||
creature->UpdateEntry(27947);
|
||||
break;
|
||||
}
|
||||
case 26796:
|
||||
{
|
||||
if (ServerAllowsTwoSideGroups())
|
||||
creature->setFaction(FACTION_HOSTILE_FOR_ALL);
|
||||
if (TeamInInstance == ALLIANCE)
|
||||
creature->UpdateEntry(26798);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnGameObjectCreate(GameObject* go) override
|
||||
{
|
||||
switch (go->GetEntry())
|
||||
{
|
||||
case 188527:
|
||||
{
|
||||
AnomalusContainmentSphere = go->GetGUID();
|
||||
if (m_auiEncounter[1] == DONE)
|
||||
go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
break;
|
||||
}
|
||||
case 188528:
|
||||
{
|
||||
OrmoroksContainmentSphere = go->GetGUID();
|
||||
if (m_auiEncounter[2] == DONE)
|
||||
go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
break;
|
||||
}
|
||||
case 188526:
|
||||
{
|
||||
TelestrasContainmentSphere = go->GetGUID();
|
||||
if (m_auiEncounter[0] == DONE)
|
||||
go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GetData(uint32 identifier) const override
|
||||
{
|
||||
switch (identifier)
|
||||
{
|
||||
case DATA_MAGUS_TELESTRA_EVENT: return m_auiEncounter[0];
|
||||
case DATA_ANOMALUS_EVENT: return m_auiEncounter[1];
|
||||
case DATA_ORMOROK_EVENT: return m_auiEncounter[2];
|
||||
case DATA_KERISTRASZA_EVENT: return m_auiEncounter[3];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SetData(uint32 identifier, uint32 data) override
|
||||
{
|
||||
switch (identifier)
|
||||
{
|
||||
case DATA_MAGUS_TELESTRA_EVENT:
|
||||
{
|
||||
if (data == DONE)
|
||||
{
|
||||
GameObject* Sphere = instance->GetGameObject(TelestrasContainmentSphere);
|
||||
if (Sphere)
|
||||
Sphere->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
}
|
||||
m_auiEncounter[0] = data;
|
||||
break;
|
||||
}
|
||||
case DATA_ANOMALUS_EVENT:
|
||||
{
|
||||
if (data == DONE)
|
||||
{
|
||||
if (GameObject* Sphere = instance->GetGameObject(AnomalusContainmentSphere))
|
||||
Sphere->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
}
|
||||
m_auiEncounter[1] = data;
|
||||
break;
|
||||
}
|
||||
case DATA_ORMOROK_EVENT:
|
||||
{
|
||||
if (data == DONE)
|
||||
{
|
||||
if (GameObject* Sphere = instance->GetGameObject(OrmoroksContainmentSphere))
|
||||
Sphere->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
}
|
||||
m_auiEncounter[2] = data;
|
||||
break;
|
||||
}
|
||||
case DATA_KERISTRASZA_EVENT:
|
||||
m_auiEncounter[3] = data;
|
||||
break;
|
||||
SetHeaders(DataHeader);
|
||||
SetBossNumber(EncounterCount);
|
||||
_teamInInstance = 0;
|
||||
}
|
||||
|
||||
if (data == DONE)
|
||||
void OnPlayerEnter(Player* player) override
|
||||
{
|
||||
OUT_SAVE_INST_DATA;
|
||||
|
||||
std::ostringstream saveStream;
|
||||
saveStream << m_auiEncounter[0] << ' ' << m_auiEncounter[1] << ' ' << m_auiEncounter[2] << ' '
|
||||
<< m_auiEncounter[3];
|
||||
|
||||
strInstData = saveStream.str();
|
||||
|
||||
SaveToDB();
|
||||
OUT_SAVE_INST_DATA_COMPLETE;
|
||||
}
|
||||
}
|
||||
|
||||
ObjectGuid GetGuidData(uint32 uiIdentifier) const override
|
||||
{
|
||||
switch (uiIdentifier)
|
||||
{
|
||||
case DATA_ANOMALUS: return Anomalus;
|
||||
case DATA_KERISTRASZA: return Keristrasza;
|
||||
case ANOMALUS_CONTAINMET_SPHERE: return AnomalusContainmentSphere;
|
||||
case ORMOROKS_CONTAINMET_SPHERE: return OrmoroksContainmentSphere;
|
||||
case TELESTRAS_CONTAINMET_SPHERE: return TelestrasContainmentSphere;
|
||||
}
|
||||
return ObjectGuid::Empty;
|
||||
}
|
||||
|
||||
std::string GetSaveData() override
|
||||
{
|
||||
return strInstData;
|
||||
}
|
||||
|
||||
void Load(const char *chrIn)
|
||||
{
|
||||
if (!chrIn)
|
||||
{
|
||||
OUT_LOAD_INST_DATA_FAIL;
|
||||
return;
|
||||
if (!_teamInInstance)
|
||||
_teamInInstance = player->GetTeam();
|
||||
}
|
||||
|
||||
OUT_LOAD_INST_DATA(chrIn);
|
||||
void OnCreatureCreate(Creature* creature) override
|
||||
{
|
||||
switch (creature->GetEntry())
|
||||
{
|
||||
case NPC_ANOMALUS:
|
||||
AnomalusGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_KERISTRASZA:
|
||||
KeristraszaGUID = creature->GetGUID();
|
||||
break;
|
||||
// Alliance npcs are spawned by default, if you are alliance, you will fight against horde npcs.
|
||||
case NPC_ALLIANCE_BERSERKER:
|
||||
if (ServerAllowsTwoSideGroups())
|
||||
creature->setFaction(FACTION_HOSTILE_FOR_ALL);
|
||||
if (_teamInInstance == ALLIANCE)
|
||||
creature->UpdateEntry(NPC_HORDE_BERSERKER);
|
||||
break;
|
||||
case NPC_ALLIANCE_RANGER:
|
||||
if (ServerAllowsTwoSideGroups())
|
||||
creature->setFaction(FACTION_HOSTILE_FOR_ALL);
|
||||
if (_teamInInstance == ALLIANCE)
|
||||
creature->UpdateEntry(NPC_HORDE_RANGER);
|
||||
break;
|
||||
case NPC_ALLIANCE_CLERIC:
|
||||
if (ServerAllowsTwoSideGroups())
|
||||
creature->setFaction(FACTION_HOSTILE_FOR_ALL);
|
||||
if (_teamInInstance == ALLIANCE)
|
||||
creature->UpdateEntry(NPC_HORDE_CLERIC);
|
||||
break;
|
||||
case NPC_ALLIANCE_COMMANDER:
|
||||
if (ServerAllowsTwoSideGroups())
|
||||
creature->setFaction(FACTION_HOSTILE_FOR_ALL);
|
||||
if (_teamInInstance == ALLIANCE)
|
||||
creature->UpdateEntry(NPC_HORDE_COMMANDER);
|
||||
break;
|
||||
case NPC_COMMANDER_STOUTBEARD:
|
||||
if (ServerAllowsTwoSideGroups())
|
||||
creature->setFaction(FACTION_HOSTILE_FOR_ALL);
|
||||
if (_teamInInstance == ALLIANCE)
|
||||
creature->UpdateEntry(NPC_COMMANDER_KOLURG);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::istringstream loadStream(chrIn);
|
||||
loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3];
|
||||
void OnGameObjectCreate(GameObject* go) override
|
||||
{
|
||||
switch (go->GetEntry())
|
||||
{
|
||||
case GO_ANOMALUS_CONTAINMET_SPHERE:
|
||||
AnomalusContainmentSphere = go->GetGUID();
|
||||
if (GetBossState(DATA_ANOMALUS) == DONE)
|
||||
go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
break;
|
||||
case GO_ORMOROKS_CONTAINMET_SPHERE:
|
||||
OrmoroksContainmentSphere = go->GetGUID();
|
||||
if (GetBossState(DATA_ORMOROK) == DONE)
|
||||
go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
break;
|
||||
case GO_TELESTRAS_CONTAINMET_SPHERE:
|
||||
TelestrasContainmentSphere = go->GetGUID();
|
||||
if (GetBossState(DATA_MAGUS_TELESTRA) == DONE)
|
||||
go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < NUMBER_OF_ENCOUNTERS; ++i)
|
||||
if (m_auiEncounter[i] == IN_PROGRESS)
|
||||
m_auiEncounter[i] = NOT_STARTED;
|
||||
bool SetBossState(uint32 type, EncounterState state) override
|
||||
{
|
||||
if (!InstanceScript::SetBossState(type, state))
|
||||
return false;
|
||||
|
||||
OUT_LOAD_INST_DATA_COMPLETE;
|
||||
switch (type)
|
||||
{
|
||||
case DATA_MAGUS_TELESTRA:
|
||||
if (state == DONE)
|
||||
{
|
||||
if (GameObject* sphere = instance->GetGameObject(TelestrasContainmentSphere))
|
||||
sphere->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
}
|
||||
break;
|
||||
case DATA_ANOMALUS:
|
||||
if (state == DONE)
|
||||
{
|
||||
if (GameObject* sphere = instance->GetGameObject(AnomalusContainmentSphere))
|
||||
sphere->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
}
|
||||
break;
|
||||
case DATA_ORMOROK:
|
||||
if (state == DONE)
|
||||
{
|
||||
if (GameObject* sphere = instance->GetGameObject(OrmoroksContainmentSphere))
|
||||
sphere->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ObjectGuid GetGuidData(uint32 type) const override
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DATA_ANOMALUS:
|
||||
return AnomalusGUID;
|
||||
case DATA_KERISTRASZA:
|
||||
return KeristraszaGUID;
|
||||
case ANOMALUS_CONTAINMET_SPHERE:
|
||||
return AnomalusContainmentSphere;
|
||||
case ORMOROKS_CONTAINMET_SPHERE:
|
||||
return OrmoroksContainmentSphere;
|
||||
case TELESTRAS_CONTAINMET_SPHERE:
|
||||
return TelestrasContainmentSphere;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ObjectGuid::Empty;
|
||||
}
|
||||
|
||||
private:
|
||||
ObjectGuid AnomalusGUID;
|
||||
ObjectGuid KeristraszaGUID;
|
||||
ObjectGuid AnomalusContainmentSphere;
|
||||
ObjectGuid OrmoroksContainmentSphere;
|
||||
ObjectGuid TelestrasContainmentSphere;
|
||||
uint32 _teamInInstance;
|
||||
};
|
||||
|
||||
InstanceScript* GetInstanceScript(InstanceMap* map) const override
|
||||
{
|
||||
return new instance_nexus_InstanceMapScript(map);
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
void AddSC_instance_nexus()
|
||||
|
||||
@@ -18,21 +18,48 @@
|
||||
#ifndef DEF_NEXUS_H
|
||||
#define DEF_NEXUS_H
|
||||
|
||||
#define NexusScriptName "instance_nexus"
|
||||
#define DataHeader "NEX"
|
||||
|
||||
uint32 const EncounterCount = 4;
|
||||
|
||||
enum DataTypes
|
||||
{
|
||||
DATA_MAGUS_TELESTRA_EVENT,
|
||||
DATA_ANOMALUS_EVENT,
|
||||
DATA_ORMOROK_EVENT,
|
||||
DATA_KERISTRASZA_EVENT,
|
||||
DATA_MAGUS_TELESTRA = 0,
|
||||
DATA_ANOMALUS = 1,
|
||||
DATA_ORMOROK = 2,
|
||||
DATA_KERISTRASZA = 3,
|
||||
|
||||
DATA_ANOMALUS,
|
||||
DATA_KERISTRASZA,
|
||||
ANOMALUS_CONTAINMET_SPHERE = 4,
|
||||
ORMOROKS_CONTAINMET_SPHERE = 5,
|
||||
TELESTRAS_CONTAINMET_SPHERE = 6
|
||||
};
|
||||
|
||||
ANOMALUS_CONTAINMET_SPHERE,
|
||||
ORMOROKS_CONTAINMET_SPHERE,
|
||||
TELESTRAS_CONTAINMET_SPHERE
|
||||
enum CreatureIds
|
||||
{
|
||||
NPC_ANOMALUS = 26763,
|
||||
NPC_KERISTRASZA = 26723,
|
||||
|
||||
// Alliance
|
||||
NPC_ALLIANCE_BERSERKER = 26800,
|
||||
NPC_ALLIANCE_RANGER = 26802,
|
||||
NPC_ALLIANCE_CLERIC = 26805,
|
||||
NPC_ALLIANCE_COMMANDER = 27949,
|
||||
NPC_COMMANDER_STOUTBEARD = 26796,
|
||||
|
||||
// Horde
|
||||
NPC_HORDE_BERSERKER = 26799,
|
||||
NPC_HORDE_RANGER = 26801,
|
||||
NPC_HORDE_CLERIC = 26803,
|
||||
NPC_HORDE_COMMANDER = 27947,
|
||||
NPC_COMMANDER_KOLURG = 26798
|
||||
};
|
||||
|
||||
enum GameObjectIds
|
||||
{
|
||||
GO_ANOMALUS_CONTAINMET_SPHERE = 188527,
|
||||
GO_ORMOROKS_CONTAINMET_SPHERE = 188528,
|
||||
GO_TELESTRAS_CONTAINMET_SPHERE = 188526
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -192,6 +192,7 @@ class instance_oculus : public InstanceMapScript
|
||||
FreeDragons();
|
||||
if (Creature* varos = instance->GetCreature(VarosGUID))
|
||||
varos->SetPhaseMask(1, true);
|
||||
events.ScheduleEvent(EVENT_VAROS_INTRO, 15000);
|
||||
}
|
||||
break;
|
||||
case DATA_VAROS:
|
||||
@@ -209,6 +210,7 @@ class instance_oculus : public InstanceMapScript
|
||||
{
|
||||
eregos->SetPhaseMask(1, true);
|
||||
GreaterWhelps();
|
||||
events.ScheduleEvent(EVENT_EREGOS_INTRO, 5000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -267,6 +269,28 @@ class instance_oculus : public InstanceMapScript
|
||||
}
|
||||
}
|
||||
|
||||
void Update(uint32 diff) override
|
||||
{
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_VAROS_INTRO:
|
||||
if (Creature* varos = instance->GetCreature(VarosGUID))
|
||||
varos->AI()->Talk(SAY_VAROS_INTRO_TEXT);
|
||||
break;
|
||||
case EVENT_EREGOS_INTRO:
|
||||
if (Creature* eregos = instance->GetCreature(EregosGUID))
|
||||
eregos->AI()->Talk(SAY_EREGOS_INTRO_TEXT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GreaterWhelps()
|
||||
{
|
||||
for (ObjectGuid guid : GreaterWhelpList)
|
||||
@@ -289,6 +313,8 @@ class instance_oculus : public InstanceMapScript
|
||||
ObjectGuid EregosCacheGUID;
|
||||
|
||||
GuidList GreaterWhelpList;
|
||||
|
||||
EventMap events;
|
||||
};
|
||||
|
||||
InstanceScript* GetInstanceScript(InstanceMap* map) const override
|
||||
|
||||
@@ -79,6 +79,18 @@ enum OculusSpells
|
||||
SPELL_DEATH_SPELL = 50415
|
||||
};
|
||||
|
||||
enum InstanceTexts
|
||||
{
|
||||
SAY_EREGOS_INTRO_TEXT = 0,
|
||||
SAY_VAROS_INTRO_TEXT = 4
|
||||
};
|
||||
|
||||
enum InstanceEvents
|
||||
{
|
||||
EVENT_VAROS_INTRO = 1,
|
||||
EVENT_EREGOS_INTRO
|
||||
};
|
||||
|
||||
enum Misc
|
||||
{
|
||||
POINT_MOVE_OUT = 1
|
||||
|
||||
@@ -28,7 +28,7 @@ EndScriptData */
|
||||
#include "SpellScript.h"
|
||||
#include "halls_of_lightning.h"
|
||||
|
||||
enum Yells
|
||||
enum Texts
|
||||
{
|
||||
SAY_INTRO_1 = 0,
|
||||
SAY_INTRO_2 = 1,
|
||||
@@ -51,6 +51,21 @@ enum Spells
|
||||
SPELL_PULSING_SHOCKWAVE_AURA = 59414
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_ARC_LIGHTNING = 1,
|
||||
EVENT_LIGHTNING_NOVA,
|
||||
EVENT_RESUME_PULSING_SHOCKWAVE,
|
||||
EVENT_INTRO_DIALOGUE
|
||||
};
|
||||
|
||||
enum Phases
|
||||
{
|
||||
// Phases are used to allow executing the intro event while UpdateVictim() returns false and convenience.
|
||||
PHASE_INTRO = 1,
|
||||
PHASE_NORMAL
|
||||
};
|
||||
|
||||
enum Misc
|
||||
{
|
||||
ACHIEV_TIMELY_DEATH_START_EVENT = 20384
|
||||
@@ -65,57 +80,41 @@ class boss_loken : public CreatureScript
|
||||
public:
|
||||
boss_loken() : CreatureScript("boss_loken") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
struct boss_lokenAI : public BossAI
|
||||
{
|
||||
return GetInstanceAI<boss_lokenAI>(creature);
|
||||
}
|
||||
|
||||
struct boss_lokenAI : public ScriptedAI
|
||||
{
|
||||
boss_lokenAI(Creature* creature) : ScriptedAI(creature)
|
||||
boss_lokenAI(Creature* creature) : BossAI(creature, DATA_LOKEN)
|
||||
{
|
||||
Initialize();
|
||||
instance = creature->GetInstanceScript();
|
||||
_isIntroDone = false;
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
m_uiArcLightning_Timer = 15000;
|
||||
m_uiLightningNova_Timer = 20000;
|
||||
m_uiResumePulsingShockwave_Timer = 1000;
|
||||
|
||||
m_uiHealthAmountModifier = 1;
|
||||
_healthAmountModifier = 1;
|
||||
}
|
||||
|
||||
InstanceScript* instance;
|
||||
|
||||
uint32 m_uiArcLightning_Timer;
|
||||
uint32 m_uiLightningNova_Timer;
|
||||
uint32 m_uiResumePulsingShockwave_Timer;
|
||||
|
||||
uint32 m_uiHealthAmountModifier;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
Initialize();
|
||||
|
||||
instance->SetBossState(DATA_LOKEN, NOT_STARTED);
|
||||
_Reset();
|
||||
instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMELY_DEATH_START_EVENT);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
_EnterCombat();
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
instance->SetBossState(DATA_LOKEN, IN_PROGRESS);
|
||||
events.SetPhase(PHASE_NORMAL);
|
||||
events.ScheduleEvent(EVENT_ARC_LIGHTNING, 15000);
|
||||
events.ScheduleEvent(EVENT_LIGHTNING_NOVA, 20000);
|
||||
events.ScheduleEvent(EVENT_RESUME_PULSING_SHOCKWAVE, 1000);
|
||||
instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMELY_DEATH_START_EVENT);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
|
||||
instance->SetBossState(DATA_LOKEN, DONE);
|
||||
_JustDied();
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_PULSING_SHOCKWAVE_AURA);
|
||||
}
|
||||
|
||||
@@ -125,66 +124,89 @@ public:
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 uiDiff) override
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
if (!_isIntroDone && me->IsValidAttackTarget(who) && me->IsWithinDistInMap(who, 40.0f))
|
||||
{
|
||||
_isIntroDone = true;
|
||||
Talk(SAY_INTRO_1);
|
||||
events.ScheduleEvent(EVENT_INTRO_DIALOGUE, 20000, 0, PHASE_INTRO);
|
||||
}
|
||||
BossAI::MoveInLineOfSight(who);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (events.IsInPhase(PHASE_NORMAL) && !UpdateVictim())
|
||||
return;
|
||||
|
||||
if (m_uiResumePulsingShockwave_Timer)
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
if (m_uiResumePulsingShockwave_Timer <= uiDiff)
|
||||
switch (eventId)
|
||||
{
|
||||
DoCast(me, SPELL_PULSING_SHOCKWAVE_AURA, true);
|
||||
me->ClearUnitState(UNIT_STATE_CASTING); // this flag breaks movement
|
||||
|
||||
DoCast(me, SPELL_PULSING_SHOCKWAVE, true);
|
||||
m_uiResumePulsingShockwave_Timer = 0;
|
||||
case EVENT_ARC_LIGHTNING:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
|
||||
DoCast(target, SPELL_ARC_LIGHTNING);
|
||||
events.ScheduleEvent(EVENT_ARC_LIGHTNING, urand(15000, 16000));
|
||||
break;
|
||||
case EVENT_LIGHTNING_NOVA:
|
||||
Talk(SAY_NOVA);
|
||||
Talk(EMOTE_NOVA);
|
||||
DoCastAOE(SPELL_LIGHTNING_NOVA);
|
||||
me->RemoveAurasDueToSpell(sSpellMgr->GetSpellIdForDifficulty(SPELL_PULSING_SHOCKWAVE, me));
|
||||
events.ScheduleEvent(EVENT_RESUME_PULSING_SHOCKWAVE, DUNGEON_MODE(5000, 4000)); // Pause Pulsing Shockwave aura
|
||||
events.ScheduleEvent(EVENT_LIGHTNING_NOVA, urand(20000, 21000));
|
||||
break;
|
||||
case EVENT_RESUME_PULSING_SHOCKWAVE:
|
||||
DoCast(me, SPELL_PULSING_SHOCKWAVE_AURA, true);
|
||||
me->ClearUnitState(UNIT_STATE_CASTING); // This flag breaks movement.
|
||||
DoCast(me, SPELL_PULSING_SHOCKWAVE, true);
|
||||
break;
|
||||
case EVENT_INTRO_DIALOGUE:
|
||||
Talk(SAY_INTRO_2);
|
||||
events.SetPhase(PHASE_NORMAL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
else
|
||||
m_uiResumePulsingShockwave_Timer -= uiDiff;
|
||||
}
|
||||
|
||||
if (m_uiArcLightning_Timer <= uiDiff)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
|
||||
DoCast(target, SPELL_ARC_LIGHTNING);
|
||||
|
||||
m_uiArcLightning_Timer = urand(15000, 16000);
|
||||
}
|
||||
else
|
||||
m_uiArcLightning_Timer -= uiDiff;
|
||||
|
||||
if (m_uiLightningNova_Timer <= uiDiff)
|
||||
{
|
||||
Talk(SAY_NOVA);
|
||||
Talk(EMOTE_NOVA);
|
||||
DoCast(me, SPELL_LIGHTNING_NOVA);
|
||||
|
||||
me->RemoveAurasDueToSpell(sSpellMgr->GetSpellIdForDifficulty(SPELL_PULSING_SHOCKWAVE, me));
|
||||
m_uiResumePulsingShockwave_Timer = DUNGEON_MODE(5000, 4000); // Pause Pulsing Shockwave aura
|
||||
m_uiLightningNova_Timer = urand(20000, 21000);
|
||||
}
|
||||
else
|
||||
m_uiLightningNova_Timer -= uiDiff;
|
||||
|
||||
// Health check
|
||||
if (HealthBelowPct(100 - 25 * m_uiHealthAmountModifier))
|
||||
{
|
||||
switch (m_uiHealthAmountModifier)
|
||||
{
|
||||
case 1: Talk(SAY_75HEALTH); break;
|
||||
case 2: Talk(SAY_50HEALTH); break;
|
||||
case 3: Talk(SAY_25HEALTH); break;
|
||||
}
|
||||
|
||||
++m_uiHealthAmountModifier;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
|
||||
{
|
||||
if (me->HealthBelowPctDamaged(100 - 25 * _healthAmountModifier, damage))
|
||||
{
|
||||
switch (_healthAmountModifier)
|
||||
{
|
||||
case 1:
|
||||
Talk(SAY_75HEALTH);
|
||||
break;
|
||||
case 2:
|
||||
Talk(SAY_50HEALTH);
|
||||
break;
|
||||
case 3:
|
||||
Talk(SAY_25HEALTH);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
++_healthAmountModifier;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 _healthAmountModifier;
|
||||
bool _isIntroDone;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetInstanceAI<boss_lokenAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_loken_pulsing_shockwave : public SpellScriptLoader
|
||||
|
||||
@@ -366,48 +366,6 @@ class npc_commander_eligor_dawnbringer : public CreatureScript
|
||||
}
|
||||
};
|
||||
|
||||
enum AlexstraszaWrGate
|
||||
{
|
||||
// Quest
|
||||
QUEST_RETURN_TO_AG_A = 12499,
|
||||
QUEST_RETURN_TO_AG_H = 12500,
|
||||
|
||||
// Movie
|
||||
MOVIE_ID_GATES = 14
|
||||
};
|
||||
|
||||
#define GOSSIP_ITEM_WHAT_HAPPENED "Alexstrasza, can you show me what happened here?"
|
||||
|
||||
class npc_alexstrasza_wr_gate : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_alexstrasza_wr_gate() : CreatureScript("npc_alexstrasza_wr_gate") { }
|
||||
|
||||
bool OnGossipHello(Player* player, Creature* creature) override
|
||||
{
|
||||
if (creature->IsQuestGiver())
|
||||
player->PrepareQuestMenu(creature->GetGUID());
|
||||
|
||||
if (player->GetQuestRewardStatus(QUEST_RETURN_TO_AG_A) || player->GetQuestRewardStatus(QUEST_RETURN_TO_AG_H))
|
||||
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_WHAT_HAPPENED, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
|
||||
|
||||
player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnGossipSelect(Player* player, Creature* /*creature*/, uint32 /*sender*/, uint32 action) override
|
||||
{
|
||||
player->PlayerTalkClass->ClearMenus();
|
||||
if (action == GOSSIP_ACTION_INFO_DEF+1)
|
||||
{
|
||||
player->CLOSE_GOSSIP_MENU();
|
||||
player->SendMovieStart(MOVIE_ID_GATES);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/*######
|
||||
## Quest Strengthen the Ancients (12096|12092)
|
||||
######*/
|
||||
@@ -746,7 +704,6 @@ class npc_torturer_lecraft : public CreatureScript
|
||||
void AddSC_dragonblight()
|
||||
{
|
||||
new npc_commander_eligor_dawnbringer();
|
||||
new npc_alexstrasza_wr_gate();
|
||||
new spell_q12096_q12092_dummy();
|
||||
new spell_q12096_q12092_bark();
|
||||
new npc_wyrmrest_defender();
|
||||
|
||||
@@ -209,52 +209,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/*######
|
||||
## npc_vereth_the_cunning
|
||||
######*/
|
||||
|
||||
enum VerethTheCunning
|
||||
{
|
||||
NPC_GEIST_RETURN_BUNNY_KC = 31049,
|
||||
NPC_LITHE_STALKER = 30894,
|
||||
SPELL_SUBDUED_LITHE_STALKER = 58151,
|
||||
};
|
||||
|
||||
class npc_vereth_the_cunning : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_vereth_the_cunning() : CreatureScript("npc_vereth_the_cunning") { }
|
||||
|
||||
struct npc_vereth_the_cunningAI : public ScriptedAI
|
||||
{
|
||||
npc_vereth_the_cunningAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
|
||||
{
|
||||
ScriptedAI::MoveInLineOfSight(who);
|
||||
|
||||
if (who->GetEntry() == NPC_LITHE_STALKER && me->IsWithinDistInMap(who, 10.0f))
|
||||
{
|
||||
if (Unit* owner = who->GetCharmer())
|
||||
{
|
||||
if (who->HasAura(SPELL_SUBDUED_LITHE_STALKER))
|
||||
{
|
||||
owner->ToPlayer()->KilledMonsterCredit(NPC_GEIST_RETURN_BUNNY_KC);
|
||||
who->ToCreature()->DisappearAndDie();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_vereth_the_cunningAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
/*######
|
||||
* npc_tournament_training_dummy
|
||||
######*/
|
||||
@@ -881,207 +835,12 @@ class npc_frostbrood_skytalon : public CreatureScript
|
||||
}
|
||||
};
|
||||
|
||||
/*######
|
||||
## The Flesh Giant Champion - Id: 13235
|
||||
######*/
|
||||
enum FleshGiant
|
||||
{
|
||||
QUEST_FLESH_GIANT_CHAMPION = 13235,
|
||||
|
||||
NPC_MORBIDUS = 30698,
|
||||
NPC_LICH_KING = 31301,
|
||||
NPC_OLAKIN = 31428,
|
||||
NPC_DHAKAR = 31306,
|
||||
|
||||
FACTION_HOSTILE = 14,
|
||||
FACTION_BASIC = 2102,
|
||||
|
||||
EVENT_INTRO = 1,
|
||||
EVENT_LK_SAY_1 = 2,
|
||||
EVENT_LK_SAY_2 = 3,
|
||||
EVENT_LK_SAY_3 = 4,
|
||||
EVENT_LK_SAY_4 = 5,
|
||||
EVENT_LK_SAY_5 = 6,
|
||||
EVENT_OUTRO = 7,
|
||||
EVENT_START = 8,
|
||||
|
||||
SPELL_SIMPLE_TELEPORT = 64195,
|
||||
|
||||
SAY_DHAKAR_START = 0,
|
||||
SAY_LK_1 = 0,
|
||||
SAY_LK_2 = 1,
|
||||
SAY_LK_3 = 2,
|
||||
SAY_LK_4 = 3,
|
||||
SAY_LK_5 = 4,
|
||||
SAY_OLAKIN_PAY = 0
|
||||
};
|
||||
|
||||
class npc_margrave_dhakar : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_margrave_dhakar() : CreatureScript("npc_margrave_dhakar") { }
|
||||
|
||||
struct npc_margrave_dhakarAI : public ScriptedAI
|
||||
{
|
||||
npc_margrave_dhakarAI(Creature* creature) : ScriptedAI(creature) , _summons(me) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
||||
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE);
|
||||
|
||||
_events.Reset();
|
||||
_summons.DespawnAll();
|
||||
}
|
||||
|
||||
void sGossipSelect(Player* player, uint32 sender, uint32 action) override
|
||||
{
|
||||
if (player->GetQuestStatus(QUEST_FLESH_GIANT_CHAMPION) == QUEST_STATUS_INCOMPLETE && !player->IsInCombat())
|
||||
{
|
||||
if (me->GetCreatureTemplate()->GossipMenuId == sender && !action)
|
||||
{
|
||||
_events.ScheduleEvent(EVENT_INTRO, 1000);
|
||||
me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
_events.Update(diff);
|
||||
|
||||
while (uint32 eventId = _events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_INTRO:
|
||||
{
|
||||
Talk(SAY_DHAKAR_START);
|
||||
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY2H);
|
||||
|
||||
if (Creature* morbidus = me->FindNearestCreature(NPC_MORBIDUS, 50.0f, true))
|
||||
{
|
||||
if (Creature* lichKing = me->SummonCreature(NPC_LICH_KING, morbidus->GetPositionX() + 10.0f, morbidus->GetPositionY(), morbidus->GetPositionZ()))
|
||||
{
|
||||
_lichKingGuid = lichKing->GetGUID();
|
||||
lichKing->SetFacingTo(morbidus->GetOrientation());
|
||||
lichKing->CastSpell(lichKing, SPELL_SIMPLE_TELEPORT, true);
|
||||
}
|
||||
}
|
||||
|
||||
_events.ScheduleEvent(EVENT_LK_SAY_1, 5000);
|
||||
break;
|
||||
}
|
||||
case EVENT_LK_SAY_1:
|
||||
{
|
||||
if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _lichKingGuid))
|
||||
lichKing->AI()->Talk(SAY_LK_1);
|
||||
_events.ScheduleEvent(EVENT_LK_SAY_2, 5000);
|
||||
break;
|
||||
}
|
||||
case EVENT_LK_SAY_2:
|
||||
{
|
||||
if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _lichKingGuid))
|
||||
lichKing->AI()->Talk(SAY_LK_2);
|
||||
_events.ScheduleEvent(EVENT_LK_SAY_3, 5000);
|
||||
break;
|
||||
}
|
||||
case EVENT_LK_SAY_3:
|
||||
{
|
||||
if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _lichKingGuid))
|
||||
lichKing->AI()->Talk(SAY_LK_3);
|
||||
_events.ScheduleEvent(EVENT_LK_SAY_4, 5000);
|
||||
break;
|
||||
}
|
||||
case EVENT_LK_SAY_4:
|
||||
{
|
||||
if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _lichKingGuid))
|
||||
lichKing->AI()->Talk(SAY_LK_4);
|
||||
_events.ScheduleEvent(EVENT_OUTRO, 12000);
|
||||
break;
|
||||
}
|
||||
case EVENT_LK_SAY_5:
|
||||
{
|
||||
if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _lichKingGuid))
|
||||
lichKing->AI()->Talk(SAY_LK_5);
|
||||
_events.ScheduleEvent(EVENT_OUTRO, 8000);
|
||||
break;
|
||||
}
|
||||
case EVENT_OUTRO:
|
||||
{
|
||||
if (Creature* olakin = me->FindNearestCreature(NPC_OLAKIN, 50.0f, true))
|
||||
olakin->AI()->Talk(SAY_OLAKIN_PAY);
|
||||
|
||||
if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _lichKingGuid))
|
||||
lichKing->DespawnOrUnsummon(0);
|
||||
|
||||
_events.ScheduleEvent(EVENT_START, 5000);
|
||||
break;
|
||||
}
|
||||
case EVENT_START:
|
||||
{
|
||||
if (Creature* morbidus = me->FindNearestCreature(NPC_MORBIDUS, 50.0f, true))
|
||||
{
|
||||
morbidus->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_DISABLE_MOVE);
|
||||
morbidus->setFaction(FACTION_HOSTILE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap _events;
|
||||
SummonList _summons;
|
||||
ObjectGuid _lichKingGuid;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_margrave_dhakarAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class npc_morbidus : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_morbidus() : CreatureScript("npc_morbidus") { }
|
||||
|
||||
struct npc_morbidusAI : public ScriptedAI
|
||||
{
|
||||
npc_morbidusAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
if (Creature* dhakar = me->FindNearestCreature(NPC_DHAKAR, 50.0f, true))
|
||||
dhakar->AI()->Reset();
|
||||
|
||||
// this will prevent the event to start without morbidus being alive
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->setFaction(FACTION_BASIC);
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_morbidusAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_icecrown()
|
||||
{
|
||||
new npc_squire_david;
|
||||
new npc_argent_valiant;
|
||||
new npc_guardian_pavilion;
|
||||
new npc_vereth_the_cunning;
|
||||
new npc_tournament_training_dummy;
|
||||
new npc_blessed_banner();
|
||||
new npc_frostbrood_skytalon();
|
||||
new npc_margrave_dhakar();
|
||||
new npc_morbidus();
|
||||
}
|
||||
@@ -21,8 +21,14 @@
|
||||
|
||||
DoorData const doorData[] =
|
||||
{
|
||||
{ GO_IKISS_DOOR, DATA_TALON_KING_IKISS, DOOR_TYPE_PASSAGE, BOUNDARY_NONE },
|
||||
{ 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE } // END
|
||||
{ GO_IKISS_DOOR, DATA_TALON_KING_IKISS, DOOR_TYPE_PASSAGE, BOUNDARY_NONE },
|
||||
{ 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE } // END
|
||||
};
|
||||
|
||||
ObjectData const gameObjectData[] =
|
||||
{
|
||||
{ GO_TALON_KING_COFFER, DATA_TALON_KING_COFFER },
|
||||
{ 0, 0 } // END
|
||||
};
|
||||
|
||||
class instance_sethekk_halls : public InstanceMapScript
|
||||
@@ -37,6 +43,7 @@ class instance_sethekk_halls : public InstanceMapScript
|
||||
SetHeaders(DataHeader);
|
||||
SetBossNumber(EncounterCount);
|
||||
LoadDoorData(doorData);
|
||||
LoadObjectData(nullptr, gameObjectData);
|
||||
}
|
||||
|
||||
void OnCreatureCreate(Creature* creature) override
|
||||
@@ -50,16 +57,27 @@ class instance_sethekk_halls : public InstanceMapScript
|
||||
}
|
||||
}
|
||||
|
||||
void OnGameObjectCreate(GameObject* go) override
|
||||
bool SetBossState(uint32 type, EncounterState state) override
|
||||
{
|
||||
if (go->GetEntry() == GO_IKISS_DOOR)
|
||||
AddDoor(go, true);
|
||||
}
|
||||
if (!InstanceScript::SetBossState(type, state))
|
||||
return false;
|
||||
|
||||
void OnGameObjectRemove(GameObject* go) override
|
||||
{
|
||||
if (go->GetEntry() == GO_IKISS_DOOR)
|
||||
AddDoor(go, false);
|
||||
switch (type)
|
||||
{
|
||||
case DATA_TALON_KING_IKISS:
|
||||
if (state == DONE)
|
||||
{
|
||||
/// @workaround: GO_FLAG_INTERACT_COND remains on the gob, but it is not handled correctly in this case
|
||||
/// gameobject should have GO_DYNFLAG_LO_ACTIVATE too, which makes gobs interactable with GO_FLAG_INTERACT_COND
|
||||
/// so just removed GO_FLAG_INTERACT_COND
|
||||
if (GameObject* coffer = GetGameObject(DATA_TALON_KING_COFFER))
|
||||
coffer->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND | GO_FLAG_NOT_SELECTABLE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -28,7 +28,10 @@ enum DataTypes
|
||||
// Encounter States/Boss GUIDs
|
||||
DATA_DARKWEAVER_SYTH = 0,
|
||||
DATA_TALON_KING_IKISS = 1,
|
||||
DATA_ANZU = 2
|
||||
DATA_ANZU = 2,
|
||||
|
||||
// Additional Data
|
||||
DATA_TALON_KING_COFFER = 3
|
||||
};
|
||||
|
||||
enum CreatureIds
|
||||
@@ -39,7 +42,8 @@ enum CreatureIds
|
||||
|
||||
enum GameObjectIds
|
||||
{
|
||||
GO_IKISS_DOOR = 177203
|
||||
GO_IKISS_DOOR = 177203,
|
||||
GO_TALON_KING_COFFER = 187372
|
||||
};
|
||||
|
||||
template<class AI>
|
||||
|
||||
@@ -31,21 +31,25 @@ class go_main_chambers_access_panel : public GameObjectScript
|
||||
return false;
|
||||
|
||||
if (go->GetEntry() == GO_ACCESS_PANEL_HYDRO && (instance->GetBossState(DATA_HYDROMANCER_THESPIA) == DONE || instance->GetBossState(DATA_HYDROMANCER_THESPIA) == SPECIAL))
|
||||
{
|
||||
instance->SetBossState(DATA_HYDROMANCER_THESPIA, SPECIAL);
|
||||
go->SetGoState(GO_STATE_ACTIVE);
|
||||
}
|
||||
|
||||
if (go->GetEntry() == GO_ACCESS_PANEL_MEK && (instance->GetBossState(DATA_MEKGINEER_STEAMRIGGER) == DONE || instance->GetBossState(DATA_MEKGINEER_STEAMRIGGER) == SPECIAL))
|
||||
{
|
||||
instance->SetBossState(DATA_MEKGINEER_STEAMRIGGER, SPECIAL);
|
||||
go->SetGoState(GO_STATE_ACTIVE);
|
||||
}
|
||||
|
||||
go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
go->SetGoState(GO_STATE_ACTIVE);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
ObjectData const gameObjectData[] =
|
||||
{
|
||||
{ GO_ACCESS_PANEL_HYDRO, DATA_ACCESS_PANEL_HYDRO },
|
||||
{ GO_ACCESS_PANEL_MEK, DATA_ACCESS_PANEL_MEK },
|
||||
{ 0, 0 } // END
|
||||
};
|
||||
|
||||
class instance_steam_vault : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
@@ -57,6 +61,7 @@ class instance_steam_vault : public InstanceMapScript
|
||||
{
|
||||
SetHeaders(DataHeader);
|
||||
SetBossNumber(EncounterCount);
|
||||
LoadObjectData(nullptr, gameObjectData);
|
||||
|
||||
DistillerState = 0;
|
||||
}
|
||||
@@ -89,6 +94,8 @@ class instance_steam_vault : public InstanceMapScript
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
InstanceScript::OnGameObjectCreate(go);
|
||||
}
|
||||
|
||||
ObjectGuid GetGuidData(uint32 type) const override
|
||||
@@ -128,6 +135,9 @@ class instance_steam_vault : public InstanceMapScript
|
||||
switch (type)
|
||||
{
|
||||
case DATA_HYDROMANCER_THESPIA:
|
||||
if (state == DONE)
|
||||
if (GameObject* panel = GetGameObject(DATA_ACCESS_PANEL_HYDRO))
|
||||
panel->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
if (state == SPECIAL)
|
||||
{
|
||||
if (GetBossState(DATA_MEKGINEER_STEAMRIGGER) == SPECIAL)
|
||||
@@ -137,6 +147,9 @@ class instance_steam_vault : public InstanceMapScript
|
||||
}
|
||||
break;
|
||||
case DATA_MEKGINEER_STEAMRIGGER:
|
||||
if (state == DONE)
|
||||
if (GameObject* panel = GetGameObject(DATA_ACCESS_PANEL_MEK))
|
||||
panel->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
if (state == SPECIAL)
|
||||
{
|
||||
if (GetBossState(DATA_HYDROMANCER_THESPIA) == SPECIAL)
|
||||
|
||||
@@ -28,7 +28,11 @@ enum DataTypes
|
||||
DATA_HYDROMANCER_THESPIA = 0,
|
||||
DATA_MEKGINEER_STEAMRIGGER = 1,
|
||||
DATA_WARLORD_KALITHRESH = 2,
|
||||
DATA_DISTILLER = 3
|
||||
DATA_DISTILLER = 3,
|
||||
|
||||
// Additional Data
|
||||
DATA_ACCESS_PANEL_HYDRO = 4,
|
||||
DATA_ACCESS_PANEL_MEK = 5
|
||||
};
|
||||
|
||||
enum CreatureIds
|
||||
|
||||
@@ -40,8 +40,6 @@ go_dragonflayer_cage
|
||||
go_tadpole_cage
|
||||
go_amberpine_outhouse
|
||||
go_hive_pod
|
||||
go_gjalerbron_cage
|
||||
go_large_gjalerbron_cage
|
||||
go_veil_skith_cage
|
||||
EndContentData */
|
||||
|
||||
@@ -1040,69 +1038,6 @@ class go_massive_seaforium_charge : public GameObjectScript
|
||||
};
|
||||
|
||||
/*######
|
||||
## go_gjalerbron_cage
|
||||
######*/
|
||||
|
||||
enum OfKeysAndCages
|
||||
{
|
||||
QUEST_ALLIANCE_OF_KEYS_AND_CAGES = 11231,
|
||||
QUEST_HORDE_OF_KEYS_AND_CAGES = 11265,
|
||||
NPC_GJALERBRON_PRISONER = 24035,
|
||||
SAY_FREE = 0,
|
||||
};
|
||||
|
||||
class go_gjalerbron_cage : public GameObjectScript
|
||||
{
|
||||
public:
|
||||
go_gjalerbron_cage() : GameObjectScript("go_gjalerbron_cage") { }
|
||||
|
||||
bool OnGossipHello(Player* player, GameObject* go) override
|
||||
{
|
||||
go->UseDoorOrButton();
|
||||
if ((player->GetTeamId() == TEAM_ALLIANCE && player->GetQuestStatus(QUEST_ALLIANCE_OF_KEYS_AND_CAGES) == QUEST_STATUS_INCOMPLETE) ||
|
||||
(player->GetTeamId() == TEAM_HORDE && player->GetQuestStatus(QUEST_HORDE_OF_KEYS_AND_CAGES) == QUEST_STATUS_INCOMPLETE))
|
||||
{
|
||||
if (Creature* prisoner = go->FindNearestCreature(NPC_GJALERBRON_PRISONER, 5.0f))
|
||||
{
|
||||
player->KilledMonsterCredit(NPC_GJALERBRON_PRISONER);
|
||||
|
||||
prisoner->AI()->Talk(SAY_FREE);
|
||||
prisoner->DespawnOrUnsummon(6000);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/*########
|
||||
## go_large_gjalerbron_cage
|
||||
#####*/
|
||||
|
||||
class go_large_gjalerbron_cage : public GameObjectScript
|
||||
{
|
||||
public:
|
||||
go_large_gjalerbron_cage() : GameObjectScript("go_large_gjalerbron_cage") { }
|
||||
|
||||
bool OnGossipHello(Player* player, GameObject* go) override
|
||||
{
|
||||
go->UseDoorOrButton();
|
||||
if ((player->GetTeamId() == TEAM_ALLIANCE && player->GetQuestStatus(QUEST_ALLIANCE_OF_KEYS_AND_CAGES) == QUEST_STATUS_INCOMPLETE) ||
|
||||
(player->GetTeamId() == TEAM_HORDE && player->GetQuestStatus(QUEST_HORDE_OF_KEYS_AND_CAGES) == QUEST_STATUS_INCOMPLETE))
|
||||
{
|
||||
std::list<Creature*> prisonerList;
|
||||
GetCreatureListWithEntryInGrid(prisonerList, go, NPC_GJALERBRON_PRISONER, INTERACTION_DISTANCE);
|
||||
for (std::list<Creature*>::const_iterator itr = prisonerList.begin(); itr != prisonerList.end(); ++itr)
|
||||
{
|
||||
player->KilledMonsterCredit(NPC_GJALERBRON_PRISONER, (*itr)->GetGUID());
|
||||
(*itr)->DespawnOrUnsummon(6000);
|
||||
(*itr)->AI()->Talk(SAY_FREE);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/*########
|
||||
#### go_veil_skith_cage
|
||||
#####*/
|
||||
|
||||
@@ -1222,8 +1157,6 @@ void AddSC_go_scripts()
|
||||
new go_amberpine_outhouse();
|
||||
new go_hive_pod();
|
||||
new go_massive_seaforium_charge();
|
||||
new go_gjalerbron_cage();
|
||||
new go_large_gjalerbron_cage();
|
||||
new go_veil_skith_cage();
|
||||
new go_frostblade_shrine();
|
||||
new go_midsummer_bonfire();
|
||||
|
||||
@@ -79,6 +79,9 @@
|
||||
|
||||
inline float finiteAlways(float f) { return std::isfinite(f) ? f : 0.0f; }
|
||||
|
||||
inline unsigned long atoul(char const* str) { return strtoul(str, nullptr, 10); }
|
||||
inline unsigned long long atoull(char const* str) { return strtoull(str, nullptr, 10); }
|
||||
|
||||
#define STRINGIZE(a) #a
|
||||
|
||||
enum TimeConstants
|
||||
|
||||
@@ -81,6 +81,14 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Ensures there's "some" free space, make sure to call Normalize() before this
|
||||
void EnsureFreeSpace()
|
||||
{
|
||||
// Double the size of the buffer if it's already full
|
||||
if (GetRemainingSpace() == 0)
|
||||
_storage.resize(_storage.size() * 2);
|
||||
}
|
||||
|
||||
void Write(void const* data, std::size_t size)
|
||||
{
|
||||
if (size)
|
||||
|
||||
@@ -90,7 +90,8 @@ public:
|
||||
return;
|
||||
|
||||
_readBuffer.Normalize();
|
||||
_socket.async_read_some(boost::asio::buffer(_readBuffer.GetWritePointer(), READ_BLOCK_SIZE),
|
||||
_readBuffer.EnsureFreeSpace();
|
||||
_socket.async_read_some(boost::asio::buffer(_readBuffer.GetWritePointer(), _readBuffer.GetRemainingSpace()),
|
||||
std::bind(&Socket<T>::ReadHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,16 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
_acceptor = new AsyncAcceptor(service, bindIp, port);
|
||||
try
|
||||
{
|
||||
_acceptor = new AsyncAcceptor(service, bindIp, port);
|
||||
}
|
||||
catch (boost::system::system_error const& err)
|
||||
{
|
||||
TC_LOG_ERROR("network", "Exception caught in SocketMgr.StartNetwork (%s:%u): %s", bindIp.c_str(), port, err.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
_threads = CreateThreads();
|
||||
|
||||
ASSERT(_threads);
|
||||
|
||||
@@ -581,6 +581,22 @@ MinCharterName = 2
|
||||
|
||||
MinPetName = 2
|
||||
|
||||
#
|
||||
# Guild.CharterCost
|
||||
# ArenaTeam.CharterCost.2v2
|
||||
# ArenaTeam.CharterCost.3v3
|
||||
# ArenaTeam.CharterCost.5v5
|
||||
# Description: Amount of money (in Copper) the petitions costs.
|
||||
# Default: 1000 - (10 Silver)
|
||||
# 800000 - (80 Gold)
|
||||
# 1200000 - (120 Gold)
|
||||
# 2000000 - (200 Gold)
|
||||
|
||||
Guild.CharterCost = 1000
|
||||
ArenaTeam.CharterCost.2v2 = 800000
|
||||
ArenaTeam.CharterCost.3v3 = 1200000
|
||||
ArenaTeam.CharterCost.5v5 = 2000000
|
||||
|
||||
#
|
||||
# MaxWhoListReturns
|
||||
# Description: Set the max number of players returned in the /who list and interface.
|
||||
|
||||
Reference in new issue
Block a user