aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/base/characters_database.sql123
-rw-r--r--sql/updates/characters/2015_01_27_00_characters.sql17
-rw-r--r--sql/updates/world/2015_01_30_00_world.sql32
-rw-r--r--sql/updates/world/2015_01_30_01_world.sql19
-rw-r--r--src/server/game/Battlefield/Battlefield.cpp24
-rw-r--r--src/server/game/Battlefield/Battlefield.h11
-rw-r--r--src/server/game/Battlegrounds/Battleground.cpp2
-rw-r--r--src/server/game/DataStores/DBCStores.cpp56
-rw-r--r--src/server/game/DataStores/DBCStores.h15
-rw-r--r--src/server/game/DataStores/DBCStructure.h1
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp8
-rw-r--r--src/server/game/Entities/GameObject/GameObject.h4
-rw-r--r--src/server/game/Entities/Player/Player.cpp607
-rw-r--r--src/server/game/Entities/Player/Player.h55
-rw-r--r--src/server/game/Entities/Unit/StatSystem.cpp2
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp53
-rw-r--r--src/server/game/Entities/Unit/Unit.h21
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp6
-rw-r--r--src/server/game/Globals/ObjectMgr.h4
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp4
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp10
-rw-r--r--src/server/game/Handlers/PetHandler.cpp2
-rw-r--r--src/server/game/Handlers/SkillHandler.cpp2
-rw-r--r--src/server/game/Handlers/SpellHandler.cpp78
-rw-r--r--src/server/game/Maps/Map.cpp26
-rw-r--r--src/server/game/Maps/Map.h11
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h6
-rw-r--r--src/server/game/OutdoorPvP/OutdoorPvP.cpp49
-rw-r--r--src/server/game/OutdoorPvP/OutdoorPvP.h23
-rw-r--r--src/server/game/Server/Packets/CombatPackets.cpp7
-rw-r--r--src/server/game/Server/Packets/CombatPackets.h19
-rw-r--r--src/server/game/Server/Packets/MiscPackets.cpp30
-rw-r--r--src/server/game/Server/Packets/MiscPackets.h40
-rw-r--r--src/server/game/Server/Packets/QueryPackets.h2
-rw-r--r--src/server/game/Server/Packets/SpellPackets.cpp119
-rw-r--r--src/server/game/Server/Packets/SpellPackets.h104
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp18
-rw-r--r--src/server/game/Server/Protocol/Opcodes.h8
-rw-r--r--src/server/game/Server/WorldSession.cpp2
-rw-r--r--src/server/game/Server/WorldSession.h10
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp7
-rw-r--r--src/server/game/Spells/Spell.cpp117
-rw-r--r--src/server/game/Spells/Spell.h14
-rw-r--r--src/server/game/Spells/SpellEffects.cpp45
-rw-r--r--src/server/game/Spells/SpellInfo.cpp68
-rw-r--r--src/server/game/Spells/SpellInfo.h1
-rw-r--r--src/server/game/Spells/SpellMgr.cpp144
-rw-r--r--src/server/game/Spells/SpellMgr.h1
-rw-r--r--src/server/game/Tools/CharacterDatabaseCleaner.cpp4
-rw-r--r--src/server/game/Weather/Weather.cpp13
-rw-r--r--src/server/game/Weather/Weather.h2
-rw-r--r--src/server/game/Weather/WeatherMgr.cpp6
-rw-r--r--src/server/scripts/Commands/cs_learn.cpp2
-rw-r--r--src/server/scripts/Commands/cs_list.cpp2
-rw-r--r--src/server/scripts/Commands/cs_lookup.cpp4
-rw-r--r--src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp2
-rw-r--r--src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp6
-rw-r--r--src/server/scripts/Kalimdor/zone_the_barrens.cpp2
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp414
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h23
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp52
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp6
-rw-r--r--src/server/scripts/Northrend/zone_zuldrak.cpp2
-rw-r--r--src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp8
-rw-r--r--src/server/scripts/Spells/spell_dk.cpp39
-rw-r--r--src/server/scripts/Spells/spell_druid.cpp2
-rw-r--r--src/server/scripts/Spells/spell_holiday.cpp4
-rw-r--r--src/server/shared/Debugging/Errors.h6
68 files changed, 1668 insertions, 958 deletions
diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql
index aa5ec6f9c5a..0528f355c81 100644
--- a/sql/base/characters_database.sql
+++ b/sql/base/characters_database.sql
@@ -514,15 +514,16 @@ DROP TABLE IF EXISTS `character_aura_effect`;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `character_aura_effect` (
`guid` bigint(20) unsigned NOT NULL,
- `casterGuid` binary(16) NOT NULL COMMENT 'Full Global Unique Identifier' ,
+ `casterGuid` binary(16) NOT NULL COMMENT 'Full Global Unique Identifier',
`itemGuid` binary(16) NOT NULL,
- `spell` int(10) unsigned NOT NULL ,
+ `spell` int(10) unsigned NOT NULL,
`effectMask` int(10) unsigned NOT NULL,
`effectIndex` tinyint(3) unsigned NOT NULL,
- `amount` int(11) NOT NULL DEFAULT 0,
- `baseAmount` int(11) NOT NULL DEFAULT 0,
-PRIMARY KEY (`guid`,`casterGuid`,`itemGuid`,`spell`,`effectMask`,`effectIndex`)
+ `amount` int(11) NOT NULL DEFAULT '0',
+ `baseAmount` int(11) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`guid`,`casterGuid`,`itemGuid`,`spell`,`effectMask`,`effectIndex`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Player System';
+/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `character_aura_effect`
@@ -965,11 +966,11 @@ DROP TABLE IF EXISTS `character_queststatus`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `character_queststatus` (
- `guid` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0',
- `quest` INT(10) UNSIGNED NOT NULL DEFAULT '0',
- `status` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',
- `timer` INT(10) UNSIGNED NOT NULL DEFAULT '0',
- PRIMARY KEY (`guid`, `quest`)
+ `guid` bigint(20) unsigned NOT NULL DEFAULT '0',
+ `quest` int(10) unsigned NOT NULL DEFAULT '0',
+ `status` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `timer` int(10) unsigned NOT NULL DEFAULT '0',
+ PRIMARY KEY (`guid`,`quest`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Player System';
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -983,31 +984,6 @@ LOCK TABLES `character_queststatus` WRITE;
UNLOCK TABLES;
--
--- Table structure for table `character_queststatus_objectives`
---
-
-DROP TABLE IF EXISTS `character_queststatus_objectives`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `character_queststatus_objectives` (
- `guid` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0',
- `quest` INT(10) UNSIGNED NOT NULL DEFAULT '0',
- `objective` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',
- `data` INT(11) NOT NULL DEFAULT '0',
- PRIMARY KEY (`guid`, `quest`, `objective`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Player System';
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `character_queststatus_objectives`
---
-
-LOCK TABLES `character_queststatus_objectives` WRITE;
-/*!40000 ALTER TABLE `character_queststatus_objectives` DISABLE KEYS */;
-/*!40000 ALTER TABLE `character_queststatus_objectives` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
-- Table structure for table `character_queststatus_daily`
--
@@ -1057,6 +1033,31 @@ LOCK TABLES `character_queststatus_monthly` WRITE;
UNLOCK TABLES;
--
+-- Table structure for table `character_queststatus_objectives`
+--
+
+DROP TABLE IF EXISTS `character_queststatus_objectives`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `character_queststatus_objectives` (
+ `guid` bigint(20) unsigned NOT NULL DEFAULT '0',
+ `quest` int(10) unsigned NOT NULL DEFAULT '0',
+ `objective` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `data` int(11) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`guid`,`quest`,`objective`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Player System';
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `character_queststatus_objectives`
+--
+
+LOCK TABLES `character_queststatus_objectives` WRITE;
+/*!40000 ALTER TABLE `character_queststatus_objectives` DISABLE KEYS */;
+/*!40000 ALTER TABLE `character_queststatus_objectives` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
-- Table structure for table `character_queststatus_rewarded`
--
@@ -2013,15 +2014,15 @@ DROP TABLE IF EXISTS `guild_finder_applicant`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `guild_finder_applicant` (
- `guildId` bigint(20) unsigned DEFAULT NULL,
- `playerGuid` bigint(20) unsigned DEFAULT NULL,
+ `guildId` bigint(20) unsigned NOT NULL DEFAULT '0',
+ `playerGuid` bigint(20) unsigned NOT NULL DEFAULT '0',
`availability` tinyint(3) unsigned DEFAULT '0',
`classRole` tinyint(3) unsigned DEFAULT '0',
`interests` tinyint(3) unsigned DEFAULT '0',
`comment` varchar(255) DEFAULT NULL,
`submitTime` int(10) unsigned DEFAULT NULL,
- UNIQUE KEY `guildId` (`guildId`,`playerGuid`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+ PRIMARY KEY (`guildId`,`playerGuid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -2049,7 +2050,7 @@ CREATE TABLE `guild_finder_guild_settings` (
`listed` tinyint(3) unsigned NOT NULL DEFAULT '0',
`comment` varchar(255) DEFAULT NULL,
PRIMARY KEY (`guildId`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -2121,7 +2122,7 @@ LOCK TABLES `guild_member_withdraw` WRITE;
UNLOCK TABLES;
--
--- Table structure for table `guild_news_log`
+-- Table structure for table `guild_newslog`
--
DROP TABLE IF EXISTS `guild_newslog`;
@@ -2291,8 +2292,9 @@ CREATE TABLE `item_loot_items` (
`under_threshold` tinyint(1) NOT NULL DEFAULT '0',
`needs_quest` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'quest drop',
`rnd_prop` int(10) NOT NULL DEFAULT '0' COMMENT 'random enchantment added when originally rolled',
- `rnd_suffix` int(10) NOT NULL DEFAULT '0' COMMENT 'random suffix added when originally rolled'
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+ `rnd_suffix` int(10) NOT NULL DEFAULT '0' COMMENT 'random suffix added when originally rolled',
+ PRIMARY KEY (`container_id`,`item_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -2313,8 +2315,9 @@ DROP TABLE IF EXISTS `item_loot_money`;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `item_loot_money` (
`container_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'guid of container (item_instance.guid)',
- `money` int(10) NOT NULL DEFAULT '0' COMMENT 'money loot (in copper)'
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+ `money` int(10) NOT NULL DEFAULT '0' COMMENT 'money loot (in copper)',
+ PRIMARY KEY (`container_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -2502,11 +2505,11 @@ CREATE TABLE `pet_aura` (
`casterGuid` binary(16) NOT NULL COMMENT 'Full Global Unique Identifier',
`spell` int(10) unsigned NOT NULL,
`effectMask` int(10) unsigned NOT NULL,
- `recalculateMask` int(10) unsigned NOT NULL DEFAULT 0,
- `stackCount` tinyint(3) unsigned NOT NULL DEFAULT 1,
- `maxDuration` int(11) NOT NULL DEFAULT 0,
- `remainTime` int(11) NOT NULL DEFAULT 0,
- `remainCharges` tinyint(3) unsigned NOT NULL DEFAULT 0,
+ `recalculateMask` int(10) unsigned NOT NULL DEFAULT '0',
+ `stackCount` tinyint(3) unsigned NOT NULL DEFAULT '1',
+ `maxDuration` int(11) NOT NULL DEFAULT '0',
+ `remainTime` int(11) NOT NULL DEFAULT '0',
+ `remainCharges` tinyint(3) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`guid`,`spell`,`effectMask`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Pet System';
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -2529,14 +2532,15 @@ DROP TABLE IF EXISTS `pet_aura_effect`;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `pet_aura_effect` (
`guid` int(10) unsigned NOT NULL COMMENT 'Global Unique Identifier',
- `casterGuid` binary(16) NOT NULL COMMENT 'Full Global Unique Identifier' ,
+ `casterGuid` binary(16) NOT NULL COMMENT 'Full Global Unique Identifier',
`spell` int(10) unsigned NOT NULL,
`effectMask` int(10) unsigned NOT NULL,
`effectIndex` tinyint(3) unsigned NOT NULL,
- `amount` int(11) NOT NULL DEFAULT 0,
- `baseAmount` int(11) NOT NULL DEFAULT 0,
-PRIMARY KEY (`guid`,`casterGuid`,`spell`,`effectMask`,`effectIndex`)
+ `amount` int(11) NOT NULL DEFAULT '0',
+ `baseAmount` int(11) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`guid`,`casterGuid`,`spell`,`effectMask`,`effectIndex`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Pet System';
+/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `pet_aura_effect`
@@ -2686,7 +2690,7 @@ CREATE TABLE `pvpstats_battlegrounds` (
`type` tinyint(3) unsigned NOT NULL,
`date` datetime NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -2720,7 +2724,7 @@ CREATE TABLE `pvpstats_players` (
`attr_4` mediumint(8) unsigned NOT NULL DEFAULT '0',
`attr_5` mediumint(8) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`battleground_id`,`character_guid`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -2747,8 +2751,9 @@ CREATE TABLE `quest_tracker` (
`quest_abandon_time` datetime DEFAULT NULL,
`completed_by_gm` tinyint(1) NOT NULL DEFAULT '0',
`core_hash` varchar(120) NOT NULL DEFAULT '0',
- `core_revision` varchar(120) NOT NULL DEFAULT '0'
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+ `core_revision` varchar(120) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`,`character_guid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -2839,4 +2844,4 @@ UNLOCK TABLES;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
--- Dump completed on 2014-10-18 18:02:06
+-- Dump completed on 2015-01-27 22:41:44
diff --git a/sql/updates/characters/2015_01_27_00_characters.sql b/sql/updates/characters/2015_01_27_00_characters.sql
new file mode 100644
index 00000000000..3ccaa4defb0
--- /dev/null
+++ b/sql/updates/characters/2015_01_27_00_characters.sql
@@ -0,0 +1,17 @@
+-- latin1 to utf8
+ALTER TABLE `guild_finder_applicant` CONVERT TO CHARACTER SET utf8, CHARACTER SET utf8;
+ALTER TABLE `guild_finder_guild_settings` CONVERT TO CHARACTER SET utf8, CHARACTER SET utf8;
+ALTER TABLE `item_loot_items` CONVERT TO CHARACTER SET utf8, CHARACTER SET utf8;
+ALTER TABLE `item_loot_money` CONVERT TO CHARACTER SET utf8, CHARACTER SET utf8;
+ALTER TABLE `pvpstats_battlegrounds` CONVERT TO CHARACTER SET utf8, CHARACTER SET utf8;
+ALTER TABLE `pvpstats_players` CONVERT TO CHARACTER SET utf8, CHARACTER SET utf8;
+ALTER TABLE `quest_tracker` CONVERT TO CHARACTER SET utf8, CHARACTER SET utf8;
+
+-- add PKs
+ALTER TABLE `guild_finder_applicant` DROP INDEX `guildId`, -- had unique instead of PK
+ ADD PRIMARY KEY (`guildId`, `playerGuid`);
+
+ALTER TABLE `item_loot_items` ADD PRIMARY KEY (`container_id`, `item_id`);
+ALTER TABLE `item_loot_money` ADD PRIMARY KEY (`container_id`);
+
+ALTER TABLE `quest_tracker` ADD PRIMARY KEY( `id`, `character_guid`);
diff --git a/sql/updates/world/2015_01_30_00_world.sql b/sql/updates/world/2015_01_30_00_world.sql
new file mode 100644
index 00000000000..57910525e52
--- /dev/null
+++ b/sql/updates/world/2015_01_30_00_world.sql
@@ -0,0 +1,32 @@
+DELETE FROM `creature_text` WHERE `entry` IN(37158,37704);
+DELETE FROM `creature_text` WHERE `entry`=37225 AND `groupid` > 15;
+INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `comment`, `BroadcastTextID`) VALUES
+(37158, 0, 0, '%s prepares to attack!', 41, 0, 100, 0, 0, 0, 'Quel''Delar', 37211),
+(37704, 0, 0, 'Quel''Delar leaps to life in the presence of Frostmourne!', 41, 0, 100, 0, 0, 0, 'Frostmourne Altar Bunny (Quel''Delar)', 37645),
+-- Uther
+(37225, 16, 0, 'Halt! Do not carry that blade any further!', 14, 0, 100, 25, 0, 16675, 'Uther the Lightbringer', 37201),
+(37225, 17, 0, 'Do you realize what you''ve done?', 14, 0, 100, 5, 0, 16676, 'Uther the Lightbringer', 37202),
+(37225, 18, 0, 'You have forged this blade from saronite, the very blood of an old god. The power of the Lich King calls to this weapon.', 12, 0, 100, 1, 0, 16677, 'Uther the Lightbringer', 37204),
+(37225, 19, 0, 'Each moment you tarry here, Quel''Delar drinks in the evil of this place.', 12, 0, 100, 1, 0, 16678, 'Uther the Lightbringer', 38442),
+(37225, 20, 0, 'There is only one way to cleanse this sword. Make haste for the Sunwell and immerse the blade in its waters.', 12, 0, 100, 25, 0, 16679, 'Uther the Lightbringer', 37205),
+(37225, 21, 0, 'I can resist Frostmourne''s call no more...', 12, 0, 100, 1, 0, 16680, 'Uther the Lightbringer', 37206);
+
+UPDATE `creature_template` SET `unit_flags`=768, `flags_extra`=0, `ScriptName`='npc_quel_delar_sword', `InhabitType`=7 WHERE `entry`=37158;
+UPDATE `creature_template` SET `ScriptName`='npc_uther_quel_delar' WHERE `entry`=37225;
+
+DELETE FROM `areatrigger_scripts` WHERE `entry`=5660;
+INSERT INTO `areatrigger_scripts` (`entry`,`ScriptName`) VALUES
+(5660, 'at_hor_uther_quel_delar_start');
+
+DELETE FROM `spell_target_position` WHERE `id` IN(70719,70700);
+INSERT INTO `spell_target_position` (`id`,`MapID`,`PositionX`,`PositionY`,`PositionZ`) VALUES
+(70719, 668, 5302, 1989, 708),
+(70700, 668, 5298, 1995, 708);
+
+DELETE FROM `creature_loot_template` WHERE `entry` = 37158 AND `item` = 50254;
+INSERT INTO `creature_loot_template` (`Entry`, `Item`, `Chance`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`) VALUES
+(37158, 50254, 100, 1, 0, 1, 1);
+
+DELETE FROM `conditions` WHERE `SourceEntry` = 73035 AND `SourceTypeOrReferenceId` = 13;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `Comment`) VALUES
+(13,1,73035,0,0,31,0,3,37704,0,0,0,0,'Essence of the Captured (73035) only hits Frostmourne Altar Bunny (Quel''Delar)');
diff --git a/sql/updates/world/2015_01_30_01_world.sql b/sql/updates/world/2015_01_30_01_world.sql
new file mode 100644
index 00000000000..0b88e0d01d4
--- /dev/null
+++ b/sql/updates/world/2015_01_30_01_world.sql
@@ -0,0 +1,19 @@
+DELETE FROM `playercreateinfo_skills` WHERE `skill` IN (795,796,798,800,804,829,840,849,904,921,924);
+INSERT INTO `playercreateinfo_skills` (`raceMask`,`classMask`,`skill`,`rank`,`comment`) VALUES
+(0, 4, 795, 0, "Hunter skills."),
+(0, 32, 796, 0, "Death Knight skills."),
+(0, 1024, 798, 0, "Druid skills."),
+(0, 2, 800, 0, "Paladin skills."),
+(0, 16, 804, 0, "Priest skills."),
+(0, 512, 829, 0, "Monk skills."),
+(0, 1, 840, 0, "Warrior skills."),
+(0, 256, 849, 0, "Warlock skills."),
+(0, 128, 904, 0, "Mage skills."),
+(0, 8, 921, 0, "Rogue skills."),
+(0, 64, 924, 0, "Shaman skills.");
+
+DELETE FROM `spell_ranks` WHERE `first_spell_id`=127650;
+INSERT INTO `spell_ranks` (`first_spell_id`,`spell_id`,`rank`) VALUES
+(127650,127650,1), -- Remove Talent: Vanishing Powder
+(127650,127649,2), -- Remove Talent: Dust of Disappearance
+(127650,113873,3); -- Remove Talent: Tome of the Clear Mind
diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp
index 54c43673411..c9f2492617a 100644
--- a/src/server/game/Battlefield/Battlefield.cpp
+++ b/src/server/game/Battlefield/Battlefield.cpp
@@ -450,6 +450,25 @@ void Battlefield::SendUpdateWorldState(uint32 variable, uint32 value, bool hidde
BroadcastPacketToZone(worldstate.Write());
}
+void Battlefield::AddCapturePoint(BfCapturePoint* cp)
+{
+ Battlefield::BfCapturePointMap::iterator i = m_capturePoints.find(cp->GetCapturePointEntry());
+ if (i != m_capturePoints.end())
+ {
+ TC_LOG_ERROR("bg.battlefield", "Battlefield::AddCapturePoint: CapturePoint %s already exists!", cp->GetCapturePointEntry());
+ delete i->second;
+ }
+ m_capturePoints[cp->GetCapturePointEntry()] = cp;
+}
+
+BfCapturePoint* Battlefield::GetCapturePoint(uint32 entry) const
+{
+ Battlefield::BfCapturePointMap::const_iterator itr = m_capturePoints.find(entry);
+ if (itr != m_capturePoints.end())
+ return itr->second;
+ return nullptr;
+}
+
void Battlefield::RegisterZone(uint32 zoneId)
{
sBattlefieldMgr->AddZone(zoneId, this);
@@ -913,10 +932,11 @@ bool BfCapturePoint::SetCapturePointData(GameObject* capturePoint)
TC_LOG_DEBUG("bg.battlefield", "Creating capture point %u", capturePoint->GetEntry());
m_capturePointGUID = capturePoint->GetGUID();
+ m_capturePointEntry = capturePoint->GetEntry();
// check info existence
GameObjectTemplate const* goinfo = capturePoint->GetGOInfo();
- if (goinfo->type != GAMEOBJECT_TYPE_CAPTURE_POINT)
+ if (goinfo->type != GAMEOBJECT_TYPE_CONTROL_ZONE)
{
TC_LOG_ERROR("misc", "OutdoorPvP: GO %u is not capture point!", capturePoint->GetEntry());
return false;
@@ -927,7 +947,7 @@ bool BfCapturePoint::SetCapturePointData(GameObject* capturePoint)
m_maxSpeed = m_maxValue / (goinfo->controlZone.minTime ? goinfo->controlZone.minTime : 60);
m_neutralValuePct = goinfo->controlZone.neutralPercent;
m_minValue = m_maxValue * goinfo->controlZone.neutralPercent / 100;
- m_capturePointEntry = capturePoint->GetEntry();
+
if (m_team == TEAM_ALLIANCE)
{
m_value = m_maxValue;
diff --git a/src/server/game/Battlefield/Battlefield.h b/src/server/game/Battlefield/Battlefield.h
index 2ea1f100ee2..3fcfc22b941 100644
--- a/src/server/game/Battlefield/Battlefield.h
+++ b/src/server/game/Battlefield/Battlefield.h
@@ -402,15 +402,8 @@ class Battlefield : public ZoneScript
void BroadcastPacketToWar(WorldPacket const* data) const;
// CapturePoint system
- void AddCapturePoint(BfCapturePoint* cp) { m_capturePoints[cp->GetCapturePointEntry()] = cp; }
-
- BfCapturePoint* GetCapturePoint(uint32 lowguid) const
- {
- Battlefield::BfCapturePointMap::const_iterator itr = m_capturePoints.find(lowguid);
- if (itr != m_capturePoints.end())
- return itr->second;
- return NULL;
- }
+ void AddCapturePoint(BfCapturePoint* cp);
+ BfCapturePoint* GetCapturePoint(uint32 entry) const;
void RegisterZone(uint32 zoneid);
bool HasPlayer(Player* player) const;
diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp
index 0bba2c84827..e870eadec1e 100644
--- a/src/server/game/Battlegrounds/Battleground.cpp
+++ b/src/server/game/Battlegrounds/Battleground.cpp
@@ -1078,7 +1078,7 @@ void Battleground::AddPlayer(Player* player)
BattlegroundPlayer bp;
bp.OfflineRemoveTime = 0;
bp.Team = team;
- bp.ActiveSpec = player->GetActiveTalentSpec();
+ bp.ActiveSpec = player->GetSpecId(player->GetActiveTalentGroup());
// Add to list/maps
m_Players[player->GetGUID()] = bp;
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index 7532a6f8c75..bd087be84dd 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -76,7 +76,6 @@ DBCStorage <ChrRacesEntry> sChrRacesStore(ChrRacesEntryfmt);
DBCStorage <ChrPowerTypesEntry> sChrPowerTypesStore(ChrClassesXPowerTypesfmt);
DBCStorage <ChrSpecializationEntry> sChrSpecializationStore(ChrSpecializationEntryfmt);
ChrSpecializationByIndexArray sChrSpecializationByIndexStore;
-SpecializationSpellsBySpecStore sSpecializationSpellsBySpecStore;
DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore(CinematicSequencesEntryfmt);
DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore(CreatureDisplayInfofmt);
DBCStorage <CreatureDisplayInfoExtraEntry> sCreatureDisplayInfoExtraStore(CreatureDisplayInfoExtrafmt);
@@ -199,6 +198,7 @@ DBCStorage <SkillTiersEntry> sSkillTiersStore(SkillTiersfmt);
DBCStorage <SoundEntriesEntry> sSoundEntriesStore(SoundEntriesfmt);
DBCStorage <SpecializationSpellsEntry> sSpecializationSpellsStore(SpecializationSpellsEntryfmt);
+std::unordered_map<uint32, std::vector<SpecializationSpellsEntry const*>> sSpecializationSpellsBySpecStore;
DBCStorage <SpellItemEnchantmentEntry> sSpellItemEnchantmentStore(SpellItemEnchantmentfmt);
DBCStorage <SpellItemEnchantmentConditionEntry> sSpellItemEnchantmentConditionStore(SpellItemEnchantmentConditionfmt);
DBCStorage <SpellEntry> sSpellStore(SpellEntryfmt);
@@ -229,9 +229,7 @@ DBCStorage <SpellShapeshiftFormEntry> sSpellShapeshiftFormStore(SpellShapeshiftF
DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore(StableSlotPricesfmt);
DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore(SummonPropertiesfmt);
DBCStorage <TalentEntry> sTalentStore(TalentEntryfmt);
-TalentBySpellIDMap sTalentBySpellIDMap;
-SpecializationSpellsMap sSpecializationSpellsMap;
-SpecializationOverrideSpellsMap sSpecializationOverrideSpellMap;
+TalentsByPosition sTalentByPos;
DBCStorage <TotemCategoryEntry> sTotemCategoryStore(TotemCategoryEntryfmt);
DBCStorage <TransportAnimationEntry> sTransportAnimationStore(TransportAnimationfmt);
@@ -546,16 +544,15 @@ void LoadDBCStores(const std::string& dataPath)
LoadDBC(availableDbcLocales, bad_dbc_files, sSkillTiersStore, dbcPath, "SkillTiers.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sSoundEntriesStore, dbcPath, "SoundEntries.dbc");//15595
LoadDBC(availableDbcLocales, bad_dbc_files, sSpecializationSpellsStore, dbcPath, "SpecializationSpells.dbc");
- for (uint32 i = 1; i < sSpecializationSpellsStore.GetNumRows(); ++i)
+ for (uint32 i = 0; i < sSpecializationSpellsStore.GetNumRows(); ++i)
{
SpecializationSpellsEntry const* specSpells = sSpecializationSpellsStore.LookupEntry(i);
if (!specSpells)
continue;
- sSpecializationSpellsBySpecStore[specSpells->SpecID].push_back(specSpells);
- if (specSpells->OverridesSpellID)
- sSpecializationOverrideSpellMap[specSpells->SpecID][specSpells->OverridesSpellID] = specSpells->SpellID;
+ sSpecializationSpellsBySpecStore[specSpells->SpecID].push_back(specSpells);
}
+
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellStore, dbcPath, "Spell.dbc"/*, &CustomSpellEntryfmt, &CustomSpellEntryIndex*/);
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCategoriesStore, dbcPath, "SpellCategories.dbc");//15595
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCategoryStore, dbcPath, "SpellCategory.dbc");
@@ -599,15 +596,17 @@ void LoadDBCStores(const std::string& dataPath)
sSpellEffectScallingByEffectId.insert(std::make_pair(spellEffectScaling->SpellEffectID, j));
}
- LoadDBC(availableDbcLocales, bad_dbc_files, sTalentStore, dbcPath, "Talent.dbc");//15595
-
- for (unsigned int i = 0; i < sTalentStore.GetNumRows(); ++i)
+ LoadDBC(availableDbcLocales, bad_dbc_files, sTalentStore, dbcPath, "Talent.dbc");//19342
+ for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
{
- TalentEntry const* talentInfo = sTalentStore.LookupEntry(i);
- if (!talentInfo)
- continue;
-
- sTalentBySpellIDMap[talentInfo->SpellID] = talentInfo;
+ if (TalentEntry const* talentInfo = sTalentStore.LookupEntry(i))
+ {
+ if (talentInfo->ClassID < MAX_CLASSES && talentInfo->TierID < MAX_TALENT_TIERS && talentInfo->ColumnIndex < MAX_TALENT_COLUMNS)
+ sTalentByPos[talentInfo->ClassID][talentInfo->TierID][talentInfo->ColumnIndex].push_back(talentInfo);
+ else
+ TC_LOG_ERROR("server.loading", "Value of class (found: %u, max allowed %u) or (found: %u, max allowed %u) tier or column (found: %u, max allowed %u) is invalid.",
+ talentInfo->ClassID, MAX_CLASSES, talentInfo->TierID, MAX_TALENT_TIERS, talentInfo->ColumnIndex, MAX_TALENT_COLUMNS);
+ }
}
//LoadDBC(availableDbcLocales, bad_dbc_files, sTeamContributionPointsStore, dbcPath, "TeamContributionPoints.dbc");
@@ -967,14 +966,6 @@ PvPDifficultyEntry const* GetBattlegroundBracketById(uint32 mapid, BattlegroundB
return NULL;
}
-TalentEntry const* GetTalentBySpellID(uint32 spellID)
-{
- auto itr = sTalentBySpellIDMap.find(spellID);
- if (itr != sTalentBySpellIDMap.end())
- return itr->second;
- return nullptr;
-}
-
uint32 GetLiquidFlags(uint32 liquidType)
{
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(liquidType))
@@ -1044,14 +1035,6 @@ SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, u
return NULL;
}
-uint32 GetTalentSpellCost(uint32 spellId)
-{
- TalentBySpellIDMap::const_iterator itr = sTalentBySpellIDMap.find(spellId);
- if (itr == sTalentBySpellIDMap.end())
- return 0;
- return 1;
-}
-
uint32 GetQuestUniqueBitFlag(uint32 questId)
{
QuestV2Entry const* v2 = sQuestV2Store.LookupEntry(questId);
@@ -1060,3 +1043,12 @@ uint32 GetQuestUniqueBitFlag(uint32 questId)
return v2->UniqueBitFlag;
}
+
+std::vector<SpecializationSpellsEntry const*> const* GetSpecializationSpells(uint32 specId)
+{
+ auto itr = sSpecializationSpellsBySpecStore.find(specId);
+ if (itr != sSpecializationSpellsBySpecStore.end())
+ return &itr->second;
+
+ return nullptr;
+}
diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h
index 8a411300a79..edbb5aa55bf 100644
--- a/src/server/game/DataStores/DBCStores.h
+++ b/src/server/game/DataStores/DBCStores.h
@@ -30,8 +30,6 @@ typedef std::list<uint32> SimpleFactionsList;
SimpleFactionsList const* GetFactionTeamList(uint32 faction);
char const* GetPetName(uint32 petfamily, uint32 dbclang);
-uint32 GetTalentSpellCost(uint32 spellId);
-TalentEntry const* GetTalentBySpellID(uint32 spellID);
int32 GetAreaFlagByAreaID(uint32 area_id); // -1 if not found
AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id);
@@ -91,14 +89,10 @@ typedef std::unordered_multimap<uint32, SkillRaceClassInfoEntry const*> SkillRac
typedef std::pair<SkillRaceClassInfoMap::iterator, SkillRaceClassInfoMap::iterator> SkillRaceClassInfoBounds;
SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_);
-typedef std::vector<SpecializationSpellsEntry const*> SpecializationSpellsBySpecEntry;
-typedef std::unordered_map<uint32, SpecializationSpellsBySpecEntry> SpecializationSpellsBySpecStore;
typedef ChrSpecializationEntry const* ChrSpecializationByIndexArray[MAX_CLASSES][MAX_SPECIALIZATIONS];
-typedef std::unordered_map<uint32, TalentEntry const*> TalentBySpellIDMap;
-
-typedef std::map<uint32, std::vector<uint32> > SpecializationSpellsMap;
-extern SpecializationSpellsMap sSpecializationSpellsMap;
-extern SpecializationOverrideSpellsMap sSpecializationOverrideSpellMap;
+std::vector<SpecializationSpellsEntry const*> const* GetSpecializationSpells(uint32 specId);
+typedef std::vector<TalentEntry const*> TalentsByPosition[MAX_CLASSES][MAX_TALENT_TIERS][MAX_TALENT_COLUMNS];
+extern TalentsByPosition sTalentByPos;
template<class T>
class GameTable
@@ -243,8 +237,6 @@ extern DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore;
extern DBCStorage <SkillTiersEntry> sSkillTiersStore;
extern DBCStorage <SoundEntriesEntry> sSoundEntriesStore;
extern SpellEffectScallingByEffectId sSpellEffectScallingByEffectId;
-extern DBCStorage <SpecializationSpellsEntry> sSpecializationSpellsStore;
-extern SpecializationSpellsBySpecStore sSpecializationSpellsBySpecStore;
extern DBCStorage <SpellCastTimesEntry> sSpellCastTimesStore;
extern DBCStorage <SpellCategoryEntry> sSpellCategoryStore;
extern DBCStorage <SpellDurationEntry> sSpellDurationStore;
@@ -271,7 +263,6 @@ extern DBCStorage <SpellTargetRestrictionsEntry> sSpellTargetRestrictionsStore;
//extern DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore;
extern DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore;
extern DBCStorage <TalentEntry> sTalentStore;
-extern TalentBySpellIDMap sTalentBySpellIDMap;
extern DBCStorage <TotemCategoryEntry> sTotemCategoryStore;
extern DBCStorage <UnitPowerBarEntry> sUnitPowerBarStore;
extern DBCStorage <VehicleEntry> sVehicleStore;
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index 69739a32854..0bad082801d 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -1788,6 +1788,7 @@ struct SummonPropertiesEntry
};
#define MAX_TALENT_TIERS 7
+#define MAX_TALENT_COLUMNS 3
struct TalentEntry
{
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index 78efc590566..bb4bed9f79a 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -1315,8 +1315,8 @@ void GameObject::Use(Unit* user)
{
if (Player* ChairUser = ObjectAccessor::FindPlayer(itr->second))
{
- if (ChairUser->IsSitState() && ChairUser->getStandState() != UNIT_STAND_STATE_SIT && ChairUser->GetExactDist2d(x_i, y_i) < 0.1f)
- continue; // This seat is already occupied by ChairUser. NOTE: Not sure if the ChairUser->getStandState() != UNIT_STAND_STATE_SIT check is required.
+ if (ChairUser->IsSitState() && ChairUser->GetStandState() != UNIT_STAND_STATE_SIT && ChairUser->GetExactDist2d(x_i, y_i) < 0.1f)
+ continue; // This seat is already occupied by ChairUser. NOTE: Not sure if the ChairUser->GetStandState() != UNIT_STAND_STATE_SIT check is required.
else
itr->second.Clear(); // This seat is unoccupied.
}
@@ -1345,7 +1345,7 @@ void GameObject::Use(Unit* user)
{
itr->second = player->GetGUID(); //this slot in now used by player
player->TeleportTo(GetMapId(), x_lowest, y_lowest, GetPositionZ(), GetOrientation(), TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET);
- player->SetStandState(UNIT_STAND_STATE_SIT_LOW_CHAIR + info->chair.chairheight);
+ player->SetStandState(UnitStandStateType(UNIT_STAND_STATE_SIT_LOW_CHAIR + info->chair.chairheight));
return;
}
}
@@ -1773,7 +1773,7 @@ void GameObject::Use(Unit* user)
WorldPacket data(SMSG_ENABLE_BARBER_SHOP, 0);
player->SendDirectMessage(&data);
- player->SetStandState(UNIT_STAND_STATE_SIT_LOW_CHAIR+info->barberChair.chairheight);
+ player->SetStandState(UnitStandStateType(UNIT_STAND_STATE_SIT_LOW_CHAIR + info->barberChair.chairheight));
return;
}
default:
diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h
index 239324c572d..ff89e3f7cc0 100644
--- a/src/server/game/Entities/GameObject/GameObject.h
+++ b/src/server/game/Entities/GameObject/GameObject.h
@@ -776,11 +776,11 @@ union GameObjectValue
{
uint32 MaxOpens;
} FishingHole;
- //29 GAMEOBJECT_TYPE_CAPTURE_POINT
+ //29 GAMEOBJECT_TYPE_CONTROL_ZONE
struct
{
OPvPCapturePoint *OPvPObj;
- } CapturePoint;
+ } ControlZone;
//33 GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING
struct
{
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index bd084491dee..d373e46fc41 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -33,6 +33,7 @@
#include "CharacterPackets.h"
#include "TalentPackets.h"
#include "Chat.h"
+#include "CombatPackets.h"
#include "Common.h"
#include "ConditionMgr.h"
#include "CreatureAI.h"
@@ -2997,13 +2998,14 @@ void Player::InitTalentForLevel()
{
uint8 level = getLevel();
// talents base at level diff (talents = level - 9 but some can be used already)
+ if (level < MIN_SPECIALIZATION_LEVEL)
+ ResetTalentSpecialization();
+
+ uint32 talentTiers = CalculateTalentsTiers();
if (level < 15)
{
// Remove all talent points
- if (GetUsedTalentCount() > 0) // Free any used talents
- {
- ResetTalents(true);
- }
+ ResetTalents(true);
}
else
{
@@ -3012,9 +3014,15 @@ void Player::InitTalentForLevel()
SetTalentGroupsCount(1);
SetActiveTalentGroup(0);
}
+
+ if (!GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_MORE_TALENTS_THAN_ALLOWED))
+ for (uint32 t = talentTiers; t < MAX_TALENT_TIERS; ++t)
+ for (uint32 c = 0; c < MAX_TALENT_COLUMNS; ++c)
+ for (TalentEntry const* talent : sTalentByPos[getClass()][t][c])
+ RemoveTalent(talent);
}
- SetUInt32Value(PLAYER_FIELD_MAX_TALENT_TIERS, CalculateTalentsPoints());
+ SetUInt32Value(PLAYER_FIELD_MAX_TALENT_TIERS, talentTiers);
if (!GetSession()->PlayerLoading())
SendTalentsInfoData(); // update at client
@@ -3293,29 +3301,20 @@ void DeleteSpellFromAllPlayers(uint32 spellId)
}
}
-bool Player::AddTalent(uint32 talentId, uint8 spec, bool learning)
+bool Player::AddTalent(TalentEntry const* talent, uint8 spec, bool learning)
{
- TalentEntry const* talentEntry = sTalentStore.LookupEntry(talentId);
-
- // Check if talent exists in Talent.dbc
- if (!talentEntry)
- {
- TC_LOG_ERROR("spells", "Player::addTalent: Talent %u not found", talentId);
- return false;
- }
-
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talentEntry->SpellID);
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talent->SpellID);
if (!spellInfo)
{
// do character spell book cleanup (all characters)
- if (!IsInWorld()) // spell load case
+ if (!IsInWorld() && !learning) // spell load case
{
- TC_LOG_ERROR("spells", "Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.", talentEntry->SpellID);
+ TC_LOG_ERROR("spells", "Player::AddTalent: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.", talent->SpellID);
- DeleteSpellFromAllPlayers(talentEntry->SpellID);
+ DeleteSpellFromAllPlayers(talent->SpellID);
}
else
- TC_LOG_ERROR("spells", "Player::addSpell: Non-existed in SpellStore spell #%u request.", talentEntry->SpellID);
+ TC_LOG_ERROR("spells", "Player::AddTalent: Non-existed in SpellStore spell #%u request.", talent->SpellID);
return false;
}
@@ -3323,40 +3322,58 @@ bool Player::AddTalent(uint32 talentId, uint8 spec, bool learning)
if (!SpellMgr::IsSpellValid(spellInfo, this, false))
{
// do character spell book cleanup (all characters)
- if (!IsInWorld()) // spell load case
+ if (!IsInWorld() && !learning) // spell load case
{
- TC_LOG_ERROR("spells", "Player::addTalent: Broken spell #%u learning not allowed, deleting for all characters in `character_talent`.", talentEntry->SpellID);
+ TC_LOG_ERROR("spells", "Player::AddTalent: Broken spell #%u learning not allowed, deleting for all characters in `character_talent`.", talent->SpellID);
- DeleteSpellFromAllPlayers(talentEntry->SpellID);
+ DeleteSpellFromAllPlayers(talent->SpellID);
}
else
- TC_LOG_ERROR("spells", "Player::addTalent: Broken spell #%u learning not allowed.", talentEntry->SpellID);
+ TC_LOG_ERROR("spells", "Player::AddTalent: Broken spell #%u learning not allowed.", talent->SpellID);
return false;
}
- PlayerTalentMap::iterator itr = GetTalentMap(spec)->find(talentId);
- if (itr == GetTalentMap(spec)->end())
- {
- //if (GetTalentBySpellID(talentEntry->SpellID))
- {
- PlayerSpellState state = learning ? PLAYERSPELL_NEW : PLAYERSPELL_UNCHANGED;
- PlayerTalent* newtalent = new PlayerTalent();
+ if (talent->OverridesSpellID)
+ AddOverrideSpell(talent->OverridesSpellID, talent->SpellID);
- newtalent->state = state;
- newtalent->spec = spec;
+ PlayerTalentMap::iterator itr = GetTalentMap(spec)->find(talent->ID);
+ if (itr != GetTalentMap(spec)->end())
+ itr->second->state = PLAYERSPELL_UNCHANGED;
+ else
+ {
+ PlayerSpellState state = learning ? PLAYERSPELL_NEW : PLAYERSPELL_UNCHANGED;
+ PlayerTalent* newtalent = new PlayerTalent();
- (*GetTalentMap(spec))[talentId] = newtalent;
+ newtalent->state = state;
+ newtalent->spec = spec;
- return true;
- }
- //else
- // TC_LOG_ERROR("spells", "Player::addTalent: Talent %u not found in talent store.", talentId);
+ (*GetTalentMap(spec))[talent->ID] = newtalent;
}
- else
- itr->second->state = PLAYERSPELL_UNCHANGED;
- return false;
+ return true;
+}
+
+void Player::RemoveTalent(TalentEntry const* talent)
+{
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talent->SpellID);
+ if (!spellInfo)
+ return;
+
+ RemoveSpell(talent->SpellID, true);
+
+ // search for spells that the talent teaches and unlearn them
+ for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ if (effect && effect->TriggerSpell > 0 && effect->Effect == SPELL_EFFECT_LEARN_SPELL)
+ RemoveSpell(effect->TriggerSpell, true);
+
+ if (talent->OverridesSpellID)
+ RemoveOverrideSpell(talent->OverridesSpellID, talent->SpellID);
+
+ // if this talent rank can be found in the PlayerTalentMap, mark the talent as removed so it gets deleted
+ PlayerTalentMap::iterator plrTalent = GetTalentMap(GetActiveTalentGroup())->find(talent->ID);
+ if (plrTalent != GetTalentMap(GetActiveTalentGroup())->end())
+ plrTalent->second->state = PLAYERSPELL_REMOVED;
}
bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent, bool disabled, bool loading /*= false*/, bool fromSkill /*= false*/)
@@ -3452,7 +3469,7 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
if (active)
{
if (spellInfo->IsPassive() && IsNeedCastPassiveSpellAtLearn(spellInfo))
- CastSpell (this, spellId, true);
+ CastSpell(this, spellId, true);
}
else if (IsInWorld())
{
@@ -3568,11 +3585,9 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
return false;
}
- uint32 talentCost = GetTalentSpellCost(spellId);
-
// cast talents with SPELL_EFFECT_LEARN_SPELL (other dependent spells will learned later as not auto-learned)
// note: all spells with SPELL_EFFECT_LEARN_SPELL isn't passive
- if (!loading && talentCost > 0 && spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL))
+ if (!loading && spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT) && spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL))
{
// ignore stance requirement for talent learn spell (stance set for spell only for client spell description show)
CastSpell(this, spellId, true);
@@ -3589,72 +3604,45 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
return false;
}
- // update used talent points count
- SetUsedTalentCount(GetUsedTalentCount() + talentCost);
-
// update free primary prof.points (if any, can be none in case GM .learn prof. learning)
if (uint32 freeProfs = GetFreePrimaryProfessionPoints())
{
if (spellInfo->IsPrimaryProfessionFirstRank())
- SetFreePrimaryProfessions(freeProfs-1);
+ SetFreePrimaryProfessions(freeProfs - 1);
}
- // add dependent skills
- uint16 maxskill = GetMaxSkillValueForLevel();
-
- SpellLearnSkillNode const* spellLearnSkill = sSpellMgr->GetSpellLearnSkill(spellId);
-
SkillLineAbilityMapBounds skill_bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId);
- if (spellLearnSkill)
+ // add dependent skills if this spell is not learned from adding skill already
+ if (!fromSkill)
{
- uint32 skill_value = GetPureSkillValue(spellLearnSkill->skill);
- uint32 skill_max_value = GetPureMaxSkillValue(spellLearnSkill->skill);
+ if (SpellLearnSkillNode const* spellLearnSkill = sSpellMgr->GetSpellLearnSkill(spellId))
+ {
+ uint32 skill_value = GetPureSkillValue(spellLearnSkill->skill);
+ uint32 skill_max_value = GetPureMaxSkillValue(spellLearnSkill->skill);
- if (skill_value < spellLearnSkill->value)
- skill_value = spellLearnSkill->value;
+ if (skill_value < spellLearnSkill->value)
+ skill_value = spellLearnSkill->value;
- uint32 new_skill_max_value = spellLearnSkill->maxvalue == 0 ? maxskill : spellLearnSkill->maxvalue;
+ uint32 new_skill_max_value = spellLearnSkill->maxvalue == 0 ? GetMaxSkillValueForLevel() : spellLearnSkill->maxvalue;
- if (skill_max_value < new_skill_max_value)
- skill_max_value = new_skill_max_value;
+ if (skill_max_value < new_skill_max_value)
+ skill_max_value = new_skill_max_value;
- SetSkill(spellLearnSkill->skill, spellLearnSkill->step, skill_value, skill_max_value);
- }
- else
- {
- // not ranked skills
- for (SkillLineAbilityMap::const_iterator _spell_idx = skill_bounds.first; _spell_idx != skill_bounds.second; ++_spell_idx)
+ SetSkill(spellLearnSkill->skill, spellLearnSkill->step, skill_value, skill_max_value);
+ }
+ else
{
- SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->SkillLine);
- if (!pSkill)
- continue;
-
- if (HasSkill(pSkill->ID))
- continue;
-
- SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(pSkill->ID, getRace(), getClass());
- if (!rcEntry)
- continue;
-
- if (_spell_idx->second->AquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN ||
- // lockpicking/runeforging special case, not have SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN
- ((pSkill->ID == SKILL_LOCKPICKING || pSkill->ID == SKILL_RUNEFORGING) && (_spell_idx->second->TrivialSkillLineRankHigh == 0 || _spell_idx->second->TrivialSkillLineRankHigh == 1)))
+ // not ranked skills
+ for (SkillLineAbilityMap::const_iterator _spell_idx = skill_bounds.first; _spell_idx != skill_bounds.second; ++_spell_idx)
{
- switch (GetSkillRangeType(rcEntry))
- {
- case SKILL_RANGE_LANGUAGE:
- SetSkill(pSkill->ID, GetSkillStep(pSkill->ID), 300, 300);
- break;
- case SKILL_RANGE_LEVEL:
- SetSkill(pSkill->ID, GetSkillStep(pSkill->ID), 1, GetMaxSkillValueForLevel());
- break;
- case SKILL_RANGE_MONO:
- SetSkill(pSkill->ID, GetSkillStep(pSkill->ID), 1, 1);
- break;
- default:
- break;
- }
+ SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->SkillLine);
+ if (!pSkill)
+ continue;
+
+ ///@todo: confirm if rogues start with lockpicking skill at level 1 but only receive the spell to use it at level 16
+ if ((_spell_idx->second->AquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN && !HasSkill(pSkill->ID)) || (pSkill->ID == SKILL_LOCKPICKING && _spell_idx->second->TrivialSkillLineRankHigh == 0))
+ LearnDefaultSkill(pSkill->ID, 0);
}
}
}
@@ -3733,8 +3721,7 @@ bool Player::IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const
bool Player::IsCurrentSpecMasterySpell(SpellInfo const* spellInfo) const
{
-
- if (ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetActiveTalentSpec()))
+ if (ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetSpecId(GetActiveTalentGroup())))
return spellInfo->Id == chrSpec->MasterySpellID[0] || spellInfo->Id == chrSpec->MasterySpellID[1];
return false;
@@ -3789,7 +3776,8 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
// unlearn non talent higher ranks (recursive)
if (uint32 nextSpell = sSpellMgr->GetNextSpellInChain(spell_id))
{
- if (HasSpell(nextSpell) && !GetTalentBySpellID(nextSpell))
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(nextSpell);
+ if (HasSpell(nextSpell) && !spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT))
RemoveSpell(nextSpell, disabled, false);
}
//unlearn spells dependent from recently removed spells
@@ -3915,6 +3903,8 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
}
}
+ m_overrideSpells.erase(spell_id);
+
if (spell_id == 46917 && m_canTitanGrip)
SetCanTitanGrip(false);
@@ -4117,11 +4107,8 @@ uint32 Player::GetNextResetTalentsCost() const
}
}
-bool Player::ResetTalents(bool noCost, bool resetTalents, bool resetSpecialization)
+bool Player::ResetTalents(bool noCost)
{
- if (!resetTalents && !resetSpecialization)
- return false;
-
sScriptMgr->OnPlayerTalentsReset(this, noCost);
// not need after this call
@@ -4143,41 +4130,30 @@ bool Player::ResetTalents(bool noCost, bool resetTalents, bool resetSpecializati
RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true);
- if (resetTalents)
+ for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
{
- for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
- {
- TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
-
- if (!talentInfo)
- continue;
-
- // unlearn only talents for character class
- // some spell learned by one class as normal spells or know at creation but another class learn it as talent,
- // to prevent unexpected lost normal learned spell skip another class talents
- if (talentInfo->ClassID != getClass())
- continue;
-
- SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID);
- if (!spellEntry)
- continue;
+ TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
+ if (!talentInfo)
+ continue;
- RemoveSpell(spellEntry->Id, false);
+ // unlearn only talents for character class
+ // some spell learned by one class as normal spells or know at creation but another class learn it as talent,
+ // to prevent unexpected lost normal learned spell skip another class talents
+ if (talentInfo->ClassID != getClass())
+ continue;
- // search for spells that the talent teaches and unlearn them, 6.x remove?
- for (SpellEffectInfo const* effect : spellEntry->GetEffectsForDifficulty(DIFFICULTY_NONE))
- if (effect && effect->TriggerSpell > 0 && effect->Effect == SPELL_EFFECT_LEARN_SPELL)
- RemoveSpell(effect->TriggerSpell, true);
+ // skip non-existant talent ranks
+ if (talentInfo->SpellID == 0)
+ continue;
- GetTalentMap(GetActiveTalentGroup())->erase(talentId);
- }
+ RemoveTalent(talentInfo);
}
- if (resetSpecialization)
- {
- SetTalentSpec(GetActiveTalentGroup(), 0);
- SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, 0);
- }
+ // Remove spec specific spells
+ RemoveSpecializationSpells();
+
+ SetSpecId(GetActiveTalentGroup(), 0);
+ SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, 0);
SQLTransaction trans = CharacterDatabase.BeginTransaction();
_SaveTalents(trans);
@@ -4205,35 +4181,6 @@ bool Player::ResetTalents(bool noCost, bool resetTalents, bool resetSpecializati
return true;
}
-bool Player::RemoveTalent(uint32 talentId)
-{
- TalentEntry const* talent = sTalentStore.LookupEntry(talentId);
- if (!talent)
- return false;
-
- uint32 spellId = talent->SpellID;
-
- SpellInfo const* unlearnSpellProto = sSpellMgr->GetSpellInfo(spellId);
-
- RemoveSpell(spellId, false);
-
- // 6.x remove?
- for (SpellEffectInfo const* effect : unlearnSpellProto->GetEffectsForDifficulty(DIFFICULTY_NONE))
- if (effect && effect->TriggerSpell > 0 && effect->Effect == SPELL_EFFECT_LEARN_SPELL)
- RemoveSpell(effect->TriggerSpell, false);
-
- GetTalentMap(GetActiveTalentSpec())->erase(talentId);
-
- // Needs to be executed orthewise the talents will be screwedsx
- SQLTransaction trans = CharacterDatabase.BeginTransaction();
- _SaveTalents(trans);
- _SaveSpells(trans);
- CharacterDatabase.CommitTransaction(trans);
-
- SendTalentsInfoData();
- return true;
-}
-
Mail* Player::GetMail(uint32 id)
{
for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr)
@@ -4298,10 +4245,10 @@ bool Player::HasSpell(uint32 spell) const
!itr->second->disabled);
}
-bool Player::HasTalent(uint32 talentId, uint8 group)
+bool Player::HasTalent(uint32 talentId, uint8 group) const
{
PlayerTalentMap::const_iterator itr = GetTalentMap(group)->find(talentId);
- return (itr != GetTalentMap(group)->end());
+ return (itr != GetTalentMap(group)->end() && itr->second->state != PLAYERSPELL_REMOVED);
}
bool Player::HasActiveSpell(uint32 spell) const
@@ -5950,26 +5897,28 @@ void Player::UpdateSkillsForLevel()
if (!rcEntry)
continue;
- if (GetSkillRangeType(rcEntry) != SKILL_RANGE_LEVEL)
- continue;
-
- if (IsWeaponSkill(rcEntry->SkillID))
- continue;
-
uint16 field = itr->second.pos / 2;
uint8 offset = itr->second.pos & 1; // itr->second.pos % 2
- //uint16 val = GetUInt16Value(PLAYER_SKILL_LINEID + SKILL_RANK_OFFSET + field, offset);
- uint16 max = GetUInt16Value(PLAYER_SKILL_LINEID + SKILL_MAX_RANK_OFFSET + field, offset);
-
- /// update only level dependent max skill values
- if (max != 1)
+ if (GetSkillRangeType(rcEntry) == SKILL_RANGE_LEVEL)
{
- SetUInt16Value(PLAYER_SKILL_LINEID + SKILL_RANK_OFFSET + field, offset, maxSkill);
- SetUInt16Value(PLAYER_SKILL_LINEID + SKILL_MAX_RANK_OFFSET + field, offset, maxSkill);
- if (itr->second.uState != SKILL_NEW)
- itr->second.uState = SKILL_CHANGED;
+ if (!IsWeaponSkill(rcEntry->SkillID))
+ {
+ uint16 max = GetUInt16Value(PLAYER_SKILL_LINEID + SKILL_MAX_RANK_OFFSET + field, offset);
+
+ /// update only level dependent max skill values
+ if (max != 1)
+ {
+ SetUInt16Value(PLAYER_SKILL_LINEID + SKILL_RANK_OFFSET + field, offset, maxSkill);
+ SetUInt16Value(PLAYER_SKILL_LINEID + SKILL_MAX_RANK_OFFSET + field, offset, maxSkill);
+ if (itr->second.uState != SKILL_NEW)
+ itr->second.uState = SKILL_CHANGED;
+ }
+ }
}
+
+ // Update level dependent skillline spells
+ LearnSkillRewardedSpells(rcEntry->SkillID, GetUInt16Value(PLAYER_SKILL_LINEID + SKILL_RANK_OFFSET + field, offset));
}
}
@@ -8414,7 +8363,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8
Spell* spell = new Spell(this, spellInfo, (count > 0) ? TRIGGERED_FULL_MASK : TRIGGERED_NONE);
spell->m_CastItem = item;
spell->m_cast_count = cast_count; // set count of casts
- spell->m_glyphIndex = glyphIndex; // glyph index
+ spell->m_misc.Data = glyphIndex; // glyph index
spell->prepare(&targets);
++count;
@@ -8442,7 +8391,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8
Spell* spell = new Spell(this, spellInfo, (count > 0) ? TRIGGERED_FULL_MASK : TRIGGERED_NONE);
spell->m_CastItem = item;
spell->m_cast_count = cast_count; // set count of casts
- spell->m_glyphIndex = glyphIndex; // glyph index
+ spell->m_misc.Data = glyphIndex; // glyph index
spell->prepare(&targets);
++count;
@@ -17192,17 +17141,19 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
if (talentSpec)
{
if (sChrSpecializationStore.LookupEntry(talentSpec))
- SetTalentSpec(i, talentSpec);
+ SetSpecId(i, talentSpec);
else
SetAtLoginFlag(AT_LOGIN_RESET_TALENTS);
}
}
- SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, GetActiveTalentSpec());
+ SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, GetSpecId(GetActiveTalentGroup()));
_LoadTalents(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TALENTS));
_LoadSpells(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELLS));
+ LearnSpecializationSpells();
+
_LoadGlyphs(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GLYPHS));
_LoadAuras(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_AURAS), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_AURA_EFFECTS), time_diff);
_LoadGlyphAuras();
@@ -18724,7 +18675,7 @@ bool Player::Satisfy(AccessRequirement const* ar, uint32 target_map, bool report
else if (mapDiff->HasMessage()) // if (missingAchievement) covered by this case
SendTransferAborted(target_map, TRANSFER_ABORT_DIFFICULTY, target_difficulty);
else if (missingItem)
- GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED_AND_ITEM), LevelMin, sObjectMgr->GetItemTemplate(missingItem)->GetName(GetSession()->GetSessionDbcLocale()));
+ GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED_AND_ITEM), LevelMin, ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(missingItem))->GetName(GetSession()->GetSessionDbcLocale()));
else if (LevelMin)
GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED), LevelMin);
}
@@ -18911,7 +18862,7 @@ void Player::SaveToDB(bool create /*=false*/)
ss.str("");
for (uint8 i = 0; i < MAX_TALENT_GROUPS; ++i)
- ss << GetTalentSpec(i) << " ";
+ ss << GetSpecId(i) << " ";
stmt->setString(index++, ss.str());
stmt->setUInt16(index++, (uint16)m_ExtraFlags);
stmt->setUInt8(index++, m_stableSlots);
@@ -19048,7 +18999,7 @@ void Player::SaveToDB(bool create /*=false*/)
ss.str("");
for (uint8 i = 0; i < MAX_TALENT_GROUPS; ++i)
- ss << GetTalentSpec(i) << " ";
+ ss << GetSpecId(i) << " ";
stmt->setString(index++, ss.str());
stmt->setUInt16(index++, (uint16)m_ExtraFlags);
stmt->setUInt8(index++, m_stableSlots);
@@ -19937,12 +19888,6 @@ bool Player::CanSpeak() const
/*** LOW LEVEL FUNCTIONS:Notifiers ***/
/*********************************************************/
-void Player::SendAttackSwingNotInRange()
-{
- WorldPacket data(SMSG_ATTACKSWING_NOTINRANGE, 0);
- GetSession()->SendPacket(&data);
-}
-
void Player::SavePositionInDB(WorldLocation const& loc, uint16 zoneId, ObjectGuid guid, SQLTransaction& trans)
{
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_POSITION);
@@ -19971,26 +19916,32 @@ void Player::SetUInt32ValueInArray(Tokenizer& Tokenizer, uint16 index, uint32 va
void Player::SendAttackSwingDeadTarget()
{
- WorldPacket data(SMSG_ATTACKSWING_DEADTARGET, 0);
- GetSession()->SendPacket(&data);
+ WorldPackets::Combat::AttackSwingError packet(ATTACKSWINGERR_DEADTARGET);
+ GetSession()->SendPacket(packet.Write());
}
void Player::SendAttackSwingCantAttack()
{
- WorldPacket data(SMSG_ATTACKSWING_CANT_ATTACK, 0);
- GetSession()->SendPacket(&data);
+ WorldPackets::Combat::AttackSwingError packet(ATTACKSWINGERR_CANT_ATTACK);
+ GetSession()->SendPacket(packet.Write());
}
-void Player::SendAttackSwingCancelAttack()
+void Player::SendAttackSwingNotInRange()
{
- WorldPacket data(SMSG_CANCEL_COMBAT, 0);
- GetSession()->SendPacket(&data);
+ WorldPackets::Combat::AttackSwingError packet(ATTACKSWINGERR_NOTINRANGE);
+ GetSession()->SendPacket(packet.Write());
}
void Player::SendAttackSwingBadFacingAttack()
{
- WorldPacket data(SMSG_ATTACKSWING_BADFACING, 0);
- GetSession()->SendPacket(&data);
+ WorldPackets::Combat::AttackSwingError packet(ATTACKSWINGERR_BADFACING);
+ GetSession()->SendPacket(packet.Write());
+}
+
+void Player::SendAttackSwingCancelAttack()
+{
+ WorldPackets::Combat::CancelCombat packet;
+ GetSession()->SendPacket(packet.Write());
}
void Player::SendAutoRepeatCancel(Unit* target)
@@ -25403,43 +25354,60 @@ void Player::CompletedAchievement(AchievementEntry const* entry)
bool Player::LearnTalent(uint32 talentId)
{
TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
-
if (!talentInfo)
return false;
- uint32 maxTalentTier = GetUInt32Value(PLAYER_FIELD_MAX_TALENT_TIERS);
+ if (talentInfo->SpecID && talentInfo->SpecID != GetSpecId(GetActiveTalentGroup()))
+ return false;
// prevent learn talent for different class (cheating)
if (talentInfo->ClassID != getClass())
return false;
// check if we have enough talent points
- if (talentInfo->TierID > maxTalentTier)
+ if (talentInfo->TierID >= GetUInt32Value(PLAYER_FIELD_MAX_TALENT_TIERS))
return false;
- // Check if player doesnt have any spell in selected collumn
- for (uint32 i = 0; i < sTalentStore.GetNumRows(); i++)
+ // Check if there is a different talent for us to learn in selected slot
+ // Example situation:
+ // Warrior talent row 2 slot 0
+ // Talent.dbc has an entry for each specialization
+ // but only 2 out of 3 have SpecID != 0
+ // We need to make sure that if player is in one of these defined specs he will not learn the other choice
+ TalentEntry const* bestSlotMatch = nullptr;
+ for (TalentEntry const* talent : sTalentByPos[getClass()][talentInfo->TierID][talentInfo->ColumnIndex])
{
- if (TalentEntry const* talent = sTalentStore.LookupEntry(i))
+ if (!talent->SpecID)
+ bestSlotMatch = talent;
+ else if (talent->SpecID == GetSpecId(GetActiveTalentGroup()))
{
- if (talentInfo->TierID == talent->TierID && HasSpell(talent->SpellID))
- return false;
+ bestSlotMatch = talent;
+ break;
}
}
+ if (talentInfo != bestSlotMatch)
+ return false;
+
+ // Check if player doesnt have any talent in current tier
+ for (uint32 c = 0; c < MAX_TALENT_COLUMNS; ++c)
+ for (TalentEntry const* talent : sTalentByPos[getClass()][talentInfo->TierID][c])
+ if (HasTalent(talent->ID, GetActiveTalentGroup()))
+ return false;
+
// spell not set in talent.dbc
uint32 spellid = talentInfo->SpellID;
- if (spellid == 0)
+ if (!spellid)
{
TC_LOG_ERROR("entities.player", "Talent.dbc has no spellInfo for talent: %u (spell id = 0)", talentId);
return false;
}
// already known
- if (HasSpell(spellid))
+ if (HasTalent(talentId, GetActiveTalentGroup()) || HasSpell(spellid))
return false;
- if (!AddTalent(talentId, GetActiveTalentGroup(), true))
+ if (!AddTalent(talentInfo, GetActiveTalentGroup(), true))
return false;
LearnSpell(spellid, false);
@@ -25451,49 +25419,42 @@ bool Player::LearnTalent(uint32 talentId)
void Player::LearnTalentSpecialization(uint32 talentSpec)
{
- if (GetActiveTalentSpec())
+ if (GetSpecId(GetActiveTalentGroup()))
return;
- SetTalentSpec(GetActiveTalentGroup(), talentSpec);
-
+ SetSpecId(GetActiveTalentGroup(), talentSpec);
SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, talentSpec);
- PlayerTalentMap* talents = GetTalentMap(GetActiveTalentGroup());
-
- for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
- {
- TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
-
- if (!talentInfo || talentInfo->ClassID != getClass() || talentInfo->SpecID != talentSpec)
- continue;
-
- for (PlayerTalentMap::iterator itr = talents->begin(); itr != talents->end();)
- {
- TalentEntry const* talent = sTalentStore.LookupEntry(itr->first);
- if (!talent || talent->TierID != talentInfo->TierID)
- {
- ++itr;
- continue;
- }
- RemoveSpell(talent->SpellID, false);
- itr = talents->erase(itr);
-
- TC_LOG_DEBUG("spells", "Player %s unlearning talent id: %u tier: %u due to specialization change", GetName().c_str(), talent->ID, talent->TierID);
- }
- }
+ // Reset only talents that have different spells for each spec
+ uint32 class_ = getClass();
+ for (uint32 t = 0; t < MAX_TALENT_TIERS; ++t)
+ for (uint32 c = 0; c < MAX_TALENT_COLUMNS; ++c)
+ if (sTalentByPos[class_][t][c].size() > 1)
+ for (TalentEntry const* talent : sTalentByPos[class_][t][c])
+ RemoveTalent(talent);
+ LearnSpecializationSpells();
SendTalentsInfoData();
+}
- SaveToDB();
+void Player::ResetTalentSpecialization()
+{
+ if (!GetSpecId(GetActiveTalentGroup()))
+ return;
- SendTalentsInfoData();
-}
+ SetSpecId(GetActiveTalentGroup(), 0);
+ SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, 0);
+ // Reset only talents that have different spells for each spec
+ uint32 class_ = getClass();
+ for (uint32 t = 0; t < MAX_TALENT_TIERS; ++t)
+ for (uint32 c = 0; c < MAX_TALENT_COLUMNS; ++c)
+ if (sTalentByPos[class_][t][c].size() > 1)
+ for (TalentEntry const* talent : sTalentByPos[class_][t][c])
+ RemoveTalent(talent);
-void Player::AddKnownCurrency(uint32 itemId)
-{
- if (CurrencyTypesEntry const* ctEntry = sCurrencyTypesStore.LookupEntry(itemId))
- SetFlag64(0, (1LL << (ctEntry->ID-1)));
+ RemoveSpecializationSpells();
+ SendTalentsInfoData();
}
void Player::UpdateFallInformationIfNeed(MovementInfo const& minfo, uint16 opcode)
@@ -25576,12 +25537,14 @@ void Player::SendTalentsInfoData()
{
WorldPackets::Talent::TalentGroupInfo groupInfoPkt;
- groupInfoPkt.SpecID = GetTalentSpec(i);
-
+ groupInfoPkt.SpecID = GetSpecId(i);
groupInfoPkt.TalentIDs.reserve(GetTalentMap(i)->size());
for (PlayerTalentMap::const_iterator itr = GetTalentMap(i)->begin(); itr != GetTalentMap(i)->end(); ++itr)
{
+ if (itr->second->state == PLAYERSPELL_REMOVED)
+ continue;
+
TalentEntry const* talentInfo = sTalentStore.LookupEntry(itr->first);
if (!talentInfo)
{
@@ -25599,9 +25562,6 @@ void Player::SendTalentsInfoData()
continue;
}
- if (!HasTalent(itr->first, i))
- continue;
-
groupInfoPkt.TalentIDs.push_back(uint16(itr->first));
}
@@ -25918,7 +25878,8 @@ void Player::_LoadTalents(PreparedQueryResult result)
if (result)
{
do
- AddTalent((*result)[0].GetUInt32(), (*result)[1].GetUInt8(), false);
+ if (TalentEntry const* talent = sTalentStore.LookupEntry((*result)[0].GetUInt32()))
+ AddTalent(talent, (*result)[1].GetUInt8(), false);
while (result->NextRow());
}
}
@@ -25929,15 +25890,25 @@ void Player::_SaveTalents(SQLTransaction& trans)
stmt->setUInt64(0, GetGUID().GetCounter());
trans->Append(stmt);
+ PlayerTalentMap* talents;
for (uint8 group = 0; group < MAX_TALENT_GROUPS; ++group)
{
- for (PlayerTalentMap::iterator itr = GetTalentMap(group)->begin(); itr != GetTalentMap(group)->end(); ++itr)
+ talents = GetTalentMap(group);
+ for (PlayerTalentMap::iterator itr = talents->begin(); itr != talents->end();)
{
+ if (itr->second->state == PLAYERSPELL_REMOVED)
+ {
+ delete itr->second;
+ itr = talents->erase(itr);
+ continue;
+ }
+
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_TALENT);
stmt->setUInt64(0, GetGUID().GetCounter());
stmt->setUInt32(1, itr->first);
stmt->setUInt8(2, itr->second->spec);
trans->Append(stmt);
+ ++itr;
}
}
}
@@ -25988,12 +25959,12 @@ void Player::UpdateTalentGroupCount(uint8 count)
SendTalentsInfoData();
}
-void Player::ActivateTalentGroup(uint8 group)
+void Player::ActivateTalentGroup(uint8 spec)
{
- if (GetActiveTalentGroup() == group)
+ if (GetActiveTalentGroup() == spec)
return;
- if (group > GetTalentGroupsCount())
+ if (spec > GetTalentGroupsCount())
return;
if (IsNonMeleeSpellCast(false))
@@ -26025,57 +25996,76 @@ void Player::ActivateTalentGroup(uint8 group)
for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
{
TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
-
if (!talentInfo)
continue;
// unlearn only talents for character class
// some spell learned by one class as normal spells or know at creation but another class learn it as talent,
// to prevent unexpected lost normal learned spell skip another class talents
- if (getClass() != talentInfo->ClassID)
+ if (talentInfo->ClassID != getClass())
continue;
- SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID);
- if (!spellEntry)
+ if (talentInfo->SpellID == 0)
+ continue;
+
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talentInfo->SpellID);
+ if (!spellInfo)
continue;
RemoveSpell(talentInfo->SpellID, true);
// search for spells that the talent teaches and unlearn them
- for (SpellEffectInfo const* effect : spellEntry->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
if (effect && effect->TriggerSpell > 0 && effect->Effect == SPELL_EFFECT_LEARN_SPELL)
RemoveSpell(effect->TriggerSpell, true);
+
+ if (talentInfo->OverridesSpellID)
+ RemoveOverrideSpell(talentInfo->OverridesSpellID, talentInfo->SpellID);
}
- // remove glyphs
+ // Remove spec specific spells
+ RemoveSpecializationSpells();
+
+ // set glyphs
for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot)
// remove secondary glyph
if (uint32 oldglyph = GetGlyph(GetActiveTalentGroup(), slot))
if (GlyphPropertiesEntry const* old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
RemoveAurasDueToSpell(old_gp->SpellID);
- // Activate new group
- SetActiveTalentGroup(group);
-
- uint32 spentTalents = 0;
+ SetActiveTalentGroup(spec);
+ SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, GetSpecId(spec));
for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
{
TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
-
if (!talentInfo)
continue;
// learn only talents for character class
- if (getClass() != talentInfo->ClassID)
+ if (talentInfo->ClassID != getClass())
continue;
- ++spentTalents;
+ if (!talentInfo->SpellID)
+ continue;
- if (HasTalent(talentInfo->SpellID, group))
- LearnSpell(talentInfo->SpellID, false);
+ // if the talent can be found in the newly activated PlayerTalentMap
+ if (HasTalent(talentInfo->ID, GetActiveTalentGroup()))
+ {
+ LearnSpell(talentInfo->SpellID, false); // add the talent to the PlayerSpellMap
+ if (talentInfo->OverridesSpellID)
+ AddOverrideSpell(talentInfo->OverridesSpellID, talentInfo->SpellID);
+ }
}
+ LearnSpecializationSpells();
+
+ if (CanUseMastery())
+ if (ChrSpecializationEntry const* specialization = sChrSpecializationStore.LookupEntry(GetSpecId(GetActiveTalentGroup())))
+ for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i)
+ if (uint32 mastery = specialization->MasterySpellID[i])
+ LearnSpell(mastery, false);
+
// set glyphs
for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot)
{
@@ -26089,7 +26079,6 @@ void Player::ActivateTalentGroup(uint8 group)
SetGlyph(slot, glyph);
}
- SetUsedTalentCount(spentTalents);
InitTalentForLevel();
{
@@ -26108,10 +26097,8 @@ void Player::ActivateTalentGroup(uint8 group)
SetPower(pw, 0);
- if (!sChrSpecializationStore.LookupEntry(GetActiveTalentSpec()))
- {
+ if (!sChrSpecializationStore.LookupEntry(GetSpecId(GetActiveTalentGroup())))
ResetTalents(true);
- }
}
void Player::ResetTimeSync()
@@ -27152,10 +27139,17 @@ void Player::SendSupercededSpell(uint32 oldSpell, uint32 newSpell)
GetSession()->SendPacket(&data);
}
-uint32 Player::CalculateTalentsPoints() const
+uint32 Player::CalculateTalentsTiers() const
{
- // 1 talent point for every 15 levels
- return getLevel() >= 100 ? 7 : uint32(floor(getLevel() / 15.f));
+ static uint32 const DefaultTalentRowLevels[MAX_TALENT_TIERS] = { 15, 30, 45, 60, 75, 90, 100 };
+ static uint32 const DKTalentRowLevels[MAX_TALENT_TIERS] = { 57, 58, 59, 60, 75, 90, 100 };
+
+ uint32 const* rowLevels = (getClass() != CLASS_DEATH_KNIGHT) ? DefaultTalentRowLevels : DKTalentRowLevels;
+ for (uint32 i = MAX_TALENT_TIERS; i; --i)
+ if (getLevel() >= rowLevels[i - 1])
+ return i;
+
+ return 0;
}
Difficulty Player::GetDifficultyID(MapEntry const* mapEntry) const
@@ -27218,3 +27212,64 @@ Difficulty Player::CheckLoadedLegacyRaidDifficultyID(Difficulty difficulty)
return difficulty;
}
+
+SpellInfo const* Player::GetCastSpellInfo(SpellInfo const* spellInfo) const
+{
+ auto range = m_overrideSpells.equal_range(spellInfo->Id);
+ for (auto itr = range.first; itr != range.second; ++itr)
+ if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(itr->second))
+ return Unit::GetCastSpellInfo(newInfo);
+
+ return Unit::GetCastSpellInfo(spellInfo);
+}
+
+void Player::RemoveOverrideSpell(uint32 overridenSpellId, uint32 newSpellId)
+{
+ auto range = m_overrideSpells.equal_range(overridenSpellId);
+ for (auto itr = range.first; itr != range.second; ++itr)
+ {
+ if (itr->second == newSpellId)
+ {
+ m_overrideSpells.erase(itr);
+ break;
+ }
+ }
+}
+
+void Player::LearnSpecializationSpells()
+{
+ if (std::vector<SpecializationSpellsEntry const*> const* specSpells = GetSpecializationSpells(GetSpecId(GetActiveTalentGroup())))
+ {
+ for (size_t j = 0; j < specSpells->size(); ++j)
+ {
+ SpecializationSpellsEntry const* specSpell = specSpells->at(j);
+ LearnSpell(specSpell->SpellID, false);
+ if (specSpell->OverridesSpellID)
+ AddOverrideSpell(specSpell->OverridesSpellID, specSpell->SpellID);
+ }
+ }
+}
+
+void Player::RemoveSpecializationSpells()
+{
+ for (uint32 i = 0; i < MAX_SPECIALIZATIONS; ++i)
+ {
+ if (ChrSpecializationEntry const* specialization = sChrSpecializationByIndexStore[getClass()][i])
+ {
+ if (std::vector<SpecializationSpellsEntry const*> const* specSpells = GetSpecializationSpells(specialization->ID))
+ {
+ for (size_t j = 0; j < specSpells->size(); ++j)
+ {
+ SpecializationSpellsEntry const* specSpell = specSpells->at(j);
+ RemoveSpell(specSpell->SpellID, true);
+ if (specSpell->OverridesSpellID)
+ RemoveOverrideSpell(specSpell->OverridesSpellID, specSpell->SpellID);
+ }
+ }
+
+ for (uint32 j = 0; j < MAX_MASTERY_SPELLS; ++j)
+ if (uint32 mastery = specialization->MasterySpellID[j])
+ RemoveAurasDueToSpell(mastery);
+ }
+ }
+}
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index e895e696bb4..a22cd007ee0 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -670,6 +670,14 @@ struct SkillStatusData
typedef std::unordered_map<uint32, SkillStatusData> SkillStatusMap;
+enum AttackSwingErr
+{
+ ATTACKSWINGERR_CANT_ATTACK = 0,
+ ATTACKSWINGERR_NOTINRANGE = 1,
+ ATTACKSWINGERR_BADFACING = 2,
+ ATTACKSWINGERR_DEADTARGET = 3
+};
+
class Quest;
class Spell;
class Item;
@@ -1239,13 +1247,15 @@ private:
struct PlayerTalentInfo
{
- PlayerTalentInfo() : UsedTalentCount(0), ResetTalentsCost(0), ResetTalentsTime(0), ActiveGroup(0), GroupsCount(1)
+ PlayerTalentInfo() :
+ ResetTalentsCost(0), ResetTalentsTime(0),
+ ActiveGroup(0), GroupsCount(1)
{
for (uint8 i = 0; i < MAX_TALENT_GROUPS; ++i)
{
GroupInfo[i].Talents = new PlayerTalentMap();
memset(GroupInfo[i].Glyphs, 0, MAX_GLYPH_SLOT_INDEX * sizeof(uint32));
- GroupInfo[i].TalentTree = 0;
+ GroupInfo[i].SpecId = 0;
}
}
@@ -1263,10 +1273,9 @@ struct PlayerTalentInfo
{
PlayerTalentMap* Talents;
uint32 Glyphs[MAX_GLYPH_SLOT_INDEX];
- uint32 TalentTree;
+ uint32 SpecId;
} GroupInfo[MAX_TALENT_GROUPS];
- uint32 UsedTalentCount;
uint32 ResetTalentsCost;
time_t ResetTalentsTime;
uint8 ActiveGroup;
@@ -1276,6 +1285,7 @@ private:
PlayerTalentInfo(PlayerTalentInfo const&);
};
+
class Player : public Unit, public GridObject<Player>
{
friend class WorldSession;
@@ -1812,6 +1822,7 @@ class Player : public Unit, public GridObject<Player>
void SendRemoveControlBar();
bool HasSpell(uint32 spell) const override;
bool HasActiveSpell(uint32 spell) const; // show in spellbook
+ SpellInfo const* GetCastSpellInfo(SpellInfo const* spellInfo) const override;
TrainerSpellState GetTrainerSpellState(TrainerSpell const* trainer_spell) const;
bool IsSpellFitByClassAndRace(uint32 spell_id) const;
bool IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const;
@@ -1831,41 +1842,37 @@ class Player : public Unit, public GridObject<Player>
void LearnSpellHighestRank(uint32 spellid);
void AddTemporarySpell(uint32 spellId);
void RemoveTemporarySpell(uint32 spellId);
+ void AddOverrideSpell(uint32 overridenSpellId, uint32 newSpellId) { m_overrideSpells.emplace(overridenSpellId, newSpellId); }
+ void RemoveOverrideSpell(uint32 overridenSpellId, uint32 newSpellId);
+ void LearnSpecializationSpells();
+ void RemoveSpecializationSpells();
void SetReputation(uint32 factionentry, uint32 value);
uint32 GetReputation(uint32 factionentry) const;
std::string GetGuildName();
// Talents
- uint32 GetUsedTalentCount() const { return _talentMgr->UsedTalentCount; }
- void SetUsedTalentCount(uint32 talents) { _talentMgr->UsedTalentCount = talents; }
uint32 GetTalentResetCost() const { return _talentMgr->ResetTalentsCost; }
void SetTalentResetCost(uint32 cost) { _talentMgr->ResetTalentsCost = cost; }
uint32 GetTalentResetTime() const { return _talentMgr->ResetTalentsTime; }
void SetTalentResetTime(time_t time_) { _talentMgr->ResetTalentsTime = time_; }
-
- uint8 GetTalentGroupsCount() const { return _talentMgr->GroupsCount; }
- void SetTalentGroupsCount(uint8 count) { _talentMgr->GroupsCount = count; }
+ uint32 GetSpecId(uint8 group) const { return _talentMgr->GroupInfo[group].SpecId; }
+ void SetSpecId(uint8 group, uint32 tree) { _talentMgr->GroupInfo[group].SpecId = tree; }
uint8 GetActiveTalentGroup() const { return _talentMgr->ActiveGroup; }
void SetActiveTalentGroup(uint8 group){ _talentMgr->ActiveGroup = group; }
+ uint8 GetTalentGroupsCount() const { return _talentMgr->GroupsCount; }
+ void SetTalentGroupsCount(uint8 count) { _talentMgr->GroupsCount = count; }
- uint32 GetTalentSpec(uint8 group) const { return _talentMgr->GroupInfo[group].TalentTree; }
- void SetTalentSpec(uint8 group, uint32 talentSpec) const { _talentMgr->GroupInfo[group].TalentTree = talentSpec; }
- uint32 GetActiveTalentSpec() const { return _talentMgr->GroupInfo[_talentMgr->ActiveGroup].TalentTree; }
-
-
- bool ResetTalents(bool noCost = false, bool resetTalents = true, bool resetSpecialization = true);
- bool RemoveTalent(uint32 talentId);
-
+ bool ResetTalents(bool noCost = false);
uint32 GetNextResetTalentsCost() const;
void InitTalentForLevel();
void SendTalentsInfoData();
bool LearnTalent(uint32 talentId);
- bool AddTalent(uint32 talentId, uint8 spec, bool learning);
- bool HasTalent(uint32 talentId, uint8 spec);
- uint32 CalculateTalentsPoints() const;
-
-
+ bool AddTalent(TalentEntry const* talent, uint8 spec, bool learning);
+ bool HasTalent(uint32 spell_id, uint8 spec) const;
+ void RemoveTalent(TalentEntry const* talent);
+ uint32 CalculateTalentsTiers() const;
void LearnTalentSpecialization(uint32 talentSpec);
+ void ResetTalentSpecialization();
// Dual Spec
void UpdateTalentGroupCount(uint8 count);
@@ -2793,6 +2800,7 @@ class Player : public Unit, public GridObject<Player>
PlayerMails m_mail;
PlayerSpellMap m_spells;
+ std::unordered_multimap<uint32 /*overridenSpellId*/, uint32 /*newSpellId*/> m_overrideSpells;
uint32 m_lastPotionId; // last used health/mana potion in combat, that block next potion use
GlobalCooldownMgr m_GlobalCooldownMgr;
@@ -2911,9 +2919,6 @@ class Player : public Unit, public GridObject<Player>
void RefundItem(Item* item);
void SendItemRefundResult(Item* item, ItemExtendedCostEntry const* iece, uint8 error);
- // know currencies are not removed at any point (0 displayed)
- void AddKnownCurrency(uint32 itemId);
-
void AdjustQuestReqItemCount(Quest const* quest);
bool IsCanDelayTeleport() const { return m_bCanDelayTeleport; }
diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp
index eea0040404e..d9d6cd9d2e5 100644
--- a/src/server/game/Entities/Unit/StatSystem.cpp
+++ b/src/server/game/Entities/Unit/StatSystem.cpp
@@ -526,7 +526,7 @@ void Player::UpdateMastery()
value += GetRatingBonusValue(CR_MASTERY);
SetFloatValue(PLAYER_MASTERY, value);
- ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetActiveTalentSpec());
+ ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetSpecId(GetActiveTalentGroup()));
if (!chrSpec)
return;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index a2adb6a320c..59822acb7ad 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -63,6 +63,7 @@
#include "MovementStructures.h"
#include "WorldSession.h"
#include "ChatPackets.h"
+#include "MiscPackets.h"
#include "MovementPackets.h"
#include "CombatPackets.h"
#include "CombatLogPackets.h"
@@ -161,6 +162,30 @@ ProcEventInfo::ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget,
_damageInfo(damageInfo), _healInfo(healInfo)
{ }
+SpellInfo const* ProcEventInfo::GetSpellInfo() const
+{
+ /// WORKAROUND: unfinished new proc system
+ if (_spell)
+ return _spell->GetSpellInfo();
+ if (_damageInfo)
+ return _damageInfo->GetSpellInfo();
+ /*if (_healInfo)
+ return _healInfo->GetSpellInfo();*/
+ return nullptr;
+}
+
+SpellSchoolMask ProcEventInfo::GetSchoolMask() const
+{
+ /// WORKAROUND: unfinished new proc system
+ if (_spell)
+ return _spell->GetSpellInfo()->GetSchoolMask();
+ if (_damageInfo)
+ return _damageInfo->GetSchoolMask();
+ /*if (_healInfo)
+ return _healInfo->GetSchoolMask();*/
+ return SPELL_SCHOOL_MASK_NONE;
+}
+
Unit::Unit(bool isWorldObject) :
WorldObject(isWorldObject), m_movedPlayer(NULL), m_lastSanctuaryTime(0),
IsAIEnabled(false), NeedChangeAI(false), LastCharmerGUID(),
@@ -12575,7 +12600,7 @@ void Unit::StopMoving()
bool Unit::IsSitState() const
{
- uint8 s = getStandState();
+ UnitStandStateType s = GetStandState();
return
s == UNIT_STAND_STATE_SIT_CHAIR || s == UNIT_STAND_STATE_SIT_LOW_CHAIR ||
s == UNIT_STAND_STATE_SIT_MEDIUM_CHAIR || s == UNIT_STAND_STATE_SIT_HIGH_CHAIR ||
@@ -12584,22 +12609,21 @@ bool Unit::IsSitState() const
bool Unit::IsStandState() const
{
- uint8 s = getStandState();
+ UnitStandStateType s = GetStandState();
return !IsSitState() && s != UNIT_STAND_STATE_SLEEP && s != UNIT_STAND_STATE_KNEEL;
}
-void Unit::SetStandState(uint8 state)
+void Unit::SetStandState(UnitStandStateType state)
{
- SetByteValue(UNIT_FIELD_BYTES_1, 0, state);
+ SetByteValue(UNIT_FIELD_BYTES_1, 0, uint8(state));
if (IsStandState())
RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_SEATED);
if (GetTypeId() == TYPEID_PLAYER)
{
- WorldPacket data(SMSG_STANDSTATE_UPDATE, 1);
- data << (uint8)state;
- ToPlayer()->GetSession()->SendPacket(&data);
+ WorldPackets::Misc::StandStateUpdate packet(state);
+ ToPlayer()->GetSession()->SendPacket(packet.Write());
}
}
@@ -16545,3 +16569,18 @@ void Unit::Whisper(uint32 textId, Player* target, bool isBossWhisper /*= false*/
packet.Initalize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, LANG_UNIVERSAL, this, target, DB2Manager::GetBroadcastTextValue(bct, locale, getGender()), 0, "", locale);
target->SendDirectMessage(packet.Write());
}
+
+SpellInfo const* Unit::GetCastSpellInfo(SpellInfo const* spellInfo) const
+{
+ Unit::AuraEffectList swaps = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS);
+ Unit::AuraEffectList const& swaps2 = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_2);
+ if (!swaps2.empty())
+ swaps.insert(swaps.end(), swaps2.begin(), swaps2.end());
+
+ for (AuraEffect const* auraEffect : swaps)
+ if (auraEffect->IsAffectingSpell(spellInfo))
+ if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(auraEffect->GetAmount()))
+ return newInfo;
+
+ return spellInfo;
+}
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 1b8c188afb4..0311b67befd 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -97,7 +97,7 @@ enum SpellModOp
SPELLMOD_COOLDOWN = 11,
SPELLMOD_EFFECT2 = 12,
SPELLMOD_IGNORE_ARMOR = 13,
- SPELLMOD_COST = 14,
+ SPELLMOD_COST = 14, // Used when SpellPowerEntry::PowerIndex == 0
SPELLMOD_CRIT_DAMAGE_BONUS = 15,
SPELLMOD_RESIST_MISS_CHANCE = 16,
SPELLMOD_JUMP_TARGETS = 17,
@@ -113,10 +113,16 @@ enum SpellModOp
SPELLMOD_VALUE_MULTIPLIER = 27,
SPELLMOD_RESIST_DISPEL_CHANCE = 28,
SPELLMOD_CRIT_DAMAGE_BONUS_2 = 29, //one not used spell
- SPELLMOD_SPELL_COST_REFUND_ON_FAIL = 30
+ SPELLMOD_SPELL_COST_REFUND_ON_FAIL = 30,
+ SPELLMOD_STACK_AMOUNT = 31, // has no effect on tooltip parsing
+ SPELLMOD_EFFECT4 = 32,
+ SPELLMOD_EFFECT5 = 33,
+ SPELLMOD_SPELL_COST2 = 34, // Used when SpellPowerEntry::PowerIndex == 1
+ SPELLMOD_JUMP_DISTANCE = 35,
+ SPELLMOD_STACK_AMOUNT2 = 37 // same as SPELLMOD_STACK_AMOUNT but affects tooltips
};
-#define MAX_SPELLMOD 32
+#define MAX_SPELLMOD 38
enum SpellValueMod
{
@@ -978,8 +984,8 @@ public:
uint32 GetSpellPhaseMask() const { return _spellPhaseMask; }
uint32 GetHitMask() const { return _hitMask; }
- SpellInfo const* GetSpellInfo() const { return NULL; }
- SpellSchoolMask GetSchoolMask() const { return SPELL_SCHOOL_MASK_NONE; }
+ SpellInfo const* GetSpellInfo() const;
+ SpellSchoolMask GetSchoolMask() const;
DamageInfo* GetDamageInfo() const { return _damageInfo; }
HealInfo* GetHealInfo() const { return _healInfo; }
@@ -1500,10 +1506,10 @@ class Unit : public WorldObject
uint32 GetCreatureType() const;
uint32 GetCreatureTypeMask() const;
- uint8 getStandState() const { return GetByteValue(UNIT_FIELD_BYTES_1, 0); }
+ UnitStandStateType GetStandState() const { return UnitStandStateType(GetByteValue(UNIT_FIELD_BYTES_1, 0)); }
bool IsSitState() const;
bool IsStandState() const;
- void SetStandState(uint8 state);
+ void SetStandState(UnitStandStateType state);
void SetStandFlags(uint8 flags) { SetByteFlag(UNIT_FIELD_BYTES_1, 2, flags); }
void RemoveStandFlags(uint8 flags) { RemoveByteFlag(UNIT_FIELD_BYTES_1, 2, flags); }
@@ -1930,6 +1936,7 @@ class Unit : public WorldObject
Spell* GetCurrentSpell(uint32 spellType) const { return m_currentSpells[spellType]; }
Spell* FindCurrentSpellBySpellId(uint32 spell_id) const;
int32 GetCurrentSpellCastTime(uint32 spell_id) const;
+ virtual SpellInfo const* GetCastSpellInfo(SpellInfo const* spellInfo) const;
ObjectGuid m_SummonSlot[MAX_SUMMON_SLOT];
ObjectGuid m_ObjectSlot[MAX_GAMEOBJECT_SLOT];
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index d588d048d3d..202165ffd57 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -156,11 +156,11 @@ bool normalizePlayerName(std::string& name)
}
// Extracts player and realm names delimited by -
-ExtendedPlayerName ExtractExtendedPlayerName(std::string& name)
+ExtendedPlayerName ExtractExtendedPlayerName(std::string const& name)
{
size_t pos = name.find('-');
if (pos != std::string::npos)
- return ExtendedPlayerName(name.substr(0, pos), name.substr(pos+1));
+ return ExtendedPlayerName(name.substr(0, pos), name.substr(pos + 1));
else
return ExtendedPlayerName(name, "");
}
@@ -1869,7 +1869,7 @@ ObjectGuid::LowType ObjectMgr::AddGOData(uint32 entry, uint32 mapId, float x, fl
data.spawnMask = 1;
data.go_state = GO_STATE_READY;
data.phaseMask = PHASEMASK_NORMAL;
- data.artKit = goinfo->type == GAMEOBJECT_TYPE_CAPTURE_POINT ? 21 : 0;
+ data.artKit = goinfo->type == GAMEOBJECT_TYPE_CONTROL_ZONE ? 21 : 0;
data.dbData = false;
AddGameobjectToGrid(guid, &data);
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index 579cc7a5d4e..428d234fdb6 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -636,12 +636,12 @@ bool normalizePlayerName(std::string& name);
struct ExtendedPlayerName
{
- ExtendedPlayerName(std::string const& name, std::string const& realm) : Name(name), Realm(realm) {}
+ ExtendedPlayerName(std::string const& name, std::string const& realm) : Name(name), Realm(realm) { }
std::string Name;
std::string Realm;
};
-ExtendedPlayerName ExtractExtendedPlayerName(std::string& name);
+ExtendedPlayerName ExtractExtendedPlayerName(std::string const& name);
struct LanguageDesc
{
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index c255d786ce3..c7a7bcbf62c 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -1369,7 +1369,7 @@ void WorldSession::HandleAlterAppearance(WorldPacket& recvData)
return;
}
- if (_player->getStandState() != UNIT_STAND_STATE_SIT_LOW_CHAIR + go->GetGOInfo()->barberChair.chairheight)
+ if (_player->GetStandState() != UNIT_STAND_STATE_SIT_LOW_CHAIR + go->GetGOInfo()->barberChair.chairheight)
{
SendBarberShopResult(BARBER_SHOP_RESULT_NOT_ON_CHAIR);
return;
@@ -1399,7 +1399,7 @@ void WorldSession::HandleAlterAppearance(WorldPacket& recvData)
_player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP, 1);
- _player->SetStandState(0); // stand up
+ _player->SetStandState(UNIT_STAND_STATE_STAND);
}
void WorldSession::HandleRemoveGlyph(WorldPacket& recvData)
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index aed2da5c534..1860904d617 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -419,7 +419,7 @@ void WorldSession::HandleLogoutRequestOpcode(WorldPackets::Character::LogoutRequ
// not set flags if player can't free move to prevent lost state at logout cancel
if (GetPlayer()->CanFreeMove())
{
- if (GetPlayer()->getStandState() == UNIT_STAND_STATE_STAND)
+ if (GetPlayer()->GetStandState() == UNIT_STAND_STATE_STAND)
GetPlayer()->SetStandState(UNIT_STAND_STATE_SIT);
GetPlayer()->SetRooted(true);
GetPlayer()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
@@ -543,13 +543,9 @@ void WorldSession::HandleSetSelectionOpcode(WorldPackets::Misc::SetSelection& pa
_player->SetSelection(packet.Selection);
}
-void WorldSession::HandleStandStateChangeOpcode(WorldPacket& recvData)
+void WorldSession::HandleStandStateChangeOpcode(WorldPackets::Misc::StandStateChange& packet)
{
- // TC_LOG_DEBUG("network", "WORLD: Received CMSG_STANDSTATECHANGE"); -- too many spam in log at lags/debug stop
- uint32 animstate;
- recvData >> animstate;
-
- _player->SetStandState(animstate);
+ _player->SetStandState(packet.StandState);
}
void WorldSession::HandleContactListOpcode(WorldPacket& recvData)
diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp
index 9a132bb1ae2..c1ac3cb18b2 100644
--- a/src/server/game/Handlers/PetHandler.cpp
+++ b/src/server/game/Handlers/PetHandler.cpp
@@ -752,7 +752,7 @@ void WorldSession::HandlePetSpellAutocastOpcode(WorldPacket& recvPacket)
charmInfo->SetSpellAutocast(spellInfo, state != 0);
}
-void WorldSession::HandlePetCastSpellOpcode(WorldPackets::Spells::SpellCastRequest& castRequest)
+void WorldSession::HandlePetCastSpellOpcode(WorldPackets::Spells::PetCastSpell& castRequest)
{
TC_LOG_DEBUG("network", "WORLD: CMSG_PET_CAST_SPELL");
/*
diff --git a/src/server/game/Handlers/SkillHandler.cpp b/src/server/game/Handlers/SkillHandler.cpp
index d7cf1226088..a83ce9f996d 100644
--- a/src/server/game/Handlers/SkillHandler.cpp
+++ b/src/server/game/Handlers/SkillHandler.cpp
@@ -32,10 +32,8 @@ void WorldSession::HandleLearnTalentsOpcode(WorldPackets::Talent::LearnTalents&
{
bool anythingLearned = false;
for (uint32 talentId : packet.Talents)
- {
if (_player->LearnTalent(talentId))
anythingLearned = true;
- }
if (anythingLearned)
_player->SendTalentsInfoData();
diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp
index e1459f696f9..55574585246 100644
--- a/src/server/game/Handlers/SpellHandler.cpp
+++ b/src/server/game/Handlers/SpellHandler.cpp
@@ -320,109 +320,53 @@ void WorldSession::HandleGameobjectReportUse(WorldPackets::GameObject::GameObjec
_player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT, go->GetEntry());
}
-void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::SpellCastRequest& castRequest)
+void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::CastSpell& cast)
{
// ignore for remote control state (for player case)
Unit* mover = _player->m_mover;
if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER)
- {
return;
- }
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(castRequest.SpellID);
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cast.Cast.SpellID);
if (!spellInfo)
{
- TC_LOG_ERROR("network", "WORLD: unknown spell id %u", castRequest.SpellID);
+ TC_LOG_ERROR("network", "WORLD: unknown spell id %u", cast.Cast.SpellID);
return;
}
if (spellInfo->IsPassive())
- {
return;
- }
Unit* caster = mover;
- if (caster->GetTypeId() == TYPEID_UNIT && !caster->ToCreature()->HasSpell(castRequest.SpellID))
+ if (caster->GetTypeId() == TYPEID_UNIT && !caster->ToCreature()->HasSpell(spellInfo->Id))
{
// If the vehicle creature does not have the spell but it allows the passenger to cast own spells
// change caster to player and let him cast
if (!_player->IsOnVehicle(caster) || spellInfo->CheckVehicle(_player) != SPELL_CAST_OK)
- {
return;
- }
caster = _player;
}
- if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(castRequest.SpellID))
- {
- // not have spell in spellbook
+ // check known spell
+ if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(spellInfo->Id))
return;
- }
-
- if (Player* plr = caster->ToPlayer())
- {
- uint32 specId = plr->GetActiveTalentSpec();
- if (specId)
- {
- if (sSpecializationOverrideSpellMap.find(specId) != sSpecializationOverrideSpellMap.end())
- {
- if (sSpecializationOverrideSpellMap[specId].find(castRequest.SpellID) != sSpecializationOverrideSpellMap[specId].end())
- {
- SpellInfo const* newSpellInfo = sSpellMgr->GetSpellInfo(sSpecializationOverrideSpellMap[specId][castRequest.SpellID]);
- if (newSpellInfo)
- {
- if (newSpellInfo->SpellLevel <= caster->getLevel())
- {
- spellInfo = newSpellInfo;
- castRequest.SpellID = newSpellInfo->Id;
- }
- }
- }
- }
- }
- }
-
- Unit::AuraEffectList swaps = mover->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS);
- Unit::AuraEffectList const& swaps2 = mover->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_2);
- if (!swaps2.empty())
- swaps.insert(swaps.end(), swaps2.begin(), swaps2.end());
- if (!swaps.empty())
- {
- for (Unit::AuraEffectList::const_iterator itr = swaps.begin(); itr != swaps.end(); ++itr)
- {
- if ((*itr)->IsAffectingSpell(spellInfo))
- {
- if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo((*itr)->GetAmount()))
- {
- spellInfo = newInfo;
- castRequest.SpellID = newInfo->Id;
- }
- break;
- }
- }
- }
+ // Check possible spell cast overrides
+ spellInfo = caster->GetCastSpellInfo(spellInfo);
// Client is resending autoshot cast opcode when other spell is cast during shoot rotation
// Skip it to prevent "interrupt" message
if (spellInfo->IsAutoRepeatRangedSpell() && caster->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)
&& caster->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)->m_spellInfo == spellInfo)
- {
return;
- }
// can't use our own spells when we're in possession of another unit,
if (_player->isPossessing())
- {
return;
- }
// client provided targets
- SpellCastTargets targets(caster, castRequest.TargetFlags, castRequest.UnitGuid, castRequest.ItemGuid, castRequest.SrcTransportGuid, castRequest.DstTransportGuid, castRequest.SrcPos, castRequest.DstPos, castRequest.Pitch, castRequest.Speed, castRequest.Name);
-
-
- //HandleClientCastFlags(recvPacket, castFlags, targets);
+ SpellCastTargets targets(caster, cast.Cast.Target);
// auto-selection buff level base at target level (in spellInfo)
if (targets.GetUnitTarget())
@@ -435,8 +379,8 @@ void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::SpellCastRequest&
}
Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE, ObjectGuid::Empty, false);
- spell->m_cast_count = castRequest.CastID; // set count of casts
- spell->m_glyphIndex = castRequest.Misc; // 6.x Misc is just a guess
+ spell->m_cast_count = cast.Cast.CastID; // set count of casts
+ spell->m_misc.Data = cast.Cast.Misc; // 6.x Misc is just a guess
spell->prepare(&targets);
}
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 41594ad7d94..724d2a7eed4 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -29,6 +29,7 @@
#include "InstanceScript.h"
#include "MapInstanced.h"
#include "MapManager.h"
+#include "MiscPackets.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Pet.h"
@@ -36,6 +37,7 @@
#include "Transport.h"
#include "Vehicle.h"
#include "VMapFactory.h"
+#include "Weather.h"
u_map_magic MapMagic = { {'M','A','P','S'} };
u_map_magic MapVersionMagic = { {'v','1','.','4'} };
@@ -49,6 +51,10 @@ u_map_magic MapLiquidMagic = { {'M','L','I','Q'} };
GridState* si_GridStates[MAX_GRID_STATE];
+
+ZoneDynamicInfo::ZoneDynamicInfo() : MusicId(0), WeatherId(WEATHER_STATE_FINE),
+ WeatherGrade(0.0f), OverrideLightId(0), LightFadeInTime(0) { }
+
Map::~Map()
{
sScriptMgr->OnDestroyMap(this);
@@ -2706,7 +2712,7 @@ uint32 Map::GetPlayersCountExceptGMs() const
return count;
}
-void Map::SendToPlayers(WorldPacket* data) const
+void Map::SendToPlayers(WorldPacket const* data) const
{
for (MapRefManager::const_iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
itr->GetSource()->GetSession()->SendPacket(data);
@@ -3491,13 +3497,10 @@ void Map::SendZoneDynamicInfo(Player* player)
player->SendDirectMessage(&data);
}
- if (uint32 weather = itr->second.WeatherId)
+ if (WeatherState weatherId = itr->second.WeatherId)
{
- WorldPacket data(SMSG_WEATHER, 4 + 4 + 1);
- data << uint32(weather);
- data << float(itr->second.WeatherGrade);
- data << uint8(0);
- player->SendDirectMessage(&data);
+ WorldPackets::Misc::Weather weather(weatherId, itr->second.WeatherGrade);
+ player->SendDirectMessage(weather.Write());
}
if (uint32 overrideLight = itr->second.OverrideLightId)
@@ -3532,7 +3535,7 @@ void Map::SetZoneMusic(uint32 zoneId, uint32 musicId)
}
}
-void Map::SetZoneWeather(uint32 zoneId, uint32 weatherId, float weatherGrade)
+void Map::SetZoneWeather(uint32 zoneId, WeatherState weatherId, float weatherGrade)
{
if (_zoneDynamicInfo.find(zoneId) == _zoneDynamicInfo.end())
_zoneDynamicInfo.insert(ZoneDynamicInfoMap::value_type(zoneId, ZoneDynamicInfo()));
@@ -3544,15 +3547,12 @@ void Map::SetZoneWeather(uint32 zoneId, uint32 weatherId, float weatherGrade)
if (!players.isEmpty())
{
- WorldPacket data(SMSG_WEATHER, 4 + 4 + 1);
- data << uint32(weatherId);
- data << float(weatherGrade);
- data << uint8(0);
+ WorldPackets::Misc::Weather weather(weatherId, weatherGrade);
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
if (Player* player = itr->GetSource())
if (player->GetZoneId() == zoneId)
- player->SendDirectMessage(&data);
+ player->SendDirectMessage(weather.Write());
}
}
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index d38852e50c9..752953091f8 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -53,6 +53,8 @@ class MapInstanced;
class BattlegroundMap;
class InstanceMap;
class Transport;
+enum WeatherState : uint32;
+
namespace Trinity { struct ObjectUpdater; }
struct ScriptAction
@@ -231,11 +233,10 @@ enum LevelRequirementVsMode
struct ZoneDynamicInfo
{
- ZoneDynamicInfo() : MusicId(0), WeatherId(0), WeatherGrade(0.0f),
- OverrideLightId(0), LightFadeInTime(0) { }
+ ZoneDynamicInfo();
uint32 MusicId;
- uint32 WeatherId;
+ WeatherState WeatherId;
float WeatherGrade;
uint32 OverrideLightId;
uint32 LightFadeInTime;
@@ -424,7 +425,7 @@ class Map : public GridRefManager<NGridType>
void AddWorldObject(WorldObject* obj) { i_worldObjects.insert(obj); }
void RemoveWorldObject(WorldObject* obj) { i_worldObjects.erase(obj); }
- void SendToPlayers(WorldPacket* data) const;
+ void SendToPlayers(WorldPacket const* data) const;
typedef MapRefManager PlayerList;
PlayerList const& GetPlayers() const { return m_mapRefManager; }
@@ -513,7 +514,7 @@ class Map : public GridRefManager<NGridType>
void SendZoneDynamicInfo(Player* player);
void SetZoneMusic(uint32 zoneId, uint32 musicId);
- void SetZoneWeather(uint32 zoneId, uint32 weatherId, float weatherGrade);
+ void SetZoneWeather(uint32 zoneId, WeatherState weatherId, float weatherGrade);
void SetZoneOverrideLight(uint32 zoneId, uint32 lightId, uint32 fadeInTime);
void UpdateAreaDependentAuras();
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index 122181fb313..7a6b20696fd 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -504,7 +504,7 @@ enum SpellAttr4
SPELL_ATTR4_UNK4 = 0x00000010, // 4 This will no longer cause guards to attack on use??
SPELL_ATTR4_UNK5 = 0x00000020, // 5
SPELL_ATTR4_NOT_STEALABLE = 0x00000040, // 6 although such auras might be dispellable, they cannot be stolen
- SPELL_ATTR4_TRIGGERED = 0x00000080, // 7 spells forced to be triggered
+ SPELL_ATTR4_CAN_CAST_WHILE_CASTING = 0x00000080, // 7 Can be cast while another cast is in progress - see CanCastWhileCasting(SpellRec const*,CGUnit_C *,int &)
SPELL_ATTR4_FIXED_DAMAGE = 0x00000100, // 8 Ignores resilience and any (except mechanic related) damage or % damage taken auras on target.
SPELL_ATTR4_TRIGGER_ACTIVATE = 0x00000200, // 9 initially disabled / trigger activate from event (Execute, Riposte, Deep Freeze end other)
SPELL_ATTR4_SPELL_VS_EXTEND_COST = 0x00000400, // 10 Rogue Shiv have this flag
@@ -1188,7 +1188,7 @@ enum SpellEffectName
SPELL_EFFECT_178 = 178, // Unused (4.3.4)
SPELL_EFFECT_CREATE_AREATRIGGER = 179,
SPELL_EFFECT_UPDATE_AREATRIGGER = 180, // NYI
- SPELL_EFFECT_REMOVE_TALENT = 181, // NYI
+ SPELL_EFFECT_REMOVE_TALENT = 181,
SPELL_EFFECT_182 = 182,
SPELL_EFFECT_183 = 183,
SPELL_EFFECT_REPUTATION_2 = 184, // NYI
@@ -1517,7 +1517,7 @@ enum SpellCastResult // 19116
SPELL_FAILED_BUILDING_ACTIVATE_NOT_READY = 257,
SPELL_FAILED_NOT_SOULBOUND = 258,
SPELL_FAILED_RIDING_VEHICLE = 259,
- SPELL_FAILED_UNKNOWN = 260, // custom value, default case
+ SPELL_FAILED_UNKNOWN = 260,
SPELL_CAST_OK = 0xFFFF // custom value, must not be sent to client
};
diff --git a/src/server/game/OutdoorPvP/OutdoorPvP.cpp b/src/server/game/OutdoorPvP/OutdoorPvP.cpp
index a23d71e0fe8..089bba92c38 100644
--- a/src/server/game/OutdoorPvP/OutdoorPvP.cpp
+++ b/src/server/game/OutdoorPvP/OutdoorPvP.cpp
@@ -141,7 +141,7 @@ bool OPvPCapturePoint::SetCapturePointData(uint32 entry, uint32 map, float x, fl
// check info existence
GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(entry);
- if (!goinfo || goinfo->type != GAMEOBJECT_TYPE_CAPTURE_POINT)
+ if (!goinfo || goinfo->type != GAMEOBJECT_TYPE_CONTROL_ZONE)
{
TC_LOG_ERROR("outdoorpvp", "OutdoorPvP: GO %u is not capture point!", entry);
return false;
@@ -548,21 +548,6 @@ bool OutdoorPvP::HandleDropFlag(Player* player, uint32 id)
return false;
}
-bool OPvPCapturePoint::HandleGossipOption(Player* /*player*/, ObjectGuid /*guid*/, uint32 /*id*/)
-{
- return false;
-}
-
-bool OPvPCapturePoint::CanTalkTo(Player* /*player*/, Creature* /*c*/, GossipMenuItems const& /*gso*/)
-{
- return false;
-}
-
-bool OPvPCapturePoint::HandleDropFlag(Player* /*player*/, uint32 /*id*/)
-{
- return false;
-}
-
int32 OPvPCapturePoint::HandleOpenGo(Player* /*player*/, ObjectGuid guid)
{
std::map<ObjectGuid, uint32>::iterator itr = m_ObjectTypes.find(guid);
@@ -573,18 +558,32 @@ int32 OPvPCapturePoint::HandleOpenGo(Player* /*player*/, ObjectGuid guid)
return -1;
}
-bool OutdoorPvP::HandleAreaTrigger(Player* /*player*/, uint32 /*trigger*/)
-{
- return false;
-}
-
-void OutdoorPvP::BroadcastPacket(WorldPacket &data) const
+void OutdoorPvP::BroadcastPacket(WorldPacket const* data) const
{
// This is faster than sWorld->SendZoneMessage
for (uint32 team = 0; team < 2; ++team)
for (GuidSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr)
if (Player* const player = ObjectAccessor::FindPlayer(*itr))
- player->GetSession()->SendPacket(&data);
+ player->SendDirectMessage(data);
+}
+
+void OutdoorPvP::AddCapturePoint(OPvPCapturePoint* cp)
+{
+ OPvPCapturePointMap::iterator i = m_capturePoints.find(cp->m_capturePointGUID);
+ if (i != m_capturePoints.end())
+ {
+ TC_LOG_ERROR("outdoorpvp", "OutdoorPvP::AddCapturePoint: CapturePoint %s already exists!", cp->m_capturePointGUID);
+ delete i->second;
+ }
+ m_capturePoints[cp->m_capturePointGUID] = cp;
+}
+
+OPvPCapturePoint* OutdoorPvP::GetCapturePoint(ObjectGuid guid) const
+{
+ OutdoorPvP::OPvPCapturePointMap::const_iterator itr = m_capturePoints.find(guid);
+ if (itr != m_capturePoints.end())
+ return itr->second;
+ return nullptr;
}
void OutdoorPvP::RegisterZone(uint32 zoneId)
@@ -622,7 +621,7 @@ void OutdoorPvP::TeamApplyBuff(TeamId team, uint32 spellId, uint32 spellId2)
void OutdoorPvP::OnGameObjectCreate(GameObject* go)
{
- if (go->GetGoType() != GAMEOBJECT_TYPE_CAPTURE_POINT)
+ if (go->GetGoType() != GAMEOBJECT_TYPE_CONTROL_ZONE)
return;
if (OPvPCapturePoint *cp = GetCapturePoint(go->GetGUID()))
@@ -631,7 +630,7 @@ void OutdoorPvP::OnGameObjectCreate(GameObject* go)
void OutdoorPvP::OnGameObjectRemove(GameObject* go)
{
- if (go->GetGoType() != GAMEOBJECT_TYPE_CAPTURE_POINT)
+ if (go->GetGoType() != GAMEOBJECT_TYPE_CONTROL_ZONE)
return;
if (OPvPCapturePoint *cp = GetCapturePoint(go->GetGUID()))
diff --git a/src/server/game/OutdoorPvP/OutdoorPvP.h b/src/server/game/OutdoorPvP/OutdoorPvP.h
index 8f4475bce13..f550a35aff0 100644
--- a/src/server/game/OutdoorPvP/OutdoorPvP.h
+++ b/src/server/game/OutdoorPvP/OutdoorPvP.h
@@ -119,11 +119,11 @@ class OPvPCapturePoint
virtual void SendChangePhase();
- virtual bool HandleGossipOption(Player* player, ObjectGuid guid, uint32 gossipid);
+ virtual bool HandleGossipOption(Player* /*player*/, ObjectGuid /*guid*/, uint32 /*gossipId*/) { return false; }
- virtual bool CanTalkTo(Player* player, Creature* c, GossipMenuItems const& gso);
+ virtual bool CanTalkTo(Player* /*player*/, Creature* /*creature*/, GossipMenuItems const& /*gso*/) { return false; }
- virtual bool HandleDropFlag(Player* player, uint32 spellId);
+ virtual bool HandleDropFlag(Player* /*player*/, uint32 /*spellId*/) { return false; }
virtual void DeleteSpawns();
@@ -204,7 +204,7 @@ class OutdoorPvP : public ZoneScript
virtual void FillInitialWorldStates(WorldPacket & /*data*/) { }
// called when a player triggers an areatrigger
- virtual bool HandleAreaTrigger(Player* player, uint32 trigger);
+ virtual bool HandleAreaTrigger(Player* /*player*/, uint32 /*trigger*/) { return false; }
// called on custom spell
virtual bool HandleCustomSpell(Player* player, uint32 spellId, GameObject* go);
@@ -274,25 +274,16 @@ class OutdoorPvP : public ZoneScript
// world state stuff
virtual void SendRemoveWorldStates(Player* /*player*/) { }
- void BroadcastPacket(WorldPacket & data) const;
+ void BroadcastPacket(WorldPacket const* data) const;
virtual void HandlePlayerEnterZone(Player* player, uint32 zone);
virtual void HandlePlayerLeaveZone(Player* player, uint32 zone);
virtual void HandlePlayerResurrects(Player* player, uint32 zone);
- void AddCapturePoint(OPvPCapturePoint* cp)
- {
- m_capturePoints[cp->m_capturePointGUID] = cp;
- }
+ void AddCapturePoint(OPvPCapturePoint* cp);
- OPvPCapturePoint * GetCapturePoint(ObjectGuid guid) const
- {
- OutdoorPvP::OPvPCapturePointMap::const_iterator itr = m_capturePoints.find(guid);
- if (itr != m_capturePoints.end())
- return itr->second;
- return NULL;
- }
+ OPvPCapturePoint * GetCapturePoint(ObjectGuid guid) const;
void RegisterZone(uint32 zoneid);
diff --git a/src/server/game/Server/Packets/CombatPackets.cpp b/src/server/game/Server/Packets/CombatPackets.cpp
index a23cbc7515b..53a489ebc21 100644
--- a/src/server/game/Server/Packets/CombatPackets.cpp
+++ b/src/server/game/Server/Packets/CombatPackets.cpp
@@ -140,3 +140,10 @@ WorldPacket const* WorldPackets::Combat::AttackerStateUpdate::Write()
return &_worldPacket;
}
+
+WorldPacket const* WorldPackets::Combat::AttackSwingError::Write()
+{
+ _worldPacket.WriteBits(Reason, 2);
+ _worldPacket.FlushBits();
+ return &_worldPacket;
+}
diff --git a/src/server/game/Server/Packets/CombatPackets.h b/src/server/game/Server/Packets/CombatPackets.h
index 012859ffc65..54d97e5774c 100644
--- a/src/server/game/Server/Packets/CombatPackets.h
+++ b/src/server/game/Server/Packets/CombatPackets.h
@@ -36,6 +36,17 @@ namespace WorldPackets
ObjectGuid Victim;
};
+ class AttackSwingError final : public ServerPacket
+ {
+ public:
+ AttackSwingError() : ServerPacket(SMSG_ATTACKSWING_ERROR, 4) { }
+ AttackSwingError(AttackSwingErr reason) : ServerPacket(SMSG_ATTACKSWING_ERROR, 4), Reason(reason) { }
+
+ WorldPacket const* Write() override;
+
+ AttackSwingErr Reason = ATTACKSWINGERR_CANT_ATTACK;
+ };
+
class AttackStop final : public ClientPacket
{
public:
@@ -165,6 +176,14 @@ namespace WorldPackets
UnkAttackerState UnkState;
float Unk = 0.0f;
};
+
+ class CancelCombat final : public ServerPacket
+ {
+ public:
+ CancelCombat() : ServerPacket(SMSG_CANCEL_COMBAT, 0) { }
+
+ WorldPacket const* Write() override { return &_worldPacket; }
+ };
}
}
diff --git a/src/server/game/Server/Packets/MiscPackets.cpp b/src/server/game/Server/Packets/MiscPackets.cpp
index da92f65020a..699d504554e 100644
--- a/src/server/game/Server/Packets/MiscPackets.cpp
+++ b/src/server/game/Server/Packets/MiscPackets.cpp
@@ -259,3 +259,33 @@ void WorldPackets::Misc::ResurrectResponse::Read()
_worldPacket >> Resurrecter;
_worldPacket >> Response;
}
+
+WorldPackets::Misc::Weather::Weather() : ServerPacket(SMSG_WEATHER, 4 + 4 + 1) { }
+
+WorldPackets::Misc::Weather::Weather(WeatherState weatherID, float intensity /*= 0.0f*/, bool abrupt /*= false*/)
+ : ServerPacket(SMSG_WEATHER, 4 + 4 + 1), WeatherID(weatherID), Intensity(intensity), Abrupt(abrupt) { }
+
+WorldPacket const* WorldPackets::Misc::Weather::Write()
+{
+ _worldPacket << uint32(WeatherID);
+ _worldPacket << float(Intensity);
+ _worldPacket.WriteBit(Abrupt);
+
+ _worldPacket.FlushBits();
+ return &_worldPacket;
+}
+
+void WorldPackets::Misc::StandStateChange::Read()
+{
+ uint32 state;
+ _worldPacket >> state;
+
+ StandState = UnitStandStateType(state);
+}
+
+WorldPacket const* WorldPackets::Misc::StandStateUpdate::Write()
+{
+ _worldPacket << uint8(State);
+
+ return &_worldPacket;
+}
diff --git a/src/server/game/Server/Packets/MiscPackets.h b/src/server/game/Server/Packets/MiscPackets.h
index b46b0aed60a..4a0d0bfbd12 100644
--- a/src/server/game/Server/Packets/MiscPackets.h
+++ b/src/server/game/Server/Packets/MiscPackets.h
@@ -23,6 +23,8 @@
#include "WorldSession.h"
#include "G3D/Vector3.h"
#include "Object.h"
+#include "Unit.h"
+#include "Weather.h"
namespace WorldPackets
{
@@ -339,7 +341,7 @@ namespace WorldPackets
void Read() override { }
};
- class RequestCemeteryListResponse : public ServerPacket
+ class RequestCemeteryListResponse final : public ServerPacket
{
public:
RequestCemeteryListResponse() : ServerPacket(SMSG_REQUEST_CEMETERY_LIST_RESPONSE, 1) { }
@@ -361,13 +363,47 @@ namespace WorldPackets
uint32 Response = 0;
};
- class AreaTriggerNoCorpse : public ServerPacket
+ class AreaTriggerNoCorpse final : public ServerPacket
{
public:
AreaTriggerNoCorpse() : ServerPacket(SMSG_AREA_TRIGGER_NO_CORPSE, 0) { }
WorldPacket const* Write() override { return &_worldPacket; }
};
+
+ class Weather final : public ServerPacket
+ {
+ public:
+ Weather();
+ Weather(WeatherState weatherID, float intensity = 0.0f, bool abrupt = false);
+
+ WorldPacket const* Write() override;
+
+ bool Abrupt = false;
+ float Intensity = 0.0f;
+ WeatherState WeatherID = WEATHER_STATE_FINE;
+ };
+
+ class StandStateChange final : public ClientPacket
+ {
+ public:
+ StandStateChange(WorldPacket&& packet) : ClientPacket(CMSG_STAND_STATE_CHANGE, std::move(packet)) { }
+
+ void Read() override;
+
+ UnitStandStateType StandState = UNIT_STAND_STATE_STAND;
+ };
+
+ class StandStateUpdate final : public ServerPacket
+ {
+ public:
+ StandStateUpdate() : ServerPacket(SMSG_STAND_STATE_UPDATE, 1) { }
+ StandStateUpdate(UnitStandStateType state) : ServerPacket(SMSG_STAND_STATE_UPDATE, 1), State(state) { }
+
+ WorldPacket const* Write() override;
+
+ UnitStandStateType State = UNIT_STAND_STATE_STAND;
+ };
}
}
diff --git a/src/server/game/Server/Packets/QueryPackets.h b/src/server/game/Server/Packets/QueryPackets.h
index 9b131ae82be..5a48db610ca 100644
--- a/src/server/game/Server/Packets/QueryPackets.h
+++ b/src/server/game/Server/Packets/QueryPackets.h
@@ -314,7 +314,7 @@ namespace WorldPackets
WorldPacket const* Write() override;
time_t CurrentTime = time_t(0);
- int32 TimeOutRequest;
+ int32 TimeOutRequest = 0;
};
}
}
diff --git a/src/server/game/Server/Packets/SpellPackets.cpp b/src/server/game/Server/Packets/SpellPackets.cpp
index 053bb6c504f..6f93fec73f2 100644
--- a/src/server/game/Server/Packets/SpellPackets.cpp
+++ b/src/server/game/Server/Packets/SpellPackets.cpp
@@ -141,78 +141,91 @@ WorldPacket const* WorldPackets::Spells::AuraUpdate::Write()
return &_worldPacket;
}
-void WorldPackets::Spells::SpellCastRequest::Read()
+ByteBuffer& operator>>(ByteBuffer& buffer, WorldPackets::Spells::TargetLocation& location)
{
- if (_worldPacket.GetOpcode() == CMSG_PET_CAST_SPELL)
- _worldPacket >> PetGuid;
-
- _worldPacket >> CastID;
- _worldPacket >> SpellID;
- _worldPacket >> Misc;
-
- _worldPacket.ResetBitPos();
-
- TargetFlags = _worldPacket.ReadBits(21);
- bool HasSrcLocation = _worldPacket.ReadBit();
- bool HasDstLocation = _worldPacket.ReadBit();
- bool HasOrientation = _worldPacket.ReadBit();
- uint32 NameLen = _worldPacket.ReadBits(7);
-
- _worldPacket >> UnitGuid;
- _worldPacket >> ItemGuid;
+ buffer >> location.Transport;
+ buffer >> location.Location.m_positionX;
+ buffer >> location.Location.m_positionY;
+ buffer >> location.Location.m_positionZ;
+ return buffer;
+}
- if (HasSrcLocation)
- {
- _worldPacket >> SrcTransportGuid;
- _worldPacket >> SrcPos.m_positionX;
- _worldPacket >> SrcPos.m_positionY;
- _worldPacket >> SrcPos.m_positionZ;
- }
+ByteBuffer& operator>>(ByteBuffer& buffer, WorldPackets::Spells::SpellTargetData& targetData)
+{
+ buffer.ResetBitPos();
- if (HasDstLocation)
- {
- _worldPacket >> DstTransportGuid;
- _worldPacket >> DstPos.m_positionX;
- _worldPacket >> DstPos.m_positionY;
- _worldPacket >> DstPos.m_positionZ;
- }
+ targetData.Flags = buffer.ReadBits(21);
+ targetData.SrcLocation.HasValue = buffer.ReadBit();
+ targetData.DstLocation.HasValue = buffer.ReadBit();
+ targetData.Orientation.HasValue = buffer.ReadBit();
+ uint32 nameLength = buffer.ReadBits(7);
- if (HasOrientation)
- _worldPacket >> Orientation;
+ buffer >> targetData.Unit;
+ buffer >> targetData.Item;
- Name = _worldPacket.ReadString(NameLen);
+ if (targetData.SrcLocation.HasValue)
+ buffer >> targetData.SrcLocation.Value;
- _worldPacket >> Pitch;
- _worldPacket >> Speed;
+ if (targetData.DstLocation.HasValue)
+ buffer >> targetData.DstLocation.Value;
- _worldPacket >> Guid;
+ if (targetData.Orientation.HasValue)
+ buffer >> targetData.Orientation.Value;
- _worldPacket.ResetBitPos();
+ targetData.Name = buffer.ReadString(nameLength);
- SendCastFlags = _worldPacket.ReadBits(5);
+ return buffer;
+}
- bool HasMoveUpdate = _worldPacket.ReadBit();
- uint32 SpellWeightCount = _worldPacket.ReadBits(2);
+ByteBuffer& operator>>(ByteBuffer& buffer, WorldPackets::Spells::MissileTrajectoryRequest& trajectory)
+{
+ buffer >> trajectory.Pitch;
+ buffer >> trajectory.Speed;
+ return buffer;
+}
- if (HasMoveUpdate)
+ByteBuffer& operator>>(ByteBuffer& buffer, WorldPackets::Spells::SpellCastRequest& request)
+{
+ buffer >> request.CastID;
+ buffer >> request.SpellID;
+ buffer >> request.Misc;
+ buffer >> request.Target;
+ buffer >> request.MissileTrajectory;
+ buffer >> request.Charmer;
+
+ buffer.ResetBitPos();
+ request.SendCastFlags = buffer.ReadBits(5);
+ request.MoveUpdate.HasValue = buffer.ReadBit();
+ request.Weight.resize(buffer.ReadBits(2));
+
+ if (request.MoveUpdate.HasValue)
+ buffer >> request.MoveUpdate.Value;
+
+ for (WorldPackets::Spells::SpellWeight& weight : request.Weight)
{
- _worldPacket >> movementInfo;
+ buffer.ResetBitPos();
+ weight.Type = buffer.ReadBits(2);
+ buffer >> weight.ID;
+ buffer >> weight.Quantity;
}
- for (uint32 i = 0; i < SpellWeightCount; ++i)
- {
- _worldPacket.ResetBitPos();
- SpellWeight unused;
- unused.Type = _worldPacket.ReadBits(2);
- _worldPacket >> unused.ID;
- _worldPacket >> unused.Quantity;
- }
+ return buffer;
+}
+
+void WorldPackets::Spells::CastSpell::Read()
+{
+ _worldPacket >> Cast;
+}
+
+void WorldPackets::Spells::PetCastSpell::Read()
+{
+ _worldPacket >> PetGUID;
+ _worldPacket >> Cast;
}
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::TargetLocation const& targetLocation)
{
data << targetLocation.Transport;
- // data << targetLocation.Location.PositionXYZStream();
data << targetLocation.Location.m_positionX;
data << targetLocation.Location.m_positionY;
data << targetLocation.Location.m_positionZ;
diff --git a/src/server/game/Server/Packets/SpellPackets.h b/src/server/game/Server/Packets/SpellPackets.h
index fa7b8e0b04a..fa5af7b2882 100644
--- a/src/server/game/Server/Packets/SpellPackets.h
+++ b/src/server/game/Server/Packets/SpellPackets.h
@@ -155,46 +155,6 @@ namespace WorldPackets
std::vector<AuraInfo> Auras;
};
- class SpellCastRequest final : public ClientPacket
- {
- public:
- struct SpellWeight
- {
- uint32 Type = 0;
- int32 ID = 0;
- uint32 Quantity = 0;
- };
-
- SpellCastRequest(WorldPacket&& packet) : ClientPacket(std::move(packet))
- {
- ASSERT(packet.GetOpcode() == CMSG_CAST_SPELL || packet.GetOpcode() == CMSG_PET_CAST_SPELL);
- }
-
- void Read() override;
-
- ObjectGuid PetGuid;
- uint8 CastID = 0;
- uint32 SpellID = 0;
- uint32 Misc = 0;
- uint32 TargetFlags = 0;
- ObjectGuid UnitGuid;
- ObjectGuid ItemGuid;
-
- ObjectGuid SrcTransportGuid;
- ObjectGuid DstTransportGuid;
- Position SrcPos;
- Position DstPos;
- float Orientation = 0.0f;
-
- std::string Name;
- float Pitch = 0.0f;
- float Speed = 0.0f;
- ObjectGuid Guid;
- uint32 SendCastFlags = 0;
-
- MovementInfo movementInfo;
- };
-
struct TargetLocation
{
ObjectGuid Transport;
@@ -208,10 +168,59 @@ namespace WorldPackets
ObjectGuid Item;
Optional<TargetLocation> SrcLocation;
Optional<TargetLocation> DstLocation;
- Optional<float> Orientation; // Not found in JAM structures
+ Optional<float> Orientation;
std::string Name;
};
+ struct MissileTrajectoryRequest
+ {
+ float Pitch = 0.0f;
+ float Speed = 0.0f;
+ };
+
+ struct SpellWeight
+ {
+ uint32 Type = 0;
+ int32 ID = 0;
+ uint32 Quantity = 0;
+ };
+
+ struct SpellCastRequest
+ {
+ uint8 CastID = 0;
+ uint32 SpellID = 0;
+ uint32 Misc = 0;
+ uint8 SendCastFlags = 0;
+ SpellTargetData Target;
+ MissileTrajectoryRequest MissileTrajectory;
+ Optional<MovementInfo> MoveUpdate;
+ std::vector<SpellWeight> Weight;
+ ObjectGuid Charmer;
+ };
+
+ class CastSpell final : public ClientPacket
+ {
+ public:
+
+ CastSpell(WorldPacket&& packet) : ClientPacket(CMSG_CAST_SPELL, std::move(packet)) { }
+
+ void Read() override;
+
+ SpellCastRequest Cast;
+ };
+
+ class PetCastSpell final : public ClientPacket
+ {
+ public:
+
+ PetCastSpell(WorldPacket&& packet) : ClientPacket(CMSG_PET_CAST_SPELL, std::move(packet)) { }
+
+ void Read() override;
+
+ ObjectGuid PetGUID;
+ SpellCastRequest Cast;
+ };
+
struct SpellMissStatus
{
uint8 Reason = 0;
@@ -392,18 +401,5 @@ namespace WorldPackets
}
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellCastLogData const& spellCastLogData);
-ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::TargetLocation const& targetLocation);
-ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellTargetData const& spellTargetData);
-ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellMissStatus const& spellMissStatus);
-ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellPowerData const& spellPowerData);
-ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::RuneData const& runeData);
-ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::MissileTrajectoryResult const& missileTrajectory);
-ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellAmmo const& spellAmmo);
-ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::ProjectileVisualData const& projectileVisual);
-ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::CreatureImmunities const& immunities);
-ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellHealPrediction const& spellPred);
-ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellCastData const& spellCastData);
-ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellModifierData const& spellModifierData);
-ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellModifier const& spellModifier);
#endif // SpellPackets_h__
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index cb8cd23482f..988a858e83b 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -255,7 +255,7 @@ void OpcodeTable::Initialize()
DEFINE_OPCODE_HANDLER_OLD(CMSG_CANCEL_TEMP_ENCHANTMENT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelTempEnchantmentOpcode);
DEFINE_HANDLER(CMSG_CANCEL_TRADE, STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, PROCESS_THREADUNSAFE, WorldPackets::Trade::CancelTrade, &WorldSession::HandleCancelTradeOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_CAN_DUEL, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
- DEFINE_HANDLER(CMSG_CAST_SPELL, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Spells::SpellCastRequest, &WorldSession::HandleCastSpellOpcode);
+ DEFINE_HANDLER(CMSG_CAST_SPELL, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Spells::CastSpell, &WorldSession::HandleCastSpellOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_CHALLENGE_MODE_REQUEST_LEADERS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_CHALLENGE_MODE_REQUEST_MAP_STATS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_CHANGE_BAG_SLOT_FLAG, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
@@ -650,7 +650,7 @@ void OpcodeTable::Initialize()
DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_BATTLE_REQUEST_WILD, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_BATTLE_SCRIPT_ERROR_NOTIFY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_CANCEL_AURA, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetCancelAuraOpcode );
- DEFINE_HANDLER(CMSG_PET_CAST_SPELL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Spells::SpellCastRequest, &WorldSession::HandlePetCastSpellOpcode);
+ DEFINE_HANDLER(CMSG_PET_CAST_SPELL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Spells::PetCastSpell, &WorldSession::HandlePetCastSpellOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_LEARN_TALENT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetLearnTalent );
DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_NAME_CACHE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_PET_NAME_QUERY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePetNameQuery );
@@ -809,7 +809,7 @@ void OpcodeTable::Initialize()
DEFINE_OPCODE_HANDLER_OLD(CMSG_SPELLCLICK, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSpellClick );
DEFINE_OPCODE_HANDLER_OLD(CMSG_SPIRIT_HEALER_ACTIVATE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSpiritHealerActivateOpcode);
DEFINE_HANDLER(CMSG_SPLIT_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::SplitItem, &WorldSession::HandleSplitItemOpcode);
- DEFINE_OPCODE_HANDLER_OLD(CMSG_STANDSTATECHANGE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleStandStateChangeOpcode );
+ DEFINE_HANDLER(CMSG_STAND_STATE_CHANGE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::StandStateChange, &WorldSession::HandleStandStateChangeOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_START_QUEST, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_STOP_DANCE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_STORE_LOOT_IN_SLOT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
@@ -938,11 +938,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKERSTATEUPDATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSTART, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSTOP, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSWING_BADFACING, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSWING_CANT_ATTACK, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSWING_DEADTARGET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSWING_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSWING_NOTINRANGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKSWING_ERROR, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_BIDDER_NOTIFICATION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_CLOSED_NOTIFICATION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_COMMAND_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
@@ -1056,7 +1052,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_UPDATE_INVITE_LIST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CAMERA_SHAKE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CANCEL_AUTO_REPEAT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_CANCEL_COMBAT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_CANCEL_COMBAT, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CANCEL_ORPHAN_SPELL_VISUAL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CANCEL_SCENE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CANCEL_SPELL_VISUAL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
@@ -1803,7 +1799,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_START, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_UPDATE_CHAIN_TARGETS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPIRIT_HEALER_CONFIRM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_STANDSTATE_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_STAND_STATE_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_START_ELAPSED_TIMER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_START_ELAPSED_TIMERS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_START_LOOT_ROLL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
@@ -1885,7 +1881,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_WARDEN_DATA, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_WARGAME_CHECK_ENTRY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_WARGAME_REQUEST_SENT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_WEATHER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_WEATHER, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_WEEKLY_LAST_RESET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_WEEKLY_RESET_CURRENCY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_WEEKLY_SPELL_USAGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h
index 971c69a2151..fa0ffde42cb 100644
--- a/src/server/game/Server/Protocol/Opcodes.h
+++ b/src/server/game/Server/Protocol/Opcodes.h
@@ -719,7 +719,7 @@ enum OpcodeClient : uint32
CMSG_SPELLCLICK = 0x0BC2,
CMSG_SPIRIT_HEALER_ACTIVATE = 0x03EC,
CMSG_SPLIT_ITEM = 0x0795,
- CMSG_STANDSTATECHANGE = 0x0ABD,
+ CMSG_STAND_STATE_CHANGE = 0x0ABD,
CMSG_START_QUEST = 0xBADD,
CMSG_STOP_DANCE = 0xBADD,
CMSG_STORE_LOOT_IN_SLOT = 0xBADD,
@@ -846,11 +846,7 @@ enum OpcodeServer : uint32
SMSG_ATTACKERSTATEUPDATE = 0x1204,
SMSG_ATTACKSTART = 0x1D3E,
SMSG_ATTACKSTOP = 0x1382,
- SMSG_ATTACKSWING_BADFACING = 0xBADD,
- SMSG_ATTACKSWING_CANT_ATTACK = 0xBADD,
- SMSG_ATTACKSWING_DEADTARGET = 0xBADD,
SMSG_ATTACKSWING_ERROR = 0x0509,
- SMSG_ATTACKSWING_NOTINRANGE = 0xBADD,
SMSG_AUCTION_BIDDER_NOTIFICATION = 0xBADD,
SMSG_AUCTION_CLOSED_NOTIFICATION = 0x058E,
SMSG_AUCTION_COMMAND_RESULT = 0x0B2D,
@@ -1712,7 +1708,7 @@ enum OpcodeServer : uint32
SMSG_SPELL_START = 0x0803,
SMSG_SPELL_UPDATE_CHAIN_TARGETS = 0x0374,
SMSG_SPIRIT_HEALER_CONFIRM = 0x1331,
- SMSG_STANDSTATE_UPDATE = 0x1311,
+ SMSG_STAND_STATE_UPDATE = 0x1311,
SMSG_START_ELAPSED_TIMER = 0x0D2A,
SMSG_START_ELAPSED_TIMERS = 0x093F,
SMSG_START_LOOT_ROLL = 0x1B84,
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index 17ca3e3c58c..166a432077c 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -1279,7 +1279,7 @@ uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) co
case CMSG_MESSAGECHAT_YELL: // 0 3.5
case CMSG_INSPECT: // 0 3.5
//case CMSG_AREA_SPIRIT_HEALER_QUERY: // not profiled
- case CMSG_STANDSTATECHANGE: // not profiled
+ case CMSG_STAND_STATE_CHANGE: // not profiled
case CMSG_RANDOM_ROLL: // not profiled
case CMSG_TIME_SYNC_RESPONSE: // not profiled
case CMSG_TRAINER_BUY_SPELL: // not profiled
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index 0707ffbb6fc..291ba0a9f66 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -203,6 +203,7 @@ namespace WorldPackets
class RepopRequest;
class RequestCemeteryList;
class ResurrectResponse;
+ class StandStateChange;
class UITimeRequest;
}
@@ -246,7 +247,8 @@ namespace WorldPackets
namespace Spells
{
class CancelAura;
- class SpellCastRequest;
+ class CastSpell;
+ class PetCastSpell;
class SetActionButton;
}
@@ -735,7 +737,7 @@ class WorldSession
void HandleZoneUpdateOpcode(WorldPacket& recvPacket);
void HandleSetSelectionOpcode(WorldPackets::Misc::SetSelection& packet);
- void HandleStandStateChangeOpcode(WorldPacket& recvPacket);
+ void HandleStandStateChangeOpcode(WorldPackets::Misc::StandStateChange& packet);
void HandleEmoteOpcode(WorldPacket& recvPacket);
void HandleContactListOpcode(WorldPacket& recvPacket);
void HandleAddFriendOpcode(WorldPacket& recvPacket);
@@ -946,7 +948,7 @@ class WorldSession
void HandleUseItemOpcode(WorldPacket& recvPacket);
void HandleOpenItemOpcode(WorldPacket& recvPacket);
- void HandleCastSpellOpcode(WorldPackets::Spells::SpellCastRequest& castRequest);
+ void HandleCastSpellOpcode(WorldPackets::Spells::CastSpell& castRequest);
void HandleCancelCastOpcode(WorldPacket& recvPacket);
void HandleCancelAuraOpcode(WorldPackets::Spells::CancelAura& cancelAura);
void HandleCancelGrowthAuraOpcode(WorldPacket& recvPacket);
@@ -1029,7 +1031,7 @@ class WorldSession
void HandlePetRename(WorldPacket& recvData);
void HandlePetCancelAuraOpcode(WorldPacket& recvPacket);
void HandlePetSpellAutocastOpcode(WorldPacket& recvPacket);
- void HandlePetCastSpellOpcode(WorldPackets::Spells::SpellCastRequest& castRequest);
+ void HandlePetCastSpellOpcode(WorldPackets::Spells::PetCastSpell& castRequest);
void HandlePetLearnTalent(WorldPacket& recvPacket);
void HandleSetActionBarToggles(WorldPacket& recvData);
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 819942901cb..9cf748ff912 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -41,6 +41,7 @@
#include "WeatherMgr.h"
#include "Pet.h"
#include "ReputationMgr.h"
+#include "MiscPackets.h"
class Aura;
//
@@ -6633,10 +6634,8 @@ void AuraEffect::HandleAuraForceWeather(AuraApplication const* aurApp, uint8 mod
if (apply)
{
- WorldPacket data(SMSG_WEATHER, (4 + 4 + 1));
-
- data << uint32(GetMiscValue()) << 1.0f << uint8(0);
- target->GetSession()->SendPacket(&data);
+ WorldPackets::Misc::Weather weather(WeatherState(GetMiscValue()), 1.0f);
+ target->GetSession()->SendPacket(weather.Write());
}
else
{
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index d729d76a1d5..387a01dbf0a 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -109,34 +109,43 @@ void SpellDestination::RelocateOffset(Position const& offset)
_position.RelocateOffset(offset);
}
-SpellCastTargets::SpellCastTargets() : m_elevation(0), m_speed(0), m_strTarget()
+SpellCastTargets::SpellCastTargets() : m_targetMask(0), m_objectTarget(nullptr), m_itemTarget(nullptr),
+ m_itemTargetEntry(0), m_elevation(0.0f), m_speed(0.0f)
{
- m_objectTarget = NULL;
- m_itemTarget = NULL;
-
- m_itemTargetEntry = 0;
-
- m_targetMask = 0;
}
-SpellCastTargets::SpellCastTargets(Unit* caster, uint32 targetMask, ObjectGuid targetGuid, ObjectGuid itemTargetGuid, ObjectGuid srcTransportGuid, ObjectGuid destTransportGuid, Position srcPos, Position destPos, float elevation, float missileSpeed, std::string targetString) :
- m_targetMask(targetMask), m_objectTargetGUID(targetGuid), m_itemTargetGUID(itemTargetGuid), m_elevation(elevation), m_speed(missileSpeed), m_strTarget(targetString)
+SpellCastTargets::SpellCastTargets(Unit* caster, WorldPackets::Spells::SpellTargetData const& spellTargetData) :
+ m_targetMask(spellTargetData.Flags), m_objectTarget(nullptr), m_itemTarget(nullptr),
+ m_objectTargetGUID(spellTargetData.Unit), m_itemTargetGUID(spellTargetData.Item),
+ m_itemTargetEntry(0), m_elevation(0.0f), m_speed(0.0f), m_strTarget(spellTargetData.Name)
{
- m_objectTarget = NULL;
- m_itemTarget = NULL;
- m_itemTargetEntry = 0;
+ if (spellTargetData.SrcLocation.HasValue)
+ {
+ m_src._transportGUID = spellTargetData.SrcLocation.Value.Transport;
+ Position* pos;
+ if (!m_src._transportGUID.IsEmpty())
+ pos = &m_src._transportOffset;
+ else
+ pos = &m_src._position;
- m_src._transportGUID = srcTransportGuid;
- if (m_src._transportGUID != ObjectGuid::Empty)
- m_src._transportOffset.Relocate(srcPos);
- else
- m_src._position.Relocate(srcPos);
+ pos->Relocate(spellTargetData.SrcLocation.Value.Location);
+ if (spellTargetData.Orientation.HasValue)
+ pos->SetOrientation(spellTargetData.Orientation.Value);
+ }
- m_dst._transportGUID = destTransportGuid;
- if (m_dst._transportGUID != ObjectGuid::Empty)
- m_dst._transportOffset.Relocate(destPos);
- else
- m_dst._position.Relocate(destPos);
+ if (spellTargetData.DstLocation.HasValue)
+ {
+ m_dst._transportGUID = spellTargetData.DstLocation.Value.Transport;
+ Position* pos;
+ if (!m_dst._transportGUID.IsEmpty())
+ pos = &m_dst._transportOffset;
+ else
+ pos = &m_dst._position;
+
+ pos->Relocate(spellTargetData.DstLocation.Value.Location);
+ if (spellTargetData.Orientation.HasValue)
+ pos->SetOrientation(spellTargetData.Orientation.Value);
+ }
Update(caster);
}
@@ -230,39 +239,6 @@ void SpellCastTargets::Write(WorldPackets::Spells::SpellTargetData& data)
if (m_targetMask & TARGET_FLAG_STRING)
data.Name = m_strTarget;
- /*data << uint32(m_targetMask);
-
- if (m_targetMask & (TARGET_FLAG_UNIT | TARGET_FLAG_CORPSE_ALLY | TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_UNIT_MINIPET))
- data << m_objectTargetGUID.WriteAsPacked();
-
- if (m_targetMask & (TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM))
- {
- if (m_itemTarget)
- data << m_itemTarget->GetPackGUID();
- else
- data << uint8(0);
- }
-
- if (m_targetMask & TARGET_FLAG_SOURCE_LOCATION)
- {
- data << m_src._transportGUID.WriteAsPacked(); // relative position guid here - transport for example
- if (!m_src._transportGUID.IsEmpty())
- data << m_src._transportOffset.PositionXYZStream();
- else
- data << m_src._position.PositionXYZStream();
- }
-
- if (m_targetMask & TARGET_FLAG_DEST_LOCATION)
- {
- data << m_dst._transportGUID.WriteAsPacked(); // relative position guid here - transport for example
- if (!m_dst._transportGUID.IsEmpty())
- data << m_dst._transportOffset.PositionXYZStream();
- else
- data << m_dst._position.PositionXYZStream();
- }
-
- if (m_targetMask & TARGET_FLAG_STRING)
- data << m_strTarget;*/
}
ObjectGuid SpellCastTargets::GetOrigUnitTargetGUID() const
@@ -641,8 +617,8 @@ m_spellValue(new SpellValue(caster->GetMap()->GetDifficultyID(), m_spellInfo)),
m_spellState = SPELL_STATE_NULL;
_triggeredCastFlags = triggerFlags;
- if (info->HasAttribute(SPELL_ATTR4_TRIGGERED))
- _triggeredCastFlags = TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT);
+ if (info->HasAttribute(SPELL_ATTR4_CAN_CAST_WHILE_CASTING))
+ _triggeredCastFlags = TriggerCastFlags(uint32(_triggeredCastFlags) | TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_CAST_DIRECTLY);
m_CastItem = NULL;
m_castItemGUID.Clear();
@@ -665,7 +641,7 @@ m_spellValue(new SpellValue(caster->GetMap()->GetDifficultyID(), m_spellInfo)),
m_procEx = 0;
focusObject = NULL;
m_cast_count = 0;
- m_glyphIndex = 0;
+ m_misc.Data = 0;
m_preCastSpell = 0;
m_triggeredByAuraSpell = NULL;
m_spellAura = NULL;
@@ -3744,7 +3720,7 @@ void Spell::SendCastResult(SpellCastResult result)
if (m_caster->ToPlayer()->GetSession()->PlayerLoading()) // don't send cast results at loading time
return;
- SendCastResult(m_caster->ToPlayer(), m_spellInfo, m_cast_count, result, m_customError);
+ SendCastResult(m_caster->ToPlayer(), m_spellInfo, m_cast_count, result, m_customError, SMSG_CAST_FAILED, m_misc.Data);
}
void Spell::SendPetCastResult(SpellCastResult result)
@@ -3756,10 +3732,10 @@ void Spell::SendPetCastResult(SpellCastResult result)
if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
return;
- SendCastResult(owner->ToPlayer(), m_spellInfo, m_cast_count, result, SPELL_CUSTOM_ERROR_NONE, SMSG_PET_CAST_FAILED);
+ SendCastResult(owner->ToPlayer(), m_spellInfo, m_cast_count, result, SPELL_CUSTOM_ERROR_NONE, SMSG_PET_CAST_FAILED, m_misc.Data);
}
-void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cast_count, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/, OpcodeServer opcode /*= SMSG_CAST_FAILED*/)
+void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cast_count, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/, OpcodeServer opcode /*= SMSG_CAST_FAILED*/, uint32 misc /*= 0*/)
{
if (result == SPELL_CAST_OK)
return;
@@ -3870,6 +3846,12 @@ void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cas
packet.FailedArg1 = missingItem; // first missing item
break;
}
+ case SPELL_FAILED_CANT_UNTALENT:
+ {
+ if (TalentEntry const* talent = sTalentStore.LookupEntry(misc))
+ packet.FailedArg1 = talent->SpellID;
+ break;
+ }
// TODO: SPELL_FAILED_NOT_STANDING
default:
break;
@@ -5606,12 +5588,25 @@ SpellCastResult Spell::CheckCast(bool strict)
break;
}
case SPELL_EFFECT_TALENT_SPEC_SELECT:
+ {
// can't change during already started arena/battleground
if (m_caster->GetTypeId() == TYPEID_PLAYER)
if (Battleground const* bg = m_caster->ToPlayer()->GetBattleground())
if (bg->GetStatus() == STATUS_IN_PROGRESS)
return SPELL_FAILED_NOT_IN_BATTLEGROUND;
break;
+ }
+ case SPELL_EFFECT_REMOVE_TALENT:
+ {
+ if (m_caster->GetTypeId() != TYPEID_PLAYER)
+ return SPELL_FAILED_BAD_TARGETS;
+ TalentEntry const* talent = sTalentStore.LookupEntry(m_misc.TalentId);
+ if (!talent)
+ return SPELL_FAILED_DONT_REPORT;
+ if (m_caster->ToPlayer()->HasSpellCooldown(talent->SpellID))
+ return SPELL_FAILED_CANT_UNTALENT;
+ break;
+ }
default:
break;
}
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index a8ff53b5cb1..48a62ab0e10 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -107,7 +107,7 @@ class SpellCastTargets
{
public:
SpellCastTargets();
- SpellCastTargets(Unit* caster, uint32 targetMask, ObjectGuid targetGuid, ObjectGuid itemTargetGuid, ObjectGuid srcTransportGuid, ObjectGuid destTransportGuid, Position srcPos, Position destPos, float elevation, float missileSpeed, std::string targetString);
+ SpellCastTargets(Unit* caster, WorldPackets::Spells::SpellTargetData const& spellTargetData);
~SpellCastTargets();
void Read(ByteBuffer& data, Unit* caster);
@@ -364,6 +364,7 @@ class Spell
void EffectGiveCurrency(SpellEffIndex effIndex);
void EffectResurrectWithAura(SpellEffIndex effIndex);
void EffectCreateAreaTrigger(SpellEffIndex effIndex);
+ void EffectRemoveTalent(SpellEffIndex effIndex);
typedef std::set<Aura*> UsedSpellMods;
@@ -444,7 +445,7 @@ class Spell
void CheckSrc() { if (!m_targets.HasSrc()) m_targets.SetSrc(*m_caster); }
void CheckDst() { if (!m_targets.HasDst()) m_targets.SetDst(*m_caster); }
- static void SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cast_count, SpellCastResult result, SpellCustomErrors customError = SPELL_CUSTOM_ERROR_NONE, OpcodeServer opcode = SMSG_CAST_FAILED);
+ static void SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cast_count, SpellCastResult result, SpellCustomErrors customError = SPELL_CUSTOM_ERROR_NONE, OpcodeServer opcode = SMSG_CAST_FAILED, uint32 misc = 0);
void SendCastResult(SpellCastResult result);
void SendPetCastResult(SpellCastResult result);
void SendSpellStart();
@@ -475,7 +476,14 @@ class Spell
ObjectGuid m_castItemGUID;
uint32 m_castItemEntry;
uint8 m_cast_count;
- uint32 m_glyphIndex;
+ union
+ {
+ // Alternate names for this value
+ uint32 TalentId;
+ uint32 GlyphSlot;
+
+ uint32 Data;
+ } m_misc;
uint32 m_preCastSpell;
SpellCastTargets m_targets;
int8 m_comboPointGain;
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 3eeb50a2d39..7c5ab810ce4 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -250,7 +250,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectUnused, //178 SPELL_EFFECT_178 unused
&Spell::EffectCreateAreaTrigger, //179 SPELL_EFFECT_CREATE_AREATRIGGER
&Spell::EffectNULL, //180 SPELL_EFFECT_UPDATE_AREATRIGGER
- &Spell::EffectNULL, //181 SPELL_EFFECT_REMOVE_TALENT
+ &Spell::EffectRemoveTalent, //181 SPELL_EFFECT_REMOVE_TALENT
&Spell::EffectNULL, //182 SPELL_EFFECT_182
&Spell::EffectNULL, //183 SPELL_EFFECT_183
&Spell::EffectNULL, //184 SPELL_EFFECT_REPUTATION
@@ -3938,11 +3938,17 @@ void Spell::EffectStuck(SpellEffIndex /*effIndex*/)
{
if (!player->GetDeathTimer())
player->RepopAtGraveyard();
-
+
+ return;
+ }
+
+ // the player dies if hearthstone is in cooldown, else the player is teleported to home
+ if (player->HasSpellCooldown(8690))
+ {
+ player->Kill(player);
return;
}
- // the player is teleported to home
player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, player->GetOrientation(), TELE_TO_SPELL);
// Stuck spell trigger Hearthstone cooldown
@@ -3999,7 +4005,7 @@ void Spell::EffectApplyGlyph(SpellEffIndex /*effIndex*/)
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
return;
- if (m_glyphIndex >= MAX_GLYPH_SLOT_INDEX)
+ if (m_misc.GlyphSlot >= MAX_GLYPH_SLOT_INDEX)
return;
Player* player = m_caster->ToPlayer();
@@ -4008,7 +4014,7 @@ void Spell::EffectApplyGlyph(SpellEffIndex /*effIndex*/)
// glyph sockets level requirement
uint8 minLevel = 0;
- switch (m_glyphIndex)
+ switch (m_misc.GlyphSlot)
{
case 0:
case 1:
@@ -4032,7 +4038,7 @@ void Spell::EffectApplyGlyph(SpellEffIndex /*effIndex*/)
{
if (GlyphPropertiesEntry const* newGlyphProperties = sGlyphPropertiesStore.LookupEntry(newGlyph))
{
- if (GlyphSlotEntry const* newGlyphSlot = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex)))
+ if (GlyphSlotEntry const* newGlyphSlot = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_misc.GlyphSlot)))
{
if (newGlyphProperties->Type != newGlyphSlot->Type)
{
@@ -4042,26 +4048,26 @@ void Spell::EffectApplyGlyph(SpellEffIndex /*effIndex*/)
}
// remove old glyph
- if (uint32 oldGlyph = player->GetGlyph(player->GetActiveTalentGroup(), m_glyphIndex))
+ if (uint32 oldGlyph = player->GetGlyph(player->GetActiveTalentGroup(), m_misc.GlyphSlot))
{
if (GlyphPropertiesEntry const* oldGlyphProperties = sGlyphPropertiesStore.LookupEntry(oldGlyph))
{
player->RemoveAurasDueToSpell(oldGlyphProperties->SpellID);
- player->SetGlyph(m_glyphIndex, 0);
+ player->SetGlyph(m_misc.GlyphSlot, 0);
}
}
player->CastSpell(m_caster, newGlyphProperties->SpellID, true);
- player->SetGlyph(m_glyphIndex, newGlyph);
+ player->SetGlyph(m_misc.GlyphSlot, newGlyph);
player->SendTalentsInfoData();
}
}
- else if (uint32 oldGlyph = player->GetGlyph(player->GetActiveTalentGroup(), m_glyphIndex)) // Removing the glyph, get the old one
+ else if (uint32 oldGlyph = player->GetGlyph(player->GetActiveTalentGroup(), m_misc.GlyphSlot)) // Removing the glyph, get the old one
{
if (GlyphPropertiesEntry const* oldGlyphProperties = sGlyphPropertiesStore.LookupEntry(oldGlyph))
{
player->RemoveAurasDueToSpell(oldGlyphProperties->SpellID);
- player->SetGlyph(m_glyphIndex, 0);
+ player->SetGlyph(m_misc.GlyphSlot, 0);
player->SendTalentsInfoData();
}
}
@@ -5762,3 +5768,20 @@ void Spell::EffectCreateAreaTrigger(SpellEffIndex /*effIndex*/)
if (!areaTrigger->CreateAreaTrigger(sObjectMgr->GetGenerator<HighGuid::AreaTrigger>()->Generate(), triggerEntry, GetCaster(), GetSpellInfo(), pos))
delete areaTrigger;
}
+
+void Spell::EffectRemoveTalent(SpellEffIndex effIndex)
+{
+ if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
+ return;
+
+ TalentEntry const* talent = sTalentStore.LookupEntry(m_misc.TalentId);
+ if (!talent)
+ return;
+
+ Player* player = unitTarget ? unitTarget->ToPlayer() : nullptr;
+ if (!player)
+ return;
+
+ player->RemoveTalent(talent);
+ player->SendTalentsInfoData();
+}
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 1f6b5238137..a70c73de6df 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -875,9 +875,71 @@ SpellEffectInfo::StaticData SpellEffectInfo::_data[TOTAL_SPELL_EFFECTS] =
{EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 177 SPELL_EFFECT_177
{EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 178 SPELL_EFFECT_178
{EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_DEST}, // 179 SPELL_EFFECT_CREATE_AREATRIGGER
- {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 180 SPELL_EFFECT_180
- {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 181 SPELL_EFFECT_181
- {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_UNIT}, // 182 SPELL_EFFECT_182
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 180 SPELL_EFFECT_UPDATE_AREATRIGGER
+ {EFFECT_IMPLICIT_TARGET_CASTER, TARGET_OBJECT_TYPE_UNIT}, // 181 SPELL_EFFECT_REMOVE_TALENT
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 182 SPELL_EFFECT_182
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 183 SPELL_EFFECT_183
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 184 SPELL_EFFECT_REPUTATION_2
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 185 SPELL_EFFECT_185
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 186 SPELL_EFFECT_186
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 187 SPELL_EFFECT_RANDOMIZE_ARCHAEOLOGY_DIGSITES
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 188 SPELL_EFFECT_188
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 189 SPELL_EFFECT_LOOT
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 190 SPELL_EFFECT_190
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 191 SPELL_EFFECT_TELEPORT_TO_DIGSITE
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 192 SPELL_EFFECT_192
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 193 SPELL_EFFECT_193
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 194 SPELL_EFFECT_194
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 195 SPELL_EFFECT_195
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 196 SPELL_EFFECT_196
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 197 SPELL_EFFECT_197
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 198 SPELL_EFFECT_198
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 199 SPELL_EFFECT_199
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 200 SPELL_EFFECT_HEAL_BATTLEPET_PCT
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 201 SPELL_EFFECT_ENABLE_BATTLE_PETS
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 202 SPELL_EFFECT_202
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 203 SPELL_EFFECT_203
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 204 SPELL_EFFECT_204
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 205 SPELL_EFFECT_205
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 206 SPELL_EFFECT_206
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 207 SPELL_EFFECT_207
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 208 SPELL_EFFECT_208
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 209 SPELL_EFFECT_209
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 210 SPELL_EFFECT_210
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 211 SPELL_EFFECT_211
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 212 SPELL_EFFECT_212
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 213 SPELL_EFFECT_213
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 214 SPELL_EFFECT_214
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 215 SPELL_EFFECT_215
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 216 SPELL_EFFECT_216
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 217 SPELL_EFFECT_217
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 218 SPELL_EFFECT_218
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 219 SPELL_EFFECT_219
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 220 SPELL_EFFECT_220
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 221 SPELL_EFFECT_221
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 222 SPELL_EFFECT_222
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 223 SPELL_EFFECT_223
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 224 SPELL_EFFECT_224
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 225 SPELL_EFFECT_225
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 226 SPELL_EFFECT_226
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 227 SPELL_EFFECT_227
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 228 SPELL_EFFECT_228
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 229 SPELL_EFFECT_229
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 230 SPELL_EFFECT_230
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 231 SPELL_EFFECT_231
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 232 SPELL_EFFECT_232
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 233 SPELL_EFFECT_233
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 234 SPELL_EFFECT_234
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 235 SPELL_EFFECT_235
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 236 SPELL_EFFECT_236
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 237 SPELL_EFFECT_237
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 238 SPELL_EFFECT_238
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 239 SPELL_EFFECT_239
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 240 SPELL_EFFECT_240
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 241 SPELL_EFFECT_241
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 242 SPELL_EFFECT_242
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 243 SPELL_EFFECT_243
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 244 SPELL_EFFECT_244
};
SpellInfo::SpellInfo(SpellEntry const* spellEntry, SpellEffectEntryMap effects)
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index 5b9cfacb56b..b585588726e 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -186,6 +186,7 @@ enum SpellCustomAttributes
SPELL_ATTR0_CU_CONE_LINE = 0x00000004,
SPELL_ATTR0_CU_SHARE_DAMAGE = 0x00000008,
SPELL_ATTR0_CU_NO_INITIAL_THREAT = 0x00000010,
+ SPELL_ATTR0_CU_IS_TALENT = 0x00000020,
SPELL_ATTR0_CU_AURA_CC = 0x00000040,
SPELL_ATTR0_CU_DIRECT_DAMAGE = 0x00000100,
SPELL_ATTR0_CU_CHARGE = 0x00000200,
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 02d3e2e2ea1..d0eff5fff00 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -1251,73 +1251,8 @@ void SpellMgr::UnloadSpellInfoChains()
mSpellChains.clear();
}
-void SpellMgr::LoadSpellTalentRanks()
-{
- /* TODO: 6.x remove this
- // cleanup core data before reload - remove reference to ChainNode from SpellInfo
- UnloadSpellInfoChains();
-
- for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
- {
- TalentEntry const* talentInfo = sTalentStore.LookupEntry(i);
- if (!talentInfo)
- continue;
-
- SpellInfo const* lastSpell = NULL;
- for (uint8 rank = MAX_TALENT_RANK - 1; rank > 0; --rank)
- {
- if (talentInfo->RankID[rank])
- {
- lastSpell = GetSpellInfo(talentInfo->RankID[rank]);
- break;
- }
- }
-
- if (!lastSpell)
- continue;
-
- SpellInfo const* firstSpell = GetSpellInfo(talentInfo->RankID[0]);
- if (!firstSpell)
- {
- TC_LOG_ERROR("spells", "SpellMgr::LoadSpellTalentRanks: First Rank Spell %u for TalentEntry %u does not exist.", talentInfo->RankID[0], i);
- continue;
- }
-
- SpellInfo const* prevSpell = NULL;
- for (uint8 rank = 0; rank < MAX_TALENT_RANK; ++rank)
- {
- uint32 spellId = talentInfo->RankID[rank];
- if (!spellId)
- break;
-
- SpellInfo const* currentSpell = GetSpellInfo(spellId);
- if (!currentSpell)
- {
- TC_LOG_ERROR("spells", "SpellMgr::LoadSpellTalentRanks: Spell %u (Rank: %u) for TalentEntry %u does not exist.", spellId, rank + 1, i);
- break;
- }
-
- SpellChainNode node;
- node.first = firstSpell;
- node.last = lastSpell;
- node.rank = rank + 1;
-
- node.prev = prevSpell;
- node.next = node.rank < MAX_TALENT_RANK ? GetSpellInfo(talentInfo->RankID[node.rank]) : NULL;
-
- mSpellChains[spellId] = node;
- mSpellInfoMap[spellId]->ChainEntry = &mSpellChains[spellId];
-
- prevSpell = currentSpell;
- }
- }*/
-}
-
void SpellMgr::LoadSpellRanks()
{
- // cleanup data and load spell ranks for talents from dbc
- LoadSpellTalentRanks();
-
uint32 oldMSTime = getMSTime();
// 0 1 2
@@ -1553,7 +1488,8 @@ void SpellMgr::LoadSpellLearnSpells()
node.active = fields[2].GetBool();
node.autoLearned = false;
- if (!GetSpellInfo(spell_id))
+ SpellInfo const* spellInfo = GetSpellInfo(spell_id);
+ if (!spellInfo)
{
TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_learn_spell` does not exist", spell_id);
continue;
@@ -1565,7 +1501,7 @@ void SpellMgr::LoadSpellLearnSpells()
continue;
}
- if (GetTalentBySpellID(node.spell))
+ if (spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT))
{
TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_learn_spell` attempt learning talent spell %u, skipped", spell_id, node.spell);
continue;
@@ -1603,7 +1539,7 @@ void SpellMgr::LoadSpellLearnSpells()
// talent or passive spells or skill-step spells auto-cast and not need dependent learning,
// pet teaching spells must not be dependent learning (cast)
// other required explicit dependent learning
- dbc_node.autoLearned = effect->TargetA.GetTarget() == TARGET_UNIT_PET || GetTalentBySpellID(spell) || entry->IsPassive() || entry->HasEffect(SPELL_EFFECT_SKILL_STEP);
+ dbc_node.autoLearned = effect->TargetA.GetTarget() == TARGET_UNIT_PET || entry->HasAttribute(SPELL_ATTR0_CU_IS_TALENT) || entry->IsPassive() || entry->HasEffect(SPELL_EFFECT_SKILL_STEP);
SpellLearnSpellMapBounds db_node_bounds = dbSpellLearnSpells.equal_range(spell);
@@ -1654,7 +1590,7 @@ void SpellMgr::LoadSpellLearnSpells()
{
if (itr->second.spell == mastery)
{
- TC_LOG_ERROR("sql.sql", "Found redundant record (entry: %u, SpellID: %u) in `spell_learn_spell`, spell added automatically as mastery learned spell from TalentTab.dbc", masteryMainSpell, mastery);
+ TC_LOG_ERROR("sql.sql", "Found redundant record (entry: %u, SpellID: %u) in `spell_learn_spell`, spell added automatically as mastery learned spell from ChrSpecialization.dbc", masteryMainSpell, mastery);
found = true;
break;
}
@@ -1711,7 +1647,7 @@ void SpellMgr::LoadSpellTargetPositions()
{
Field* fields = result->Fetch();
- uint32 Spell_ID = fields[0].GetUInt32();
+ uint32 spellId = fields[0].GetUInt32();
SpellEffIndex effIndex = SpellEffIndex(fields[1].GetUInt8());
SpellTargetPosition st;
@@ -1724,27 +1660,27 @@ void SpellMgr::LoadSpellTargetPositions()
MapEntry const* mapEntry = sMapStore.LookupEntry(st.target_mapId);
if (!mapEntry)
{
- TC_LOG_ERROR("sql.sql", "Spell (ID: %u, EffectIndex: %u) is using a non-existant MapID (ID: %u).", Spell_ID, effIndex, st.target_mapId);
+ TC_LOG_ERROR("sql.sql", "Spell (Id: %u, EffectIndex: %u) is using a non-existant MapID (ID: %u).", spellId, effIndex, st.target_mapId);
continue;
}
if (st.target_X == 0 && st.target_Y == 0 && st.target_Z == 0)
{
- TC_LOG_ERROR("sql.sql", "Spell (ID: %u, EffectIndex: %u): target coordinates not provided.", Spell_ID, effIndex);
+ TC_LOG_ERROR("sql.sql", "Spell (Id: %u, EffectIndex: %u): target coordinates not provided.", spellId, effIndex);
continue;
}
- SpellInfo const* spellInfo = GetSpellInfo(Spell_ID);
+ SpellInfo const* spellInfo = GetSpellInfo(spellId);
if (!spellInfo)
{
- TC_LOG_ERROR("sql.sql", "Spell (ID: %u) listed in `spell_target_position` does not exist.", Spell_ID);
+ TC_LOG_ERROR("sql.sql", "Spell (Id: %u) listed in `spell_target_position` does not exist.", spellId);
continue;
}
SpellEffectInfo const* effect = spellInfo->GetEffect(effIndex);
if (!effect)
{
- TC_LOG_ERROR("sql.sql", "Spell (Id: %u, effIndex: %u) listed in `spell_target_position` does not have an effect at index %u.", Spell_ID, effIndex, effIndex);
+ TC_LOG_ERROR("sql.sql", "Spell (Id: %u, EffectIndex: %u) listed in `spell_target_position` does not have an effect at index %u.", spellId, effIndex, effIndex);
continue;
}
@@ -1756,19 +1692,13 @@ void SpellMgr::LoadSpellTargetPositions()
if (effect->TargetA.GetTarget() == TARGET_DEST_DB || effect->TargetB.GetTarget() == TARGET_DEST_DB)
{
- TC_LOG_ERROR("sql.sql", "Spell (Id: %u, effIndex: %u) listed in `spell_target_position` does not have TARGET_DEST_DB as target at index %u.", Spell_ID, effIndex, effIndex);
- continue;
- }
-
- if (effect->TargetA.GetTarget() == TARGET_DEST_DB || effect->TargetB.GetTarget() == TARGET_DEST_DB)
- {
- std::pair<uint32, SpellEffIndex> key = std::make_pair(Spell_ID, effIndex);
+ std::pair<uint32, SpellEffIndex> key = std::make_pair(spellId, effIndex);
mSpellTargetPositions[key] = st;
++count;
}
else
{
- TC_LOG_ERROR("sql.sql", "Spell (Id: %u, effIndex: %u) listed in `spell_target_position` does not have target TARGET_DEST_DB (17).", Spell_ID, effIndex);
+ TC_LOG_ERROR("sql.sql", "Spell (Id: %u, EffectIndex: %u) listed in `spell_target_position` does not have target TARGET_DEST_DB (17).", spellId, effIndex);
continue;
}
@@ -1776,38 +1706,26 @@ void SpellMgr::LoadSpellTargetPositions()
/*
// Check all spells
- for (uint32 i = 1; i < GetSpellInfoStoreSize; ++i)
+ for (uint32 i = 1; i < GetSpellInfoStoreSize(); ++i)
{
SpellInfo const* spellInfo = GetSpellInfo(i);
if (!spellInfo)
continue;
- bool found = false;
- for (int j = 0; j < MAX_SPELL_EFFECTS; ++j)
+ for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
{
- switch (spellInfo->Effects[j].TargetA)
- {
- case TARGET_DEST_DB:
- found = true;
- break;
- }
- if (found)
- break;
- switch (spellInfo->Effects[j].TargetB)
- {
- case TARGET_DEST_DB:
- found = true;
- break;
- }
- if (found)
- break;
- }
- if (found)
- {
- if (!sSpellMgr->GetSpellTargetPosition(i))
- TC_LOG_DEBUG("spells", "Spell (ID: %u) does not have record in `spell_target_position`", i);
+ SpellEffectInfo const* effect = spellInfo->GetEffect(j);
+ if (!effect)
+ continue;
+
+ if (effect->TargetA.GetTarget() != TARGET_DEST_DB && effect->TargetB.GetTarget() != TARGET_DEST_DB)
+ continue;
+
+ if (!GetSpellTargetPosition(i, SpellEffIndex(j)))
+ TC_LOG_DEBUG("spells", "Spell (Id: %u, EffectIndex: %u) does not have record in `spell_target_position`.", i, j);
}
- }*/
+ }
+ */
TC_LOG_INFO("server.loading", ">> Loaded %u spell teleport coordinates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
@@ -2891,6 +2809,11 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
TC_LOG_INFO("server.loading", ">> Loaded %u spell custom attributes from DB in %u ms", count, GetMSTimeDiffToNow(oldMSTime2));
}
+ std::set<uint32> talentSpells;
+ for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
+ if (TalentEntry const* talentInfo = sTalentStore.LookupEntry(i))
+ talentSpells.insert(talentInfo->SpellID);
+
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
{
spellInfo = mSpellInfoMap[i];
@@ -3004,6 +2927,9 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
if (spellInfo->SpellVisual[0] == 3879)
spellInfo->AttributesCu |= SPELL_ATTR0_CU_CONE_BACK;
+ if (talentSpells.count(spellInfo->Id))
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_IS_TALENT;
+
switch (spellInfo->SpellFamilyName)
{
case SPELLFAMILY_WARRIOR:
@@ -3761,7 +3687,7 @@ void SpellMgr::LoadSpellInfoCorrections()
case 45440: // Steam Tonk Controller
case 60256: // Collect Sample
// Crashes client on pressing ESC
- spellInfo->AttributesEx4 &= ~SPELL_ATTR4_TRIGGERED;
+ spellInfo->AttributesEx4 &= ~SPELL_ATTR4_CAN_CAST_WHILE_CASTING;
break;
case 96942: // Gaze of Occu'thar
case 101009: // Gaze of Occu'thar
diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h
index 74423f6e4f3..36ffe105c54 100644
--- a/src/server/game/Spells/SpellMgr.h
+++ b/src/server/game/Spells/SpellMgr.h
@@ -695,7 +695,6 @@ class SpellMgr
// Loading data at server startup
void UnloadSpellInfoChains();
- void LoadSpellTalentRanks();
void LoadSpellRanks();
void LoadSpellRequired();
void LoadSpellLearnSkills();
diff --git a/src/server/game/Tools/CharacterDatabaseCleaner.cpp b/src/server/game/Tools/CharacterDatabaseCleaner.cpp
index bd1d1897d5b..e065439b5ab 100644
--- a/src/server/game/Tools/CharacterDatabaseCleaner.cpp
+++ b/src/server/game/Tools/CharacterDatabaseCleaner.cpp
@@ -22,6 +22,7 @@
#include "World.h"
#include "Database/DatabaseEnv.h"
#include "SpellMgr.h"
+#include "SpellInfo.h"
#include "DBCStores.h"
void CharacterDatabaseCleaner::CleanDatabase()
@@ -128,7 +129,8 @@ void CharacterDatabaseCleaner::CleanCharacterSkills()
bool CharacterDatabaseCleaner::SpellCheck(uint32 spell_id)
{
- return sSpellMgr->GetSpellInfo(spell_id) && GetTalentBySpellID(spell_id) != nullptr;
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id);
+ return spellInfo && !spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT);
}
void CharacterDatabaseCleaner::CleanCharacterSpell()
diff --git a/src/server/game/Weather/Weather.cpp b/src/server/game/Weather/Weather.cpp
index 9ad77761123..ecceb0b102f 100644
--- a/src/server/game/Weather/Weather.cpp
+++ b/src/server/game/Weather/Weather.cpp
@@ -30,6 +30,7 @@
#include "ScriptMgr.h"
#include "Opcodes.h"
#include "WorldSession.h"
+#include "MiscPackets.h"
/// Create the Weather object
Weather::Weather(uint32 zone, WeatherData const* weatherChances)
@@ -194,9 +195,8 @@ bool Weather::ReGenerate()
void Weather::SendWeatherUpdateToPlayer(Player* player)
{
- WorldPacket data(SMSG_WEATHER, (4+4+4));
- data << uint32(GetWeatherState()) << (float)m_grade << uint8(0);
- player->GetSession()->SendPacket(&data);
+ WorldPackets::Misc::Weather weather(GetWeatherState(), m_grade);
+ player->GetSession()->SendPacket(weather.Write());
}
/// Send the new weather to all players in the zone
@@ -210,13 +210,10 @@ bool Weather::UpdateWeather()
WeatherState state = GetWeatherState();
- WorldPacket data(SMSG_WEATHER, (4+4+4));
- data << uint32(state);
- data << (float)m_grade;
- data << uint8(0);
+ WorldPackets::Misc::Weather weather(state, m_grade);
//- Returns false if there were no players found to update
- if (!sWorld->SendZoneMessage(m_zone, &data))
+ if (!sWorld->SendZoneMessage(m_zone, weather.Write()))
return false;
///- Log the event
diff --git a/src/server/game/Weather/Weather.h b/src/server/game/Weather/Weather.h
index 04d38b19c73..93a5ecd448f 100644
--- a/src/server/game/Weather/Weather.h
+++ b/src/server/game/Weather/Weather.h
@@ -43,7 +43,7 @@ struct WeatherData
uint32 ScriptId;
};
-enum WeatherState
+enum WeatherState : uint32
{
WEATHER_STATE_FINE = 0,
WEATHER_STATE_FOG = 1, // Used in some instance encounters.
diff --git a/src/server/game/Weather/WeatherMgr.cpp b/src/server/game/Weather/WeatherMgr.cpp
index 8f599b8514b..883e622bf50 100644
--- a/src/server/game/Weather/WeatherMgr.cpp
+++ b/src/server/game/Weather/WeatherMgr.cpp
@@ -28,6 +28,7 @@
#include "WorldPacket.h"
#include "Opcodes.h"
#include "WorldSession.h"
+#include "MiscPackets.h"
namespace WeatherMgr
{
@@ -144,9 +145,8 @@ void LoadWeatherData()
void SendFineWeatherUpdateToPlayer(Player* player)
{
- WorldPacket data(SMSG_WEATHER, (4+4+4));
- data << (uint32)WEATHER_STATE_FINE << (float)0.0f << uint8(0);
- player->GetSession()->SendPacket(&data);
+ WorldPackets::Misc::Weather weather(WEATHER_STATE_FINE);
+ player->GetSession()->SendPacket(weather.Write());
}
void Update(uint32 diff)
diff --git a/src/server/scripts/Commands/cs_learn.cpp b/src/server/scripts/Commands/cs_learn.cpp
index e607bd3f082..7a34ba55110 100644
--- a/src/server/scripts/Commands/cs_learn.cpp
+++ b/src/server/scripts/Commands/cs_learn.cpp
@@ -204,7 +204,7 @@ public:
// learn highest rank of talent and learn all non-talent spell ranks (recursive by tree)
player->LearnSpellHighestRank(talentInfo->SpellID);
- player->AddTalent(talentInfo->SpellID, player->GetActiveTalentGroup(), true);
+ player->AddTalent(talentInfo, player->GetActiveTalentGroup(), true);
}
handler->SendSysMessage(LANG_COMMAND_LEARN_CLASS_TALENTS);
diff --git a/src/server/scripts/Commands/cs_list.cpp b/src/server/scripts/Commands/cs_list.cpp
index c06dba9dc4e..0ee987aadf6 100644
--- a/src/server/scripts/Commands/cs_list.cpp
+++ b/src/server/scripts/Commands/cs_list.cpp
@@ -435,11 +435,11 @@ public:
handler->PSendSysMessage(LANG_COMMAND_TARGET_LISTAURAS, auras.size());
for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
- bool talent = (GetTalentBySpellID(itr->second->GetBase()->GetId()) != nullptr);
AuraApplication const* aurApp = itr->second;
Aura const* aura = aurApp->GetBase();
char const* name = aura->GetSpellInfo()->SpellName;
+ bool talent = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR0_CU_IS_TALENT);
std::ostringstream ss_name;
ss_name << "|cffffffff|Hspell:" << aura->GetId() << "|h[" << name << "]|h|r";
diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp
index 626a0cbb086..41bd04c5dca 100644
--- a/src/server/scripts/Commands/cs_lookup.cpp
+++ b/src/server/scripts/Commands/cs_lookup.cpp
@@ -814,7 +814,7 @@ public:
SpellInfo const* learnSpellInfo = effect ? sSpellMgr->GetSpellInfo(effect->TriggerSpell) : NULL;
- bool talent = (GetTalentBySpellID(id) != nullptr);
+ bool talent = spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT);
bool passive = spellInfo->IsPassive();
bool active = target && target->HasAura(id);
@@ -886,7 +886,7 @@ public:
SpellInfo const* learnSpellInfo = effect ? sSpellMgr->GetSpellInfo(effect->TriggerSpell) : NULL;
- bool talent = (GetTalentBySpellID(id) != nullptr);
+ bool talent = spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT);
bool passive = spellInfo->IsPassive();
bool active = target && target->HasAura(id);
diff --git a/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp b/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp
index 2f10aa858f9..7550faeaec1 100644
--- a/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp
+++ b/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp
@@ -177,7 +177,7 @@ public:
if (creature->IsQuestGiver())
player->PrepareQuestMenu(creature->GetGUID());
- if (player->GetQuestStatus(5742) == QUEST_STATUS_INCOMPLETE && player->getStandState() == UNIT_STAND_STATE_SIT)
+ if (player->GetQuestStatus(5742) == QUEST_STATUS_INCOMPLETE && player->GetStandState() == UNIT_STAND_STATE_SIT)
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID());
diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp
index 463d1ee7e0b..3e9852ae909 100644
--- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp
+++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp
@@ -22,6 +22,7 @@
#include "SpellInfo.h"
#include "WorldPacket.h"
#include "Opcodes.h"
+#include "Packets/MiscPackets.h"
enum Texts
{
@@ -146,9 +147,8 @@ class boss_ossirian : public CreatureScript
if (!map->IsDungeon())
return;
- WorldPacket data(SMSG_WEATHER, (4+4+4));
- data << uint32(WEATHER_STATE_HEAVY_SANDSTORM) << float(1) << uint8(0);
- map->SendToPlayers(&data);
+ WorldPackets::Misc::Weather weather(WEATHER_STATE_HEAVY_SANDSTORM, 1.0f);
+ map->SendToPlayers(weather.Write());
for (uint8 i = 0; i < NUM_TORNADOS; ++i)
{
diff --git a/src/server/scripts/Kalimdor/zone_the_barrens.cpp b/src/server/scripts/Kalimdor/zone_the_barrens.cpp
index 4268cafa1ea..232261df951 100644
--- a/src/server/scripts/Kalimdor/zone_the_barrens.cpp
+++ b/src/server/scripts/Kalimdor/zone_the_barrens.cpp
@@ -547,7 +547,7 @@ public:
{
if (!HasEscortState(STATE_ESCORT_ESCORTING))
{
- if (me->getStandState() == UNIT_STAND_STATE_DEAD)
+ if (me->GetStandState() == UNIT_STAND_STATE_DEAD)
me->SetStandState(UNIT_STAND_STATE_STAND);
IsPostEvent = false;
diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp
index d15b8a53a9a..6a76d4c688e 100644
--- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp
@@ -21,6 +21,7 @@
#include "SpellScript.h"
#include "Transport.h"
#include "Player.h"
+#include "MoveSplineInit.h"
#include "halls_of_reflection.h"
enum Text
@@ -342,6 +343,20 @@ class npc_jaina_or_sylvanas_intro_hor : public CreatureScript
public:
npc_jaina_or_sylvanas_intro_hor() : CreatureScript("npc_jaina_or_sylvanas_intro_hor") { }
+ bool OnGossipHello(Player* player, Creature* creature) override
+ {
+ // override default gossip
+ if (InstanceScript* instance = creature->GetInstanceScript())
+ if (instance->GetData(DATA_QUEL_DELAR_EVENT) == IN_PROGRESS || instance->GetData(DATA_QUEL_DELAR_EVENT) == SPECIAL)
+ {
+ player->PlayerTalkClass->ClearMenus();
+ return true;
+ }
+
+ // load default gossip
+ return false;
+ }
+
struct npc_jaina_or_sylvanas_intro_horAI : public ScriptedAI
{
npc_jaina_or_sylvanas_intro_horAI(Creature* creature) : ScriptedAI(creature)
@@ -1998,6 +2013,13 @@ class at_hor_intro_start : public AreaTriggerScript
if (_instance->GetData(DATA_INTRO_EVENT) == NOT_STARTED)
_instance->SetData(DATA_INTRO_EVENT, IN_PROGRESS);
+ if (player->HasAura(SPELL_QUEL_DELAR_COMPULSION) && (player->GetQuestStatus(QUEST_HALLS_OF_REFLECTION_ALLIANCE) == QUEST_STATUS_INCOMPLETE ||
+ player->GetQuestStatus(QUEST_HALLS_OF_REFLECTION_HORDE) == QUEST_STATUS_INCOMPLETE) && _instance->GetData(DATA_QUEL_DELAR_EVENT) == NOT_STARTED)
+ {
+ _instance->SetData(DATA_QUEL_DELAR_EVENT, IN_PROGRESS);
+ _instance->SetGuidData(DATA_QUEL_DELAR_INVOKER, player->GetGUID());
+ }
+
return true;
}
};
@@ -2330,6 +2352,395 @@ class npc_lumbering_abomination : public CreatureScript
}
};
+enum QuelDelarUther
+{
+ ACTION_UTHER_START_SCREAM = 1,
+ ACTION_UTHER_OUTRO = 2,
+
+ EVENT_UTHER_1 = 1,
+ EVENT_UTHER_2 = 2,
+ EVENT_UTHER_3 = 3,
+ EVENT_UTHER_4 = 4,
+ EVENT_UTHER_5 = 5,
+ EVENT_UTHER_6 = 6,
+ EVENT_UTHER_7 = 7,
+ EVENT_UTHER_8 = 8,
+ EVENT_UTHER_9 = 9,
+ EVENT_UTHER_10 = 10,
+ EVENT_UTHER_11 = 11,
+ EVENT_UTHER_FACING = 12,
+ EVENT_UTHER_KNEEL = 13,
+
+ SAY_UTHER_QUEL_DELAR_1 = 16,
+ SAY_UTHER_QUEL_DELAR_2 = 17,
+ SAY_UTHER_QUEL_DELAR_3 = 18,
+ SAY_UTHER_QUEL_DELAR_4 = 19,
+ SAY_UTHER_QUEL_DELAR_5 = 20,
+ SAY_UTHER_QUEL_DELAR_6 = 21,
+
+ SPELL_ESSENCE_OF_CAPTURED_1 = 73036
+};
+
+enum QuelDelarSword
+{
+ SPELL_WHIRLWIND_VISUAL = 70300,
+ SPELL_HEROIC_STRIKE = 29426,
+ SPELL_WHIRLWIND = 67716,
+ SPELL_BLADESTORM = 67541,
+
+ NPC_QUEL_DELAR = 37158,
+ POINT_TAKE_OFF = 1,
+
+ EVENT_QUEL_DELAR_INIT = 1,
+ EVENT_QUEL_DELAR_FLIGHT_INIT = 2,
+ EVENT_QUEL_DELAR_FLIGHT = 3,
+ EVENT_QUEL_DELAR_LAND = 4,
+ EVENT_QUEL_DELAR_FIGHT = 5,
+ EVENT_QUEL_DELAR_BLADESTORM = 6,
+ EVENT_QUEL_DELAR_HEROIC_STRIKE = 7,
+ EVENT_QUEL_DELAR_WHIRLWIND = 8,
+
+ SAY_QUEL_DELAR_SWORD = 0
+};
+
+enum QuelDelarMisc
+{
+ SAY_FROSTMOURNE_BUNNY = 0,
+ SPELL_QUEL_DELAR_WILL = 70698
+};
+
+Position const QuelDelarCenterPos = { 5309.259f, 2006.390f, 718.046f, 0.0f };
+Position const QuelDelarSummonPos = { 5298.473f, 1994.852f, 709.424f, 3.979351f };
+Position const QuelDelarMovement[] =
+{
+ { 5292.870f, 1998.950f, 718.046f, 0.0f },
+ { 5295.819f, 1991.912f, 707.707f, 0.0f },
+ { 5295.301f, 1989.782f, 708.696f, 0.0f }
+};
+
+Position const UtherQuelDelarMovement[] =
+{
+ { 5336.830f, 1981.700f, 709.319f, 0.0f },
+ { 5314.350f, 1993.440f, 707.726f, 0.0f }
+};
+
+class npc_uther_quel_delar : public CreatureScript
+{
+ public:
+ npc_uther_quel_delar() : CreatureScript("npc_uther_quel_delar") { }
+
+ struct npc_uther_quel_delarAI : public ScriptedAI
+ {
+ npc_uther_quel_delarAI(Creature* creature) : ScriptedAI(creature)
+ {
+ _instance = me->GetInstanceScript();
+ }
+
+ void Reset() override
+ {
+ // Prevent to break Uther in intro event during instance encounter
+ if (_instance->GetData(DATA_QUEL_DELAR_EVENT) != IN_PROGRESS && _instance->GetData(DATA_QUEL_DELAR_EVENT) != SPECIAL)
+ return;
+
+ _events.Reset();
+ _events.ScheduleEvent(EVENT_UTHER_1, 1);
+ }
+
+ void DamageTaken(Unit* /*attacker*/, uint32& damage) override
+ {
+ if (damage >= me->GetHealth())
+ damage = me->GetHealth() - 1;
+ }
+
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_UTHER_START_SCREAM:
+ _instance->SetData(DATA_QUEL_DELAR_EVENT, SPECIAL);
+ _events.ScheduleEvent(EVENT_UTHER_2, 0);
+ break;
+ case ACTION_UTHER_OUTRO:
+ _events.ScheduleEvent(EVENT_UTHER_6, 0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void MovementInform(uint32 /*type*/, uint32 pointId) override
+ {
+ switch (pointId)
+ {
+ case 1:
+ _events.ScheduleEvent(EVENT_UTHER_FACING, 1000);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ // Prevent to break Uther in intro event during instance encounter
+ if (_instance->GetData(DATA_QUEL_DELAR_EVENT) != IN_PROGRESS && _instance->GetData(DATA_QUEL_DELAR_EVENT) != SPECIAL)
+ return;
+
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_UTHER_1:
+ Talk(SAY_UTHER_QUEL_DELAR_1);
+ break;
+ case EVENT_UTHER_2:
+ if (Creature* bunny = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_FROSTMOURNE_ALTAR_BUNNY)))
+ if (Unit* target = ObjectAccessor::GetPlayer(*me, _instance->GetGuidData(DATA_QUEL_DELAR_INVOKER)))
+ bunny->CastSpell(target, SPELL_QUEL_DELAR_WILL, true);
+ _events.ScheduleEvent(EVENT_UTHER_3, 2000);
+ break;
+ case EVENT_UTHER_3:
+ me->SummonCreature(NPC_QUEL_DELAR, QuelDelarSummonPos);
+ _events.ScheduleEvent(EVENT_UTHER_4, 2000);
+ break;
+ case EVENT_UTHER_4:
+ Talk(SAY_UTHER_QUEL_DELAR_2);
+ _events.ScheduleEvent(EVENT_UTHER_5, 8000);
+ break;
+ case EVENT_UTHER_5:
+ me->GetMotionMaster()->MovePoint(1, UtherQuelDelarMovement[0]);
+ break;
+ case EVENT_UTHER_6:
+ me->SetWalk(true);
+ me->GetMotionMaster()->MovePoint(0, UtherQuelDelarMovement[1]);
+ _events.ScheduleEvent(EVENT_UTHER_7, 5000);
+ break;
+ case EVENT_UTHER_7:
+ Talk(SAY_UTHER_QUEL_DELAR_3);
+ _events.ScheduleEvent(EVENT_UTHER_8, 12000);
+ break;
+ case EVENT_UTHER_8:
+ Talk(SAY_UTHER_QUEL_DELAR_4);
+ _events.ScheduleEvent(EVENT_UTHER_9, 7000);
+ break;
+ case EVENT_UTHER_9:
+ Talk(SAY_UTHER_QUEL_DELAR_5);
+ _events.ScheduleEvent(EVENT_UTHER_10, 10000);
+ break;
+ case EVENT_UTHER_10:
+ Talk(SAY_UTHER_QUEL_DELAR_6);
+ _events.ScheduleEvent(EVENT_UTHER_11, 5000);
+ break;
+ case EVENT_UTHER_11:
+ DoCast(me, SPELL_ESSENCE_OF_CAPTURED_1, true);
+ me->DespawnOrUnsummon(3000);
+ _instance->SetData(DATA_QUEL_DELAR_EVENT, DONE);
+ break;
+ case EVENT_UTHER_FACING:
+ if (Creature* bunny = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_FROSTMOURNE_ALTAR_BUNNY)))
+ me->SetFacingToObject(bunny);
+ _events.ScheduleEvent(EVENT_UTHER_KNEEL, 1000);
+ break;
+ case EVENT_UTHER_KNEEL:
+ me->HandleEmoteCommand(EMOTE_STATE_KNEEL);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private:
+ EventMap _events;
+ InstanceScript* _instance;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetHallsOfReflectionAI<npc_uther_quel_delarAI>(creature);
+ }
+};
+
+class npc_quel_delar_sword : public CreatureScript
+{
+ public:
+ npc_quel_delar_sword() : CreatureScript("npc_quel_delar_sword") { }
+
+ struct npc_quel_delar_swordAI : public ScriptedAI
+ {
+ npc_quel_delar_swordAI(Creature* creature) : ScriptedAI(creature)
+ {
+ _instance = me->GetInstanceScript();
+ me->SetDisplayId(me->GetCreatureTemplate()->Modelid2);
+ _intro = true;
+ }
+
+ void Reset() override
+ {
+ _events.Reset();
+ me->SetSpeed(MOVE_FLIGHT, 4.5f, true);
+ DoCast(SPELL_WHIRLWIND_VISUAL);
+ if (_intro)
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_INIT, 0);
+ else
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
+ }
+
+ void EnterCombat(Unit* /*victim*/) override
+ {
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_HEROIC_STRIKE, 4000);
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_BLADESTORM, 6000);
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_WHIRLWIND, 6000);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (Creature* uther = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_UTHER_QUEL_DELAR)))
+ uther->AI()->DoAction(ACTION_UTHER_OUTRO);
+ }
+
+ void MovementInform(uint32 type, uint32 pointId) override
+ {
+ if (type != EFFECT_MOTION_TYPE)
+ return;
+
+ switch (pointId)
+ {
+ case POINT_TAKE_OFF:
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_FLIGHT, 0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ if (!UpdateVictim())
+ {
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_QUEL_DELAR_INIT:
+ if (Creature* bunny = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_FROSTMOURNE_ALTAR_BUNNY)))
+ bunny->AI()->Talk(SAY_FROSTMOURNE_BUNNY);
+ _intro = false;
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_FLIGHT_INIT, 2500);
+ break;
+ case EVENT_QUEL_DELAR_FLIGHT_INIT:
+ me->GetMotionMaster()->MoveTakeoff(POINT_TAKE_OFF, QuelDelarMovement[0]);
+ break;
+ case EVENT_QUEL_DELAR_FLIGHT:
+ {
+ Movement::MoveSplineInit init(me);
+ FillCirclePath(QuelDelarCenterPos, 18.0f, 718.046f, init.Path(), true);
+ init.SetFly();
+ init.SetCyclic();
+ init.SetAnimation(Movement::ToFly);
+ init.Launch();
+
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_LAND, 15000);
+ break;
+ }
+ case EVENT_QUEL_DELAR_LAND:
+ me->StopMoving();
+ me->GetMotionMaster()->Clear();
+ me->GetMotionMaster()->MoveLand(0, QuelDelarMovement[1]);
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_FIGHT, 6000);
+ break;
+ case EVENT_QUEL_DELAR_FIGHT:
+ Talk(SAY_QUEL_DELAR_SWORD);
+ me->GetMotionMaster()->MovePoint(0, QuelDelarMovement[2]);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else
+ {
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_QUEL_DELAR_BLADESTORM:
+ DoCast(me, SPELL_BLADESTORM);
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_BLADESTORM, 10000);
+ break;
+ case EVENT_QUEL_DELAR_HEROIC_STRIKE:
+ DoCastVictim(SPELL_HEROIC_STRIKE);
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_HEROIC_STRIKE, 6000);
+ break;
+ case EVENT_QUEL_DELAR_WHIRLWIND:
+ DoCastAOE(SPELL_WHIRLWIND);
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_WHIRLWIND, 1000);
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ }
+
+ private:
+ void FillCirclePath(Position const& centerPos, float radius, float z, Movement::PointsArray& path, bool clockwise)
+ {
+ float step = clockwise ? -M_PI / 8.0f : M_PI / 8.0f;
+ float angle = centerPos.GetAngle(me->GetPositionX(), me->GetPositionY());
+
+ for (uint8 i = 0; i < 16; angle += step, ++i)
+ {
+ G3D::Vector3 point;
+ point.x = centerPos.GetPositionX() + radius * cosf(angle);
+ point.y = centerPos.GetPositionY() + radius * sinf(angle);
+ point.z = z;
+ path.push_back(point);
+ }
+ }
+
+ EventMap _events;
+ InstanceScript* _instance;
+ bool _intro;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetHallsOfReflectionAI<npc_quel_delar_swordAI>(creature);
+ }
+};
+
+// 5660
+class at_hor_uther_quel_delar_start : public AreaTriggerScript
+{
+ public:
+ at_hor_uther_quel_delar_start() : AreaTriggerScript("at_hor_uther_quel_delar_start") { }
+
+ bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override
+ {
+ if (player->IsGameMaster())
+ return true;
+
+ InstanceScript* _instance = player->GetInstanceScript();
+
+ if (_instance->GetData(DATA_QUEL_DELAR_EVENT) == IN_PROGRESS)
+ if (Creature* uther = ObjectAccessor::GetCreature(*player, _instance->GetGuidData(DATA_UTHER_QUEL_DELAR)))
+ uther->AI()->DoAction(ACTION_UTHER_START_SCREAM);
+
+ return true;
+ }
+};
+
// 72900 - Start Halls of Reflection Quest AE
class spell_hor_start_halls_of_reflection_quest_ae : public SpellScriptLoader
{
@@ -2447,6 +2858,7 @@ void AddSC_halls_of_reflection()
new at_hor_waves_restarter();
new at_hor_impenetrable_door();
new at_hor_shadow_throne();
+ new at_hor_uther_quel_delar_start();
new npc_jaina_or_sylvanas_intro_hor();
new npc_jaina_or_sylvanas_escape_hor();
new npc_the_lich_king_escape_hor();
@@ -2461,6 +2873,8 @@ void AddSC_halls_of_reflection()
new npc_raging_ghoul();
new npc_risen_witch_doctor();
new npc_lumbering_abomination();
+ new npc_uther_quel_delar();
+ new npc_quel_delar_sword();
new spell_hor_start_halls_of_reflection_quest_ae();
new spell_hor_evasion();
new spell_hor_gunship_cannon_fire();
diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h
index 9594617fa9a..d2f9ab5d262 100644
--- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h
+++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h
@@ -46,7 +46,13 @@ enum DataTypes
DATA_ESCAPE_LEADER = 10,
DATA_ICEWALL = 11,
DATA_ICEWALL_TARGET = 12,
- DATA_GUNSHIP = 13
+ DATA_GUNSHIP = 13,
+
+ // Quest stuff
+ DATA_QUEL_DELAR_EVENT = 14,
+ DATA_FROSTMOURNE_ALTAR_BUNNY = 15,
+ DATA_UTHER_QUEL_DELAR = 16,
+ DATA_QUEL_DELAR_INVOKER = 17
};
enum CreatureIds
@@ -131,7 +137,8 @@ enum InstanceEvents
EVENT_NEXT_WAVE = 2,
EVENT_DO_WIPE = 3,
EVENT_ADD_WAVE = 4,
- EVENT_SPAWN_ESCAPE_EVENT = 5
+ EVENT_SPAWN_ESCAPE_EVENT = 5,
+ EVENT_QUEL_DELAR_SUMMON_UTHER = 6
};
enum InstanceEventIds
@@ -160,7 +167,17 @@ enum InstanceSpells
// Gunship
SPELL_GUNSHIP_CANNON_FIRE = 70017,
SPELL_GUNSHIP_CANNON_FIRE_MISSILE_ALLIANCE = 70021,
- SPELL_GUNSHIP_CANNON_FIRE_MISSILE_HORDE = 70246
+ SPELL_GUNSHIP_CANNON_FIRE_MISSILE_HORDE = 70246,
+
+ // Halls of Reflection quest
+ SPELL_QUEL_DELAR_COMPULSION = 70013,
+ SPELL_ESSENCE_OF_CAPTURED = 70720
+};
+
+enum InstanceQuests
+{
+ QUEST_HALLS_OF_REFLECTION_ALLIANCE = 24480,
+ QUEST_HALLS_OF_REFLECTION_HORDE = 24561
};
enum InstanceWorldStates
diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
index ae2023fd255..820821e4151 100644
--- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
@@ -73,6 +73,8 @@ Position const SpawnPos[] =
{ 5299.250f, 2035.998f, 707.7781f, 5.026548f }
};
+Position const UtherQuelDalarPos = { 5302.001f, 1988.698f, 707.7781f, 3.700098f };
+
class instance_halls_of_reflection : public InstanceMapScript
{
public:
@@ -89,6 +91,7 @@ class instance_halls_of_reflection : public InstanceMapScript
_waveCount = 0;
_introState = NOT_STARTED;
_frostswornGeneralState = NOT_STARTED;
+ _quelDelarState = NOT_STARTED;
events.Reset();
}
@@ -159,6 +162,9 @@ class instance_halls_of_reflection : public InstanceMapScript
case NPC_ICE_WALL_TARGET:
IcewallTargetGUID = creature->GetGUID();
break;
+ case NPC_UTHER:
+ UtherGUID = creature->GetGUID();
+ break;
default:
break;
}
@@ -439,6 +445,18 @@ class instance_halls_of_reflection : public InstanceMapScript
HandleGameObject(ShadowThroneDoorGUID, true);
_frostswornGeneralState = data;
break;
+ case DATA_QUEL_DELAR_EVENT:
+ if (data == IN_PROGRESS)
+ {
+ if (_quelDelarState == NOT_STARTED)
+ {
+ if (Creature* bunny = instance->GetCreature(FrostmourneAltarBunnyGUID))
+ bunny->CastSpell((Unit*)NULL, SPELL_ESSENCE_OF_CAPTURED);
+ events.ScheduleEvent(EVENT_QUEL_DELAR_SUMMON_UTHER, 2000);
+ }
+ }
+ _quelDelarState = data;
+ break;
default:
break;
}
@@ -446,6 +464,18 @@ class instance_halls_of_reflection : public InstanceMapScript
SaveToDB();
}
+ void SetGuidData(uint32 type, ObjectGuid data) override
+ {
+ switch (type)
+ {
+ case DATA_QUEL_DELAR_INVOKER:
+ QuelDelarInvokerGUID = data;
+ break;
+ default:
+ break;
+ }
+ }
+
// wave scheduling, checked when wave npcs die
void OnUnitDeath(Unit* unit) override
{
@@ -491,6 +521,9 @@ class instance_halls_of_reflection : public InstanceMapScript
case EVENT_SPAWN_ESCAPE_EVENT:
SpawnEscapeEvent();
break;
+ case EVENT_QUEL_DELAR_SUMMON_UTHER:
+ instance->SummonCreature(NPC_UTHER, UtherQuelDalarPos);
+ break;
}
}
@@ -649,6 +682,8 @@ class instance_halls_of_reflection : public InstanceMapScript
return _introState;
case DATA_FROSTSWORN_GENERAL:
return _frostswornGeneralState;
+ case DATA_QUEL_DELAR_EVENT:
+ return _quelDelarState;
default:
break;
}
@@ -682,6 +717,12 @@ class instance_halls_of_reflection : public InstanceMapScript
return IcewallGUID;
case DATA_ICEWALL_TARGET:
return IcewallTargetGUID;
+ case DATA_FROSTMOURNE_ALTAR_BUNNY:
+ return FrostmourneAltarBunnyGUID;
+ case DATA_UTHER_QUEL_DELAR:
+ return UtherGUID;
+ case DATA_QUEL_DELAR_INVOKER:
+ return QuelDelarInvokerGUID;
default:
break;
}
@@ -691,7 +732,7 @@ class instance_halls_of_reflection : public InstanceMapScript
void WriteSaveDataMore(std::ostringstream& data) override
{
- data << _introState << ' ' << _frostswornGeneralState;
+ data << _introState << ' ' << _frostswornGeneralState << ' ' << _quelDelarState;
}
void ReadSaveDataMore(std::istringstream& data) override
@@ -708,6 +749,12 @@ class instance_halls_of_reflection : public InstanceMapScript
SetData(DATA_FROSTSWORN_GENERAL, DONE);
else
SetData(DATA_FROSTSWORN_GENERAL, NOT_STARTED);
+
+ data >> temp;
+ if (temp == DONE)
+ SetData(DATA_QUEL_DELAR_EVENT, DONE);
+ else
+ SetData(DATA_QUEL_DELAR_EVENT, NOT_STARTED);
}
private:
@@ -731,6 +778,7 @@ class instance_halls_of_reflection : public InstanceMapScript
uint32 _waveCount;
uint32 _introState;
uint32 _frostswornGeneralState;
+ uint32 _quelDelarState;
EventMap events;
GuidSet waveGuidList[8];
@@ -740,6 +788,8 @@ class instance_halls_of_reflection : public InstanceMapScript
ObjectGuid CaptainGUID;
ObjectGuid IcewallGUID;
ObjectGuid IcewallTargetGUID;
+ ObjectGuid QuelDelarInvokerGUID;
+ ObjectGuid UtherGUID;
GuidSet GunshipCannonGUIDs;
GuidSet GunshipStairGUIDs;
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp
index 3c068915585..5dcf4854943 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp
@@ -353,9 +353,9 @@ static bool IsEncounterFinished(Unit* who)
if (!mkii || !vx001 || !aerial)
return false;
- if (mkii->getStandState() == UNIT_STAND_STATE_DEAD &&
- vx001->getStandState() == UNIT_STAND_STATE_DEAD &&
- aerial->getStandState() == UNIT_STAND_STATE_DEAD)
+ if (mkii->GetStandState() == UNIT_STAND_STATE_DEAD &&
+ vx001->GetStandState() == UNIT_STAND_STATE_DEAD &&
+ aerial->GetStandState() == UNIT_STAND_STATE_DEAD)
{
who->Kill(mkii);
who->Kill(vx001);
diff --git a/src/server/scripts/Northrend/zone_zuldrak.cpp b/src/server/scripts/Northrend/zone_zuldrak.cpp
index f73930181f0..91c796a6e69 100644
--- a/src/server/scripts/Northrend/zone_zuldrak.cpp
+++ b/src/server/scripts/Northrend/zone_zuldrak.cpp
@@ -313,7 +313,7 @@ public:
{
player->KilledMonsterCredit(gymerDummy->GetEntry(), gymerDummy->GetGUID());
gymerDummy->CastSpell(gymerDummy, SPELL_GYMER_LOCK_EXPLOSION, true);
- gymerDummy->DespawnOrUnsummon();
+ gymerDummy->DespawnOrUnsummon(4 * IN_MILLISECONDS);
}
}
return true;
diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp
index 9aa1981eabb..38ccf33a612 100644
--- a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp
+++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp
@@ -535,7 +535,7 @@ class boss_kaelthas : public CreatureScript
case 2:
Advisor = (ObjectAccessor::GetCreature(*me, m_auiAdvisorGuid[0]));
- if (Advisor && (Advisor->getStandState() == UNIT_STAND_STATE_DEAD))
+ if (Advisor && (Advisor->GetStandState() == UNIT_STAND_STATE_DEAD))
{
Talk(SAY_INTRO_SANGUINAR);
@@ -569,7 +569,7 @@ class boss_kaelthas : public CreatureScript
case 4:
Advisor = (ObjectAccessor::GetCreature(*me, m_auiAdvisorGuid[1]));
- if (Advisor && (Advisor->getStandState() == UNIT_STAND_STATE_DEAD))
+ if (Advisor && (Advisor->GetStandState() == UNIT_STAND_STATE_DEAD))
{
Talk(SAY_INTRO_CAPERNIAN);
@@ -603,7 +603,7 @@ class boss_kaelthas : public CreatureScript
case 6:
Advisor = (ObjectAccessor::GetCreature(*me, m_auiAdvisorGuid[2]));
- if (Advisor && (Advisor->getStandState() == UNIT_STAND_STATE_DEAD))
+ if (Advisor && (Advisor->GetStandState() == UNIT_STAND_STATE_DEAD))
{
Talk(SAY_INTRO_TELONICUS);
@@ -638,7 +638,7 @@ class boss_kaelthas : public CreatureScript
case 8:
Advisor = (ObjectAccessor::GetCreature(*me, m_auiAdvisorGuid[3]));
- if (Advisor && (Advisor->getStandState() == UNIT_STAND_STATE_DEAD))
+ if (Advisor && (Advisor->GetStandState() == UNIT_STAND_STATE_DEAD))
{
Phase = 2;
instance->SetData(DATA_KAELTHASEVENT, 2);
diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp
index 00071c4804e..65b25564401 100644
--- a/src/server/scripts/Spells/spell_dk.cpp
+++ b/src/server/scripts/Spells/spell_dk.cpp
@@ -452,7 +452,7 @@ class spell_dk_death_coil : public SpellScriptLoader
{
SpellInfo const* DCD = sSpellMgr->EnsureSpellInfo(SPELL_DK_DEATH_COIL_DAMAGE);
SpellEffectInfo const* eff = DCD->GetEffect(EFFECT_0);
- int32 bp = caster->SpellDamageBonusDone(target, DCD, eff->CalcValue(caster), DIRECT_DAMAGE, eff);
+ int32 bp = caster->SpellDamageBonusDone(target, DCD, eff->CalcValue(caster), SPELL_DIRECT_DAMAGE, eff);
caster->CastCustomSpell(target, SPELL_DK_DEATH_COIL_BARRIER, &bp, nullptr, nullptr, true);
}
@@ -658,11 +658,7 @@ class spell_dk_festering_strike : public SpellScriptLoader
{
PrepareSpellScript(spell_dk_festering_strike_SpellScript);
- public:
- spell_dk_festering_strike_SpellScript() { }
-
- private:
- bool Validate(SpellInfo const* spellInfo) override
+ bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_DK_FROST_FEVER) || !sSpellMgr->GetSpellInfo(SPELL_DK_BLOOD_PLAGUE) || !sSpellMgr->GetSpellInfo(SPELL_DK_CHAINS_OF_ICE))
return false;
@@ -671,7 +667,7 @@ class spell_dk_festering_strike : public SpellScriptLoader
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
- int32 extraDuration = GetSpellInfo()->GetEffect(EFFECT_2)->CalcValue();
+ int32 extraDuration = GetEffectValue();
Unit* target = GetHitUnit();
ObjectGuid casterGUID = GetCaster()->GetGUID();
@@ -726,6 +722,11 @@ class spell_dk_ghoul_explode : public SpellScriptLoader
return true;
}
+ void HandleDamage(SpellEffIndex /*effIndex*/)
+ {
+ SetHitDamage(GetCaster()->CountPctFromMaxHealth(GetEffectInfo(EFFECT_2)->CalcValue(GetCaster())));
+ }
+
void Suicide(SpellEffIndex /*effIndex*/)
{
if (Unit* unitTarget = GetHitUnit())
@@ -737,6 +738,7 @@ class spell_dk_ghoul_explode : public SpellScriptLoader
void Register() override
{
+ OnEffectHitTarget += SpellEffectFn(spell_dk_ghoul_explode_SpellScript::HandleDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
OnEffectHitTarget += SpellEffectFn(spell_dk_ghoul_explode_SpellScript::Suicide, EFFECT_1, SPELL_EFFECT_SCHOOL_DAMAGE);
}
};
@@ -760,7 +762,8 @@ class spell_dk_glyph_of_deaths_embrace : public SpellScriptLoader
bool CheckProc(ProcEventInfo& eventInfo)
{
- return (GetTarget()->GetCreatureType() == CREATURE_TYPE_UNDEAD && GetTarget()->GetOwner());
+ Unit* actionTarget = eventInfo.GetActionTarget();
+ return actionTarget && actionTarget->GetCreatureType() == CREATURE_TYPE_UNDEAD && actionTarget->GetOwner();
}
void Register() override
@@ -793,6 +796,11 @@ class spell_dk_glyph_of_runic_power : public SpellScriptLoader
return true;
}
+ bool Load() override
+ {
+ return GetUnitOwner()->getClass() == CLASS_DEATH_KNIGHT;
+ }
+
bool CheckProc(ProcEventInfo& eventInfo)
{
return eventInfo.GetSpellInfo() && (eventInfo.GetSpellInfo()->GetAllEffectsMechanicMask() & (1 << MECHANIC_SNARE | 1 << MECHANIC_ROOT | 1 << MECHANIC_FREEZE));
@@ -801,8 +809,7 @@ class spell_dk_glyph_of_runic_power : public SpellScriptLoader
void HandleProc(ProcEventInfo& eventInfo)
{
if (Unit* target = eventInfo.GetProcTarget())
- if (target->getClass() == CLASS_DEATH_KNIGHT)
- target->CastSpell(target, SPELL_DK_GLYPH_OF_RUNIC_POWER_TRIGGERED, true);
+ target->CastSpell(target, SPELL_DK_GLYPH_OF_RUNIC_POWER_TRIGGERED, true);
}
void Register() override
@@ -945,7 +952,7 @@ class spell_dk_raise_dead : public SpellScriptLoader
void HandleDummy(SpellEffIndex /*effIndex*/)
{
- GetCaster()->CastSpell(((Unit*)nullptr), GetSpellInfo()->GetEffect(EFFECT_0)->CalcValue(), true);
+ GetCaster()->CastSpell(((Unit*)nullptr), GetEffectValue(), true);
}
void Register() override
@@ -1075,19 +1082,23 @@ class spell_dk_will_of_the_necropolis : public SpellScriptLoader
{
PrepareAuraScript(spell_dk_will_of_the_necropolis_AuraScript);
- bool Validate(SpellInfo const* /*spellInfo*/) override
+ bool Validate(SpellInfo const* spellInfo) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_DK_WILL_OF_THE_NECROPOLIS))
return false;
+ if (!spellInfo->GetEffect(EFFECT_0))
+ return false;
return true;
}
bool CheckProc(ProcEventInfo& eventInfo)
{
- if (GetTarget()->HasAura(SPELL_DK_WILL_OF_THE_NECROPOLIS))
+ Unit* target = GetTarget();
+
+ if (target->HasAura(SPELL_DK_WILL_OF_THE_NECROPOLIS))
return false;
- return GetTarget()->HealthBelowPctDamaged(30, eventInfo.GetDamageInfo()->GetDamage());
+ return target->HealthBelowPctDamaged(GetSpellInfo()->GetEffect(EFFECT_0)->CalcValue(target), eventInfo.GetDamageInfo()->GetDamage());
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp
index 669fb8838fb..dd002dedee5 100644
--- a/src/server/scripts/Spells/spell_druid.cpp
+++ b/src/server/scripts/Spells/spell_druid.cpp
@@ -164,7 +164,7 @@ class spell_dru_eclipse_energize : public SpellScriptLoader
Player* caster = GetCaster()->ToPlayer();
// No boomy, no deal.
- if (caster->GetActiveTalentSpec() != TALENT_SPEC_DRUID_BALANCE)
+ if (caster->GetSpecId(caster->GetActiveTalentGroup()) != TALENT_SPEC_DRUID_BALANCE)
return;
switch (GetSpellInfo()->Id)
diff --git a/src/server/scripts/Spells/spell_holiday.cpp b/src/server/scripts/Spells/spell_holiday.cpp
index 44dd17e5624..e6e97a9d04a 100644
--- a/src/server/scripts/Spells/spell_holiday.cpp
+++ b/src/server/scripts/Spells/spell_holiday.cpp
@@ -64,7 +64,7 @@ class spell_love_is_in_the_air_romantic_picnic : public SpellScriptLoader
Unit* caster = GetCaster();
// If our player is no longer sit, remove all auras
- if (target->getStandState() != UNIT_STAND_STATE_SIT)
+ if (target->GetStandState() != UNIT_STAND_STATE_SIT)
{
target->RemoveAura(SPELL_ROMANTIC_PICNIC_ACHIEV);
target->RemoveAura(GetAura());
@@ -83,7 +83,7 @@ class spell_love_is_in_the_air_romantic_picnic : public SpellScriptLoader
target->VisitNearbyWorldObject(INTERACTION_DISTANCE*2, searcher);
for (std::list<Player*>::const_iterator itr = playerList.begin(); itr != playerList.end(); ++itr)
{
- if ((*itr) != target && (*itr)->HasAura(GetId())) // && (*itr)->getStandState() == UNIT_STAND_STATE_SIT)
+ if ((*itr) != target && (*itr)->HasAura(GetId())) // && (*itr)->GetStandState() == UNIT_STAND_STATE_SIT)
{
if (caster)
{
diff --git a/src/server/shared/Debugging/Errors.h b/src/server/shared/Debugging/Errors.h
index df770c2aa47..4d4624b63dd 100644
--- a/src/server/shared/Debugging/Errors.h
+++ b/src/server/shared/Debugging/Errors.h
@@ -49,4 +49,10 @@ namespace Trinity
#define ASSERT WPAssert
+template <typename T> inline T* ASSERT_NOTNULL(T* pointer)
+{
+ ASSERT(pointer);
+ return pointer;
+}
+
#endif