diff options
124 files changed, 4192 insertions, 1297 deletions
diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index e5ba6356da9..24e15893461 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -215,7 +215,7 @@ CREATE TABLE `realmlist` ( LOCK TABLES `realmlist` WRITE; /*!40000 ALTER TABLE `realmlist` DISABLE KEYS */; -INSERT INTO `realmlist` VALUES (1,'Trinity','127.0.0.1',8085,1,0,1,0,0,12340); +INSERT INTO `realmlist` VALUES (1,'Trinity','127.0.0.1','127.0.0.1','255.255.255.0',8085,1,0,1,0,0,12340); /*!40000 ALTER TABLE `realmlist` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/auth/2013_02_04_00_auth_misc.sql b/sql/updates/auth/2013_02_04_00_auth_misc.sql new file mode 100644 index 00000000000..815df637be0 --- /dev/null +++ b/sql/updates/auth/2013_02_04_00_auth_misc.sql @@ -0,0 +1,176 @@ +-- Delete bad data from the DB before adding foreign keys +DELETE FROM `account_access` WHERE `id` NOT IN (SELECT `id` FROM `account`); + +-- Need them first in case of re-execute due to foreign keys +DROP TABLE IF EXISTS `rbac_account_permissions`; +DROP TABLE IF EXISTS `rbac_account_roles`; +DROP TABLE IF EXISTS `rbac_account_groups`; +DROP TABLE IF EXISTS `rbac_role_permissions`; +DROP TABLE IF EXISTS `rbac_group_roles`; +DROP TABLE IF EXISTS `rbac_security_level_groups`; +DROP TABLE IF EXISTS `rbac_permissions`; +DROP TABLE IF EXISTS `rbac_roles`; +DROP TABLE IF EXISTS `rbac_groups`; + +CREATE TABLE IF NOT EXISTS `rbac_groups` ( + `id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Group id', + `name` varchar(50) NOT NULL COMMENT 'Group name', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Group List'; + +CREATE TABLE IF NOT EXISTS `rbac_roles` ( + `id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Role id', + `name` varchar(50) NOT NULL COMMENT 'Role name', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Roles List'; + +CREATE TABLE IF NOT EXISTS `rbac_permissions` ( + `id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Permission id', + `name` varchar(100) NOT NULL COMMENT 'Permission name', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Permission List'; + +CREATE TABLE IF NOT EXISTS `rbac_group_roles` ( + `groupId` int(10) unsigned NOT NULL COMMENT 'group id', + `roleId` int(10) unsigned NOT NULL COMMENT 'Role id', + PRIMARY KEY (`groupId`, `roleId`), + CONSTRAINT `fk__rbac_group_roles__rbac_roles` + FOREIGN KEY (`roleId`) REFERENCES `rbac_roles`(`id`) + ON DELETE CASCADE ON UPDATE RESTRICT, + CONSTRAINT `fk__rbac_group_roles__rbac_groups` + FOREIGN KEY (`groupId`) REFERENCES `rbac_groups`(`id`) + ON DELETE CASCADE ON UPDATE RESTRICT +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Group Role relation'; + +CREATE TABLE IF NOT EXISTS `rbac_role_permissions` ( + `roleId` int(10) unsigned NOT NULL COMMENT 'Role id', + `permissionId` int(10) unsigned NOT NULL COMMENT 'Permission id', + PRIMARY KEY (`roleId`, `permissionId`), + CONSTRAINT `fk__role_permissions__rbac_roles` + FOREIGN KEY (`roleId`) REFERENCES `rbac_roles`(`id`) + ON DELETE CASCADE ON UPDATE RESTRICT, + CONSTRAINT `fk__role_permissions__rbac_permissions` + FOREIGN KEY (`permissionId`) REFERENCES `rbac_permissions`(`id`) + ON DELETE CASCADE ON UPDATE RESTRICT +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Role Permission relation'; + +CREATE TABLE IF NOT EXISTS `rbac_security_level_groups` ( + `secId` int(10) unsigned NOT NULL COMMENT 'Security Level id', + `groupId` int(10) unsigned NOT NULL COMMENT 'group id', + PRIMARY KEY (`secId`, `groupId`), + CONSTRAINT `fk__rbac_security_level_groups__rbac_groups` + FOREIGN KEY (`groupId`) REFERENCES `rbac_groups`(`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Default groups to assign when an account is set gm level'; + +CREATE TABLE IF NOT EXISTS `rbac_account_groups` ( + `accountId` int(10) unsigned NOT NULL COMMENT 'Account id', + `groupId` int(10) unsigned NOT NULL COMMENT 'Group id', + `realmId` int(11) NOT NULL DEFAULT '-1' COMMENT 'Realm Id, -1 means all', + PRIMARY KEY (`accountId`, `groupId`, `realmId`), + CONSTRAINT `fk__rbac_account_groups__account` + FOREIGN KEY (`accountId`) REFERENCES `account`(`id`) + ON DELETE CASCADE ON UPDATE RESTRICT, + CONSTRAINT `fk__rbac_account_groups__rbac_groups` + FOREIGN KEY (`groupId`) REFERENCES `rbac_groups`(`id`) + ON DELETE CASCADE ON UPDATE RESTRICT +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Account-Group relation'; + +CREATE TABLE IF NOT EXISTS `rbac_account_roles` ( + `accountId` int(10) unsigned NOT NULL COMMENT 'Account id', + `roleId` int(10) unsigned NOT NULL COMMENT 'Role id', + `granted` tinyint(1) NOT NULL default 1 COMMENT 'Granted = 1, Denied = 0', + `realmId` int(11) NOT NULL DEFAULT '-1' COMMENT 'Realm Id, -1 means all', + PRIMARY KEY (`accountId`, `roleId`, `realmId`), + CONSTRAINT `fk__rbac_account_roles__account` + FOREIGN KEY (`accountId`) REFERENCES `account`(`id`) + ON DELETE CASCADE ON UPDATE RESTRICT, + CONSTRAINT `fk__rbac_account_roles__rbac_roles` + FOREIGN KEY (`roleId`) REFERENCES `rbac_roles`(`id`) + ON DELETE CASCADE ON UPDATE RESTRICT +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Account-Role relation'; + +CREATE TABLE IF NOT EXISTS `rbac_account_permissions` ( + `accountId` int(10) unsigned NOT NULL COMMENT 'Account id', + `permissionId` int(10) unsigned NOT NULL COMMENT 'Permission id', + `granted` tinyint(1) NOT NULL default 1 COMMENT 'Granted = 1, Denied = 0', + `realmId` int(11) NOT NULL DEFAULT '-1' COMMENT 'Realm Id, -1 means all', + PRIMARY KEY (`accountId`, `permissionId`, `realmId`), + CONSTRAINT `fk__rbac_account_permissions__account` + FOREIGN KEY (`accountId`) REFERENCES `account`(`id`) + ON DELETE CASCADE ON UPDATE RESTRICT, + CONSTRAINT `fk__rbac_account_roles__rbac_permissions` + FOREIGN KEY (`permissionId`) REFERENCES `rbac_permissions`(`id`) + ON DELETE CASCADE ON UPDATE RESTRICT +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Account-Permission relation'; + +DELETE FROM `rbac_permissions` WHERE `id` BETWEEN 1 AND 10; +INSERT INTO `rbac_permissions` (`id`, `name`) VALUES +(1, 'Instant logout'), +(2, 'Skip Queue'), +(3, 'Join Normal Battleground'), +(4, 'Join Random Battleground'), +(5, 'Join Arenas'), +(6, 'Join Dungeon Finder'), +(7, 'Player Commands (Temporal till commands moved to rbac)'), +(8, 'Moderator Commands (Temporal till commands moved to rbac)'), +(9, 'GameMaster Commands (Temporal till commands moved to rbac)'), +(10, 'Administrator Commands (Temporal till commands moved to rbac)'); + +DELETE FROM `rbac_roles` WHERE `id` BETWEEN 1 AND 7; +INSERT INTO `rbac_roles` (`id`, `name`) VALUES +(1, 'Player Commands'), +(2, 'Moderator Commands'), +(3, 'GameMaster Commands'), +(4, 'Administrator Commands'), +(5, 'Quick Login/Logout'), +(6, 'Use Battleground/Arenas'), +(7, 'Use Dungeon Finder'); + +DELETE FROM `rbac_groups` WHERE `id` BETWEEN 1 AND 4; +INSERT INTO `rbac_groups` (`id`, `name`) VALUES +(1, 'Player'), +(2, 'Moderator'), +(3, 'GameMaster'), +(4, 'Administrator'); + +DELETE FROM `rbac_role_permissions` WHERE `roleId` BETWEEN 1 AND 7; +INSERT INTO `rbac_role_permissions` (`roleId`, `permissionId`) VALUES +(5, 1), +(5, 2), +(6, 3), +(6, 4), +(6, 5), +(7, 6), +(1, 7), +(2, 8), +(3, 9), +(4, 10); + +DELETE FROM `rbac_group_roles` WHERE `groupId` BETWEEN 1 AND 4; +INSERT INTO `rbac_group_roles` (`groupId`, `roleId`) VALUES +(1, 1), +(1, 6), +(1, 7), +(2, 2), +(2, 5), +(3, 3), +(4, 4); + +TRUNCATE `rbac_account_groups`; +INSERT INTO `rbac_account_groups` (`accountId`, `groupId`, `realmId`) SELECT `id`, 1, -1 FROM `account`; -- Add Player group to all accounts +INSERT INTO `rbac_account_groups` (`accountId`, `groupId`, `realmId`) SELECT `id`, 2, `RealmID` FROM `account_access` WHERE `gmlevel` > 0; -- Add Moderator group to all Moderator or higher GM level +INSERT INTO `rbac_account_groups` (`accountId`, `groupId`, `realmId`) SELECT `id`, 3, `RealmID` FROM `account_access` WHERE `gmlevel` > 1; -- Add GameMaster group to all GameMasters or higher GM level +INSERT INTO `rbac_account_groups` (`accountId`, `groupId`, `realmId`) SELECT `id`, 4, `RealmID` FROM `account_access` WHERE `gmlevel` > 2; -- Add Administrator group to all Administrators + +TRUNCATE `rbac_security_level_groups`; +INSERT INTO `rbac_security_level_groups` (`secId`, `groupId`) VALUES +(0, 1), +(1, 1), +(1, 2), +(2, 1), +(2, 2), +(2, 3), +(3, 1), +(3, 2), +(3, 3), +(3, 4); diff --git a/sql/updates/world/2013_02_01_00_world_gameobject.sql b/sql/updates/world/2013_02_01_00_world_gameobject.sql new file mode 100644 index 00000000000..2476d623c5a --- /dev/null +++ b/sql/updates/world/2013_02_01_00_world_gameobject.sql @@ -0,0 +1 @@ +DELETE FROM `gameobject` WHERE `id`=180184; diff --git a/sql/updates/world/2013_02_01_01_world_spell_loot_template.sql b/sql/updates/world/2013_02_01_01_world_spell_loot_template.sql new file mode 100644 index 00000000000..0185f464412 --- /dev/null +++ b/sql/updates/world/2013_02_01_01_world_spell_loot_template.sql @@ -0,0 +1,12 @@ +-- loot for Prismatic Black Diamond +DELETE FROM `spell_loot_template` WHERE `entry`=62941; +INSERT INTO `spell_loot_template` (`entry`, `item`, `ChanceOrQuestChance`, `lootmode`, `groupid`, `mincountOrRef`, `maxcount`) VALUES +(62941, 23094, 0, 1, 1, 1, 1), +(62941, 23095, 0, 1, 1, 1, 1), +(62941, 28595, 0, 1, 1, 1, 1), +(62941, 23116, 0, 1, 1, 1, 1), +(62941, 23118, 0, 1, 1, 1, 1), +(62941, 23119, 0, 1, 1, 1, 1), +(62941, 23120, 0, 1, 1, 1, 1), +(62941, 23114, 0, 1, 1, 1, 1), +(62941, 23115, 0, 1, 1, 1, 1); diff --git a/sql/updates/world/2013_02_01_02_world_spell_script_names.sql b/sql/updates/world/2013_02_01_02_world_spell_script_names.sql new file mode 100644 index 00000000000..33b7b1fab6e --- /dev/null +++ b/sql/updates/world/2013_02_01_02_world_spell_script_names.sql @@ -0,0 +1,4 @@ +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_marrowgar_bone_slice'; +INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES +(69055,'spell_marrowgar_bone_slice'), +(70814,'spell_marrowgar_bone_slice'); diff --git a/sql/updates/world/2013_02_01_03_world_wdbverified.sql b/sql/updates/world/2013_02_01_03_world_wdbverified.sql new file mode 100644 index 00000000000..1f47ff75825 --- /dev/null +++ b/sql/updates/world/2013_02_01_03_world_wdbverified.sql @@ -0,0 +1,2 @@ +UPDATE `npc_text` SET `WDBVerified`=1 WHERE `ID` IN (16777215, 31023); +UPDATE `gameobject_template` SET `WDBVerified`=1 WHERE `entry` IN (401003, 300238, 300212, 300209, 300208, 300207, 300204, 300203, 300200, 300199, 300190, 300188, 300187, 300185, 300182, 300175, 300170, 300033); diff --git a/sql/updates/world/2013_02_03_00_world_lfg_entrances.sql b/sql/updates/world/2013_02_03_00_world_lfg_entrances.sql new file mode 100644 index 00000000000..e308c001d29 --- /dev/null +++ b/sql/updates/world/2013_02_03_00_world_lfg_entrances.sql @@ -0,0 +1 @@ +ALTER TABLE `lfg_entrances` CHARACTER SET utf8 COLLATE utf8_general_ci, ENGINE MyISAM; diff --git a/sql/updates/world/2013_02_04_00_world_misc.sql b/sql/updates/world/2013_02_04_00_world_misc.sql new file mode 100644 index 00000000000..ff8021653ab --- /dev/null +++ b/sql/updates/world/2013_02_04_00_world_misc.sql @@ -0,0 +1,60 @@ +-- Something Stinks (A:24655 H:24536) +SET @GUID := 85637; -- set by TDB (need 10)(85637,85638,85639,85640,85641,85642,85643,85644,85645,85646,43498,43502,45075,45099) +SET @EVENT := 8; -- Love is in the Air + +SET @BUNNY := 38288; -- Love Guard Perfume Bunny +SET @GUARD_SW := 68; -- Stormwind City Guard +SET @PATROOLER_SW := 1976; -- Stormwind City Patroller +SET @GUARD_ORG := 3296; -- Orgrimmar Grunt +SET @ELITE_ORG := 14304; -- Kor'kron Elite + +SET @SPELL_PULSE := 71520; -- Heavily Perfumed Pulse +SET @SPELL_BUFF := 71507; -- Heavily Perfumed +SET @SPELL_ANALYSIS := 70192; -- Fragrant Air Analysis + + +DELETE FROM `creature` WHERE `id`=@BUNNY; +INSERT INTO `creature` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`modelid`,`equipment_id`,`position_x`,`position_y`,`position_z`,`orientation`,`spawntimesecs`,`spawndist`,`currentwaypoint`,`curhealth`,`curmana`,`MovementType`,`npcflag`,`unit_flags`,`dynamicflags`) VALUES +(@GUID+0,@BUNNY,0,1,1,0,0,-8825.604,629.3108,94.1137,0,300,0,0,1,0,0,0,0,0), -- sw trade district +(@GUID+1,@BUNNY,0,1,1,0,0,-8988.889,849.4149,105.9425,0,300,0,0,1,0,0,0,0,0), -- sw mage quarter +(@GUID+2,@BUNNY,0,1,1,0,0,-8737.654,1051.887,90.8816,0,300,0,0,1,0,0,0,0,0), -- sw the park +(@GUID+3,@BUNNY,0,1,1,0,0,-8625.038,780.0799,96.73399,0,300,0,0,1,0,0,0,0,0), -- sw cathedral square +(@GUID+4,@BUNNY,0,1,1,0,0,-8433.189,607.2205,95.13025,0,300,0,0,1,0,0,0,0,0), -- sw dwarven district +(@GUID+5,@BUNNY,0,1,1,0,0,-8486.955,390.5139,108.4689,0,300,0,0,1,0,0,0,0,0), -- sw stormwind keep +(@GUID+6,@BUNNY,0,1,1,0,0,-8676.724,444.5052,99.73087,0,300,0,0,1,0,0,0,0,0), -- sw old town +-- +(@GUID+7,@BUNNY,1,1,1,0,0,1573.92,-4397.11,16.00813,0,300,0,0,1,0,0,0,0,0), -- org valley of strength +(@GUID+8,@BUNNY,1,1,1,0,0,1893.24,-4507.31,24.94853,0,300,0,0,1,0,0,0,0,0), -- org the drag +(@GUID+9,@BUNNY,1,1,1,0,0,2015.27,-4687.4,28.61023,0,300,0,0,1,0,0,0,0,0); -- org valley of honor + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=@SPELL_PULSE; +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=17 AND `SourceEntry`=@SPELL_BUFF; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`NegativeCondition`,`ErrorType`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES +(13,1,@SPELL_PULSE,0,0,31,0,3,@GUARD_SW,0,0,0,0,'',"Heavily Perfumed Pulse target Stormwind City Guard"), +(13,1,@SPELL_PULSE,0,1,31,0,3,@PATROOLER_SW,0,0,0,0,'',"Heavily Perfumed Pulse target Stormwind City Patroller"), +(13,1,@SPELL_PULSE,0,2,31,0,3,@GUARD_ORG,0,0,0,0,'',"Heavily Perfumed Pulse target Orgrimmar Grunt"), +(13,1,@SPELL_PULSE,0,3,31,0,3,@ELITE_ORG,0,0,0,0,'',"Heavily Perfumed Pulse target Kor'kron Elite"), +(17,0,@SPELL_BUFF,0,0,1,0,@SPELL_BUFF,0,0,1,0,0,'',"Apply Heavily Perfumed only when missing"); + +UPDATE `creature_template` SET `AIName`='SmartAI',`InhabitType`=4,`flags_extra`=`flags_extra`|128 WHERE `entry`=@BUNNY; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@BUNNY AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@BUNNY,0,0,0,60,0,100,0,0,0,600000,600000,11,@SPELL_PULSE,0,0,0,0,0,1,0,0,0,0,0,0,0,"On update(each 10 min) - Cast - Self"); + +-- ussing this because dummy effect #1 of spell 70192 is to remove the buff +DELETE FROM `spell_linked_spell` WHERE `spell_trigger`=@SPELL_ANALYSIS; +INSERT INTO `spell_linked_spell` (`spell_trigger`,`spell_effect`,`type`,`comment`) VALUES +(@SPELL_ANALYSIS,-@SPELL_BUFF,1,'Remove Heavily Perfumed on Fragrant Air Analysis hit'); + +DELETE FROM `game_event_creature` WHERE `eventEntry`=@EVENT AND `guid` BETWEEN @GUID+0 AND @GUID+9; +INSERT INTO `game_event_creature` (`eventEntry`,`guid`) VALUES +(@EVENT,@GUID+0), +(@EVENT,@GUID+1), +(@EVENT,@GUID+2), +(@EVENT,@GUID+3), +(@EVENT,@GUID+4), +(@EVENT,@GUID+5), +(@EVENT,@GUID+6), +(@EVENT,@GUID+7), +(@EVENT,@GUID+8), +(@EVENT,@GUID+9); diff --git a/sql/updates/world/2013_02_04_01_world_creature_text.sql b/sql/updates/world/2013_02_04_01_world_creature_text.sql new file mode 100644 index 00000000000..c52aa380c49 --- /dev/null +++ b/sql/updates/world/2013_02_04_01_world_creature_text.sql @@ -0,0 +1,165 @@ +-- Ragnaros +UPDATE `creature_text` SET `text`='TOO SOON! YOU HAVE AWAKENED ME TOO SOON, EXECUTUS! WHAT IS THE MEANING OF THIS INTRUSION???' WHERE `entry`=11502 AND `groupid`=1; +UPDATE `creature_text` SET `text`='FOOL! YOU ALLOWED THESE INSECTS TO RUN RAMPANT THROUGH THE HALLOWED CORE? AND NOW YOU LEAD THEM TO MY VERY LAIR? YOU HAVE FAILED ME, EXECUTUS! JUSTICE SHALL BE MET, INDEED!' WHERE `entry`=11502 AND `groupid`=3; +UPDATE `creature_text` SET `text`='NOW FOR YOU, INSECTS! BOLDLY, YOU SOUGHT THE POWER OF RAGNAROS. NOW YOU SHALL SEE IT FIRSTHAND!' WHERE `entry`=11502 AND `groupid`=4; +UPDATE `creature_text` SET `text`='DIE, INSECT!' WHERE `entry`=11502 AND `groupid`=9; + +-- Core Rager +UPDATE `creature_text` SET `text`='%s refuses to die while its master is endangered!' WHERE `entry`=11672 AND `groupid`=0; + +-- Morridune +UPDATE `creature_text` SET `text`='Aku''mai is dead! At last, I can leave this wretched place.' WHERE `entry`=6729 AND `groupid`=0; +UPDATE `creature_text` SET `text`='Speak with me to hear my tale.' WHERE `entry`=6729 AND `groupid`=1; + +-- Amnennar the Coldbringer +UPDATE `creature_text` SET `text`='You''ll never leave this place alive.' WHERE `entry`=7358 AND `groupid`=0; +UPDATE `creature_text` SET `text`='Come, spirits - attend your master!' WHERE `entry`=7358 AND `groupid`=2; +UPDATE `creature_text` SET `text`='Too easy.', `type`=12 WHERE `entry`=7358 AND `groupid`=4; + +-- Weegli Blastfuse +UPDATE `creature_text` SET `text`='Oh no! Here they come!' WHERE `entry`=7607 AND `groupid`=0; +UPDATE `creature_text` SET `text`='Ok, here I go!' WHERE `entry`=7607 AND `groupid`=1; + +-- The Prophet Skeram +UPDATE `creature_text` SET `text`='Are you so eager to die? I will be happy to accommodate you...' WHERE `entry`=15263 AND `groupid`=0 AND `id`=0; +UPDATE `creature_text` SET `text`='You only delay the inevitable!' WHERE `entry`=15263 AND `groupid`=3; + +-- Ossirian the Unscarred +UPDATE `creature_text` SET `text`='Sands of the desert, rise and block out the sun!' WHERE `entry`=15339 AND `groupid`=2; + +-- General Rajaxx +UPDATE `creature_text` SET `text`='Warriors, Captains, continue the fight! ' WHERE `entry`=15341 AND `groupid`=9; +UPDATE `creature_text` SET `text`='Breathe your last!' WHERE `entry`=15341 AND `groupid`=11; + +-- Buru the Gorger +UPDATE `creature_text` SET `text`='%s sets eyes on $n!' WHERE `entry`=15370 AND `groupid`=0; + +-- Spectral Stable Hand +UPDATE `creature_text` SET `type`=12 WHERE `entry`=15551 AND `groupid`=0 AND `id`=0; +UPDATE `creature_text` SET `text`='What will become of--' WHERE `entry`=15551 AND `groupid`=0 AND `id`=1; + +-- Medivh +UPDATE `creature_text` SET `text`='The time has come! Gul''dan, order your warlocks to double their efforts! Moments from now the gateway will open and your Horde will be released upon this ripe, unsuspecting world!' WHERE `entry`=15608 AND `groupid`=0; +UPDATE `creature_text` SET `text`='Champions! My shield grows weak!' WHERE `entry`=15608 AND `groupid`=2; +UPDATE `creature_text` SET `text`='No! Damn this feeble, mortal coil!' WHERE `entry`=15608 AND `groupid`=5; +UPDATE `creature_text` SET `text`='I am grateful for your aid, champions. Now, Gul''dan''s Horde will sweep across this world like a locust swarm, and all my designs, all my carefully-laid plans will at last fall into place.' WHERE `entry`=15608 AND `groupid`=6; +UPDATE `creature_text` SET `text`='Orcs of the Horde! This portal is the gateway to your new destiny! Azeroth lies before you, ripe for the taking!' WHERE `entry`=15608 AND `groupid`=7; + +-- Moroes <Tower Steward> +UPDATE `creature_text` SET `text`='Hm, unannounced visitors. Preparations must be made...' WHERE `entry`=15687 AND `groupid`=0; +UPDATE `creature_text` SET `text`='How terribly clumsy of me.' WHERE `entry`=15687 AND `groupid`=3; + +-- Terestian Illhoof +UPDATE `creature_text` SET `text`='Your blood will anoint my circle!' WHERE `entry`=15688 AND `groupid`=0 AND `id`=0; +UPDATE `creature_text` SET `text`='My life is yours, oh great one...' WHERE `entry`=15688 AND `groupid`=1; +UPDATE `creature_text` SET `text`='Ah, you''re just in time. The rituals are about to begin!' WHERE `entry`=15688 AND `groupid`=2; +UPDATE `creature_text` SET `text`='Please accept this humble offering, oh great one...' WHERE `entry`=15688 AND `groupid`=3 AND `id`=0; +UPDATE `creature_text` SET `text`='Let this sacrifice serve as testament to my fealty.' WHERE `entry`=15688 AND `groupid`=3 AND `id`=1; +UPDATE `creature_text` SET `text`='Come, you dwellers in the dark! Rally to my call!' WHERE `entry`=15688 AND `groupid`=4 AND `id`=0; +UPDATE `creature_text` SET `text`='Gather, my pets... there is plenty for all!' WHERE `entry`=15688 AND `groupid`=4 AND `id`=1; + +-- Prince Malchezaar +UPDATE `creature_text` SET `text`='How can you hope to stand against such overwhelming power?' WHERE `entry`=15690 AND `groupid`=5; +UPDATE `creature_text` SET `text`='I refuse to concede defeat! I am a prince of the Eredar! I... am...' WHERE `entry`=15690 AND `groupid`=8; + +-- The Curator +UPDATE `creature_text` SET `text`='This Curator is equipped for gallery protection.' WHERE `entry`=15691 AND `groupid`=1 AND `id`=1; +UPDATE `creature_text` SET `text`='Curator is no longer operation-a-l.' WHERE `entry`=15691 AND `groupid`=5; + +-- Thaddius +UPDATE `creature_text` SET `text`='You are too late!! I... must... obey!!' WHERE `entry`=15928 AND `groupid`=0; +UPDATE `creature_text` SET `text`='Kill...' WHERE `entry`=15928 AND `groupid`=1 AND `id`=0; +UPDATE `creature_text` SET `text`='Eat... your... bones...' WHERE `entry`=15928 AND `groupid`=1 AND `id`=1; +UPDATE `creature_text` SET `text`='Break... you!!' WHERE `entry`=15928 AND `groupid`=1 AND `id`=2; +UPDATE `creature_text` SET `text`='You... die now!!' WHERE `entry`=15928 AND `groupid`=2; +UPDATE `creature_text` SET `text`='Now you feel pain...' WHERE `entry`=15928 AND `groupid`=3; + +-- Feugen +UPDATE `creature_text` SET `text`='Feugen make master happy.' WHERE `entry`=15930 AND `groupid`=1; + +-- Grand Widow Faerlina +UPDATE `creature_text` SET `text`='Your old lives, your mortal desires mean nothing... you are acolytes of the master now, and you will serve the cause without question! The greatest glory is to die in the master''s service!' WHERE `entry`=15953 AND `groupid`=0; +UPDATE `creature_text` SET `text`='The master will avenge me!!' WHERE `entry`=15953 AND `groupid`=3; + +-- Anub'Rekhan +UPDATE `creature_text` SET `text`='Yes, run! It makes the blood pump faster!' WHERE `entry`=15956 AND `groupid`=0 AND `id`=2; +UPDATE `creature_text` SET `text`='I hear little hearts beating. Yes... beating faster now... soon the beating will stop.' WHERE `entry`=15956 AND `groupid`=1 AND `id`=1; +UPDATE `creature_text` SET `text`='Which one shall I eat first? So difficult to choose. They all smell so delicious...' WHERE `entry`=15956 AND `groupid`=1 AND `id`=3; +UPDATE `creature_text` SET `text`='Closer now. Tasty morsels. I''ve been too long without food, without blood to drink.' WHERE `entry`=15956 AND `groupid`=1 AND `id`=4; +UPDATE `creature_text` SET `text`='Shhh... it will all be over soon.' WHERE `entry`=15956 AND `groupid`=2; + +-- Kel'Thuzad +UPDATE `creature_text` SET `text`='Your forces are nearly marshaled to strike back against your enemies, my liege.' WHERE `entry`=15990 AND `groupid`=0; +UPDATE `creature_text` SET `text`='Yes, master. The time of their ultimate demise draws close.... What is this?' WHERE `entry`=15990 AND `groupid`=2; +UPDATE `creature_text` SET `text`='As you command, master!' WHERE `entry`=15990 AND `groupid`=4; +UPDATE `creature_text` SET `text`='Fools! You think yourselves triumphant? You have only taken one step closer to the abyss!' WHERE `entry`=15990 AND `groupid`=6 AND `id`=1; +UPDATE `creature_text` SET `text`='%s cackles maniacally.', `type`=16 WHERE `entry`=15990 AND `groupid`=8 AND `id`=1; +UPDATE `creature_text` SET `text`='Agghhhh! Do... not... rejoice! Your victory is a hollow one, for I shall return with powers beyond your imagining!' WHERE `entry`=15990 AND `groupid`=9; +UPDATE `creature_text` SET `text`='Your soul is bound to me, now!' WHERE `entry`=15990 AND `groupid`=10 AND `id`=0; +UPDATE `creature_text` SET `text`='Master, I require aid!' WHERE `entry`=15990 AND `groupid`=12; +UPDATE `creature_text` SET `text`='Minions, servants, soldiers of the cold dark! Obey the call of Kel''Thuzad!' WHERE `entry`=15990 AND `groupid`=14; + +-- Patchwerk +UPDATE `creature_text` SET `text`='Kel''thuzad make Patchwerk his avatar of war!' WHERE `entry`=16028 AND `groupid`=0 AND `id`=1; +UPDATE `creature_text` SET `text`='What... happen to-' WHERE `entry`=16028 AND `groupid`=2; +UPDATE `creature_text` SET `text`='%s goes into a frenzy!', `type`=41 WHERE `entry`=16028 AND `groupid`=4; + +-- Spectral Servant +UPDATE `creature_text` SET `type`=12 WHERE `entry`=16407 AND `groupid`=0 AND `id`=0; + +-- Maiden of Virtue +UPDATE `creature_text` SET `text`='Your behavior will not be tolerated.' WHERE `entry`=16457 AND `groupid`=0; + +-- Shade of Aran +UPDATE `creature_text` SET `text`='Please, no more! My son... he''s gone mad!' WHERE `entry`=16524 AND `groupid`=0 AND `id`=0; +UPDATE `creature_text` SET `text`='I''ll show you: this beaten dog still has some teeth!' WHERE `entry`=16524 AND `groupid`=1 AND `id`=0; +UPDATE `creature_text` SET `text`='Burn, you hellish fiends!' WHERE `entry`=16524 AND `groupid`=1 AND `id`=1; +UPDATE `creature_text` SET `text`='Yes, yes my son is quite powerful... but I have powers of my own!' WHERE `entry`=16524 AND `groupid`=3 AND `id`=0; +UPDATE `creature_text` SET `text`='I''m not finished yet! No, I have a few more tricks up my sleeve...', `type`=12 WHERE `entry`=16524 AND `groupid`=5; +UPDATE `creature_text` SET `text`='At last the nightmare is over...' WHERE `entry`=16524 AND `groupid`=8; + +-- Martik Tor'seldori +UPDATE `creature_text` SET `text`='Brothers and sisters, I have been to the promised land. I have tasted in the sublime energy. I have felt bliss - bliss so engrossing and all encompassing that I was left wondering if I had stumbled upon the dreams of gods.' WHERE `entry`=16577 AND `groupid`=0; + +-- Grand Warlock Nethekurse +UPDATE `creature_text` SET `text`='You can have that one, I no longer need him!' WHERE `entry`=16807 AND `groupid`=1 AND `id`=0; +UPDATE `creature_text` SET `text`='Yes, beat him mercilessly! His skull is as thick as an ogre''s!' WHERE `entry`=16807 AND `groupid`=1 AND `id`=1; +UPDATE `creature_text` SET `text`='Don''t waste your time on that one, he''s weak!' WHERE `entry`=16807 AND `groupid`=1 AND `id`=2; +UPDATE `creature_text` SET `text`='One pitiful wretch down. Go on, take another one!' WHERE `entry`=16807 AND `groupid`=2 AND `id`=0; +UPDATE `creature_text` SET `text`='Ah, what a waste... next!' WHERE `entry`=16807 AND `groupid`=2 AND `id`=1; +UPDATE `creature_text` SET `text`='Thank you for saving me the trouble. Now it''s my turn to have some fun!' WHERE `entry`=16807 AND `groupid`=2 AND `id`=3; +UPDATE `creature_text` SET `text`='Beg for your pitiful life!' WHERE `entry`=16807 AND `groupid`=3 AND `id`=0; +UPDATE `creature_text` SET `text`='Run, coward, run! ' WHERE `entry`=16807 AND `groupid`=3 AND `id`=1; -- Blizz fail. +UPDATE `creature_text` SET `text`='Your pain amuses me!' WHERE `entry`=16807 AND `groupid`=3 AND `id`=2; +UPDATE `creature_text` SET `text`='I''m already bored!' WHERE `entry`=16807 AND `groupid`=4 AND `id`=0; +UPDATE `creature_text` SET `text`='Come on, show me a real fight!' WHERE `entry`=16807 AND `groupid`=4 AND `id`=1; +UPDATE `creature_text` SET `text`='I had more fun torturing the peons!' WHERE `entry`=16807 AND `groupid`=4 AND `id`=2; +UPDATE `creature_text` SET `text`='You lose.' WHERE `entry`=16807 AND `groupid`=5 AND `id`=0; +UPDATE `creature_text` SET `text`='Oh, just die!' WHERE `entry`=16807 AND `groupid`=5 AND `id`=1; +UPDATE `creature_text` SET `text`='What... a shame.' WHERE `entry`=16807 AND `groupid`=6; + +-- Warchief Kargath Bladefist +UPDATE `creature_text` SET `text`='Ours is the TRUE Horde! The only Horde!' WHERE `entry`=16808 AND `groupid`=0 AND `id`=0; +UPDATE `creature_text` SET `text`='I am called Bladefist for a reason. As you will see.' WHERE `entry`=16808 AND `groupid`=0 AND `id`=2; +UPDATE `creature_text` SET `text`='I am the ONLY warchief!' WHERE `entry`=16808 AND `groupid`=1 AND `id`=1; +UPDATE `creature_text` SET `text`='The true Horde... will prevail.' WHERE `entry`=16808 AND `groupid`=2; + +-- Barnes <The Stage Manager> +UPDATE `creature_text` SET `text`='Welcome ladies and gentlemen, to this evening''s presentation!' WHERE `entry`=16812 AND `groupid`=0; +UPDATE `creature_text` SET `text`='Tonight we plumb the depths of the human soul as we join a lost, lonely girl trying desperately--with the help of her loyal companions--to find her way home!' WHERE `entry`=16812 AND `groupid`=1; +UPDATE `creature_text` SET `text`='But she is pursued... by a wicked, malevolent crone!' WHERE `entry`=16812 AND `groupid`=2; +UPDATE `creature_text` SET `text`='Will she survive? Will she prevail? Only time will tell. And now... on with the show!' WHERE `entry`=16812 AND `groupid`=3; +UPDATE `creature_text` SET `text`='Good evening ladies and gentlemen, welcome to this evening''s presentation!' WHERE `entry`=16812 AND `groupid`=4; +UPDATE `creature_text` SET `text`='Tonight, things are not what they seem... for tonight your eyes may not be trusted!' WHERE `entry`=16812 AND `groupid`=5; +UPDATE `creature_text` SET `text`='Take for instance this quiet elderly woman waiting for a visit from her granddaughter... surely there is nothing to fear from this sweet, gray-haired old lady!' WHERE `entry`=16812 AND `groupid`=6; +UPDATE `creature_text` SET `text`='But don''t let me pull the wool over your eyes! See for yourself what lies beneath those covers! And now... on with the show!' WHERE `entry`=16812 AND `groupid`=7; +UPDATE `creature_text` SET `text`='Welcome ladies and gentlemen, to this evening''s presentation!' WHERE `entry`=16812 AND `groupid`=8; +UPDATE `creature_text` SET `text`='Tonight... we explore a tale of forbidden love!' WHERE `entry`=16812 AND `groupid`=9; +UPDATE `creature_text` SET `text`='But beware, for not all love stories end happily, as you may find out. Sometimes, love pricks like a thorn!' WHERE `entry`=16812 AND `groupid`=10; +UPDATE `creature_text` SET `text`='But don''t take it from me; see for yourself what tragedy lies ahead when the paths of star crossed lovers meet! And now... on with the show!' WHERE `entry`=16812 AND `groupid`=11; + +-- Shadow Council Enforcer +UPDATE `creature_text` SET `text`='Gul''dan speaks the truth! We should return at once to tell our brothers of the news! Retreat back through the portal!', `type`=14 WHERE `entry`=17023 AND `groupid`=0; + +-- Nightbane +UPDATE `creature_text` SET `text`='%s takes a deep breath.', `type`=41 WHERE `entry`=17225 AND `groupid`=4; diff --git a/sql/updates/world/2013_02_04_02_world_misc.sql b/sql/updates/world/2013_02_04_02_world_misc.sql new file mode 100644 index 00000000000..300d0e31bcb --- /dev/null +++ b/sql/updates/world/2013_02_04_02_world_misc.sql @@ -0,0 +1,119 @@ +-- Pilfering Perfume (A:24656 H:24541) + +SET @QUEST_A := 24656; +SET @QUEST_H := 24541; + +SET @SNIP := 38066; -- Inspector Snip Snagglebolt +SET @SNAP := 37172; -- Detective Snap Snagglebolt +SET @MENUID := 10976; + +SET @TRIGGER_SW_OUT := 5703; -- outside +SET @TRIGGER_SW_IN := 5704; -- inside +SET @TRIGGER_ORG_OUT := 5705; -- outside +SET @TRIGGER_ORG_IN := 5706; -- inside + +SET @SPELL_UNIFORM := 71450; -- Crown Parcel Service Uniform +SET @SPELL_CONTRABAND := 71459; -- Crown Chemical Co. Contraband + +SET @SPELL_CREDIT_A := 71522; -- Crown Chemical Co. Supplies +SET @SPELL_CREDIT_H := 71539; -- Crown Chemical Co. Supplies + +SET @GUID := 48571; -- set by TDB,need 3 (48571,48572,48573) +SET @EVENT := 8; -- Love is in the Air +SET @NPC_GUARD := 37671; -- Crown Supply Guard + +-- missing npcs on horde side +DELETE FROM `creature` WHERE `id`=@NPC_GUARD; +INSERT INTO `creature` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`modelid`,`equipment_id`,`position_x`,`position_y`,`position_z`,`orientation`,`spawntimesecs`,`spawndist`,`currentwaypoint`,`curhealth`,`curmana`,`MovementType`,`npcflag`,`unit_flags`,`dynamicflags`) VALUES +(@GUID+0,@NPC_GUARD,1,1,1,0,0,1391.2,-4486.23,31.4544,3.3355,300,0,0,42,0,0,0,0,0), +(@GUID+1,@NPC_GUARD,1,1,1,0,0,1392.66,-4481.87,31.3782,1.97284,300,0,0,42,0,0,0,0,0), +(@GUID+2,@NPC_GUARD,1,1,1,0,0,1393.92,-4489.57,31.4737,4.93701,300,0,0,42,0,0,0,0,0); + +DELETE FROM `game_event_creature` WHERE `eventEntry`=@EVENT AND `guid` BETWEEN @GUID+0 AND @GUID+2; +INSERT INTO `game_event_creature` (`eventEntry`,`guid`) VALUES +(@EVENT,@GUID+0), +(@EVENT,@GUID+1), +(@EVENT,@GUID+2); + +-- removing a wrong spawn +DELETE FROM `creature` WHERE `guid`=40507; +DELETE FROM `game_event_creature` WHERE `guid`=40507; + +-- deleting wrong previous spawns and reusing some guids to spawn proper ones +DELETE FROM `gameobject` WHERE `guid` IN (24416,24417,24418,24419,24420,24421,24422,24423,24433,24434,24435,24436,24437,24438,24439,24440,24441); +INSERT INTO `gameobject` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`position_x`,`position_y`,`position_z`,`orientation`,`rotation0`,`rotation1`,`rotation2`,`rotation3`,`spawntimesecs`,`animprogress`,`state`) VALUES +(24416,181015,1,1,1,1392.938,-4485.202,31.41421,0,0,0,0,1,120,255,1), +(24417,201778,1,1,1,1393.677,-4486.033,32.67227,0,0,0,0,1,120,255,1), +(24418,201752,1,1,1,1394.184,-4484.108,31.24833,4.32842,0,0,0,1,120,255,1), +(24419,201778,1,1,1,1394.26,-4484.368,32.50796,5.148723,0,0,0,1,120,255,1), +(24420,201752,1,1,1,1393.319,-4486.797,31.42903,4.101525,0,0,0,1,120,255,1), +(24421,201752,1,1,1,1394.401,-4485.688,31.35416,5.916668,0,0,0,1,120,255,1), +(24422,201752,1,1,1,1394.042,-4488.397,31.4775,4.32842,0,0,0,1,120,255,1), +(24423,201752,1,1,1,1396.476,-4482.715,32.14788,4.32842,0,0,0,1,120,255,1), +(24433,181015,1,1,1,1395.002,-4487.113,31.37537,3.874631,0,0,0,1,120,255,1), +(24434,181015,1,1,1,1396.632,-4482.505,30.87226,5.166176,0,0,0,1,120,255,1), +(24435,201752,1,1,1,1395.813,-4486.439,32.56021,1.710422,0,0,0,1,120,255,1), +(24436,201752,1,1,1,1396.595,-4486.056,31.15484,4.32842,0,0,0,1,120,255,1), +(24437,201752,1,1,1,1397.377,-4488.021,33.71862,0.157079,0,0,0,1,120,255,1), +(24438,181015,1,1,1,1397.51,-4487.901,32.46279,3.68265,0,0,0,1,120,255,1), +(24439,201752,1,1,1,1397.571,-4487.939,31.21067,3.33359,0,0,0,1,120,255,1); +-- these guids will remain free +DELETE FROM `game_event_gameobject` WHERE `eventEntry`=@EVENT AND `guid` IN (24440,24441); + +-- Snip & Snap sai +UPDATE `creature_template` SET `npcflag`=`npcflag`|1|2,`gossip_menu_id`=@MENUID,`AIName`='SmartAI' WHERE `entry` IN (@SNIP,@SNAP); +DELETE FROM `smart_scripts` WHERE `entryorguid` IN (@SNIP,@SNAP) AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@SNIP,0,0,0,19,0,100,0,@QUEST_A,0,0,0,11,@SPELL_UNIFORM,0,0,0,0,0,7,0,0,0,0,0,0,0,'Snip - On quest accept - Spellcast'), +(@SNIP,0,1,2,62,0,100,0,@MENUID,0,0,0,72,0,0,0,0,0,0,7,0,0,0,0,0,0,0,'Snip - On gossip option select - Close gossip'), +(@SNIP,0,2,0,61,0,100,0,0,0,0,0,11,@SPELL_UNIFORM,0,0,0,0,0,7,0,0,0,0,0,0,0,'Snip - On gossip option accept - Spellcast'), +-- +(@SNAP,0,0,0,19,0,100,0,@QUEST_H,0,0,0,11,@SPELL_UNIFORM,0,0,0,0,0,7,0,0,0,0,0,0,0,'Snap - On quest accept - Spellcast'), +(@SNAP,0,1,2,62,0,100,0,@MENUID,0,0,0,72,0,0,0,0,0,0,7,0,0,0,0,0,0,0,'Snap - On gossip option select - Close gossip'), +(@SNAP,0,2,0,61,0,100,0,0,0,0,0,11,@SPELL_UNIFORM,0,0,0,0,0,7,0,0,0,0,0,0,0,'Snap - On gossip option accept - Spellcast'); + +DELETE FROM `areatrigger_involvedrelation` WHERE `id` IN (@TRIGGER_SW_OUT,@TRIGGER_SW_IN,@TRIGGER_ORG_OUT,@TRIGGER_ORG_IN); +INSERT INTO `areatrigger_involvedrelation` (`id`,`quest`) VALUES +(@TRIGGER_SW_OUT,@QUEST_A), +(@TRIGGER_SW_IN,@QUEST_A), +-- +(@TRIGGER_ORG_OUT,@QUEST_H), +(@TRIGGER_ORG_IN,@QUEST_H); + +DELETE FROM `areatrigger_scripts` WHERE `entry` IN (@TRIGGER_SW_OUT,@TRIGGER_SW_IN,@TRIGGER_ORG_OUT,@TRIGGER_ORG_IN); +INSERT INTO `areatrigger_scripts` (`entry`,`ScriptName`) VALUES +(@TRIGGER_SW_OUT,'SmartTrigger'), +(@TRIGGER_SW_IN,'SmartTrigger'), +-- +(@TRIGGER_ORG_OUT,'SmartTrigger'), +(@TRIGGER_ORG_IN,'SmartTrigger'); + +-- usig invoker cast because normal cast doesn't want to work(LoS issue,i think) +DELETE FROM `smart_scripts` WHERE `entryorguid` IN (@TRIGGER_SW_OUT,@TRIGGER_SW_IN,@TRIGGER_ORG_OUT,@TRIGGER_ORG_IN) AND `source_type`=2; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@TRIGGER_SW_OUT,2,0,0,46,0,100,0,@TRIGGER_SW_OUT,0,0,0,85,@SPELL_CONTRABAND,0,0,0,0,0,7,0,0,0,0,0,0,0,"On Trigger - Cast - Invoker"), +(@TRIGGER_SW_IN,2,0,0,46,0,100,0,@TRIGGER_SW_IN,0,0,0,85,@SPELL_CREDIT_A,0,0,0,0,0,7,0,0,0,0,0,0,0,"On Trigger - Cast - Invoker"), +-- +(@TRIGGER_ORG_OUT,2,0,0,46,0,100,0,@TRIGGER_ORG_OUT,0,0,0,85,@SPELL_CONTRABAND,0,0,0,0,0,7,0,0,0,0,0,0,0,"On Trigger - Cast - Invoker"), +(@TRIGGER_ORG_IN,2,0,0,46,0,100,0,@TRIGGER_ORG_IN,0,0,0,85,@SPELL_CREDIT_H,0,0,0,0,0,7,0,0,0,0,0,0,0,"On Trigger - Cast - Invoker"); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=22 AND `SourceEntry` IN (@TRIGGER_SW_OUT,@TRIGGER_SW_IN,@TRIGGER_ORG_OUT,@TRIGGER_ORG_IN); +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=@MENUID; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`NegativeCondition`,`ErrorType`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES +(22,1,@TRIGGER_SW_OUT,2,0,1,0,@SPELL_UNIFORM,0,0,0,0,0,'','execute sai only if player has aura'), +(22,1,@TRIGGER_SW_IN,2,0,1,0,@SPELL_CONTRABAND,0,0,0,0,0,'','execute sai only if player has aura'), +(15,@MENUID,0,0,0,9,0,@QUEST_A,0,0,0,0,0,'','show gossip option only if player has quest taken'), +-- +(22,1,@TRIGGER_ORG_OUT,2,0,1,0,@SPELL_UNIFORM,0,0,0,0,0,'','execute sai only if player has aura'), +(22,1,@TRIGGER_ORG_IN,2,0,1,0,@SPELL_CONTRABAND,0,0,0,0,0,'','execute sai only if player has aura'), +(15,@MENUID,0,0,1,9,0,@QUEST_H,0,0,0,0,0,'','show gossip option only if player has quest taken'); + +DELETE FROM `spell_linked_spell` WHERE `spell_trigger` IN (@SPELL_CREDIT_A,@SPELL_CREDIT_H,-@SPELL_UNIFORM); +INSERT INTO `spell_linked_spell` (`spell_trigger`,`spell_effect`,`type`,`comment`) VALUES +(@SPELL_CREDIT_A,-@SPELL_UNIFORM,1,'Remove Crown Parcel Service Uniform on Crown Chemical Co. Supplies hit'), +(@SPELL_CREDIT_H,-@SPELL_UNIFORM,1,'Remove Crown Parcel Service Uniform on Crown Chemical Co. Supplies hit'), +(-@SPELL_UNIFORM,-@SPELL_CONTRABAND,0,'Remove Crown Chemical Co. Contraband when Crown Parcel Service Uniform is removed'); + +DELETE FROM `spell_script_names` WHERE `spell_id`=@SPELL_UNIFORM; +INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES +(@SPELL_UNIFORM,'spell_gen_aura_service_uniform'); diff --git a/sql/updates/world/2013_02_04_03_world_misc.sql b/sql/updates/world/2013_02_04_03_world_misc.sql new file mode 100644 index 00000000000..a609d411b6e --- /dev/null +++ b/sql/updates/world/2013_02_04_03_world_misc.sql @@ -0,0 +1,53 @@ +DELETE FROM `trinity_string` WHERE `entry` BETWEEN 63 AND 95; +INSERT INTO trinity_string (entry, content_default) VALUES +(63, "Wrong parameter id: %u, does not exist"), +(64, "Wrong parameter realmId: %d"), +(65, "Couldn't add group %u (%s) realmId %d. Account %u (%s) already has that group"), +(66, "Couldn't remove group %u (%s) realmId %d. Account %u (%s) does not have that group"), +(67, "Added group %u (%s) realmId %d to account %u (%s)"), +(68, "Removed group %u (%s) realmId %d from account %u (%s)"), +(69, "Account %u (%s) groups:"), +(70, "Empty List"), +(71, "- %u (%s)"), +(72, "Couldn't grant role %u (%s) realmId %d. Account %u (%s) already has that role"), +(73, "Couldn't grant role %u (%s) realmId %d. Account %u (%s) has that role in deny list"), +(74, "Granted role %u (%s) realmId %d to account %u (%s)"), +(75, "Couldn't deny role %u (%s) realmId %d. Account %u (%s) already has that role"), +(76, "Couldn't deny role %u (%s) realmId %d. Account %u (%s) has that role in deny list"), +(77, "Denied role %u (%s) realmId %d to account %u (%s)"), +(78, "Denied role %u (%s) realmId %d to account %u (%s)"), +(79, "Couldn't revoke role %u (%s) realmId %d. Account %u (%s) does not have that role"), +(80, "Account %u (%s) granted roles:"), +(81, "Account %u (%s) denied roles:"), +(82, "Couldn't grant permission %u (%s) realmId %d. Account %u (%s) already has that permission"), +(83, "Couldn't grant permission %u (%s) realmId %d. Account %u (%s) has that permission in deny list"), +(84, "Granted permission %u (%s) realmId %d to account %u (%s)"), +(85, "Couldn't deny permission %u (%s) realmId %d. Account %u (%s) already has that permission"), +(86, "Couldn't deny permission %u (%s) realmId %d. Account %u (%s) has that permission in deny list"), +(87, "Denied permission %u (%s) realmId %d to account %u (%s)"), +(88, "Revoked permission %u (%s) realmId %d to account %u (%s)"), +(89, "Couldn't revoke permission %u (%s) realmId %d. Account %u (%s) does not have that permission"), +(90, "Account %u (%s) granted permissions:"), +(91, "Account %u (%s) denied permissions:"), +(92, "Account %u (%s) global permissions:"), +(93, "Groups:"), +(94, "Roles:"), +(95, "Permissions:"); + +DELETE FROM `command` WHERE `name` LIKE '.rbac%'; +INSERT INTO `command` (`name`, `security`, `help`) VALUES +('.rbac account', 3, 'Syntax: .rbac account [$account]\n\nView permissions of selected player or given account\nNote: Only those that affect current realm\n\nNote: Shows real permissions after checking group and roles'), +('.rbac account group', 3, 'Syntax: .rbac account group [$account]\n\nView groups of selected player or given account\nNote: Only those that affect current realm'), +('.rbac account group add', 3, 'Syntax: .rbac account group add [$account] #id [#realmId]\n\nAdd a group to selected player or given account.\n\n#reamID may be -1 for all realms.'), +('.rbac account group remove', 3, 'Syntax: .rbac account group remove [$account] #id\n\nRemove a group from selected player or given account.'), +('.rbac account role', 3, 'Syntax: .rbac account role [$account]\n\nView roles of selected player or given account\nNote: Only those that affect current realm\nNote: Only those directly granted or denied, does not include inherited roles from groups'), +('.rbac account role grant', 3, 'Syntax: .rbac account role grant [$account] #id [#realmId]\n\nGrant a role to selected player or given account.\n\n#reamID may be -1 for all realms.'), +('.rbac account role deny', 3, 'Syntax: .rbac account role deny [$account] #id [#realmId]\n\nDeny a role to selected player or given account.\n\n#reamID may be -1 for all realms.'), +('.rbac account role revoke', 3, 'Syntax: .rbac account role revoke [$account] #id\n\nRemove a role from an account\n\nNote: Removes the role from granted or denied roles'), +('.rbac account permission', 3, 'Syntax: .rbac account permission [$account]\n\nView permissions of selected player or given account\nNote: Only those that affect current realm\nNote: Only those directly granted or denied, does not include inherited permissions from roles'), +('.rbac account permission grant', 3, 'Syntax: .rbac account permission grant [$account] #id [#realmId]\n\nGrant a permission to selected player or given account.\n\n#reamID may be -1 for all realms.'), +('.rbac account permission deny', 3, 'Syntax: .rbac account permission deny [$account] #id [#realmId]\n\nDeny a permission to selected player or given account.\n\n#reamID may be -1 for all realms.'), +('.rbac account permission revoke', 3, 'Syntax: .rbac account permission revoke [$account] #id\n\nRemove a permission from an account\n\nNote: Removes the permission from granted or denied permissions'), +('.rbac list groups', 3, 'Syntax: .rbac list groups [$id]\n\nView list of all groups. If $id is given will show group info and his inherited roles.'), +('.rbac list roles', 3, 'Syntax: .rbac list roles [$id]\n\nView list of all roles. If $id is given will show role info and his inherited permissions.'), +('.rbac list permissions', 3, 'Syntax: .rbac list permissions [$id]\n\nView list of all permissions. If $id is given will show only info for that permission.'); diff --git a/src/server/collision/Models/GameObjectModel.cpp b/src/server/collision/Models/GameObjectModel.cpp index 54283389387..e166a860cd2 100644 --- a/src/server/collision/Models/GameObjectModel.cpp +++ b/src/server/collision/Models/GameObjectModel.cpp @@ -48,7 +48,10 @@ ModelList model_list; void LoadGameObjectModelList() { +#ifndef NO_CORE_FUNCS uint32 oldMSTime = getMSTime(); +#endif + FILE* model_list_file = fopen((sWorld->GetDataPath() + "vmaps/" + VMAP::GAMEOBJECT_MODELS).c_str(), "rb"); if (!model_list_file) { diff --git a/src/server/game/AI/CoreAI/ReactorAI.cpp b/src/server/game/AI/CoreAI/ReactorAI.cpp index 31b9a82c534..b9c235176bc 100644 --- a/src/server/game/AI/CoreAI/ReactorAI.cpp +++ b/src/server/game/AI/CoreAI/ReactorAI.cpp @@ -23,10 +23,7 @@ #include "ObjectAccessor.h" #include "CreatureAIImpl.h" -#define REACTOR_VISIBLE_RANGE (26.46f) - -int -ReactorAI::Permissible(const Creature* creature) +int ReactorAI::Permissible(const Creature* creature) { if (creature->isCivilian() || creature->IsNeutralToAll()) return PERMIT_BASE_REACTIVE; @@ -34,24 +31,10 @@ ReactorAI::Permissible(const Creature* creature) return PERMIT_BASE_NO; } -void -ReactorAI::MoveInLineOfSight(Unit*) -{ -} - -void -ReactorAI::UpdateAI(const uint32 /*time_diff*/) +void ReactorAI::UpdateAI(uint32 const /*diff*/) { - // update i_victimGuid if me->getVictim() !=0 and changed if (!UpdateVictim()) return; - if (me->isAttackReady()) - { - if (me->IsWithinMeleeRange(me->getVictim())) - { - me->AttackerStateUpdate(me->getVictim()); - me->resetAttackTimer(); - } - } + DoMeleeAttackIfReady(); } diff --git a/src/server/game/AI/CoreAI/ReactorAI.h b/src/server/game/AI/CoreAI/ReactorAI.h index 39af09c4a9d..f7de3b99565 100644 --- a/src/server/game/AI/CoreAI/ReactorAI.h +++ b/src/server/game/AI/CoreAI/ReactorAI.h @@ -29,9 +29,9 @@ class ReactorAI : public CreatureAI explicit ReactorAI(Creature* c) : CreatureAI(c) {} - void MoveInLineOfSight(Unit*); + void MoveInLineOfSight(Unit*) {} + void UpdateAI(uint32 const diff); - void UpdateAI(const uint32); static int Permissible(const Creature*); }; #endif diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp index 09ba2cc19b1..7f0d387c2f1 100644 --- a/src/server/game/AI/CoreAI/UnitAI.cpp +++ b/src/server/game/AI/CoreAI/UnitAI.cpp @@ -103,8 +103,7 @@ void UnitAI::DoAddAuraToAllHostilePlayers(uint32 spellid) if (unit->GetTypeId() == TYPEID_PLAYER) me->AddAura(spellid, unit); } - }else - return; + } } void UnitAI::DoCastToAllHostilePlayers(uint32 spellid, bool triggered) @@ -118,8 +117,7 @@ void UnitAI::DoCastToAllHostilePlayers(uint32 spellid, bool triggered) if (unit->GetTypeId() == TYPEID_PLAYER) me->CastSpell(unit, spellid, triggered); } - }else - return; + } } void UnitAI::DoCast(uint32 spellId) @@ -240,7 +238,10 @@ void UnitAI::FillAISpellInfo() } //Enable PlayerAI when charmed -void PlayerAI::OnCharmed(bool apply) { me->IsAIEnabled = apply; } +void PlayerAI::OnCharmed(bool apply) +{ + me->IsAIEnabled = apply; +} void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/) { diff --git a/src/server/game/AI/CreatureAIImpl.h b/src/server/game/AI/CreatureAIImpl.h index 559240c4a3f..6c5cb5622b3 100644 --- a/src/server/game/AI/CreatureAIImpl.h +++ b/src/server/game/AI/CreatureAIImpl.h @@ -313,96 +313,177 @@ const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, c class EventMap { - typedef std::map<uint32, uint32> StorageType; + /** + * Internal storage type. + * Key: Time as uint32 when the event should occur. + * Value: The event data as uint32. + * + * Structure of event data: + * - Bit 0 - 15: Event Id. + * - Bit 16 - 23: Group + * - Bit 24 - 31: Phase + * - Pattern: 0xPPGGEEEE + */ + typedef std::multimap<uint32, uint32> EventStore; public: EventMap() : _time(0), _phase(0) {} - // Returns current timer value, does not represent real dates/times - uint32 GetTimer() const { return _time; } - - // Removes all events and clears phase + /** + * @name Reset + * @brief Removes all scheduled events and resets time and phase. + */ void Reset() { - _eventMap.clear(); _time = 0; _phase = 0; + _eventMap.clear(); + _time = 0; + _phase = 0; + } + + /** + * @name Update + * @brief Updates the timer of the event map. + * @param time Value to be added to time. + */ + void Update(uint32 time) + { + _time += time; } - void Update(uint32 time) { _time += time; } + /** + * @name GetTimer + * @return Current timer value. + */ + uint32 GetTimer() const + { + return _time; + } - uint32 GetPhaseMask() const { return (_phase >> 24) & 0xFF; } + /** + * @name GetPhaseMask + * @return Active phases as mask. + */ + uint8 GetPhaseMask() const + { + return _phase; + } - bool Empty() const { return _eventMap.empty(); } + /** + * @name Empty + * @return True, if there are no events scheduled. + */ + bool Empty() const + { + return _eventMap.empty(); + } - // Sets event phase, must be in range 1 - 8 - void SetPhase(uint32 phase) + /** + * @name SetPhase + * @brief Sets the phase of the map (absolute). + * @param phase Phase which should be set. Values: 1 - 8. 0 resets phase. + */ + void SetPhase(uint8 phase) { - if (phase && phase < 8) - _phase = (1 << (phase + 24)); - else if (!phase) + if (!phase) _phase = 0; + else if (phase <= 8) + _phase = (1 << (phase - 1)); } - // Creates new event entry in map with given id, time, group if given (1 - 8) and phase if given (1 - 8) - // 0 for group/phase means it belongs to no group or runs in all phases - void ScheduleEvent(uint32 eventId, uint32 time, uint32 groupId = 0, uint32 phase = 0) + /** + * @name AddPhase + * @brief Activates the given phase (bitwise). + * @param phase Phase which should be activated. Values: 1 - 8 + */ + void AddPhase(uint8 phase) { - time += _time; - if (groupId && groupId < 9) - eventId |= (1 << (groupId + 16)); - if (phase && phase < 8) - eventId |= (1 << (phase + 24)); - StorageType::const_iterator itr = _eventMap.find(time); - while (itr != _eventMap.end()) - { - ++time; - itr = _eventMap.find(time); - } + if (phase && phase <= 8) + _phase |= (1 << (phase - 1)); + } - _eventMap.insert(StorageType::value_type(time, eventId)); + /** + * @name RemovePhase + * @brief Deactivates the given phase (bitwise). + * @param phase Phase which should be deactivated. Values: 1 - 8. + */ + void RemovePhase(uint8 phase) + { + if (phase && phase <= 8) + _phase &= ~(1 << (phase - 1)); } - // Removes event with specified id and creates new entry for it - void RescheduleEvent(uint32 eventId, uint32 time, uint32 groupId = 0, uint32 phase = 0) + /** + * @name ScheduleEvent + * @brief Creates new event entry in map. + * @param eventId The id of the new event. + * @param time The time in milliseconds until the event occurs. + * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group. + * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases. + */ + void ScheduleEvent(uint32 eventId, uint32 time, uint32 group = 0, uint8 phase = 0) + { + if (group && group <= 8) + eventId |= (1 << (group + 15)); + + if (phase && phase <= 8) + eventId |= (1 << (phase + 23)); + + _eventMap.insert(EventStore::value_type(_time + time, eventId)); + } + + /** + * @name RescheduleEvent + * @brief Cancels the given event and reschedules it. + * @param eventId The id of the event. + * @param time The time in milliseconds until the event occurs. + * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group. + * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases. + */ + void RescheduleEvent(uint32 eventId, uint32 time, uint32 group = 0, uint8 phase = 0) { CancelEvent(eventId); - ScheduleEvent(eventId, time, groupId, phase); + ScheduleEvent(eventId, time, group, phase); } - // Reschedules closest event + /** + * @name RepeatEvent + * @brief Cancels the closest event and reschedules it. + * @param time Time until the event occurs. + */ void RepeatEvent(uint32 time) { - if (_eventMap.empty()) + if (Empty()) return; uint32 eventId = _eventMap.begin()->second; _eventMap.erase(_eventMap.begin()); - time += _time; - StorageType::const_iterator itr = _eventMap.find(time); - while (itr != _eventMap.end()) - { - ++time; - itr = _eventMap.find(time); - } - - _eventMap.insert(StorageType::value_type(time, eventId)); + ScheduleEvent(eventId, time); } - // Removes first event + /** + * @name PopEvent + * @brief Remove the first event in the map. + */ void PopEvent() { - if (!_eventMap.empty()) + if (!Empty()) _eventMap.erase(_eventMap.begin()); } - // Gets next event id to execute and removes it from map + /** + * @name ExecuteEvent + * @brief Returns the next event to execute and removes it from map. + * @return Id of the event to execute. + */ uint32 ExecuteEvent() { - while (!_eventMap.empty()) + while (!Empty()) { - StorageType::iterator itr = _eventMap.begin(); + EventStore::iterator itr = _eventMap.begin(); + if (itr->first > _time) return 0; - else if (_phase && (itr->second & 0xFF000000) && !(itr->second & _phase)) + else if (_phase && (itr->second & 0xFF000000) && !((itr->second >> 24) & _phase)) _eventMap.erase(itr); else { @@ -411,18 +492,24 @@ class EventMap return eventId; } } + return 0; } - // Gets next event id to execute + /** + * @name GetEvent + * @brief Returns the next event to execute. + * @return Id of the event to execute. + */ uint32 GetEvent() { - while (!_eventMap.empty()) + while (!Empty()) { - StorageType::iterator itr = _eventMap.begin(); + EventStore::iterator itr = _eventMap.begin(); + if (itr->first > _time) return 0; - else if (_phase && (itr->second & 0xFF000000) && !(itr->second & _phase)) + else if (_phase && (itr->second & 0xFF000000) && !(itr->second & (_phase << 24))) _eventMap.erase(itr); else return (itr->second & 0x0000FFFF); @@ -431,81 +518,150 @@ class EventMap return 0; } - // Delay all events + /** + * @name DelayEvents + * @brief Delays all events in the map. If delay is greater than or equal internal timer, delay will be 0. + * @param delay Amount of delay. + */ void DelayEvents(uint32 delay) { - if (delay < _time) - _time -= delay; - else - _time = 0; + _time = delay < _time ? _time - delay : 0; } - // Delay all events having the specified Group - void DelayEvents(uint32 delay, uint32 groupId) + /** + * @name DelayEvents + * @brief Delay all events of the same group. + * @param delay Amount of delay. + * @param group Group of the events. + */ + void DelayEvents(uint32 delay, uint32 group) { - uint32 nextTime = _time + delay; - uint32 groupMask = (1 << (groupId + 16)); - for (StorageType::iterator itr = _eventMap.begin(); itr != _eventMap.end() && itr->first < nextTime;) + if (!group || group > 8 || Empty()) + return; + + EventStore delayed; + + for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();) { - if (itr->second & groupMask) + if (itr->second & (1 << (group + 15))) { - ScheduleEvent(itr->second, itr->first - _time + delay); - _eventMap.erase(itr); - itr = _eventMap.begin(); + delayed.insert(EventStore::value_type(itr->first + delay, itr->second)); + _eventMap.erase(itr++); } else ++itr; } + + _eventMap.insert(delayed.begin(), delayed.end()); } - // Cancel events with specified id + /** + * @name CancelEvent + * @brief Cancels all events of the specified id. + * @param eventId Event id to cancel. + */ void CancelEvent(uint32 eventId) { - for (StorageType::iterator itr = _eventMap.begin(); itr != _eventMap.end();) + if (Empty()) + return; + + for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();) { if (eventId == (itr->second & 0x0000FFFF)) - { - _eventMap.erase(itr); - itr = _eventMap.begin(); - } + _eventMap.erase(itr++); else ++itr; } } - // Cancel events belonging to specified group - void CancelEventGroup(uint32 groupId) + /** + * @name CancelEventGroup + * @brief Cancel events belonging to specified group. + * @param group Group to cancel. + */ + void CancelEventGroup(uint32 group) { - uint32 groupMask = (1 << (groupId + 16)); + if (!group || group > 8 || Empty()) + return; - for (StorageType::iterator itr = _eventMap.begin(); itr != _eventMap.end();) + for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();) { - if (itr->second & groupMask) - { - _eventMap.erase(itr); - itr = _eventMap.begin(); - } + if (itr->second & (1 << (group + 15))) + _eventMap.erase(itr++); else ++itr; } } - // Returns time of next event to execute - // To get how much time remains substract _time + /** + * @name GetNextEventTime + * @brief Returns closest occurence of specified event. + * @param eventId Wanted event id. + * @return Time of found event. + */ uint32 GetNextEventTime(uint32 eventId) const { - for (StorageType::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr) + if (Empty()) + return 0; + + for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr) if (eventId == (itr->second & 0x0000FFFF)) return itr->first; return 0; } + /** + * @name GetNextEventTime + * @return Time of next event. + */ + uint32 GetNextEventTime() const + { + return Empty() ? 0 : _eventMap.begin()->first; + } + + /** + * @name IsInPhase + * @brief Returns wether event map is in specified phase or not. + * @param phase Wanted phase. + * @return True, if phase of event map contains specified phase. + */ + bool IsInPhase(uint8 phase) + { + return phase <= 8 && (!phase || _phase & (1 << (phase - 1))); + } + private: + /** + * @name _time + * @brief Internal timer. + * + * This does not represent the real date/time value. + * It's more like a stopwatch: It can run, it can be stopped, + * it can be resetted and so on. Events occur when this timer + * has reached their time value. Its value is changed in the + * Update method. + */ uint32 _time; - uint32 _phase; - StorageType _eventMap; + /** + * @name _phase + * @brief Phase mask of the event map. + * + * Contains the phases the event map is in. Multiple + * phases from 1 to 8 can be set with SetPhase or + * AddPhase. RemovePhase deactives a phase. + */ + uint8 _phase; + + /** + * @name _eventMap + * @brief Internal event storage map. Contains the scheduled events. + * + * See typedef at the beginning of the class for more + * details. + */ + EventStore _eventMap; }; enum AITarget diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index 9709cb0ecc2..090c73f456f 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -108,6 +108,14 @@ void ScriptedAI::AttackStartNoMove(Unit* who) DoStartNoMovement(who); } +void ScriptedAI::AttackStart(Unit* who) +{ + if (IsCombatMovementAllowed()) + CreatureAI::AttackStart(who); + else + AttackStartNoMove(who); +} + void ScriptedAI::UpdateAI(uint32 const /*diff*/) { //Check if we have a current target diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h index 50363f20ed5..15068557aca 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h @@ -136,6 +136,9 @@ struct ScriptedAI : public CreatureAI //Called at creature aggro either by MoveInLOS or Attack Start void EnterCombat(Unit* /*victim*/) {} + // Called before EnterCombat even before the creature is in combat. + void AttackStart(Unit* /*target*/); + // ************* //AI Helper Functions // ************* @@ -191,7 +194,11 @@ struct ScriptedAI : public CreatureAI void SetEquipmentSlots(bool loadDefault, int32 mainHand = EQUIP_NO_CHANGE, int32 offHand = EQUIP_NO_CHANGE, int32 ranged = EQUIP_NO_CHANGE); - //Generally used to control if MoveChase() is to be used or not in AttackStart(). Some creatures does not chase victims + // Used to control if MoveChase() is to be used or not in AttackStart(). Some creatures does not chase victims + // NOTE: If you use SetCombatMovement while the creature is in combat, it will do NOTHING - This only affects AttackStart + // You should make the necessary to make it happen so. + // Remember that if you modified _isCombatMovementAllowed (e.g: using SetCombatMovement) it will not be reset at Reset(). + // It will keep the last value you set. void SetCombatMovement(bool allowMovement); bool IsCombatMovementAllowed() const { return _isCombatMovementAllowed; } diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 86d86739bc9..e37b9e777d8 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -1893,12 +1893,19 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } case SMART_ACTION_JUMP_TO_POS: { - if (!me) + ObjectList* targets = GetTargets(e, unit); + if (!targets) break; - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MoveJump(e.target.x, e.target.y, e.target.z, (float)e.action.jump.speedxy, (float)e.action.jump.speedz); + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (Creature* creature = (*itr)->ToCreature()) + { + creature->GetMotionMaster()->Clear(); + creature->GetMotionMaster()->MoveJump(e.target.x, e.target.y, e.target.z, (float)e.action.jump.speedxy, (float)e.action.jump.speedz); + } // TODO: Resume path when reached jump location + + delete targets; break; } case SMART_ACTION_GO_SET_LOOT_STATE: @@ -1977,23 +1984,48 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } case SMART_ACTION_SET_HOME_POS: { - if (!me) + ObjectList* targets = GetTargets(e, unit); + if (!targets) break; - if (e.GetTargetType() == SMART_TARGET_SELF) - me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); - else if (e.GetTargetType() == SMART_TARGET_POSITION) - me->SetHomePosition(e.target.x, e.target.y, e.target.z, e.target.o); - else - sLog->outError(LOG_FILTER_SQL, "SmartScript: Action target for SMART_ACTION_SET_HOME_POS is not using SMART_TARGET_SELF or SMART_TARGET_POSITION, skipping"); + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsCreature(*itr)) + { + if (e.GetTargetType() == SMART_TARGET_SELF) + (*itr)->ToCreature()->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); + else if (e.GetTargetType() == SMART_TARGET_POSITION) + (*itr)->ToCreature()->SetHomePosition(e.target.x, e.target.y, e.target.z, e.target.o); + else + sLog->outError(LOG_FILTER_SQL, "SmartScript: Action target for SMART_ACTION_SET_HOME_POS is not using SMART_TARGET_SELF or SMART_TARGET_POSITION, skipping"); + } - break; + delete targets; + break; } case SMART_ACTION_SET_HEALTH_REGEN: { - if (!me || me->GetTypeId() != TYPEID_UNIT) + ObjectList* targets = GetTargets(e, unit); + if (!targets) break; - me->setRegeneratingHealth(e.action.setHealthRegen.regenHealth ? true : false); + + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsCreature(*itr)) + (*itr)->ToCreature()->setRegeneratingHealth(e.action.setHealthRegen.regenHealth ? true : false); + + delete targets; + break; + } + case SMART_ACTION_SET_ROOT: + { + ObjectList* targets = GetTargets(e, unit); + if (!targets) + break; + + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsCreature(*itr)) + (*itr)->ToCreature()->SetControlled(e.action.setRoot.root ? true : false, UNIT_STATE_ROOT); + + delete targets; break; } default: diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index a49ae031e63..90534de327a 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -906,6 +906,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_ACTION_SEND_TARGET_TO_TARGET: case SMART_ACTION_SET_HOME_POS: case SMART_ACTION_SET_HEALTH_REGEN: + case SMART_ACTION_SET_ROOT: break; default: sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Not handled action_type(%u), event_type(%u), Entry %d SourceType %u Event %u, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id); diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index c88ef206b00..88f9ce4f6f4 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -486,8 +486,9 @@ enum SMART_ACTION SMART_ACTION_SEND_TARGET_TO_TARGET = 100, // id SMART_ACTION_SET_HOME_POS = 101, // none SMART_ACTION_SET_HEALTH_REGEN = 102, // 0/1 + SMART_ACTION_SET_ROOT = 103, // off/on - SMART_ACTION_END = 103 + SMART_ACTION_END = 104 }; struct SmartAction @@ -919,6 +920,11 @@ struct SmartAction uint32 regenHealth; } setHealthRegen; + struct + { + uint32 root; + } setRoot; + //! Note for any new future actions //! All parameters must have type uint32 diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp index 3c3eded1f68..ce382342de8 100644 --- a/src/server/game/Accounts/AccountMgr.cpp +++ b/src/server/game/Accounts/AccountMgr.cpp @@ -17,6 +17,7 @@ */ #include "AccountMgr.h" +#include "Config.h" #include "DatabaseEnv.h" #include "ObjectAccessor.h" #include "Player.h" @@ -26,6 +27,7 @@ AccountMgr::AccountMgr() { + } AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password) @@ -44,12 +46,22 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass stmt->setString(0, username); stmt->setString(1, CalculateShaPassHash(username, password)); - LoginDatabase.Execute(stmt); + LoginDatabase.DirectExecute(stmt); // Enforce saving, otherwise AddGroup can fail stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS_INIT); LoginDatabase.Execute(stmt); + // Add default rbac groups for that security level + RBACData* rbac = new RBACData(GetId(username), username, -1); + // No need to Load From DB, as it's new data + + RBACGroupContainer const& groupsToAdd = _defaultGroups[0]; // 0: Default sec level + for (RBACGroupContainer::const_iterator it = groupsToAdd.begin(); it != groupsToAdd.end(); ++it) + rbac->AddGroup(*it, -1); + + delete rbac; + return AOR_OK; // everything's fine } @@ -303,3 +315,206 @@ bool AccountMgr::IsConsoleAccount(uint32 gmlevel) { return gmlevel == SEC_CONSOLE; } + +void AccountMgr::LoadRBAC() +{ + uint32 oldMSTime = getMSTime(); + uint32 count1 = 0; + uint32 count2 = 0; + uint32 count3 = 0; + + QueryResult result = LoginDatabase.Query("SELECT id, name FROM rbac_permissions"); + if (!result) + { + sLog->outInfo(LOG_FILTER_SQL, ">> Loaded 0 account permission definitions. DB table `rbac_permissions` is empty."); + return; + } + + do + { + Field* field = result->Fetch(); + uint32 id = field[0].GetUInt32(); + _permissions[id] = new RBACPermission(id, field[1].GetString()); + ++count1; + } + while (result->NextRow()); + + result = LoginDatabase.Query("SELECT id, name FROM rbac_roles"); + if (!result) + { + sLog->outInfo(LOG_FILTER_SQL, ">> Loaded 0 account role definitions. DB table `rbac_roles` is empty."); + return; + } + + do + { + Field* field = result->Fetch(); + uint32 id = field[0].GetUInt32(); + _roles[id] = new RBACRole(id, field[1].GetString()); + ++count2; + } + while (result->NextRow()); + + result = LoginDatabase.Query("SELECT roleId, permissionId FROM rbac_role_permissions"); + if (!result) + { + sLog->outInfo(LOG_FILTER_SQL, ">> Loaded 0 account role-permission definitions. DB table `rbac_role_permissions` is empty."); + return; + } + + do + { + Field* field = result->Fetch(); + uint32 id = field[0].GetUInt32(); + RBACRole* role = _roles[id]; + role->GrantPermission(field[1].GetUInt32()); + } + while (result->NextRow()); + + result = LoginDatabase.Query("SELECT id, name FROM rbac_groups"); + if (!result) + { + sLog->outInfo(LOG_FILTER_SQL, ">> Loaded 0 account group definitions. DB table `rbac_groups` is empty."); + return; + } + + do + { + Field* field = result->Fetch(); + uint32 id = field[0].GetUInt32(); + _groups[id] = new RBACGroup(id, field[1].GetString()); + ++count3; + } + while (result->NextRow()); + + result = LoginDatabase.Query("SELECT groupId, roleId FROM rbac_group_roles"); + if (!result) + { + sLog->outInfo(LOG_FILTER_SQL, ">> Loaded 0 account group-role definitions. DB table `rbac_group_roles` is empty."); + return; + } + + do + { + Field* field = result->Fetch(); + uint32 id = field[0].GetUInt32(); + RBACGroup* group = _groups[id]; + group->GrantRole(field[1].GetUInt32()); + } + while (result->NextRow()); + + result = LoginDatabase.Query("SELECT secId, groupId FROM rbac_security_level_groups ORDER by secId ASC"); + if (!result) + { + sLog->outInfo(LOG_FILTER_SQL, ">> Loaded 0 account default groups for security levels definitions. DB table `rbac_security_level_groups` is empty."); + return; + } + + uint8 lastSecId = 255; + RBACGroupContainer* groups = NULL; + do + { + Field* field = result->Fetch(); + uint8 secId = field[0].GetUInt8(); + + if (lastSecId != secId) + groups = &_defaultGroups[secId]; + + groups->insert(field[1].GetUInt32()); + } + while (result->NextRow()); + + sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u permission definitions, %u role definitions and %u group definitions in %u ms", count1, count2, count3, GetMSTimeDiffToNow(oldMSTime)); +} + +void AccountMgr::UpdateAccountAccess(RBACData* rbac, uint32 accountId, uint8 securityLevel, int32 realmId) +{ + int32 serverRealmId = realmId != -1 ? realmId : ConfigMgr::GetIntDefault("RealmID", 0); + bool needDelete = false; + if (!rbac) + { + needDelete = true; + rbac = new RBACData(accountId, "", serverRealmId); + rbac->LoadFromDB(); + } + + // Get max security level and realm (checking current realm and -1) + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ACCESS_BY_ID); + stmt->setUInt32(0, accountId); + stmt->setInt32(1, serverRealmId); + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (result) + { + do + { + Field* field = result->Fetch(); + uint8 secLevel = field[0].GetUInt8(); + int32 realmId = field[1].GetUInt32(); + + RBACGroupContainer const& groupsToRemove = _defaultGroups[secLevel]; + for (RBACGroupContainer::const_iterator it = groupsToRemove.begin(); it != groupsToRemove.end(); ++it) + rbac->RemoveGroup(*it, realmId); + } + while (result->NextRow()); + } + + // Add new groups depending on the new security Level + RBACGroupContainer const& groupsToAdd = _defaultGroups[securityLevel]; + for (RBACGroupContainer::const_iterator it = groupsToAdd.begin(); it != groupsToAdd.end(); ++it) + rbac->AddGroup(*it, realmId); + + if (needDelete) + delete rbac; + + // Delete old security level from DB + if (realmId == -1) + { + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS); + stmt->setUInt32(0, accountId); + LoginDatabase.Execute(stmt); + } + else + { + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS_BY_REALM); + stmt->setUInt32(0, accountId); + stmt->setUInt32(1, realmId); + LoginDatabase.Execute(stmt); + } + + // Add new security level + if (securityLevel) + { + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_ACCESS); + stmt->setUInt32(0, accountId); + stmt->setUInt8(1, securityLevel); + stmt->setInt32(2, realmId); + LoginDatabase.Execute(stmt); + } +} + +RBACGroup const* AccountMgr::GetRBACGroup(uint32 group) const +{ + RBACGroupsContainer::const_iterator it = _groups.find(group); + if (it != _groups.end()) + return it->second; + + return NULL; +} + +RBACRole const* AccountMgr::GetRBACRole(uint32 role) const +{ + RBACRolesContainer::const_iterator it = _roles.find(role); + if (it != _roles.end()) + return it->second; + + return NULL; +} + +RBACPermission const* AccountMgr::GetRBACPermission(uint32 permission) const +{ + RBACPermissionsContainer::const_iterator it = _permissions.find(permission); + if (it != _permissions.end()) + return it->second; + + return NULL; +} diff --git a/src/server/game/Accounts/AccountMgr.h b/src/server/game/Accounts/AccountMgr.h index c8de5688e73..90c533ca5fa 100644 --- a/src/server/game/Accounts/AccountMgr.h +++ b/src/server/game/Accounts/AccountMgr.h @@ -19,8 +19,7 @@ #ifndef _ACCMGR_H #define _ACCMGR_H -#include "Define.h" -#include <string> +#include "RBAC.h" #include <ace/Singleton.h> enum AccountOpResult @@ -35,6 +34,11 @@ enum AccountOpResult #define MAX_ACCOUNT_STR 16 +typedef std::map<uint32, RBACPermission*> RBACPermissionsContainer; +typedef std::map<uint32, RBACRole*> RBACRolesContainer; +typedef std::map<uint32, RBACGroup*> RBACGroupsContainer; +typedef std::map<uint32, RBACGroupContainer> RBACDefaultSecurityGroupContainer; + class AccountMgr { friend class ACE_Singleton<AccountMgr, ACE_Null_Mutex>; @@ -43,7 +47,7 @@ class AccountMgr AccountMgr(); public: - static AccountOpResult CreateAccount(std::string username, std::string password); + AccountOpResult CreateAccount(std::string username, std::string password); static AccountOpResult DeleteAccount(uint32 accountId); static AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword); static AccountOpResult ChangePassword(uint32 accountId, std::string newPassword); @@ -62,6 +66,23 @@ class AccountMgr static bool IsGMAccount(uint32 gmlevel); static bool IsAdminAccount(uint32 gmlevel); static bool IsConsoleAccount(uint32 gmlevel); + + void UpdateAccountAccess(RBACData* rbac, uint32 accountId, uint8 securityLevel, int32 realmId); + + void LoadRBAC(); + RBACGroup const* GetRBACGroup(uint32 group) const; + RBACRole const* GetRBACRole(uint32 role) const; + RBACPermission const* GetRBACPermission(uint32 permission) const; + + RBACGroupsContainer const& GetRBACGroupList() const { return _groups; } + RBACRolesContainer const& GetRBACRoleList() const { return _roles; } + RBACPermissionsContainer const& GetRBACPermissionList() const { return _permissions; } + + private: + RBACPermissionsContainer _permissions; + RBACRolesContainer _roles; + RBACGroupsContainer _groups; + RBACDefaultSecurityGroupContainer _defaultGroups; }; #define sAccountMgr ACE_Singleton<AccountMgr, ACE_Null_Mutex>::instance() diff --git a/src/server/game/Accounts/RBAC.cpp b/src/server/game/Accounts/RBAC.cpp new file mode 100644 index 00000000000..4a069df05cd --- /dev/null +++ b/src/server/game/Accounts/RBAC.cpp @@ -0,0 +1,336 @@ +/*
+ * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "RBAC.h"
+#include "AccountMgr.h"
+#include "DatabaseEnv.h"
+
+RBACCommandResult RBACData::AddGroup(uint32 groupId, int32 realmId /* = 0 */)
+{
+ // Check if group Id exists
+ RBACGroup const* group = sAccountMgr->GetRBACGroup(groupId);
+ if (!group)
+ return RBAC_ID_DOES_NOT_EXISTS;
+
+ // Already added?
+ std::pair<std::set<uint32>::iterator, bool> ret = _groups.insert(groupId);
+ if (!ret.second)
+ return RBAC_CANT_ADD_ALREADY_ADDED;
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_RBAC_ACCOUNT_GROUP);
+ stmt->setUInt32(0, GetId());
+ stmt->setUInt32(1, groupId);
+ stmt->setInt32(2, realmId);
+ LoginDatabase.Execute(stmt);
+
+ CalculateNewPermissions();
+ }
+
+ return RBAC_OK;
+}
+
+RBACCommandResult RBACData::RemoveGroup(uint32 groupId, int32 realmId /* = 0 */)
+{
+ // could remove it?
+ if (!_groups.erase(groupId))
+ return RBAC_CANT_REVOKE_NOT_IN_LIST;
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_RBAC_ACCOUNT_GROUP);
+ stmt->setUInt32(0, GetId());
+ stmt->setUInt32(1, groupId);
+ stmt->setInt32(2, realmId);
+ LoginDatabase.Execute(stmt);
+
+ CalculateNewPermissions();
+ }
+
+ return RBAC_OK;
+}
+
+RBACCommandResult RBACData::GrantRole(uint32 roleId, int32 realmId /* = 0*/)
+{
+ // Check if role Id exists
+ RBACRole const* role = sAccountMgr->GetRBACRole(roleId);
+ if (!role)
+ return RBAC_ID_DOES_NOT_EXISTS;
+
+ // Check if already added in denied list
+ if (_deniedRoles.find(roleId) != _deniedRoles.end())
+ return RBAC_IN_DENIED_LIST;
+
+ // Already added?
+ std::pair<std::set<uint32>::iterator, bool> ret = _grantedRoles.insert(roleId);
+ if (!ret.second)
+ return RBAC_CANT_ADD_ALREADY_ADDED;
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ SaveRole(roleId, true, realmId);
+ CalculateNewPermissions();
+ }
+
+ return RBAC_OK;
+}
+
+RBACCommandResult RBACData::DenyRole(uint32 roleId, int32 realmId /* = 0*/)
+{
+ // Check if role Id exists
+ RBACRole const* role = sAccountMgr->GetRBACRole(roleId);
+ if (!role)
+ return RBAC_ID_DOES_NOT_EXISTS;
+
+ // Check if already added in granted list
+ if (_grantedRoles.find(roleId) != _grantedRoles.end())
+ return RBAC_IN_GRANTED_LIST;
+
+ // Already added?
+ std::pair<std::set<uint32>::iterator, bool> ret = _deniedRoles.insert(roleId);
+ if (!ret.second)
+ return RBAC_CANT_ADD_ALREADY_ADDED;
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ SaveRole(roleId, false, realmId);
+ CalculateNewPermissions();
+ }
+
+ return RBAC_OK;
+}
+
+void RBACData::SaveRole(uint32 roleId, bool granted, int32 realmId)
+{
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_RBAC_ACCOUNT_ROLE);
+ stmt->setUInt32(0, GetId());
+ stmt->setUInt32(1, roleId);
+ stmt->setBool(2, granted);
+ stmt->setInt32(3, realmId);
+ LoginDatabase.Execute(stmt);
+}
+
+RBACCommandResult RBACData::RevokeRole(uint32 roleId, int32 realmId /* = 0*/)
+{
+ uint8 revoked = _grantedRoles.erase(roleId) + _deniedRoles.erase(roleId);
+
+ // could remove it?
+ if (!revoked)
+ return RBAC_CANT_REVOKE_NOT_IN_LIST;
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_RBAC_ACCOUNT_ROLE);
+ stmt->setUInt32(0, GetId());
+ stmt->setUInt32(1, roleId);
+ stmt->setInt32(2, realmId);
+ LoginDatabase.Execute(stmt);
+
+ CalculateNewPermissions();
+ }
+
+ return RBAC_OK;
+}
+
+RBACCommandResult RBACData::GrantPermission(uint32 permissionId, int32 realmId /* = 0*/)
+{
+ // Check if permission Id exists
+ RBACPermission const* perm = sAccountMgr->GetRBACPermission(permissionId);
+ if (!perm)
+ return RBAC_ID_DOES_NOT_EXISTS;
+
+ // Check if already added in denied list
+ if (_deniedPerms.test(permissionId))
+ return RBAC_IN_DENIED_LIST;
+
+ // Already added?
+ if (_grantedPerms.test(permissionId))
+ return RBAC_CANT_ADD_ALREADY_ADDED;
+
+ _grantedPerms.set(permissionId);
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ SavePermission(permissionId, true, realmId);
+ CalculateNewPermissions();
+ }
+
+ return RBAC_OK;
+}
+
+RBACCommandResult RBACData::DenyPermission(uint32 permissionId, int32 realmId /* = 0*/)
+{
+ // Check if permission Id exists
+ RBACPermission const* perm = sAccountMgr->GetRBACPermission(permissionId);
+ if (!perm)
+ return RBAC_ID_DOES_NOT_EXISTS;
+
+ // Check if already added in granted list
+ if (_grantedPerms.test(permissionId))
+ return RBAC_IN_GRANTED_LIST;
+
+ // Already added?
+ if (_deniedPerms.test(permissionId))
+ return RBAC_CANT_ADD_ALREADY_ADDED;
+
+ _deniedPerms.set(permissionId);
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ SavePermission(permissionId, false, realmId);
+ CalculateNewPermissions();
+ }
+
+ return RBAC_OK;
+}
+
+void RBACData::SavePermission(uint32 permission, bool granted, int32 realmId)
+{
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_RBAC_ACCOUNT_PERMISSION);
+ stmt->setUInt32(0, GetId());
+ stmt->setUInt32(1, permission);
+ stmt->setBool(2, granted);
+ stmt->setInt32(3, realmId);
+ LoginDatabase.Execute(stmt);
+}
+
+RBACCommandResult RBACData::RevokePermission(uint32 permission, int32 realmId /* = 0*/)
+{
+ // Check if it's present in any list
+ if (!_grantedPerms.test(permission) && !_deniedPerms.test(permission))
+ return RBAC_CANT_REVOKE_NOT_IN_LIST;
+
+ _grantedPerms.reset(permission);
+ _deniedPerms.reset(permission);
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_RBAC_ACCOUNT_PERMISSION);
+ stmt->setUInt32(0, GetId());
+ stmt->setUInt32(1, permission);
+ stmt->setInt32(2, realmId);
+ LoginDatabase.Execute(stmt);
+
+ CalculateNewPermissions();
+ }
+
+ return RBAC_OK;
+}
+
+void RBACData::LoadFromDB()
+{
+ // Load account group that affect current realm
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_GROUPS);
+ stmt->setUInt32(0, GetId());
+ stmt->setInt32(1, GetRealmId());
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+
+ if (result)
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ AddGroup(fields[0].GetUInt32());
+ }
+ while (result->NextRow());
+ }
+
+ // Load account roles (granted and denied) that affect current realm
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_ROLES);
+ stmt->setUInt32(0, GetId());
+ stmt->setInt32(1, GetRealmId());
+ result = LoginDatabase.Query(stmt);
+
+ if (result)
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ if (fields[1].GetBool())
+ GrantRole(fields[0].GetUInt32());
+ else
+ DenyRole(fields[0].GetUInt32());
+ }
+ while (result->NextRow());
+ }
+
+ // Load account permissions (granted and denied) that affect current realm
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS);
+ stmt->setUInt32(0, GetId());
+ stmt->setInt32(1, GetRealmId());
+
+ result = LoginDatabase.Query(stmt);
+ if (result)
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ if (fields[1].GetBool())
+ GrantPermission(fields[0].GetUInt32());
+ else
+ DenyPermission(fields[0].GetUInt32());
+ }
+ while (result->NextRow());
+ }
+
+ // Force calculation of permissions, it wasn't performed at load time
+ // while adding groups, roles and permissions
+ CalculateNewPermissions();
+}
+
+void RBACData::CalculateNewPermissions()
+{
+ // Get the list of directly granted roles
+ RBACRoleContainer tempGrantedRoles = GetGrantedRoles();
+
+ // Add those roles inherited from groups
+ for (RBACGroupContainer::const_iterator itGroup = _groups.begin(); itGroup != _groups.end(); ++itGroup)
+ {
+ RBACGroup const* group = sAccountMgr->GetRBACGroup(*itGroup);
+ if (!group) // Should never happen due to foreign keys in DB
+ continue;
+
+ RBACRoleContainer const& roles = group->GetRoles();
+ for (RBACRoleContainer::const_iterator it = roles.begin(); it != roles.end(); ++it)
+ tempGrantedRoles.insert(*it);
+ }
+
+ // Get the list of granted permissions
+ _globalPerms = GetGrantedPermissions();
+
+ // Add those permissions inherited from roles granted
+ for (RBACRoleContainer::const_iterator it = tempGrantedRoles.begin(); it != tempGrantedRoles.end(); ++it)
+ if (RBACRole const* role = sAccountMgr->GetRBACRole(*it))
+ _globalPerms |= role->GetPermissions();
+
+ // Remove denied permissions from the list
+ _globalPerms &= ~GetDeniedPermissions();
+
+ // Remove those permissions inherited from denied roles
+ for (RBACRoleContainer::const_iterator it = _deniedRoles.begin(); it != _deniedRoles.end(); ++it)
+ if (RBACRole const* role = sAccountMgr->GetRBACRole(*it))
+ _globalPerms &= ~role->GetPermissions();
+}
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h new file mode 100644 index 00000000000..5420df29d17 --- /dev/null +++ b/src/server/game/Accounts/RBAC.h @@ -0,0 +1,410 @@ +/*
+ * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+* @file RBAC.h
+* @brief Role Based Access Control related classes definition
+*
+* This file contains all the classes and enums used to implement
+* Role Based Access Control
+*
+* RBAC Rules:
+* - Pemission: Defines an autorization to perform certain operation.
+* - Role: Set of permissions.
+* - Group: Set of roles.
+* - An Account can have multiple groups, roles and permissions.
+* - Account Groups can only be granted or revoked
+* - Account Roles and Permissions can be granted, denied or revoked
+* - Grant: Assignment of the object (role/permission) and allow it
+* - Deny: Assignment of the object (role/permission) and deny it
+* - Revoke: Removal of the object (role/permission) no matter if it was granted or denied
+* - Global Permissions are computed as:
+* Group Grants + Role Grants + User Grans - Role Grants - User Grants
+* - Groups, Roles and Permissions can be assigned by realm
+*/
+
+#ifndef _RBAC_H
+#define _RBAC_H
+
+#include "Define.h"
+#include <string>
+#include <bitset>
+#include <set>
+#include <map>
+
+enum RBACPermissions
+{
+ RBAC_PERM_INSTANT_LOGOUT = 1,
+ RBAC_PERM_SKIP_QUEUE,
+ RBAC_PERM_JOIN_NORMAL_BG,
+ RBAC_PERM_JOIN_RANDOM_BG,
+ RBAC_PERM_JOIN_ARENAS,
+ RBAC_PERM_JOIN_DUNGEON_FINDER,
+ RBAC_PERM_PLAYER_COMMANDS,
+ RBAC_PERM_MODERATOR_COMMANDS,
+ RBAC_PERM_GAMEMASTER_COMMANDS,
+ RBAC_PERM_ADMINISTRATOR_COMMANDS,
+ RBAC_PERM_MAX
+};
+
+enum RBACCommandResult
+{
+ RBAC_OK,
+ RBAC_CANT_ADD_ALREADY_ADDED,
+ RBAC_CANT_REVOKE_NOT_IN_LIST,
+ RBAC_IN_GRANTED_LIST,
+ RBAC_IN_DENIED_LIST,
+ RBAC_ID_DOES_NOT_EXISTS
+};
+
+typedef std::bitset<RBAC_PERM_MAX> RBACPermissionContainer;
+typedef std::set<uint32> RBACRoleContainer;
+typedef std::set<uint32> RBACGroupContainer;
+
+class RBACObject
+{
+ public:
+ RBACObject(uint32 id = 0, std::string const& name = ""):
+ _id(id), _name(name) { }
+
+ /// Gets the Name of the Object
+ std::string const& GetName() const { return _name; }
+ /// Gets the Id of the Object
+ uint32 GetId() const { return _id; }
+
+ private:
+ uint32 _id; ///> id of the object
+ std::string _name; ///> name of the object
+};
+
+/// Permission: Defines an autorization to perform certain operation
+class RBACPermission: public RBACObject
+{
+ public:
+ RBACPermission(uint32 id = 0, std::string const& name = ""):
+ RBACObject(id, name) { }
+};
+
+/// Set of Permissions
+class RBACRole: public RBACObject
+{
+ public:
+ RBACRole(uint32 id = 0, std::string const& name = ""):
+ RBACObject(id, name) { }
+
+ /// Gets the Permissions assigned to this role
+ RBACPermissionContainer const& GetPermissions() const { return _perms; }
+ /// Grants a Permission (Adds)
+ void GrantPermission(uint32 id) { _perms.set(id); }
+ /// Revokes a Permission (Removes)
+ void RevokePermission(uint32 id) { _perms.reset(id); }
+
+ private:
+ RBACPermissionContainer _perms; ///> Set of permissions
+};
+
+/// Set of Roles
+class RBACGroup: public RBACObject
+{
+ public:
+ RBACGroup(uint32 id = 0, std::string const& name = ""):
+ RBACObject(id, name) { }
+
+ /// Gets the Roles assigned to this group
+ RBACRoleContainer const& GetRoles() const { return _roles; }
+ /// Grants a Role (Adds)
+ void GrantRole(uint32 role) { _roles.insert(role); }
+ /// Revokes a Role (Removes)
+ void RevokeRole(uint32 role) { _roles.erase(role); }
+
+ private:
+ RBACRoleContainer _roles; ///> Set of Roles
+};
+
+/*
+ * @name RBACData
+ * @brief Contains all needed information about the acccount
+ *
+ * This class contains all the data needed to calculate the account permissions.
+ * RBACDAta is formed by group permissions and user permissions through:
+ * - Granted Groups, which contains roles, which contains permissions: Set of granted permissions
+ * - Granted Roles, which contains permissions: Set of granted permissions
+ * - Denied Roles, which contains permissions: Set of denied permissions
+ * - Granted Permissions
+ * - Denied Permissions
+ *
+ * Calculation of current Permissions: Granted permissions - Denied permissions
+ * - Granted permissions: through groups, through roles and directly assigned
+ * - Denied permissions: through roles and directly assigned
+ */
+class RBACData: public RBACObject
+{
+ public:
+ RBACData(uint32 id, std::string const& name, int32 realmId):
+ RBACObject(id, name), _realmId(realmId) { }
+
+ /**
+ * @name HasPermission
+ * @brief Checks if certain action is allowed
+ *
+ * Checks if certain action can be performed.
+ *
+ * @return grant or deny action
+ *
+ * Example Usage:
+ * @code
+ * bool Player::CanJoinArena(Battleground* bg)
+ * {
+ * return bg->isArena() && HasPermission(RBAC_PERM_JOIN_ARENA);
+ * }
+ * @endcode
+ */
+ bool HasPermission(uint32 permission) { return _globalPerms.test(permission); }
+
+ // Functions enabled to be used by command system
+ /// Returns all the granted permissions (after computation)
+ RBACPermissionContainer const& GetPermissions() const { return _globalPerms; }
+ /// Returns all the granted permissions
+ RBACPermissionContainer const& GetGrantedPermissions() const { return _grantedPerms; }
+ /// Returns all the denied permissions
+ RBACPermissionContainer const& GetDeniedPermissions() const { return _deniedPerms; }
+ /// Returns all the granted roles
+ RBACRoleContainer const& GetGrantedRoles() const { return _grantedRoles; }
+ /// Returns all the denied roles
+ RBACRoleContainer const& GetDeniedRoles() const { return _deniedRoles; }
+ /// Returns all the granted groups
+ RBACGroupContainer const& GetGroups() const { return _groups; }
+
+ /**
+ * @name AddGroup
+ * @brief Adds new group
+ *
+ * Add a new group to the account. If realm is 0 or the group can not be added
+ * No save to db action will be performed.
+ *
+ * Fails if group Id does not exists or group already present
+ *
+ * @param groupId group to be added
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to add the group
+ *
+ * Example Usage:
+ * @code
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 groupId = 2;
+ * if (rbac->AddGroup(groupId) == RBAC_OK)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Group %u succesfully added", groupId);
+ * @endcode
+ */
+ RBACCommandResult AddGroup(uint32 groupId, int32 realmId = 0);
+
+ /**
+ * @name RemoveGroup
+ * @brief Removes a group
+ *
+ * Removes a group from the account. If realm is 0 or the group can not be removed
+ * No save to db action will be performed. Any delete operation will always affect
+ * "all realms (-1)" in addition to the realm specified
+ *
+ * Fails if group not present
+ *
+ * @param groupId group to be removed
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to remove the group
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 groupId = 2;
+ * if (rbac->RemoveGroup(groupId) == RBAC_OK)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Group %u succesfully removed", groupId);
+ * @endcode
+ */
+ RBACCommandResult RemoveGroup(uint32 groupId, int32 realmId = 0);
+
+ /**
+ * @name GrantRole
+ * @brief Grants a role
+ *
+ * Grants a role to the account. If realm is 0 or the role can not be added
+ * No save to db action will be performed.
+ *
+ * Fails if role Id does not exists or role already granted or denied
+ *
+ * @param roleId role to be granted
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to grant the role
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 roleId = 2;
+ * if (rbac->GrantRole(roleId) == RBAC_IN_DENIED_LIST)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Failed to grant role %u, already denied", roleId);
+ * @endcode
+ */
+ RBACCommandResult GrantRole(uint32 roleId, int32 realmId = 0);
+
+ /**
+ * @name DenyRole
+ * @brief Denies a role
+ *
+ * Denied a role to the account. If realm is 0 or the role can not be added
+ * No save to db action will be performed.
+ *
+ * Fails if role Id does not exists or role already granted or denied
+ *
+ * @param roleId role to be denied
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to deny the role
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 roleId = 2;
+ * if (rbac->DenyRole(roleId) == RBAC_ID_DOES_NOT_EXISTS)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Role Id %u does not exists", roleId);
+ * @endcode
+ */
+ RBACCommandResult DenyRole(uint32 roleId, int32 realmId = 0);
+
+ /**
+ * @name RevokeRole
+ * @brief Removes a role
+ *
+ * Removes a role from the account. If realm is 0 or the role can not be removed
+ * No save to db action will be performed. Any delete operation will always affect
+ * "all realms (-1)" in addition to the realm specified
+ *
+ * Fails if role not present
+ *
+ * @param roleId role to be removed
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to remove the role
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 roleId = 2;
+ * if (rbac->RevokeRole(roleId) == RBAC_OK)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Role %u succesfully removed", roleId);
+ * @endcode
+ */
+ RBACCommandResult RevokeRole(uint32 roleId, int32 realmId = 0);
+
+ /**
+ * @name GrantRole
+ * @brief Grants a permission
+ *
+ * Grants a permission to the account. If realm is 0 or the permission can not be added
+ * No save to db action will be performed.
+ *
+ * Fails if permission Id does not exists or permission already granted or denied
+ *
+ * @param permissionId permission to be granted
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to grant the permission
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 permissionId = 2;
+ * if (rbac->GrantRole(permissionId) == RBAC_IN_DENIED_LIST)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Failed to grant permission %u, already denied", permissionId);
+ * @endcode
+ */
+ RBACCommandResult GrantPermission(uint32 permissionId, int32 realmId = 0);
+
+ /**
+ * @name DenyPermission
+ * @brief Denies a permission
+ *
+ * Denied a permission to the account. If realm is 0 or the permission can not be added
+ * No save to db action will be performed.
+ *
+ * Fails if permission Id does not exists or permission already granted or denied
+ *
+ * @param permissionId permission to be denied
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to deny the permission
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 permissionId = 2;
+ * if (rbac->DenyRole(permissionId) == RBAC_ID_DOES_NOT_EXISTS)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Role Id %u does not exists", permissionId);
+ * @endcode
+ */
+ RBACCommandResult DenyPermission(uint32 permissionId, int32 realmId = 0);
+
+ /**
+ * @name RevokePermission
+ * @brief Removes a permission
+ *
+ * Removes a permission from the account. If realm is 0 or the permission can not be removed
+ * No save to db action will be performed. Any delete operation will always affect
+ * "all realms (-1)" in addition to the realm specified
+ *
+ * Fails if permission not present
+ *
+ * @param permissionId permission to be removed
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to remove the permission
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 permissionId = 2;
+ * if (rbac->RevokeRole(permissionId) == RBAC_OK)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Permission %u succesfully removed", permissionId);
+ * @endcode
+ */
+ RBACCommandResult RevokePermission(uint32 permissionId, int32 realmId = 0);
+
+ /// Loads all permissions, groups and roles assigned to current account
+ void LoadFromDB();
+ private:
+ /// Saves a role to DB, Granted or Denied
+ void SaveRole(uint32 role, bool granted, int32 realm);
+ /// Saves a permission to DB, Granted or Denied
+ void SavePermission(uint32 role, bool granted, int32 realm);
+
+ /**
+ * @name CalculateNewPermissions
+ * @brief Calculates new permissions
+ *
+ * Calculates new permissions after some change in groups, roles or permissions.
+ * The calculation is done Granted - Denied:
+ * - Granted permissions: through groups, through roles and directly assigned
+ * - Denied permissions: through roles and directly assigned
+ */
+ void CalculateNewPermissions();
+
+ int32 GetRealmId() { return _realmId; }
+
+ int32 _realmId; ///> RealmId Affected
+ RBACGroupContainer _groups; ///> Granted groups
+ RBACRoleContainer _grantedRoles; ///> Granted roles
+ RBACRoleContainer _deniedRoles; ///> Denied roles
+ RBACPermissionContainer _grantedPerms; ///> Granted permissions
+ RBACPermissionContainer _deniedPerms; ///> Denied permissions
+ RBACPermissionContainer _globalPerms; ///> Calculated permissions
+};
+
+#endif
diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 2fd55ac29ef..1de9c785ed2 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -2209,6 +2209,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaList() return; } + uint32 loaded = 0; for (uint32 entryId = 0; entryId < sAchievementCriteriaStore.GetNumRows(); ++entryId) { AchievementCriteriaEntry const* criteria = sAchievementMgr->GetAchievementCriteria(entryId); @@ -2220,9 +2221,11 @@ void AchievementGlobalMgr::LoadAchievementCriteriaList() if (criteria->timeLimit) m_AchievementCriteriasByTimedType[criteria->timedType].push_back(criteria); + + ++loaded; } - sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %lu achievement criteria in %u ms", (unsigned long)m_AchievementCriteriasByType->size(), GetMSTimeDiffToNow(oldMSTime)); + sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u achievement criteria in %u ms", loaded, GetMSTimeDiffToNow(oldMSTime)); } void AchievementGlobalMgr::LoadAchievementReferenceList() @@ -2284,14 +2287,14 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData() } uint32 dataType = fields[1].GetUInt8(); - const char* scriptName = fields[4].GetCString(); + std::string scriptName = fields[4].GetString(); uint32 scriptId = 0; - if (strcmp(scriptName, "")) // not empty + if (scriptName.length()) // not empty { if (dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT) sLog->outError(LOG_FILTER_SQL, "Table `achievement_criteria_data` has ScriptName set for non-scripted data type (Entry: %u, type %u), useless data.", criteria_id, dataType); else - scriptId = sObjectMgr->GetScriptId(scriptName); + scriptId = sObjectMgr->GetScriptId(scriptName.c_str()); } AchievementCriteriaData data(dataType, fields[2].GetUInt32(), fields[3].GetUInt32(), scriptId); diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index 0bf7c8591e3..b8f80fb36ac 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -122,8 +122,27 @@ const char *ChatHandler::GetTrinityString(int32 entry) const bool ChatHandler::isAvailable(ChatCommand const& cmd) const { - // check security level only for simple command (without child commands) - return m_session->GetSecurity() >= AccountTypes(cmd.SecurityLevel); + uint32 permission = 0; + + ///@Workaround:: Fast adaptation to RBAC system till all commands are moved to permissions + switch (AccountTypes(cmd.SecurityLevel)) + { + case SEC_ADMINISTRATOR: + permission = RBAC_PERM_ADMINISTRATOR_COMMANDS; + break; + case SEC_GAMEMASTER: + permission = RBAC_PERM_GAMEMASTER_COMMANDS; + break; + case SEC_MODERATOR: + permission = RBAC_PERM_MODERATOR_COMMANDS; + break; + case SEC_PLAYER: + default: + permission = RBAC_PERM_PLAYER_COMMANDS; + break; + } + + return m_session->HasPermission(permission); } bool ChatHandler::HasLowerSecurity(Player* target, uint64 guid, bool strong) @@ -431,7 +450,7 @@ bool ChatHandler::ParseCommands(char const* text) std::string fullcmd = text; - if (m_session && AccountMgr::IsPlayerAccount(m_session->GetSecurity()) && !sWorld->getBoolConfig(CONFIG_ALLOW_PLAYER_COMMANDS)) + if (m_session && !m_session->HasPermission(RBAC_PERM_PLAYER_COMMANDS)) return false; /// chat case (.command or !command format) diff --git a/src/server/game/DungeonFinding/LFG.cpp b/src/server/game/DungeonFinding/LFG.cpp new file mode 100644 index 00000000000..ce16ad5533e --- /dev/null +++ b/src/server/game/DungeonFinding/LFG.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "LFG.h" +#include "Language.h" +#include "ObjectMgr.h" + +namespace lfg +{ + +std::string ConcatenateDungeons(LfgDungeonSet const& dungeons) +{ + std::string dungeonstr = ""; + if (!dungeons.empty()) + { + std::ostringstream o; + LfgDungeonSet::const_iterator it = dungeons.begin(); + o << (*it); + for (++it; it != dungeons.end(); ++it) + o << ", " << uint32(*it); + dungeonstr = o.str(); + } + return dungeonstr; +} + +std::string GetRolesString(uint8 roles) +{ + std::string rolesstr = ""; + + if (roles & PLAYER_ROLE_TANK) + rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_TANK)); + + if (roles & PLAYER_ROLE_HEALER) + { + if (!rolesstr.empty()) + rolesstr.append(", "); + rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_HEALER)); + } + + if (roles & PLAYER_ROLE_DAMAGE) + { + if (!rolesstr.empty()) + rolesstr.append(", "); + rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_DAMAGE)); + } + + if (roles & PLAYER_ROLE_LEADER) + { + if (!rolesstr.empty()) + rolesstr.append(", "); + rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_LEADER)); + } + + if (rolesstr.empty()) + rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_NONE)); + + return rolesstr; +} + +std::string GetStateString(LfgState state) +{ + int32 entry = LANG_LFG_ERROR; + switch (state) + { + case LFG_STATE_NONE: + entry = LANG_LFG_STATE_NONE; + break; + case LFG_STATE_ROLECHECK: + entry = LANG_LFG_STATE_ROLECHECK; + break; + case LFG_STATE_QUEUED: + entry = LANG_LFG_STATE_QUEUED; + break; + case LFG_STATE_PROPOSAL: + entry = LANG_LFG_STATE_PROPOSAL; + break; + case LFG_STATE_DUNGEON: + entry = LANG_LFG_STATE_DUNGEON; + break; + case LFG_STATE_BOOT: + entry = LANG_LFG_STATE_BOOT; + break; + case LFG_STATE_FINISHED_DUNGEON: + entry = LANG_LFG_STATE_FINISHED_DUNGEON; + break; + case LFG_STATE_RAIDBROWSER: + entry = LANG_LFG_STATE_RAIDBROWSER; + break; + } + + return std::string(sObjectMgr->GetTrinityStringForDBCLocale(entry)); +} + +} // namespace lfg diff --git a/src/server/game/DungeonFinding/LFG.h b/src/server/game/DungeonFinding/LFG.h index ebbcfb1d71a..541e4d6bd43 100644 --- a/src/server/game/DungeonFinding/LFG.h +++ b/src/server/game/DungeonFinding/LFG.h @@ -20,6 +20,9 @@ #include "Common.h" +namespace lfg +{ + enum LFGEnum { LFG_TANKS_NEEDED = 1, @@ -99,4 +102,10 @@ typedef std::list<uint64> LfgGuidList; typedef std::map<uint64, uint8> LfgRolesMap; typedef std::map<uint64, uint64> LfgGroupsMap; +std::string ConcatenateDungeons(LfgDungeonSet const& dungeons); +std::string GetRolesString(uint8 roles); +std::string GetStateString(LfgState state); + +} // namespace lfg + #endif diff --git a/src/server/game/DungeonFinding/LFGGroupData.cpp b/src/server/game/DungeonFinding/LFGGroupData.cpp index 427225bf323..f711514e26d 100644 --- a/src/server/game/DungeonFinding/LFGGroupData.cpp +++ b/src/server/game/DungeonFinding/LFGGroupData.cpp @@ -18,6 +18,9 @@ #include "LFG.h" #include "LFGGroupData.h" +namespace lfg +{ + LfgGroupData::LfgGroupData(): m_State(LFG_STATE_NONE), m_OldState(LFG_STATE_NONE), m_Leader(0), m_Dungeon(0), m_KicksLeft(LFG_GROUP_MAX_KICKS) { } @@ -122,3 +125,5 @@ uint8 LfgGroupData::GetKicksLeft() const { return m_KicksLeft; } + +} // namespace lfg diff --git a/src/server/game/DungeonFinding/LFGGroupData.h b/src/server/game/DungeonFinding/LFGGroupData.h index 2ad020d3bc1..47e562c37aa 100644 --- a/src/server/game/DungeonFinding/LFGGroupData.h +++ b/src/server/game/DungeonFinding/LFGGroupData.h @@ -20,6 +20,9 @@ #include "LFG.h" +namespace lfg +{ + enum LfgGroupEnum { LFG_GROUP_MAX_KICKS = 3, @@ -75,4 +78,6 @@ class LfgGroupData uint8 m_KicksLeft; ///< Number of kicks left }; +} // namespace lfg + #endif diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index 0f23925cc2b..e18a103e21c 100644 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -33,6 +33,9 @@ #include "GameEventMgr.h" #include "WorldSession.h" +namespace lfg +{ + LFGMgr::LFGMgr(): m_QueueTimer(0), m_lfgProposalId(1), m_options(sWorld->getIntConfig(CONFIG_LFG_OPTIONSMASK)) { @@ -95,89 +98,6 @@ void LFGMgr::_SaveToDB(uint64 guid, uint32 db_guid) CharacterDatabase.Execute(stmt); } -std::string LFGMgr::ConcatenateDungeons(LfgDungeonSet const& dungeons) -{ - std::string dungeonstr = ""; - if (!dungeons.empty()) - { - std::ostringstream o; - LfgDungeonSet::const_iterator it = dungeons.begin(); - o << (*it); - for (++it; it != dungeons.end(); ++it) - o << ", " << uint32(*it); - dungeonstr = o.str(); - } - return dungeonstr; -} - -std::string LFGMgr::GetRolesString(uint8 roles) -{ - std::string rolesstr = ""; - - if (roles & PLAYER_ROLE_TANK) - rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_TANK)); - - if (roles & PLAYER_ROLE_HEALER) - { - if (!rolesstr.empty()) - rolesstr.append(", "); - rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_HEALER)); - } - - if (roles & PLAYER_ROLE_DAMAGE) - { - if (!rolesstr.empty()) - rolesstr.append(", "); - rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_DAMAGE)); - } - - if (roles & PLAYER_ROLE_LEADER) - { - if (!rolesstr.empty()) - rolesstr.append(", "); - rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_LEADER)); - } - - if (rolesstr.empty()) - rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_NONE)); - - return rolesstr; -} - -std::string LFGMgr::GetStateString(LfgState state) -{ - int32 entry = LANG_LFG_ERROR; - switch (state) - { - case LFG_STATE_NONE: - entry = LANG_LFG_STATE_NONE; - break; - case LFG_STATE_ROLECHECK: - entry = LANG_LFG_STATE_ROLECHECK; - break; - case LFG_STATE_QUEUED: - entry = LANG_LFG_STATE_QUEUED; - break; - case LFG_STATE_PROPOSAL: - entry = LANG_LFG_STATE_PROPOSAL; - break; - case LFG_STATE_DUNGEON: - entry = LANG_LFG_STATE_DUNGEON; - break; - case LFG_STATE_BOOT: - entry = LANG_LFG_STATE_BOOT; - break; - case LFG_STATE_FINISHED_DUNGEON: - entry = LANG_LFG_STATE_FINISHED_DUNGEON; - break; - case LFG_STATE_RAIDBROWSER: - entry = LANG_LFG_STATE_RAIDBROWSER; - break; - } - - return std::string(sObjectMgr->GetTrinityStringForDBCLocale(entry)); -} - /// Load rewards for completing dungeons void LFGMgr::LoadRewards() { @@ -207,7 +127,7 @@ void LFGMgr::LoadRewards() uint32 firstQuestId = fields[2].GetUInt32(); uint32 otherQuestId = fields[3].GetUInt32(); - if (!GetLFGDungeon(dungeonId)) + if (!GetLFGDungeonEntry(dungeonId)) { sLog->outError(LOG_FILTER_SQL, "Dungeon %u specified in table `lfg_dungeon_rewards` does not exist!", dungeonId); continue; @@ -248,11 +168,6 @@ LFGDungeonData const* LFGMgr::GetLFGDungeon(uint32 id) return NULL; } -LFGDungeonContainer & LFGMgr::GetLFGDungeonMap() -{ - return LfgDungeonStore; -} - void LFGMgr::LoadLFGDungeons(bool reload /* = false */) { uint32 oldMSTime = getMSTime(); @@ -464,6 +379,7 @@ void LFGMgr::InitializeLockedDungeons(Player* player, uint8 level /* = 0 */) uint8 expansion = player->GetSession()->Expansion(); LfgDungeonSet const& dungeons = GetDungeonsByRandom(0); LfgLockMap lock; + bool denyJoin = !player->GetSession()->HasPermission(RBAC_PERM_JOIN_DUNGEON_FINDER); for (LfgDungeonSet::const_iterator it = dungeons.begin(); it != dungeons.end(); ++it) { @@ -472,7 +388,9 @@ void LFGMgr::InitializeLockedDungeons(Player* player, uint8 level /* = 0 */) continue; uint32 lockData = 0; - if (dungeon->expansion > expansion) + if (denyJoin) + lockData = LFG_LOCKSTATUS_RAID_LOCKED; + else if (dungeon->expansion > expansion) lockData = LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION; else if (DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, dungeon->map, player)) lockData = LFG_LOCKSTATUS_RAID_LOCKED; @@ -554,7 +472,9 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const } // Check player or group member restrictions - if (player->InBattleground() || player->InArena() || player->InBattlegroundQueue()) + if (!player->GetSession()->HasPermission(RBAC_PERM_JOIN_DUNGEON_FINDER)) + joinData.result = LFG_JOIN_NOT_MEET_REQS; + else if (player->InBattleground() || player->InArena() || player->InBattlegroundQueue()) joinData.result = LFG_JOIN_USING_BG_SYSTEM; else if (player->HasAura(LFG_SPELL_DUNGEON_DESERTER)) joinData.result = LFG_JOIN_DESERTER; @@ -573,6 +493,8 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const { if (Player* plrg = itr->getSource()) { + if (!plrg->GetSession()->HasPermission(RBAC_PERM_JOIN_DUNGEON_FINDER)) + joinData.result = LFG_JOIN_PARTY_NOT_MEET_REQS; if (plrg->HasAura(LFG_SPELL_DUNGEON_DESERTER)) joinData.result = LFG_JOIN_PARTY_DESERTER; else if (plrg->HasAura(LFG_SPELL_DUNGEON_COOLDOWN)) @@ -1675,7 +1597,7 @@ const std::string& LFGMgr::GetComment(uint64 guid) return PlayersStore[guid].GetComment(); } -bool LFGMgr::IsTeleported(uint64 pguid) +bool LFGMgr::hasPendingTeleport(uint64 pguid) { if (std::find(teleportStore.begin(), teleportStore.end(), pguid) != teleportStore.end()) { @@ -2039,3 +1961,56 @@ void LFGMgr::SetupGroupMember(uint64 guid, uint64 gguid) SetGroup(guid, gguid); AddPlayerToGroup(gguid, guid); } + +bool LFGMgr::selectedRandomLfgDungeon(uint64 guid) +{ + if (GetState(guid) != LFG_STATE_NONE) + { + LfgDungeonSet const& dungeons = GetSelectedDungeons(guid); + if (!dungeons.empty()) + { + LFGDungeonData const* dungeon = GetLFGDungeon(*dungeons.begin()); + if (dungeon && (dungeon->type == LFG_TYPE_RANDOM || dungeon->seasonal)) + return true; + } + } + + return false; +} + +bool LFGMgr::inLfgDungeonMap(uint64 guid, uint32 map, Difficulty difficulty) +{ + if (!IS_GROUP_GUID(guid)) + guid = GetGroup(guid); + + if (uint32 dungeonId = GetDungeon(guid, true)) + if (LFGDungeonData const* dungeon = GetLFGDungeon(dungeonId)) + if (uint32(dungeon->map) == map && dungeon->difficulty == difficulty) + return true; + + return false; +} + +uint32 LFGMgr::GetLFGDungeonEntry(uint32 id) +{ + if (id) + if (LFGDungeonData const* dungeon = GetLFGDungeon(id)) + return dungeon->Entry(); + + return 0; +} + +LfgDungeonSet LFGMgr::GetRandomAndSeasonalDungeons(uint8 level, uint8 expansion) +{ + LfgDungeonSet randomDungeons; + for (lfg::LFGDungeonContainer::const_iterator itr = LfgDungeonStore.begin(); itr != LfgDungeonStore.end(); ++itr) + { + lfg::LFGDungeonData const& dungeon = itr->second; + if ((dungeon.type == lfg::LFG_TYPE_RANDOM || (dungeon.seasonal && sLFGMgr->IsSeasonActive(dungeon.id))) + && dungeon.expansion <= expansion && dungeon.minlevel <= level && level <= dungeon.maxlevel) + randomDungeons.insert(dungeon.Entry()); + } + return randomDungeons; +} + +} // namespace lfg diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h index 74c7ca9e3d3..07c4281f86f 100644 --- a/src/server/game/DungeonFinding/LFGMgr.h +++ b/src/server/game/DungeonFinding/LFGMgr.h @@ -30,6 +30,9 @@ class Group; class Player; class Quest; +namespace lfg +{ + enum LfgOptions { LFG_OPTION_ENABLE_DUNGEON_FINDER = 0x01, @@ -296,91 +299,125 @@ class LFGMgr ~LFGMgr(); public: + // Functions used outside lfg namespace void Update(uint32 diff); - // Reward - void LoadRewards(); + // World.cpp + /// Finish the dungeon for the given group. All check are performed using internal lfg data void FinishDungeon(uint64 gguid, uint32 dungeonId); - LfgReward const* GetRandomDungeonReward(uint32 dungeon, uint8 level); - - // Queue - void JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, std::string const& comment); - void LeaveLfg(uint64 guid); - - // Role Check - void UpdateRoleCheck(uint64 gguid, uint64 guid = 0, uint8 roles = PLAYER_ROLE_NONE); - - // Group Matching - static bool CheckGroupRoles(LfgRolesMap &groles, bool removeLeaderFlag = true); - void GetCompatibleDungeons(LfgDungeonSet& dungeons, LfgGuidSet const& players, LfgLockPartyMap& lockMap); - - // Proposals - uint32 AddProposal(LfgProposal& proposal); - void UpdateProposal(uint32 proposalId, uint64 guid, bool accept); + /// Loads rewards for random dungeons + void LoadRewards(); + /// Loads dungeons from dbc and adds teleport coords + void LoadLFGDungeons(bool reload = false); - // Teleportation - void TeleportPlayer(Player* player, bool out, bool fromOpcode = false); + // Multiple files + /// Check if given guid applied for random dungeon + bool selectedRandomLfgDungeon(uint64 guid); + /// Check if given guid applied for given map and difficulty. Used to know + bool inLfgDungeonMap(uint64 guid, uint32 map, Difficulty difficulty); + /// Get selected dungeons + LfgDungeonSet const& GetSelectedDungeons(uint64 guid); + /// Get current lfg state + LfgState GetState(uint64 guid); + /// Get current dungeon + uint32 GetDungeon(uint64 guid, bool asId = true); + /// Get the map id of the current dungeon + uint32 GetDungeonMapId(uint64 guid); + /// Get kicks left in current group + uint8 GetKicksLeft(uint64 gguid); + /// Load Lfg group info from DB + void _LoadFromDB(Field* fields, uint64 guid); + /// Initializes player data after loading group data from DB + void SetupGroupMember(uint64 guid, uint64 gguid); + /// Player has pending teleport action + bool hasPendingTeleport(uint64 guid); + /// Return Lfg dungeon entry for given dungeon id + uint32 GetLFGDungeonEntry(uint32 id); - // Vote kick - void InitBoot(uint64 gguid, uint64 kguid, uint64 vguid, std::string const& reason); - void UpdateBoot(uint64 guid, bool accept); + // cs_lfg + /// Get current player roles + uint8 GetRoles(uint64 guid); + /// Get current player comment (used for LFR) + std::string const& GetComment(uint64 gguid); + /// Gets current lfg options + uint32 GetOptions(); // cs_lfg + /// Sets new lfg options + void SetOptions(uint32 options); + /// Checks if given lfg option is enabled + bool isOptionEnabled(uint32 option); + /// Clears queue - Only for internal testing + void Clean(); + /// Dumps the state of the queue - Only for internal testing + std::string DumpQueueInfo(bool full = false); + // LFGScripts + /// Get leader of the group (using internal data) + uint64 GetLeader(uint64 guid); + /// Initializes locked dungeons for given player (called at login or level change) void InitializeLockedDungeons(Player* player, uint8 level = 0); - - void SetRoles(uint64 guid, uint8 roles); - void SetComment(uint64 guid, std::string const& comment); + /// Inits new proposal to boot a player + void InitBoot(uint64 gguid, uint64 kguid, uint64 vguid, std::string const& reason); + /// Sets player team void SetTeam(uint64 guid, uint8 team); + /// Sets player group void SetGroup(uint64 guid, uint64 group); + /// Gets player group + uint64 GetGroup(uint64 guid); + /// Sets the leader of the group void SetLeader(uint64 gguid, uint64 leader); - void SetState(uint64 guid, LfgState state); - - void _LoadFromDB(Field* fields, uint64 guid); - void _SaveToDB(uint64 guid, uint32 db_guid); - - void RemovePlayerData(uint64 guid); + /// Removes saved group data void RemoveGroupData(uint64 guid); + /// Removes a player from a group uint8 RemovePlayerFromGroup(uint64 gguid, uint64 guid); + /// Adds player to group void AddPlayerToGroup(uint64 gguid, uint64 guid); + // LFGHandler + /// Get locked dungeons LfgLockMap const& GetLockedDungeons(uint64 guid); - LfgDungeonSet const& GetSelectedDungeons(uint64 guid); - uint32 GetDungeon(uint64 guid, bool asId = true); - uint32 GetDungeonMapId(uint64 guid); - LfgState GetState(uint64 guid); + /// Returns current lfg status + LfgUpdateData GetLfgStatus(uint64 guid); + /// Checks if Seasonal dungeon is active + bool IsSeasonActive(uint32 dungeonId); + /// Gets the random dungeon reward corresponding to given dungeon and player level + LfgReward const* GetRandomDungeonReward(uint32 dungeon, uint8 level); + /// Returns all random and seasonal dungeons for given level and expansion + LfgDungeonSet GetRandomAndSeasonalDungeons(uint8 level, uint8 expansion); + /// Teleport a player to/from selected dungeon + void TeleportPlayer(Player* player, bool out, bool fromOpcode = false); + /// Updates player boot proposal with new player answer + void UpdateBoot(uint64 guid, bool accept); + /// Updates proposal to join dungeon with player answer + void UpdateProposal(uint32 proposalId, uint64 guid, bool accept); + /// Updates the role check with player answer + void UpdateRoleCheck(uint64 gguid, uint64 guid = 0, uint8 roles = PLAYER_ROLE_NONE); + /// Sets player lfg roles + void SetRoles(uint64 guid, uint8 roles); + /// Sets player lfr comment + void SetComment(uint64 guid, std::string const& comment); + /// Join Lfg with selected roles, dungeons and comment + void JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, std::string const& comment); + /// Leaves lfg + void LeaveLfg(uint64 guid); + + // LfgQueue + /// Get last lfg state (NONE, DUNGEON or FINISHED_DUNGEON) LfgState GetOldState(uint64 guid); - uint8 GetKicksLeft(uint64 gguid); - uint64 GetLeader(uint64 guid); + /// Check if given group guid is lfg bool IsLfgGroup(uint64 guid); - uint8 GetRoles(uint64 guid); - std::string const& GetComment(uint64 gguid); - LfgGuidSet const& GetPlayers(uint64 guid); + /// Gets the player count of given group uint8 GetPlayerCount(uint64 guid); - - bool IsTeleported(uint64 guid); - + /// Add a new Proposal + uint32 AddProposal(LfgProposal& proposal); + /// Checks if all players are queued bool AllQueued(LfgGuidList const& check); - void Clean(); - + /// Checks if given roles match, modifies given roles map with new roles + static bool CheckGroupRoles(LfgRolesMap &groles, bool removeLeaderFlag = true); + /// Checks if given players are ignoring each other static bool HasIgnore(uint64 guid1, uint64 guid2); + /// Sends queue status to player static void SendLfgQueueStatus(uint64 guid, LfgQueueStatusData const& data); - bool isOptionEnabled(uint32 option); - uint32 GetOptions(); - void SetOptions(uint32 options); - LfgUpdateData GetLfgStatus(uint64 guid); - bool IsSeasonActive(uint32 dungeonId); - - std::string DumpQueueInfo(bool full = false); - static std::string ConcatenateDungeons(LfgDungeonSet const& dungeons); - static std::string GetRolesString(uint8 roles); - static std::string GetStateString(LfgState state); - - void LoadLFGDungeons(bool reload = false); - LFGDungeonData const* GetLFGDungeon(uint32 id); - LFGDungeonContainer& GetLFGDungeonMap(); - void SetupGroupMember(uint64 guid, uint64 gguid); - uint64 GetGroup(uint64 guid); - private: uint8 GetTeam(uint64 guid); void RestoreState(uint64 guid, char const* debugMsg); @@ -389,6 +426,11 @@ class LFGMgr void SetSelectedDungeons(uint64 guid, LfgDungeonSet const& dungeons); void SetLockedDungeons(uint64 guid, LfgLockMap const& lock); void DecreaseKicksLeft(uint64 guid); + void SetState(uint64 guid, LfgState state); + void RemovePlayerData(uint64 guid); + void GetCompatibleDungeons(LfgDungeonSet& dungeons, LfgGuidSet const& players, LfgLockPartyMap& lockMap); + void _SaveToDB(uint64 guid, uint32 db_guid); + LFGDungeonData const* GetLFGDungeon(uint32 id); // Proposals void RemoveProposal(LfgProposalContainer::iterator itProposal, LfgUpdateType type); @@ -407,6 +449,8 @@ class LFGMgr void SendLfgUpdatePlayer(uint64 guid, LfgUpdateData const& data); void SendLfgUpdateProposal(uint64 guid, LfgProposal const& proposal); + LfgGuidSet const& GetPlayers(uint64 guid); + // General variables uint32 m_QueueTimer; ///< used to check interval of update uint32 m_lfgProposalId; ///< used as internal counter for proposals @@ -426,5 +470,7 @@ class LFGMgr LfgGuidList teleportStore; ///< Players being teleported }; -#define sLFGMgr ACE_Singleton<LFGMgr, ACE_Null_Mutex>::instance() +} // namespace lfg + +#define sLFGMgr ACE_Singleton<lfg::LFGMgr, ACE_Null_Mutex>::instance() #endif diff --git a/src/server/game/DungeonFinding/LFGPlayerData.cpp b/src/server/game/DungeonFinding/LFGPlayerData.cpp index 410076f7e75..e8ef430bc1f 100644 --- a/src/server/game/DungeonFinding/LFGPlayerData.cpp +++ b/src/server/game/DungeonFinding/LFGPlayerData.cpp @@ -17,6 +17,9 @@ #include "LFGPlayerData.h" +namespace lfg +{ + LfgPlayerData::LfgPlayerData(): m_State(LFG_STATE_NONE), m_OldState(LFG_STATE_NONE), m_Team(0), m_Group(0), m_Roles(0), m_Comment("") {} @@ -122,3 +125,5 @@ LfgDungeonSet const& LfgPlayerData::GetSelectedDungeons() const { return m_SelectedDungeons; } + +} // namespace lfg diff --git a/src/server/game/DungeonFinding/LFGPlayerData.h b/src/server/game/DungeonFinding/LFGPlayerData.h index 055924fd364..a425ce77bad 100644 --- a/src/server/game/DungeonFinding/LFGPlayerData.h +++ b/src/server/game/DungeonFinding/LFGPlayerData.h @@ -20,6 +20,9 @@ #include "LFG.h" +namespace lfg +{ + /** Stores all lfg data needed about the player. */ @@ -68,4 +71,6 @@ class LfgPlayerData LfgDungeonSet m_SelectedDungeons; ///< Selected Dungeons when joined LFG }; +} // namespace lfg + #endif diff --git a/src/server/game/DungeonFinding/LFGQueue.cpp b/src/server/game/DungeonFinding/LFGQueue.cpp index f1d2dbb313d..6a98fccecdc 100644 --- a/src/server/game/DungeonFinding/LFGQueue.cpp +++ b/src/server/game/DungeonFinding/LFGQueue.cpp @@ -27,6 +27,9 @@ #include "World.h" #include "GroupMgr.h" +namespace lfg +{ + /** Given a list of guids returns the concatenation using | as delimiter @@ -431,7 +434,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(LfgGuidList check) { std::ostringstream o; for (LfgRolesMap::const_iterator it = debugRoles.begin(); it != debugRoles.end(); ++it) - o << ", " << it->first << ": " << sLFGMgr->GetRolesString(it->second); + o << ", " << it->first << ": " << GetRolesString(it->second); sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) Roles not compatible%s", strGuids.c_str(), o.str().c_str()); SetCompatibles(strGuids, LFG_INCOMPATIBLES_NO_ROLES); @@ -441,12 +444,12 @@ LfgCompatibility LFGQueue::CheckCompatibility(LfgGuidList check) LfgGuidList::iterator itguid = check.begin(); proposalDungeons = QueueDataStore[*itguid].dungeons; std::ostringstream o; - o << ", " << *itguid << ": (" << sLFGMgr->ConcatenateDungeons(proposalDungeons) << ")"; + o << ", " << *itguid << ": (" << ConcatenateDungeons(proposalDungeons) << ")"; for (++itguid; itguid != check.end(); ++itguid) { LfgDungeonSet temporal; LfgDungeonSet &dungeons = QueueDataStore[*itguid].dungeons; - o << ", " << *itguid << ": (" << sLFGMgr->ConcatenateDungeons(dungeons) << ")"; + o << ", " << *itguid << ": (" << ConcatenateDungeons(dungeons) << ")"; std::set_intersection(proposalDungeons.begin(), proposalDungeons.end(), dungeons.begin(), dungeons.end(), std::inserter(temporal, temporal.begin())); proposalDungeons = temporal; } @@ -671,3 +674,5 @@ void LFGQueue::UpdateBestCompatibleInQueue(LfgQueueDataContainer::iterator itrQu --queueData.dps; } } + +} // namespace lfg diff --git a/src/server/game/DungeonFinding/LFGQueue.h b/src/server/game/DungeonFinding/LFGQueue.h index acb78d2c0f2..db7e7bbf318 100644 --- a/src/server/game/DungeonFinding/LFGQueue.h +++ b/src/server/game/DungeonFinding/LFGQueue.h @@ -20,6 +20,9 @@ #include "LFG.h" +namespace lfg +{ + enum LfgCompatibility { LFG_COMPATIBILITY_PENDING, @@ -140,4 +143,6 @@ class LFGQueue LfgGuidList newToQueueStore; ///< New groups to add to queue }; +} // namespace lfg + #endif diff --git a/src/server/game/DungeonFinding/LFGScripts.cpp b/src/server/game/DungeonFinding/LFGScripts.cpp index 568b61eef2f..ac95d289397 100644 --- a/src/server/game/DungeonFinding/LFGScripts.cpp +++ b/src/server/game/DungeonFinding/LFGScripts.cpp @@ -29,6 +29,9 @@ #include "ObjectAccessor.h" #include "WorldSession.h" +namespace lfg +{ + LFGPlayerScript::LFGPlayerScript() : PlayerScript("LFGPlayerScript") { } @@ -208,3 +211,5 @@ void LFGGroupScript::OnInviteMember(Group* group, uint64 guid) if (leader && !gguid) sLFGMgr->LeaveLfg(leader); } + +} // namespace lfg diff --git a/src/server/game/DungeonFinding/LFGScripts.h b/src/server/game/DungeonFinding/LFGScripts.h index 227543e1899..e9c6b1499d1 100644 --- a/src/server/game/DungeonFinding/LFGScripts.h +++ b/src/server/game/DungeonFinding/LFGScripts.h @@ -26,6 +26,9 @@ class Player; class Group; +namespace lfg +{ + class LFGPlayerScript : public PlayerScript { public: @@ -50,3 +53,5 @@ class LFGGroupScript : public GroupScript void OnChangeLeader(Group* group, uint64 newLeaderGuid, uint64 oldLeaderGuid); void OnInviteMember(Group* group, uint64 guid); }; + +} // namespace lfg diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index f20d452dc96..8f89e58ad5a 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -777,64 +777,57 @@ void Object::BuildFieldsUpdate(Player* player, UpdateDataMapType& data_map) cons BuildValuesUpdateBlockForPlayer(&iter->second, iter->first); } -void Object::GetUpdateFieldData(Player const* target, uint32*& flags, bool& isOwner, bool& isItemOwner, bool& hasSpecialInfo, bool& isPartyMember) const +uint32 Object::GetUpdateFieldData(Player const* target, uint32*& flags) const { - // This function assumes updatefield index is always valid + uint32 visibleFlag = UF_FLAG_PUBLIC; + + if (target == this) + visibleFlag |= UF_FLAG_PRIVATE; + switch (GetTypeId()) { case TYPEID_ITEM: case TYPEID_CONTAINER: flags = ItemUpdateFieldFlags; - isOwner = isItemOwner = ((Item*)this)->GetOwnerGUID() == target->GetGUID(); + if (((Item*)this)->GetOwnerGUID() == target->GetGUID()) + visibleFlag |= UF_FLAG_OWNER | UF_FLAG_ITEM_OWNER; break; case TYPEID_UNIT: case TYPEID_PLAYER: { Player* plr = ToUnit()->GetCharmerOrOwnerPlayerOrPlayerItself(); flags = UnitUpdateFieldFlags; - isOwner = ToUnit()->GetOwnerGUID() == target->GetGUID(); - hasSpecialInfo = ToUnit()->HasAuraTypeWithCaster(SPELL_AURA_EMPATHY, target->GetGUID()); - isPartyMember = plr && plr->IsInSameGroupWith(target); + if (ToUnit()->GetOwnerGUID() == target->GetGUID()) + visibleFlag |= UF_FLAG_OWNER; + + if (HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_SPECIALINFO)) + if (ToUnit()->HasAuraTypeWithCaster(SPELL_AURA_EMPATHY, target->GetGUID())) + visibleFlag |= UF_FLAG_SPECIAL_INFO; + + if (plr && plr->IsInSameRaidWith(target)) + visibleFlag |= UF_FLAG_PARTY_MEMBER; break; } case TYPEID_GAMEOBJECT: flags = GameObjectUpdateFieldFlags; - isOwner = ToGameObject()->GetOwnerGUID() == target->GetGUID(); + if (ToGameObject()->GetOwnerGUID() == target->GetGUID()) + visibleFlag |= UF_FLAG_OWNER; break; case TYPEID_DYNAMICOBJECT: flags = DynamicObjectUpdateFieldFlags; - isOwner = ((DynamicObject*)this)->GetCasterGUID() == target->GetGUID(); + if (((DynamicObject*)this)->GetCasterGUID() == target->GetGUID()) + visibleFlag |= UF_FLAG_OWNER; break; case TYPEID_CORPSE: flags = CorpseUpdateFieldFlags; - isOwner = ToCorpse()->GetOwnerGUID() == target->GetGUID(); + if (ToCorpse()->GetOwnerGUID() == target->GetGUID()) + visibleFlag |= UF_FLAG_OWNER; break; case TYPEID_OBJECT: break; } -} -bool Object::IsUpdateFieldVisible(uint32 flags, bool isSelf, bool isOwner, bool isItemOwner, bool isPartyMember) const -{ - if (flags == UF_FLAG_NONE) - return false; - - if (flags & UF_FLAG_PUBLIC) - return true; - - if (flags & UF_FLAG_PRIVATE && isSelf) - return true; - - if (flags & UF_FLAG_OWNER && isOwner) - return true; - - if (flags & UF_FLAG_ITEM_OWNER && isItemOwner) - return true; - - if (flags & UF_FLAG_PARTY_MEMBER && isPartyMember) - return true; - - return false; + return visibleFlag; } void Object::_LoadIntoDataField(std::string const& data, uint32 startOffset, uint32 count) @@ -857,16 +850,10 @@ void Object::_LoadIntoDataField(std::string const& data, uint32 startOffset, uin void Object::_SetUpdateBits(UpdateMask* updateMask, Player* target) const { uint32* flags = NULL; - bool isSelf = target == this; - bool isOwner = false; - bool isItemOwner = false; - bool hasSpecialInfo = false; - bool isPartyMember = false; - - GetUpdateFieldData(target, flags, isOwner, isItemOwner, hasSpecialInfo, isPartyMember); + uint32 visibleFlag = GetUpdateFieldData(target, flags); for (uint16 index = 0; index < m_valuesCount; ++index) - if (_fieldNotifyFlags & flags[index] || (flags[index] & UF_FLAG_SPECIAL_INFO && hasSpecialInfo) || (_changesMask.GetBit(index) && IsUpdateFieldVisible(flags[index], isSelf, isOwner, isItemOwner, isPartyMember))) + if (_fieldNotifyFlags & flags[index] || ((flags[index] & visibleFlag) & UF_FLAG_SPECIAL_INFO) || (_changesMask.GetBit(index) && (flags[index] & visibleFlag))) updateMask->SetBit(index); } @@ -874,16 +861,10 @@ void Object::_SetCreateBits(UpdateMask* updateMask, Player* target) const { uint32* value = m_uint32Values; uint32* flags = NULL; - bool isSelf = target == this; - bool isOwner = false; - bool isItemOwner = false; - bool hasSpecialInfo = false; - bool isPartyMember = false; - - GetUpdateFieldData(target, flags, isOwner, isItemOwner, hasSpecialInfo, isPartyMember); + uint32 visibleFlag = GetUpdateFieldData(target, flags); for (uint16 index = 0; index < m_valuesCount; ++index, ++value) - if (_fieldNotifyFlags & flags[index] || (flags[index] & UF_FLAG_SPECIAL_INFO && hasSpecialInfo) || (*value && IsUpdateFieldVisible(flags[index], isSelf, isOwner, isItemOwner, isPartyMember))) + if (_fieldNotifyFlags & flags[index] || ((flags[index] & visibleFlag) & UF_FLAG_SPECIAL_INFO) || (*value && (flags[index] & visibleFlag))) updateMask->SetBit(index); } diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 641f9afb154..ae3d545b7d7 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -326,9 +326,7 @@ class Object std::string _ConcatFields(uint16 startIndex, uint16 size) const; void _LoadIntoDataField(std::string const& data, uint32 startOffset, uint32 count); - void GetUpdateFieldData(Player const* target, uint32*& flags, bool& isOwner, bool& isItemOwner, bool& hasSpecialInfo, bool& isPartyMember) const; - - bool IsUpdateFieldVisible(uint32 flags, bool isSelf, bool isOwner, bool isItemOwner, bool isPartyMember) const; + uint32 GetUpdateFieldData(Player const* target, uint32*& flags) const; void _SetUpdateBits(UpdateMask* updateMask, Player* target) const; void _SetCreateBits(UpdateMask* updateMask, Player* target) const; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 82a1164b423..dc98facc5ab 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -7446,7 +7446,7 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) if (Group* group = GetGroup()) { SetGroupUpdateFlag(GROUP_UPDATE_FULL); - if (GetSession() && group->isLFGGroup() && sLFGMgr->IsTeleported(GetGUID())) + if (GetSession() && group->isLFGGroup() && sLFGMgr->hasPendingTeleport(GetGUID())) { for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) { @@ -11913,7 +11913,7 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto) const InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObject const* lootedObject) const { - LfgDungeonSet const& dungeons = sLFGMgr->GetSelectedDungeons(GetGUID()); + lfg::LfgDungeonSet const& dungeons = sLFGMgr->GetSelectedDungeons(GetGUID()); if (dungeons.empty()) return EQUIP_ERR_OK; // not using LFG @@ -11923,10 +11923,7 @@ InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObje // check if looted object is inside the lfg dungeon bool lootedObjectInDungeon = false; Map const* map = lootedObject->GetMap(); - if (uint32 dungeonId = sLFGMgr->GetDungeon(GetGroup()->GetGUID(), true)) - if (LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(dungeonId)) - if (uint32(dungeon->map) == map->GetId() && dungeon->difficulty == map->GetDifficulty()) - lootedObjectInDungeon = true; + lootedObjectInDungeon = sLFGMgr->inLfgDungeonMap(GetGroup()->GetGUID(), map->GetId(), map->GetDifficulty()); if (!lootedObjectInDungeon) return EQUIP_ERR_OK; @@ -21760,12 +21757,21 @@ void Player::LeaveBattleground(bool teleportToEntryPoint) } } -bool Player::CanJoinToBattleground(Battleground const* /*bg*/) const +bool Player::CanJoinToBattleground(Battleground const* bg) const { // check Deserter debuff if (HasAura(26013)) return false; + if (bg->isArena() && !GetSession()->HasPermission(RBAC_PERM_JOIN_ARENAS)) + return false; + + if (bg->IsRandom() && !GetSession()->HasPermission(RBAC_PERM_JOIN_RANDOM_BG)) + return false; + + if (!GetSession()->HasPermission(RBAC_PERM_JOIN_NORMAL_BG)) + return false; + return true; } @@ -22049,26 +22055,28 @@ void Player::InitPrimaryProfessions() SetFreePrimaryProfessions(sWorld->getIntConfig(CONFIG_MAX_PRIMARY_TRADE_SKILL)); } -void Player::ModifyMoney(int32 d) +bool Player::ModifyMoney(int32 amount, bool sendError /*= true*/) { - sScriptMgr->OnPlayerMoneyChanged(this, d); + if (!amount) + return true; + + sScriptMgr->OnPlayerMoneyChanged(this, amount); - if (d < 0) - SetMoney (GetMoney() > uint32(-d) ? GetMoney() + d : 0); + if (amount < 0) + SetMoney (GetMoney() > uint32(-amount) ? GetMoney() + amount : 0); else { - uint32 newAmount = 0; - if (GetMoney() < uint32(MAX_MONEY_AMOUNT - d)) - newAmount = GetMoney() + d; + if (GetMoney() < uint32(MAX_MONEY_AMOUNT - amount)) + SetMoney(GetMoney() + amount); else { - // "At Gold Limit" - newAmount = MAX_MONEY_AMOUNT; - if (d) + if (sendError) SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, NULL, NULL); + return false; } - SetMoney (newAmount); } + + return true; } Unit* Player::GetSelectedUnit() const @@ -23424,14 +23432,14 @@ PartyResult Player::CanUninviteFromGroup() const if (!sLFGMgr->GetKicksLeft(gguid)) return ERR_PARTY_LFG_BOOT_LIMIT; - LfgState state = sLFGMgr->GetState(gguid); - if (state == LFG_STATE_BOOT) + lfg::LfgState state = sLFGMgr->GetState(gguid); + if (state == lfg::LFG_STATE_BOOT) return ERR_PARTY_LFG_BOOT_IN_PROGRESS; - if (grp->GetMembersCount() <= LFG_GROUP_KICK_VOTES_NEEDED) + if (grp->GetMembersCount() <= lfg::LFG_GROUP_KICK_VOTES_NEEDED) return ERR_PARTY_LFG_BOOT_TOO_FEW_PLAYERS; - if (state == LFG_STATE_FINISHED_DUNGEON) + if (state == lfg::LFG_STATE_FINISHED_DUNGEON) return ERR_PARTY_LFG_BOOT_DUNGEON_COMPLETE; if (grp->isRollLootActive()) @@ -23461,21 +23469,17 @@ PartyResult Player::CanUninviteFromGroup() const bool Player::isUsingLfg() { - return sLFGMgr->GetState(GetGUID()) != LFG_STATE_NONE; + return sLFGMgr->GetState(GetGUID()) != lfg::LFG_STATE_NONE; } bool Player::inRandomLfgDungeon() { - if (isUsingLfg()) + if (sLFGMgr->selectedRandomLfgDungeon(GetGUID())) { - const LfgDungeonSet& dungeons = sLFGMgr->GetSelectedDungeons(GetGUID()); - if (!dungeons.empty()) - { - LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(*dungeons.begin()); - if (dungeon && (dungeon->type == LFG_TYPE_RANDOM || dungeon->seasonal)) - return true; - } + Map const* map = GetMap(); + return sLFGMgr->inLfgDungeonMap(GetGUID(), map->GetId(), map->GetDifficulty()); } + return false; } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index a69f8c44715..64980b9551e 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1546,7 +1546,7 @@ class Player : public Unit, public GridObject<Player> void setWeaponChangeTimer(uint32 time) {m_weaponChangeTimer = time;} uint32 GetMoney() const { return GetUInt32Value(PLAYER_FIELD_COINAGE); } - void ModifyMoney(int32 d); + bool ModifyMoney(int32 amount, bool sendError = true); bool HasEnoughMoney(uint32 amount) const { return (GetMoney() >= amount); } bool HasEnoughMoney(int32 amount) const { diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 948b88d4702..e3a2430f63a 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -15296,15 +15296,32 @@ void Unit::SetControlled(bool apply, UnitState state) { switch (state) { - case UNIT_STATE_STUNNED: if (HasAuraType(SPELL_AURA_MOD_STUN)) return; - else SetStunned(false); break; - case UNIT_STATE_ROOT: if (HasAuraType(SPELL_AURA_MOD_ROOT) || GetVehicle()) return; - else SetRooted(false); break; - case UNIT_STATE_CONFUSED:if (HasAuraType(SPELL_AURA_MOD_CONFUSE)) return; - else SetConfused(false); break; - case UNIT_STATE_FLEEING: if (HasAuraType(SPELL_AURA_MOD_FEAR)) return; - else SetFeared(false); break; - default: return; + case UNIT_STATE_STUNNED: + if (HasAuraType(SPELL_AURA_MOD_STUN)) + return; + + SetStunned(false); + break; + case UNIT_STATE_ROOT: + if (HasAuraType(SPELL_AURA_MOD_ROOT) || GetVehicle()) + return; + + SetRooted(false); + break; + case UNIT_STATE_CONFUSED: + if (HasAuraType(SPELL_AURA_MOD_CONFUSE)) + return; + + SetConfused(false); + break; + case UNIT_STATE_FLEEING: + if (HasAuraType(SPELL_AURA_MOD_FEAR)) + return; + + SetFeared(false); + break; + default: + return; } ClearUnitState(state); diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index a3a5c865a48..1dd824759c9 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -5010,7 +5010,7 @@ void ObjectMgr::LoadInstanceEncounters() continue; } - if (lastEncounterDungeon && !sLFGMgr->GetLFGDungeon(lastEncounterDungeon)) + if (lastEncounterDungeon && !sLFGMgr->GetLFGDungeonEntry(lastEncounterDungeon)) { sLog->outError(LOG_FILTER_SQL, "Table `instance_encounters` has an encounter %u (%s) marked as final for invalid dungeon id %u, skipped!", entry, dungeonEncounter->encounterName[0], lastEncounterDungeon); continue; diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 711e07ef941..eb2d33c63a0 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -1496,7 +1496,7 @@ void Group::SendUpdateToPlayer(uint64 playerGUID, MemberSlot* slot) data << uint8(slot->roles); if (isLFGGroup()) { - data << uint8(sLFGMgr->GetState(m_guid) == LFG_STATE_FINISHED_DUNGEON ? 2 : 0); // FIXME - Dungeon save status? 2 = done + data << uint8(sLFGMgr->GetState(m_guid) == lfg::LFG_STATE_FINISHED_DUNGEON ? 2 : 0); // FIXME - Dungeon save status? 2 = done data << uint32(sLFGMgr->GetDungeon(m_guid)); } diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 376ee011638..c424e5d3ffe 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -1755,16 +1755,20 @@ bool Guild::HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool sScriptMgr->OnGuildMemberWitdrawMoney(this, player, amount, repair); SQLTransaction trans = CharacterDatabase.BeginTransaction(); - // Update remaining money amount - member->UpdateBankWithdrawValue(trans, GUILD_BANK_MAX_TABS, amount); - // Remove money from bank - _ModifyBankMoney(trans, amount, false); // Add money to player (if required) if (!repair) { - player->ModifyMoney(amount); + if (!player->ModifyMoney(amount)) + return false; + player->SaveGoldToDB(trans); } + + // Update remaining money amount + member->UpdateBankWithdrawValue(trans, GUILD_BANK_MAX_TABS, amount); + // Remove money from bank + _ModifyBankMoney(trans, amount, false); + // Log guild bank event _LogBankEvent(trans, repair ? GUILD_BANK_LOG_REPAIR_MONEY : GUILD_BANK_LOG_WITHDRAW_MONEY, uint8(0), player->GetGUIDLow(), amount); CharacterDatabase.CommitTransaction(trans); diff --git a/src/server/game/Handlers/LFGHandler.cpp b/src/server/game/Handlers/LFGHandler.cpp index 0654ae326f9..619e9b68b51 100644 --- a/src/server/game/Handlers/LFGHandler.cpp +++ b/src/server/game/Handlers/LFGHandler.cpp @@ -23,20 +23,20 @@ #include "WorldPacket.h" #include "WorldSession.h" -void BuildPlayerLockDungeonBlock(WorldPacket& data, LfgLockMap const& lock) +void BuildPlayerLockDungeonBlock(WorldPacket& data, lfg::LfgLockMap const& lock) { data << uint32(lock.size()); // Size of lock dungeons - for (LfgLockMap::const_iterator it = lock.begin(); it != lock.end(); ++it) + for (lfg::LfgLockMap::const_iterator it = lock.begin(); it != lock.end(); ++it) { data << uint32(it->first); // Dungeon entry (id + type) data << uint32(it->second); // Lock status } } -void BuildPartyLockDungeonBlock(WorldPacket& data, const LfgLockPartyMap& lockMap) +void BuildPartyLockDungeonBlock(WorldPacket& data, lfg::LfgLockPartyMap const& lockMap) { data << uint8(lockMap.size()); - for (LfgLockPartyMap::const_iterator it = lockMap.begin(); it != lockMap.end(); ++it) + for (lfg::LfgLockPartyMap::const_iterator it = lockMap.begin(); it != lockMap.end(); ++it) { data << uint64(it->first); // Player guid BuildPlayerLockDungeonBlock(data, it->second); @@ -45,7 +45,7 @@ void BuildPartyLockDungeonBlock(WorldPacket& data, const LfgLockPartyMap& lockMa void WorldSession::HandleLfgJoinOpcode(WorldPacket& recvData) { - if (!sLFGMgr->isOptionEnabled(LFG_OPTION_ENABLE_DUNGEON_FINDER | LFG_OPTION_ENABLE_RAID_BROWSER) || + if (!sLFGMgr->isOptionEnabled(lfg::LFG_OPTION_ENABLE_DUNGEON_FINDER | lfg::LFG_OPTION_ENABLE_RAID_BROWSER) || (GetPlayer()->GetGroup() && GetPlayer()->GetGroup()->GetLeaderGUID() != GetPlayer()->GetGUID() && (GetPlayer()->GetGroup()->GetMembersCount() == MAXGROUPSIZE || !GetPlayer()->GetGroup()->isLFGGroup()))) { @@ -66,7 +66,7 @@ void WorldSession::HandleLfgJoinOpcode(WorldPacket& recvData) return; } - LfgDungeonSet newDungeons; + lfg::LfgDungeonSet newDungeons; for (int8 i = 0; i < numDungeons; ++i) { uint32 dungeon; @@ -167,21 +167,12 @@ void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recvData* GetPlayerInfo().c_str()); // Get Random dungeons that can be done at a certain level and expansion - LfgDungeonSet randomDungeons; uint8 level = GetPlayer()->getLevel(); - uint8 expansion = GetPlayer()->GetSession()->Expansion(); - - LFGDungeonContainer& LfgDungeons = sLFGMgr->GetLFGDungeonMap(); - for (LFGDungeonContainer::const_iterator itr = LfgDungeons.begin(); itr != LfgDungeons.end(); ++itr) - { - LFGDungeonData const& dungeon = itr->second; - if ((dungeon.type == LFG_TYPE_RANDOM || (dungeon.seasonal && sLFGMgr->IsSeasonActive(dungeon.id))) - && dungeon.expansion <= expansion && dungeon.minlevel <= level && level <= dungeon.maxlevel) - randomDungeons.insert(dungeon.Entry()); - } + lfg::LfgDungeonSet const& randomDungeons = + sLFGMgr->GetRandomAndSeasonalDungeons(level, GetPlayer()->GetSession()->Expansion()); // Get player locked Dungeons - LfgLockMap const& lock = sLFGMgr->GetLockedDungeons(guid); + lfg::LfgLockMap const& lock = sLFGMgr->GetLockedDungeons(guid); uint32 rsize = uint32(randomDungeons.size()); uint32 lsize = uint32(lock.size()); @@ -189,10 +180,10 @@ void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recvData* WorldPacket data(SMSG_LFG_PLAYER_INFO, 1 + rsize * (4 + 1 + 4 + 4 + 4 + 4 + 1 + 4 + 4 + 4) + 4 + lsize * (1 + 4 + 4 + 4 + 4 + 1 + 4 + 4 + 4)); data << uint8(randomDungeons.size()); // Random Dungeon count - for (LfgDungeonSet::const_iterator it = randomDungeons.begin(); it != randomDungeons.end(); ++it) + for (lfg::LfgDungeonSet::const_iterator it = randomDungeons.begin(); it != randomDungeons.end(); ++it) { data << uint32(*it); // Dungeon Entry (id + type) - LfgReward const* reward = sLFGMgr->GetRandomDungeonReward(*it, level); + lfg::LfgReward const* reward = sLFGMgr->GetRandomDungeonReward(*it, level); Quest const* quest = NULL; bool done = false; if (reward) @@ -250,7 +241,7 @@ void WorldSession::HandleLfgPartyLockInfoRequestOpcode(WorldPacket& /*recvData* return; // Get the locked dungeons of the other party members - LfgLockPartyMap lockMap; + lfg::LfgLockPartyMap lockMap; for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) { Player* plrg = itr->getSource(); @@ -265,7 +256,7 @@ void WorldSession::HandleLfgPartyLockInfoRequestOpcode(WorldPacket& /*recvData* } uint32 size = 0; - for (LfgLockPartyMap::const_iterator it = lockMap.begin(); it != lockMap.end(); ++it) + for (lfg::LfgLockPartyMap::const_iterator it = lockMap.begin(); it != lockMap.end(); ++it) size += 8 + 4 + uint32(it->second.size()) * (4 + 4); sLog->outDebug(LOG_FILTER_LFG, "SMSG_LFG_PARTY_INFO %s", GetPlayerInfo().c_str()); @@ -297,7 +288,7 @@ void WorldSession::HandleLfgGetStatus(WorldPacket& /*recvData*/) sLog->outDebug(LOG_FILTER_LFG, "CMSG_LFG_GET_STATUS %s", GetPlayerInfo().c_str()); uint64 guid = GetPlayer()->GetGUID(); - LfgUpdateData updateData = sLFGMgr->GetLfgStatus(guid); + lfg::LfgUpdateData updateData = sLFGMgr->GetLfgStatus(guid); if (GetPlayer()->GetGroup()) { @@ -313,19 +304,19 @@ void WorldSession::HandleLfgGetStatus(WorldPacket& /*recvData*/) } } -void WorldSession::SendLfgUpdatePlayer(LfgUpdateData const& updateData) +void WorldSession::SendLfgUpdatePlayer(lfg::LfgUpdateData const& updateData) { bool queued = false; uint8 size = uint8(updateData.dungeons.size()); switch (updateData.updateType) { - case LFG_UPDATETYPE_JOIN_QUEUE: - case LFG_UPDATETYPE_ADDED_TO_QUEUE: + case lfg::LFG_UPDATETYPE_JOIN_QUEUE: + case lfg::LFG_UPDATETYPE_ADDED_TO_QUEUE: queued = true; break; - case LFG_UPDATETYPE_UPDATE_STATUS: - queued = updateData.state == LFG_STATE_QUEUED; + case lfg::LFG_UPDATETYPE_UPDATE_STATUS: + queued = updateData.state == lfg::LFG_STATE_QUEUED; break; default: break; @@ -343,14 +334,14 @@ void WorldSession::SendLfgUpdatePlayer(LfgUpdateData const& updateData) data << uint8(0); // unk - Always 0 data << uint8(size); - for (LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it) + for (lfg::LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it) data << uint32(*it); data << updateData.comment; } SendPacket(&data); } -void WorldSession::SendLfgUpdateParty(const LfgUpdateData& updateData) +void WorldSession::SendLfgUpdateParty(const lfg::LfgUpdateData& updateData) { bool join = false; bool queued = false; @@ -358,15 +349,15 @@ void WorldSession::SendLfgUpdateParty(const LfgUpdateData& updateData) switch (updateData.updateType) { - case LFG_UPDATETYPE_ADDED_TO_QUEUE: // Rolecheck Success + case lfg::LFG_UPDATETYPE_ADDED_TO_QUEUE: // Rolecheck Success queued = true; // no break on purpose - case LFG_UPDATETYPE_PROPOSAL_BEGIN: + case lfg::LFG_UPDATETYPE_PROPOSAL_BEGIN: join = true; break; - case LFG_UPDATETYPE_UPDATE_STATUS: - join = updateData.state != LFG_STATE_ROLECHECK && updateData.state != LFG_STATE_NONE; - queued = updateData.state == LFG_STATE_QUEUED; + case lfg::LFG_UPDATETYPE_UPDATE_STATUS: + join = updateData.state != lfg::LFG_STATE_ROLECHECK && updateData.state != lfg::LFG_STATE_NONE; + queued = updateData.state == lfg::LFG_STATE_QUEUED; break; default: break; @@ -387,7 +378,7 @@ void WorldSession::SendLfgUpdateParty(const LfgUpdateData& updateData) data << uint8(0); // unk - Always 0 data << uint8(size); - for (LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it) + for (lfg::LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it) data << uint32(*it); data << updateData.comment; } @@ -406,9 +397,9 @@ void WorldSession::SendLfgRoleChosen(uint64 guid, uint8 roles) SendPacket(&data); } -void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck& roleCheck) +void WorldSession::SendLfgRoleCheckUpdate(lfg::LfgRoleCheck const& roleCheck) { - LfgDungeonSet dungeons; + lfg::LfgDungeonSet dungeons; if (roleCheck.rDungeonId) dungeons.insert(roleCheck.rDungeonId); else @@ -418,16 +409,11 @@ void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck& roleCheck) WorldPacket data(SMSG_LFG_ROLE_CHECK_UPDATE, 4 + 1 + 1 + dungeons.size() * 4 + 1 + roleCheck.roles.size() * (8 + 1 + 4 + 1)); data << uint32(roleCheck.state); // Check result - data << uint8(roleCheck.state == LFG_ROLECHECK_INITIALITING); + data << uint8(roleCheck.state == lfg::LFG_ROLECHECK_INITIALITING); data << uint8(dungeons.size()); // Number of dungeons if (!dungeons.empty()) - { - for (LfgDungeonSet::iterator it = dungeons.begin(); it != dungeons.end(); ++it) - { - LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(*it); - data << uint32(dungeon ? dungeon->Entry() : 0); // Dungeon - } - } + for (lfg::LfgDungeonSet::iterator it = dungeons.begin(); it != dungeons.end(); ++it) + data << uint32(sLFGMgr->GetLFGDungeonEntry(*it)); // Dungeon data << uint8(roleCheck.roles.size()); // Players in group if (!roleCheck.roles.empty()) @@ -441,7 +427,7 @@ void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck& roleCheck) Player* player = ObjectAccessor::FindPlayer(guid); data << uint8(player ? player->getLevel() : 0); // Level - for (LfgRolesMap::const_iterator it = roleCheck.roles.begin(); it != roleCheck.roles.end(); ++it) + for (lfg::LfgRolesMap::const_iterator it = roleCheck.roles.begin(); it != roleCheck.roles.end(); ++it) { if (it->first == roleCheck.leader) continue; @@ -458,10 +444,10 @@ void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck& roleCheck) SendPacket(&data); } -void WorldSession::SendLfgJoinResult(LfgJoinResultData const& joinData) +void WorldSession::SendLfgJoinResult(lfg::LfgJoinResultData const& joinData) { uint32 size = 0; - for (LfgLockPartyMap::const_iterator it = joinData.lockmap.begin(); it != joinData.lockmap.end(); ++it) + for (lfg::LfgLockPartyMap::const_iterator it = joinData.lockmap.begin(); it != joinData.lockmap.end(); ++it) size += 8 + 4 + uint32(it->second.size()) * (4 + 4); sLog->outDebug(LOG_FILTER_LFG, "SMSG_LFG_JOIN_RESULT %s checkResult: %u checkValue: %u", @@ -475,7 +461,7 @@ void WorldSession::SendLfgJoinResult(LfgJoinResultData const& joinData) SendPacket(&data); } -void WorldSession::SendLfgQueueStatus(LfgQueueStatusData const& queueData) +void WorldSession::SendLfgQueueStatus(lfg::LfgQueueStatusData const& queueData) { sLog->outDebug(LOG_FILTER_LFG, "SMSG_LFG_QUEUE_STATUS %s dungeon: %u, waitTime: %d, " "avgWaitTime: %d, waitTimeTanks: %d, waitTimeHealer: %d, waitTimeDps: %d, " @@ -498,7 +484,7 @@ void WorldSession::SendLfgQueueStatus(LfgQueueStatusData const& queueData) SendPacket(&data); } -void WorldSession::SendLfgPlayerReward(LfgPlayerRewardData const& rewardData) +void WorldSession::SendLfgPlayerReward(lfg::LfgPlayerRewardData const& rewardData) { if (!rewardData.rdungeonEntry || !rewardData.sdungeonEntry || !rewardData.quest) return; @@ -532,42 +518,42 @@ void WorldSession::SendLfgPlayerReward(LfgPlayerRewardData const& rewardData) SendPacket(&data); } -void WorldSession::SendLfgBootProposalUpdate(LfgPlayerBoot const& boot) +void WorldSession::SendLfgBootProposalUpdate(lfg::LfgPlayerBoot const& boot) { uint64 guid = GetPlayer()->GetGUID(); - LfgAnswer playerVote = boot.votes.find(guid)->second; + lfg::LfgAnswer playerVote = boot.votes.find(guid)->second; uint8 votesNum = 0; uint8 agreeNum = 0; uint32 secsleft = uint8((boot.cancelTime - time(NULL)) / 1000); - for (LfgAnswerContainer::const_iterator it = boot.votes.begin(); it != boot.votes.end(); ++it) + for (lfg::LfgAnswerContainer::const_iterator it = boot.votes.begin(); it != boot.votes.end(); ++it) { - if (it->second != LFG_ANSWER_PENDING) + if (it->second != lfg::LFG_ANSWER_PENDING) { ++votesNum; - if (it->second == LFG_ANSWER_AGREE) + if (it->second == lfg::LFG_ANSWER_AGREE) ++agreeNum; } } sLog->outDebug(LOG_FILTER_LFG, "SMSG_LFG_BOOT_PROPOSAL_UPDATE %s inProgress: %u - " "didVote: %u - agree: %u - victim: %u votes: %u - agrees: %u - left: %u - " "needed: %u - reason %s", - GetPlayerInfo().c_str(), uint8(boot.inProgress), uint8(playerVote != LFG_ANSWER_PENDING), - uint8(playerVote == LFG_ANSWER_AGREE), GUID_LOPART(boot.victim), votesNum, agreeNum, - secsleft, LFG_GROUP_KICK_VOTES_NEEDED, boot.reason.c_str()); + GetPlayerInfo().c_str(), uint8(boot.inProgress), uint8(playerVote != lfg::LFG_ANSWER_PENDING), + uint8(playerVote == lfg::LFG_ANSWER_AGREE), GUID_LOPART(boot.victim), votesNum, agreeNum, + secsleft, lfg::LFG_GROUP_KICK_VOTES_NEEDED, boot.reason.c_str()); WorldPacket data(SMSG_LFG_BOOT_PROPOSAL_UPDATE, 1 + 1 + 1 + 8 + 4 + 4 + 4 + 4 + boot.reason.length()); data << uint8(boot.inProgress); // Vote in progress - data << uint8(playerVote != LFG_ANSWER_PENDING); // Did Vote - data << uint8(playerVote == LFG_ANSWER_AGREE); // Agree + data << uint8(playerVote != lfg::LFG_ANSWER_PENDING); // Did Vote + data << uint8(playerVote == lfg::LFG_ANSWER_AGREE); // Agree data << uint64(boot.victim); // Victim GUID data << uint32(votesNum); // Total Votes data << uint32(agreeNum); // Agree Count data << uint32(secsleft); // Time Left - data << uint32(LFG_GROUP_KICK_VOTES_NEEDED); // Needed Votes + data << uint32(lfg::LFG_GROUP_KICK_VOTES_NEEDED); // Needed Votes data << boot.reason.c_str(); // Kick reason SendPacket(&data); } -void WorldSession::SendLfgUpdateProposal(LfgProposal const& proposal) +void WorldSession::SendLfgUpdateProposal(lfg::LfgProposal const& proposal) { uint64 guid = GetPlayer()->GetGUID(); uint64 gguid = proposal.players.find(guid)->second.group; @@ -580,13 +566,12 @@ void WorldSession::SendLfgUpdateProposal(LfgProposal const& proposal) // show random dungeon if player selected random dungeon and it's not lfg group if (!silent) { - LfgDungeonSet const& playerDungeons = sLFGMgr->GetSelectedDungeons(guid); + lfg::LfgDungeonSet const& playerDungeons = sLFGMgr->GetSelectedDungeons(guid); if (playerDungeons.find(proposal.dungeonId) == playerDungeons.end()) dungeonEntry = (*playerDungeons.begin()); } - if (LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(dungeonEntry)) - dungeonEntry = dungeon->Entry(); + dungeonEntry = sLFGMgr->GetLFGDungeonEntry(dungeonEntry); WorldPacket data(SMSG_LFG_PROPOSAL_UPDATE, 4 + 1 + 4 + 4 + 1 + 1 + proposal.players.size() * (4 + 1 + 1 + 1 + 1 +1)); data << uint32(dungeonEntry); // Dungeon @@ -596,9 +581,9 @@ void WorldSession::SendLfgUpdateProposal(LfgProposal const& proposal) data << uint8(silent); // Show proposal window data << uint8(proposal.players.size()); // Group size - for (LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it) + for (lfg::LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it) { - LfgProposalPlayer const& player = it->second; + lfg::LfgProposalPlayer const& player = it->second; data << uint32(player.role); // Role data << uint8(it->first == guid); // Self player if (!player.group) // Player not it a group @@ -611,8 +596,8 @@ void WorldSession::SendLfgUpdateProposal(LfgProposal const& proposal) data << uint8(player.group == proposal.group); // In dungeon (silent) data << uint8(player.group == gguid); // Same Group than player } - data << uint8(player.accept != LFG_ANSWER_PENDING);// Answered - data << uint8(player.accept == LFG_ANSWER_AGREE); // Accepted + data << uint8(player.accept != lfg::LFG_ANSWER_PENDING);// Answered + data << uint8(player.accept == lfg::LFG_ANSWER_AGREE); // Accepted } SendPacket(&data); } diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp index 5aeb59e7383..14b6df23061 100644 --- a/src/server/game/Handlers/MailHandler.cpp +++ b/src/server/game/Handlers/MailHandler.cpp @@ -532,13 +532,18 @@ void WorldSession::HandleMailTakeMoney(WorldPacket& recvData) return; } - player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_OK); + if (!player->ModifyMoney(m->money, false)) + { + player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_TOO_MUCH_GOLD); + return; + } - player->ModifyMoney(m->money); m->money = 0; m->state = MAIL_STATE_CHANGED; player->m_mailsUpdated = true; + player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_OK); + // save money and mail to prevent cheating SQLTransaction trans = CharacterDatabase.BeginTransaction(); player->SaveGoldToDB(trans); diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index aa4c9f35085..6272f42ec8c 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -396,7 +396,7 @@ void WorldSession::HandleLogoutRequestOpcode(WorldPacket& /*recvData*/) //instant logout in taverns/cities or on taxi or for admins, gm's, mod's if its enabled in worldserver.conf if (GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) || GetPlayer()->isInFlight() || - GetSecurity() >= AccountTypes(sWorld->getIntConfig(CONFIG_INSTANT_LOGOUT))) + HasPermission(RBAC_PERM_INSTANT_LOGOUT)) { WorldPacket data(SMSG_LOGOUT_RESPONSE, 1+4); data << uint8(0); diff --git a/src/server/game/Handlers/TradeHandler.cpp b/src/server/game/Handlers/TradeHandler.cpp index 2f9db8687c3..bb31b5c1dc8 100644 --- a/src/server/game/Handlers/TradeHandler.cpp +++ b/src/server/game/Handlers/TradeHandler.cpp @@ -292,6 +292,20 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) return; } + if (_player->GetMoney() >= uint32(MAX_MONEY_AMOUNT) - his_trade->GetMoney()) + { + _player->SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, NULL, NULL); + my_trade->SetAccepted(false, true); + return; + } + + if (trader->GetMoney() >= uint32(MAX_MONEY_AMOUNT) - my_trade->GetMoney()) + { + trader->SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, NULL, NULL); + his_trade->SetAccepted(false, true); + return; + } + // not accept if some items now can't be trade (cheating) for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { @@ -302,6 +316,7 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); return; } + if (item->IsBindedNotWith(trader)) { SendTradeStatus(TRADE_STATUS_NOT_ELIGIBLE); diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index fa94232d5b4..128cf358557 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -26,6 +26,7 @@ #include "SpellInfo.h" #include "Group.h" #include "Player.h" +#include "Containers.h" static Rates const qualityToRate[MAX_ITEM_QUALITY] = { @@ -51,10 +52,26 @@ LootStore LootTemplates_Reference("reference_loot_template", "reference LootStore LootTemplates_Skinning("skinning_loot_template", "creature skinning id", true); LootStore LootTemplates_Spell("spell_loot_template", "spell id (random item creating)", false); +struct NotMatchingLootMode : public std::unary_function<LootStoreItem*, bool> +{ + explicit NotMatchingLootMode(uint16 lootMode) : _lootMode(lootMode) { } + + bool operator()(LootStoreItem* item) const + { + return !(item->lootmode & _lootMode); + } + +private: + uint16 _lootMode; +}; + class LootTemplate::LootGroup // A set of loot definitions for items (refs are not allowed) { public: - void AddEntry(LootStoreItem& item); // Adds an entry to the group (at loading stage) + LootGroup() { } + ~LootGroup(); + + void AddEntry(LootStoreItem* item); // Adds an entry to the group (at loading stage) bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry bool HasQuestDropForPlayer(Player const* player) const; // The same for active quests of the player @@ -72,7 +89,11 @@ class LootTemplate::LootGroup // A set of loot def LootStoreItemList ExplicitlyChanced; // Entries with chances defined in DB LootStoreItemList EqualChanced; // Zero chances - every entry takes the same chance - LootStoreItem const* Roll() const; // Rolls an item from the group, returns NULL if all miss their chances + LootStoreItem const* Roll(uint16 lootMode) const; // Rolls an item from the group, returns NULL if all miss their chances + + // This class must never be copied - storing pointers + LootGroup(LootGroup const&); + LootGroup& operator=(LootGroup const&); }; //Remove all data and free all memory @@ -126,10 +147,13 @@ uint32 LootStore::LoadLootTable() continue; // error already printed to log/console. } - LootStoreItem storeitem = LootStoreItem(item, chanceOrQuestChance, lootmode, group, mincountOrRef, maxcount); + LootStoreItem* storeitem = new LootStoreItem(item, chanceOrQuestChance, lootmode, group, mincountOrRef, maxcount); - if (!storeitem.IsValid(*this, entry)) // Validity checks + if (!storeitem->IsValid(*this, entry)) // Validity checks + { + delete storeitem; continue; + } // Looking for the template of the entry // often entries are put together @@ -139,7 +163,7 @@ uint32 LootStore::LoadLootTable() tab = m_LootTemplates.find(entry); if (tab == m_LootTemplates.end()) { - std::pair< LootTemplateMap::iterator, bool > pr = m_LootTemplates.insert(LootTemplateMap::value_type(entry, new LootTemplate)); + std::pair< LootTemplateMap::iterator, bool > pr = m_LootTemplates.insert(LootTemplateMap::value_type(entry, new LootTemplate())); tab = pr.first; } } @@ -182,7 +206,7 @@ void LootStore::ResetConditions() for (LootTemplateMap::iterator itr = m_LootTemplates.begin(); itr != m_LootTemplates.end(); ++itr) { ConditionList empty; - (*itr).second->CopyConditions(empty); + itr->second->CopyConditions(empty); } } @@ -327,7 +351,6 @@ LootItem::LootItem(LootStoreItem const& li) needs_quest = li.needs_quest; - count = urand(li.mincountOrRef, li.maxcount); // constructor called for mincountOrRef > 0 only randomSuffix = GenerateEnchSuffixFactor(itemid); randomPropertyId = Item::GenerateItemRandomPropertyId(itemid); is_looted = 0; @@ -376,26 +399,30 @@ void LootItem::AddAllowedLooter(const Player* player) // // Inserts the item into the loot (called by LootTemplate processors) -void Loot::AddItem(LootStoreItem const & item) +void Loot::AddItem(LootStoreItem const& item) { - if (item.needs_quest) // Quest drop - { - if (quest_items.size() < MAX_NR_QUEST_ITEMS) - quest_items.push_back(LootItem(item)); - } - else if (items.size() < MAX_NR_LOOT_ITEMS) // Non-quest drop + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item.itemid); + if (!proto) + return; + + uint32 count = urand(item.mincountOrRef, item.maxcount); + uint32 stacks = count / proto->GetMaxStackSize() + (count % proto->GetMaxStackSize() ? 1 : 0); + + std::vector<LootItem>& lootItems = item.needs_quest ? quest_items : items; + uint32 limit = item.needs_quest ? MAX_NR_QUEST_ITEMS : MAX_NR_LOOT_ITEMS; + + for (uint32 i = 0; i < stacks && lootItems.size() < limit; ++i) { - items.push_back(LootItem(item)); + LootItem generatedLoot(item); + generatedLoot.count = std::min(count, proto->GetMaxStackSize()); + lootItems.push_back(generatedLoot); + count -= proto->GetMaxStackSize(); // non-conditional one-player only items are counted here, // free for all items are counted in FillFFALoot(), // non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot() - if (item.conditions.empty()) - { - ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item.itemid); - if (!proto || (proto->Flags & ITEM_PROTO_FLAG_PARTY_LOOT) == 0) - ++unlootedCount; - } + if (!item.needs_quest && item.conditions.empty() && !(proto->Flags & ITEM_PROTO_FLAG_PARTY_LOOT)) + ++unlootedCount; } } @@ -1024,34 +1051,56 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) // --------- LootTemplate::LootGroup --------- // +LootTemplate::LootGroup::~LootGroup() +{ + while (!ExplicitlyChanced.empty()) + { + delete ExplicitlyChanced.back(); + ExplicitlyChanced.pop_back(); + } + + while (!EqualChanced.empty()) + { + delete EqualChanced.back(); + EqualChanced.pop_back(); + } +} + // Adds an entry to the group (at loading stage) -void LootTemplate::LootGroup::AddEntry(LootStoreItem& item) +void LootTemplate::LootGroup::AddEntry(LootStoreItem* item) { - if (item.chance != 0) + if (item->chance != 0) ExplicitlyChanced.push_back(item); else EqualChanced.push_back(item); } // Rolls an item from the group, returns NULL if all miss their chances -LootStoreItem const* LootTemplate::LootGroup::Roll() const +LootStoreItem const* LootTemplate::LootGroup::Roll(uint16 lootMode) const { - if (!ExplicitlyChanced.empty()) // First explicitly chanced entries are checked + LootStoreItemList possibleLoot = ExplicitlyChanced; + possibleLoot.remove_if(NotMatchingLootMode(lootMode)); + + if (!possibleLoot.empty()) // First explicitly chanced entries are checked { - float Roll = (float)rand_chance(); + float roll = (float)rand_chance(); - for (uint32 i = 0; i < ExplicitlyChanced.size(); ++i) // check each explicitly chanced entry in the template and modify its chance based on quality. + for (LootStoreItemList::const_iterator itr = possibleLoot.begin(); itr != possibleLoot.end(); ++itr) // check each explicitly chanced entry in the template and modify its chance based on quality. { - if (ExplicitlyChanced[i].chance >= 100.0f) - return &ExplicitlyChanced[i]; + LootStoreItem* item = *itr; + if (item->chance >= 100.0f) + return item; - Roll -= ExplicitlyChanced[i].chance; - if (Roll < 0) - return &ExplicitlyChanced[i]; + roll -= item->chance; + if (roll < 0) + return item; } } - if (!EqualChanced.empty()) // If nothing selected yet - an item is taken from equal-chanced part - return &EqualChanced[irand(0, EqualChanced.size()-1)]; + + possibleLoot = EqualChanced; + possibleLoot.remove_if(NotMatchingLootMode(lootMode)); + if (!possibleLoot.empty()) // If nothing selected yet - an item is taken from equal-chanced part + return Trinity::Containers::SelectRandomContainerElement(possibleLoot); return NULL; // Empty drop from the group } @@ -1059,12 +1108,14 @@ LootStoreItem const* LootTemplate::LootGroup::Roll() const // True if group includes at least 1 quest drop entry bool LootTemplate::LootGroup::HasQuestDrop() const { - for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i) - if (i->needs_quest) + for (LootStoreItemList::const_iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i) + if ((*i)->needs_quest) return true; - for (LootStoreItemList::const_iterator i=EqualChanced.begin(); i != EqualChanced.end(); ++i) - if (i->needs_quest) + + for (LootStoreItemList::const_iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i) + if ((*i)->needs_quest) return true; + return false; } @@ -1072,111 +1123,30 @@ bool LootTemplate::LootGroup::HasQuestDrop() const bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player const* player) const { for (LootStoreItemList::const_iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i) - if (player->HasQuestForItem(i->itemid)) + if (player->HasQuestForItem((*i)->itemid)) return true; + for (LootStoreItemList::const_iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i) - if (player->HasQuestForItem(i->itemid)) + if (player->HasQuestForItem((*i)->itemid)) return true; + return false; } void LootTemplate::LootGroup::CopyConditions(ConditionList /*conditions*/) { for (LootStoreItemList::iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i) - { - i->conditions.clear(); - } + (*i)->conditions.clear(); + for (LootStoreItemList::iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i) - { - i->conditions.clear(); - } + (*i)->conditions.clear(); } // Rolls an item from the group (if any takes its chance) and adds the item to the loot void LootTemplate::LootGroup::Process(Loot& loot, uint16 lootMode) const { - // build up list of possible drops - LootStoreItemList EqualPossibleDrops = EqualChanced; - LootStoreItemList ExplicitPossibleDrops = ExplicitlyChanced; - - uint8 uiAttemptCount = 0; - const uint8 uiMaxAttempts = ExplicitlyChanced.size() + EqualChanced.size(); - - while (!ExplicitPossibleDrops.empty() || !EqualPossibleDrops.empty()) - { - if (uiAttemptCount == uiMaxAttempts) // already tried rolling too many times, just abort - return; - - LootStoreItem* item = NULL; - - // begin rolling (normally called via Roll()) - LootStoreItemList::iterator itr; - uint8 itemSource = 0; - if (!ExplicitPossibleDrops.empty()) // First explicitly chanced entries are checked - { - itemSource = 1; - float Roll = (float)rand_chance(); - // check each explicitly chanced entry in the template and modify its chance based on quality - for (itr = ExplicitPossibleDrops.begin(); itr != ExplicitPossibleDrops.end(); itr = ExplicitPossibleDrops.erase(itr)) - { - if (itr->chance >= 100.0f) - { - item = &*itr; - break; - } - - Roll -= itr->chance; - if (Roll < 0) - { - item = &*itr; - break; - } - } - } - if (item == NULL && !EqualPossibleDrops.empty()) // If nothing selected yet - an item is taken from equal-chanced part - { - itemSource = 2; - itr = EqualPossibleDrops.begin(); - std::advance(itr, irand(0, EqualPossibleDrops.size()-1)); - item = &*itr; - } - // finish rolling - - ++uiAttemptCount; - - if (item != NULL && item->lootmode & lootMode) // only add this item if roll succeeds and the mode matches - { - bool duplicate = false; - if (ItemTemplate const* _proto = sObjectMgr->GetItemTemplate(item->itemid)) - { - uint8 _item_counter = 0; - for (LootItemList::const_iterator _item = loot.items.begin(); _item != loot.items.end(); ++_item) - if (_item->itemid == item->itemid) // search through the items that have already dropped - { - ++_item_counter; - if (_proto->InventoryType == 0 && _item_counter == 3) // Non-equippable items are limited to 3 drops - duplicate = true; - else if (_proto->InventoryType != 0 && _item_counter == 1) // Equippable item are limited to 1 drop - duplicate = true; - } - } - if (duplicate) // if item->itemid is a duplicate, remove it - switch (itemSource) - { - case 1: // item came from ExplicitPossibleDrops - ExplicitPossibleDrops.erase(itr); - break; - case 2: // item came from EqualPossibleDrops - EqualPossibleDrops.erase(itr); - break; - } - else // otherwise, add the item and exit the function - { - loot.AddItem(*item); - return; - } - } - } + if (LootStoreItem const* item = Roll(lootMode)) + loot.AddItem(*item); } // Overall chance for the group without equal chanced items @@ -1185,8 +1155,8 @@ float LootTemplate::LootGroup::RawTotalChance() const float result = 0; for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i) - if (!i->needs_quest) - result += i->chance; + if (!(*i)->needs_quest) + result += (*i)->chance; return result; } @@ -1214,25 +1184,27 @@ void LootTemplate::LootGroup::Verify(LootStore const& lootstore, uint32 id, uint void LootTemplate::LootGroup::CheckLootRefs(LootTemplateMap const& /*store*/, LootIdSet* ref_set) const { - for (LootStoreItemList::const_iterator ieItr=ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr) + for (LootStoreItemList::const_iterator ieItr = ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr) { - if (ieItr->mincountOrRef < 0) + LootStoreItem* item = *ieItr; + if (item->mincountOrRef < 0) { - if (!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef)) - LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef); + if (!LootTemplates_Reference.GetLootFor(-item->mincountOrRef)) + LootTemplates_Reference.ReportNotExistedId(-item->mincountOrRef); else if (ref_set) - ref_set->erase(-ieItr->mincountOrRef); + ref_set->erase(-item->mincountOrRef); } } - for (LootStoreItemList::const_iterator ieItr=EqualChanced.begin(); ieItr != EqualChanced.end(); ++ieItr) + for (LootStoreItemList::const_iterator ieItr = EqualChanced.begin(); ieItr != EqualChanced.end(); ++ieItr) { - if (ieItr->mincountOrRef < 0) + LootStoreItem* item = *ieItr; + if (item->mincountOrRef < 0) { - if (!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef)) - LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef); + if (!LootTemplates_Reference.GetLootFor(-item->mincountOrRef)) + LootTemplates_Reference.ReportNotExistedId(-item->mincountOrRef); else if (ref_set) - ref_set->erase(-ieItr->mincountOrRef); + ref_set->erase(-item->mincountOrRef); } } } @@ -1241,14 +1213,30 @@ void LootTemplate::LootGroup::CheckLootRefs(LootTemplateMap const& /*store*/, Lo // --------- LootTemplate --------- // +LootTemplate::~LootTemplate() +{ + while (!Entries.empty()) + { + delete Entries.back(); + Entries.pop_back(); + } + + for (size_t i = 0; i < Groups.size(); ++i) + delete Groups[i]; + Groups.clear(); +} + // Adds an entry to the group (at loading stage) -void LootTemplate::AddEntry(LootStoreItem& item) +void LootTemplate::AddEntry(LootStoreItem* item) { - if (item.group > 0 && item.mincountOrRef > 0) // Group + if (item->group > 0 && item->mincountOrRef > 0) // Group { - if (item.group >= Groups.size()) - Groups.resize(item.group); // Adds new group the the loot template if needed - Groups[item.group-1].AddEntry(item); // Adds new entry to the group + if (item->group >= Groups.size()) + Groups.resize(item->group, NULL); // Adds new group the the loot template if needed + if (!Groups[item->group - 1]) + Groups[item->group - 1] = new LootGroup(); + + Groups[item->group-1]->AddEntry(item); // Adds new entry to the group } else // Non-grouped entries and references are stored together Entries.push_back(item); @@ -1257,10 +1245,11 @@ void LootTemplate::AddEntry(LootStoreItem& item) void LootTemplate::CopyConditions(ConditionList conditions) { for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i) - i->conditions.clear(); + (*i)->conditions.clear(); for (LootGroups::iterator i = Groups.begin(); i != Groups.end(); ++i) - i->CopyConditions(conditions); + if (LootGroup* group = *i) + group->CopyConditions(conditions); } void LootTemplate::CopyConditions(LootItem* li) const @@ -1268,10 +1257,11 @@ void LootTemplate::CopyConditions(LootItem* li) const // Copies the conditions list from a template item to a LootItem for (LootStoreItemList::const_iterator _iter = Entries.begin(); _iter != Entries.end(); ++_iter) { - if (_iter->itemid != li->itemid) + LootStoreItem* item = *_iter; + if (item->itemid != li->itemid) continue; - li->conditions = _iter->conditions; + li->conditions = item->conditions; break; } } @@ -1284,54 +1274,42 @@ void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId if (groupId > Groups.size()) return; // Error message already printed at loading stage - Groups[groupId-1].Process(loot, lootMode); + if (!Groups[groupId - 1]) + return; + + Groups[groupId-1]->Process(loot, lootMode); return; } // Rolling non-grouped items for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i) { - if (i->lootmode &~ lootMode) // Do not add if mode mismatch + LootStoreItem* item = *i; + if (item->lootmode &~ lootMode) // Do not add if mode mismatch continue; - if (!i->Roll(rate)) - continue; // Bad luck for the entry - - if (ItemTemplate const* _proto = sObjectMgr->GetItemTemplate(i->itemid)) - { - uint8 _item_counter = 0; - LootItemList::const_iterator _item = loot.items.begin(); - for (; _item != loot.items.end(); ++_item) - if (_item->itemid == i->itemid) // search through the items that have already dropped - { - ++_item_counter; - if (_proto->InventoryType == 0 && _item_counter == 3) // Non-equippable items are limited to 3 drops - continue; - else if (_proto->InventoryType != 0 && _item_counter == 1) // Equippable item are limited to 1 drop - continue; - } - if (_item != loot.items.end()) - continue; - } + if (!item->Roll(rate)) + continue; // Bad luck for the entry - if (i->mincountOrRef < 0) // References processing + if (item->mincountOrRef < 0) // References processing { - LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(-i->mincountOrRef); + LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(-item->mincountOrRef); if (!Referenced) - continue; // Error message already printed at loading stage + continue; // Error message already printed at loading stage - uint32 maxcount = uint32(float(i->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT)); - for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator - Referenced->Process(loot, rate, lootMode, i->group); + uint32 maxcount = uint32(float(item->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT)); + for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator + Referenced->Process(loot, rate, lootMode, item->group); } - else // Plain entries (not a reference, not grouped) - loot.AddItem(*i); // Chance is already checked, just add + else // Plain entries (not a reference, not grouped) + loot.AddItem(*item); // Chance is already checked, just add } // Now processing groups for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i) - i->Process(loot, lootMode); + if (LootGroup* group = *i) + group->Process(loot, lootMode); } // True if template includes at least 1 quest drop entry @@ -1341,27 +1319,33 @@ bool LootTemplate::HasQuestDrop(LootTemplateMap const& store, uint8 groupId) con { if (groupId > Groups.size()) return false; // Error message [should be] already printed at loading stage - return Groups[groupId-1].HasQuestDrop(); + + if (!Groups[groupId - 1]) + return false; + + return Groups[groupId-1]->HasQuestDrop(); } for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i) { - if (i->mincountOrRef < 0) // References + LootStoreItem* item = *i; + if (item->mincountOrRef < 0) // References { - LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef); + LootTemplateMap::const_iterator Referenced = store.find(-item->mincountOrRef); if (Referenced == store.end()) continue; // Error message [should be] already printed at loading stage - if (Referenced->second->HasQuestDrop(store, i->group)) + if (Referenced->second->HasQuestDrop(store, item->group)) return true; } - else if (i->needs_quest) + else if (item->needs_quest) return true; // quest drop found } // Now processing groups for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i) - if (i->HasQuestDrop()) - return true; + if (LootGroup* group = *i) + if (group->HasQuestDrop()) + return true; return false; } @@ -1373,28 +1357,34 @@ bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player co { if (groupId > Groups.size()) return false; // Error message already printed at loading stage - return Groups[groupId-1].HasQuestDropForPlayer(player); + + if (!Groups[groupId - 1]) + return false; + + return Groups[groupId-1]->HasQuestDropForPlayer(player); } // Checking non-grouped entries for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i) { - if (i->mincountOrRef < 0) // References processing + LootStoreItem* item = *i; + if (item->mincountOrRef < 0) // References processing { - LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef); + LootTemplateMap::const_iterator Referenced = store.find(-item->mincountOrRef); if (Referenced == store.end()) continue; // Error message already printed at loading stage - if (Referenced->second->HasQuestDropForPlayer(store, player, i->group)) + if (Referenced->second->HasQuestDropForPlayer(store, player, item->group)) return true; } - else if (player->HasQuestForItem(i->itemid)) + else if (player->HasQuestForItem(item->itemid)) return true; // active quest drop found } // Now checking groups for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i) - if (i->HasQuestDropForPlayer(player)) - return true; + if (LootGroup* group = *i) + if (group->HasQuestDropForPlayer(player)) + return true; return false; } @@ -1403,8 +1393,9 @@ bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player co void LootTemplate::Verify(LootStore const& lootstore, uint32 id) const { // Checking group chances - for (uint32 i=0; i < Groups.size(); ++i) - Groups[i].Verify(lootstore, id, i+1); + for (uint32 i = 0; i < Groups.size(); ++i) + if (Groups[i]) + Groups[i]->Verify(lootstore, id, i + 1); // TODO: References validity checks } @@ -1413,18 +1404,21 @@ void LootTemplate::CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_se { for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr) { - if (ieItr->mincountOrRef < 0) + LootStoreItem* item = *ieItr; + if (item->mincountOrRef < 0) { - if (!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef)) - LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef); + if (!LootTemplates_Reference.GetLootFor(-item->mincountOrRef)) + LootTemplates_Reference.ReportNotExistedId(-item->mincountOrRef); else if (ref_set) - ref_set->erase(-ieItr->mincountOrRef); + ref_set->erase(-item->mincountOrRef); } } for (LootGroups::const_iterator grItr = Groups.begin(); grItr != Groups.end(); ++grItr) - grItr->CheckLootRefs(store, ref_set); + if (LootGroup* group = *grItr) + group->CheckLootRefs(store, ref_set); } + bool LootTemplate::addConditionItem(Condition* cond) { if (!cond || !cond->isLoaded())//should never happen, checked at loading @@ -1432,41 +1426,48 @@ bool LootTemplate::addConditionItem(Condition* cond) sLog->outError(LOG_FILTER_LOOT, "LootTemplate::addConditionItem: condition is null"); return false; } + if (!Entries.empty()) { for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i) { - if (i->itemid == uint32(cond->SourceEntry)) + if ((*i)->itemid == uint32(cond->SourceEntry)) { - i->conditions.push_back(cond); + (*i)->conditions.push_back(cond); return true; } } } + if (!Groups.empty()) { for (LootGroups::iterator groupItr = Groups.begin(); groupItr != Groups.end(); ++groupItr) { - LootStoreItemList* itemList = (*groupItr).GetExplicitlyChancedItemList(); + LootGroup* group = *groupItr; + if (!group) + continue; + + LootStoreItemList* itemList = group->GetExplicitlyChancedItemList(); if (!itemList->empty()) { for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i) { - if ((*i).itemid == uint32(cond->SourceEntry)) + if ((*i)->itemid == uint32(cond->SourceEntry)) { - (*i).conditions.push_back(cond); + (*i)->conditions.push_back(cond); return true; } } } - itemList = (*groupItr).GetEqualChancedItemList(); + + itemList = group->GetEqualChancedItemList(); if (!itemList->empty()) { for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i) { - if ((*i).itemid == uint32(cond->SourceEntry)) + if ((*i)->itemid == uint32(cond->SourceEntry)) { - (*i).conditions.push_back(cond); + (*i)->conditions.push_back(cond); return true; } } @@ -1479,10 +1480,9 @@ bool LootTemplate::addConditionItem(Condition* cond) bool LootTemplate::isReference(uint32 id) { for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr) - { - if (ieItr->itemid == id && ieItr->mincountOrRef < 0) + if ((*ieItr)->itemid == id && (*ieItr)->mincountOrRef < 0) return true; - } + return false;//not found or not reference } diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h index 759064385a5..df2717ee36e 100644 --- a/src/server/game/Loot/LootMgr.h +++ b/src/server/game/Loot/LootMgr.h @@ -27,6 +27,7 @@ #include <map> #include <vector> +#include <list> enum RollType { @@ -174,7 +175,7 @@ class LootTemplate; typedef std::vector<QuestItem> QuestItemList; typedef std::vector<LootItem> LootItemList; typedef std::map<uint32, QuestItemList*> QuestItemMap; -typedef std::vector<LootStoreItem> LootStoreItemList; +typedef std::list<LootStoreItem*> LootStoreItemList; typedef UNORDERED_MAP<uint32, LootTemplate*> LootTemplateMap; typedef std::set<uint32> LootIdSet; @@ -218,11 +219,14 @@ class LootStore class LootTemplate { class LootGroup; // A set of loot definitions for items (refs are not allowed inside) - typedef std::vector<LootGroup> LootGroups; + typedef std::vector<LootGroup*> LootGroups; public: + LootTemplate() { } + ~LootTemplate(); + // Adds an entry to the group (at loading stage) - void AddEntry(LootStoreItem& item); + void AddEntry(LootStoreItem* item); // Rolls for every item in the template and adds the rolled items the the loot void Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId = 0) const; void CopyConditions(ConditionList conditions); @@ -242,6 +246,10 @@ class LootTemplate private: LootStoreItemList Entries; // not grouped only LootGroups Groups; // groups have own (optimised) processing, grouped entries go there + + // Objects of this class must never be copied, we are storing pointers in container + LootTemplate(LootTemplate const&); + LootTemplate& operator=(LootTemplate const&); }; //===================================================== diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 184450ef8d6..288592d1029 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -2486,11 +2486,7 @@ bool InstanceMap::AddPlayerToMap(Player* player) } if (group && group->isLFGGroup()) - if (uint32 dungeonId = sLFGMgr->GetDungeon(group->GetGUID(), true)) - if (LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(dungeonId)) - if (LFGDungeonData const* randomDungeon = sLFGMgr->GetLFGDungeon(*(sLFGMgr->GetSelectedDungeons(player->GetGUID()).begin()))) - if (uint32(dungeon->map) == GetId() && dungeon->difficulty == GetDifficulty() && randomDungeon->type == LFG_TYPE_RANDOM) - player->CastSpell(player, LFG_SPELL_LUCK_OF_THE_DRAW, true); + player->CastSpell(player, lfg::LFG_SPELL_LUCK_OF_THE_DRAW, true); } // for normal instances cancel the reset schedule when the diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index e13cc86747c..5868b60b722 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -86,7 +86,40 @@ enum TrinityStrings LANG_CONNECTED_PLAYERS = 60, LANG_ACCOUNT_ADDON = 61, LANG_IMPROPER_VALUE = 62, - // Room for more level 0 63-99 not used + LANG_RBAC_WRONG_PARAMETER_ID = 63, + LANG_RBAC_WRONG_PARAMETER_REALM = 64, + LANG_RBAC_GROUP_IN_LIST = 65, + LANG_RBAC_GROUP_NOT_IN_LIST = 66, + LANG_RBAC_GROUP_ADDED = 67, + LANG_RBAC_GROUP_REMOVED = 68, + LANG_RBAC_GROUP_LIST_HEADER = 69, + LANG_RBAC_LIST_EMPTY = 70, + LANG_RBAC_LIST_ELEMENT = 71, + LANG_RBAC_ROLE_GRANTED_IN_LIST = 72, + LANG_RBAC_ROLE_GRANTED_IN_DENIED_LIST = 73, + LANG_RBAC_ROLE_GRANTED = 74, + LANG_RBAC_ROLE_DENIED_IN_LIST = 75, + LANG_RBAC_ROLE_DENIED_IN_GRANTED_LIST = 76, + LANG_RBAC_ROLE_DENIED = 77, + LANG_RBAC_ROLE_REVOKED = 78, + LANG_RBAC_ROLE_REVOKED_NOT_IN_LIST = 79, + LANG_RBAC_ROLE_LIST_HEADER_GRANTED = 80, + LANG_RBAC_ROLE_LIST_HEADER_DENIED = 81, + LANG_RBAC_PERM_GRANTED_IN_LIST = 82, + LANG_RBAC_PERM_GRANTED_IN_DENIED_LIST = 83, + LANG_RBAC_PERM_GRANTED = 84, + LANG_RBAC_PERM_DENIED_IN_LIST = 85, + LANG_RBAC_PERM_DENIED_IN_GRANTED_LIST = 86, + LANG_RBAC_PERM_DENIED = 87, + LANG_RBAC_PERM_REVOKED = 88, + LANG_RBAC_PERM_REVOKED_NOT_IN_LIST = 89, + LANG_RBAC_PERM_LIST_HEADER_GRANTED = 90, + LANG_RBAC_PERM_LIST_HEADER_DENIED = 91, + LANG_RBAC_PERM_LIST_GLOBAL = 92, + LANG_RBAC_LIST_GROUPS_HEADER = 93, + LANG_RBAC_LIST_ROLES_HEADER = 94, + LANG_RBAC_LIST_PERMISSIONS_HEADER = 95, + // Room for more level 0 96-99 not used // level 1 chat LANG_GLOBAL_NOTIFY = 100, diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp index 06b2315f294..1f5503948c8 100755 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp @@ -128,8 +128,6 @@ void EffectMovementGenerator::Finalize(Unit* unit) if (unit->GetTypeId() != TYPEID_UNIT) return; - if (unit->ToCreature()->AI()) - unit->ToCreature()->AI()->MovementInform(EFFECT_MOTION_TYPE, m_Id); // Need restore previous movement since we have no proper states system if (unit->isAlive() && !unit->HasUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_FLEEING)) { @@ -138,4 +136,7 @@ void EffectMovementGenerator::Finalize(Unit* unit) else unit->GetMotionMaster()->Initialize(); } + + if (unit->ToCreature()->AI()) + unit->ToCreature()->AI()->MovementInform(EFFECT_MOTION_TYPE, m_Id); } diff --git a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp index 801219b2a5a..29d1bb50a8f 100644 --- a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp +++ b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp @@ -146,7 +146,7 @@ namespace Movement //data.append<float>(&mov.m_float_values[SpeedWalk], SpeedMaxCount); //if (mov.SplineEnabled()) { - MoveSplineFlag splineFlags = move_spline.splineflags; + MoveSplineFlag const& splineFlags = move_spline.splineflags; data << splineFlags.raw(); diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index efd45188d42..afc153a5000 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -70,6 +70,7 @@ void AddSC_mmaps_commandscript(); void AddSC_modify_commandscript(); void AddSC_npc_commandscript(); void AddSC_quest_commandscript(); +void AddSC_rbac_commandscript(); void AddSC_reload_commandscript(); void AddSC_reset_commandscript(); void AddSC_server_commandscript(); @@ -700,6 +701,7 @@ void AddCommandScripts() AddSC_modify_commandscript(); AddSC_npc_commandscript(); AddSC_quest_commandscript(); + AddSC_rbac_commandscript(); AddSC_reload_commandscript(); AddSC_reset_commandscript(); AddSC_server_commandscript(); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 6c689319bc7..522dc95105d 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -21,6 +21,7 @@ */ #include "WorldSocket.h" // must be first to make ACE happy with ACE includes in it +#include "Config.h" #include "Common.h" #include "DatabaseEnv.h" #include "Log.h" @@ -115,7 +116,8 @@ WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8 m_TutorialsChanged(false), recruiterId(recruiter), isRecruiter(isARecruiter), - timeLastWhoCommand(0) + timeLastWhoCommand(0), + _RBACData(NULL) { if (sock) { @@ -143,8 +145,8 @@ WorldSession::~WorldSession() m_Socket = NULL; } - if (_warden) - delete _warden; + delete _warden; + delete _RBACData; ///- empty incoming packet queue WorldPacket* packet = NULL; @@ -1200,3 +1202,24 @@ void WorldSession::InitWarden(BigNumber* k, std::string const& os) // _warden->Init(this, k); } } + +void WorldSession::LoadPermissions() +{ + uint32 id = GetAccountId(); + std::string name; + int32 realmId = ConfigMgr::GetIntDefault("RealmID", 0); + AccountMgr::GetName(id, name); + + _RBACData = new RBACData(id, name, realmId); + _RBACData->LoadFromDB(); +} + +RBACData* WorldSession::GetRBACData() +{ + return _RBACData; +} + +bool WorldSession::HasPermission(uint32 permission) +{ + return _RBACData->HasPermission(permission); +} diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index abe048279db..d6877b8a18a 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -24,6 +24,7 @@ #define __WORLDSESSION_H #include "Common.h" +#include "AccountMgr.h" #include "SharedDefines.h" #include "AddonMgr.h" #include "DatabaseEnv.h" @@ -48,15 +49,18 @@ struct AreaTableEntry; struct AuctionEntry; struct DeclinedName; struct ItemTemplate; +struct MovementInfo; + +namespace lfg +{ struct LfgJoinResultData; -struct LfgLockStatus; struct LfgPlayerBoot; struct LfgProposal; struct LfgQueueStatusData; struct LfgPlayerRewardData; struct LfgRoleCheck; struct LfgUpdateData; -struct MovementInfo; +} enum AccountDataType { @@ -213,6 +217,10 @@ class WorldSession void SendAuthResponse(uint8 code, bool shortForm, uint32 queuePos = 0); void SendClientCacheVersion(uint32 version); + RBACData* GetRBACData(); + bool HasPermission(uint32 permissionId); + void LoadPermissions(); + AccountTypes GetSecurity() const { return _security; } uint32 GetAccountId() const { return _accountId; } Player* GetPlayer() const { return _player; } @@ -782,16 +790,16 @@ class WorldSession void HandleLfrLeaveOpcode(WorldPacket& recvData); void HandleLfgGetStatus(WorldPacket& recvData); - void SendLfgUpdatePlayer(LfgUpdateData const& updateData); - void SendLfgUpdateParty(LfgUpdateData const& updateData); + void SendLfgUpdatePlayer(lfg::LfgUpdateData const& updateData); + void SendLfgUpdateParty(lfg::LfgUpdateData const& updateData); void SendLfgRoleChosen(uint64 guid, uint8 roles); - void SendLfgRoleCheckUpdate(LfgRoleCheck const& pRoleCheck); + void SendLfgRoleCheckUpdate(lfg::LfgRoleCheck const& pRoleCheck); void SendLfgLfrList(bool update); - void SendLfgJoinResult(LfgJoinResultData const& joinData); - void SendLfgQueueStatus(LfgQueueStatusData const& queueData); - void SendLfgPlayerReward(LfgPlayerRewardData const& lfgPlayerRewardData); - void SendLfgBootProposalUpdate(LfgPlayerBoot const& boot); - void SendLfgUpdateProposal(LfgProposal const& proposal); + void SendLfgJoinResult(lfg::LfgJoinResultData const& joinData); + void SendLfgQueueStatus(lfg::LfgQueueStatusData const& queueData); + void SendLfgPlayerReward(lfg::LfgPlayerRewardData const& lfgPlayerRewardData); + void SendLfgBootProposalUpdate(lfg::LfgPlayerBoot const& boot); + void SendLfgUpdateProposal(lfg::LfgProposal const& proposal); void SendLfgDisabled(); void SendLfgOfferContinue(uint32 dungeonEntry); void SendLfgTeleportError(uint8 err); @@ -951,6 +959,7 @@ class WorldSession bool isRecruiter; ACE_Based::LockedQueue<WorldPacket*, ACE_Thread_Mutex> _recvQueue; time_t timeLastWhoCommand; + RBACData* _RBACData; }; #endif /// @} diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 74c2dceadf0..8b102518e84 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -953,6 +953,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) m_Session->LoadGlobalAccountData(); m_Session->LoadTutorialsData(); m_Session->ReadAddonsInfo(recvPacket); + m_Session->LoadPermissions(); // Initialize Warden system only if it is enabled by config if (sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED)) diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 05119af2582..d6b19e6010a 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -2375,7 +2375,10 @@ void AuraEffect::HandleAuraTrackCreatures(AuraApplication const* aurApp, uint8 m if (target->GetTypeId() != TYPEID_PLAYER) return; - target->SetUInt32Value(PLAYER_TRACK_CREATURES, (apply) ? ((uint32)1)<<(GetMiscValue()-1) : 0); + if (apply) + target->SetFlag(PLAYER_TRACK_CREATURES, uint32(1) << (GetMiscValue() - 1)); + else + target->RemoveFlag(PLAYER_TRACK_CREATURES, uint32(1) << (GetMiscValue() - 1)); } void AuraEffect::HandleAuraTrackResources(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -2388,7 +2391,10 @@ void AuraEffect::HandleAuraTrackResources(AuraApplication const* aurApp, uint8 m if (target->GetTypeId() != TYPEID_PLAYER) return; - target->SetUInt32Value(PLAYER_TRACK_RESOURCES, (apply) ? ((uint32)1)<<(GetMiscValue()-1): 0); + if (apply) + target->SetFlag(PLAYER_TRACK_RESOURCES, uint32(1) << (GetMiscValue() - 1)); + else + target->RemoveFlag(PLAYER_TRACK_RESOURCES, uint32(1) << (GetMiscValue() - 1)); } void AuraEffect::HandleAuraTrackStealthed(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -3339,22 +3345,19 @@ void AuraEffect::HandleAuraModEffectImmunity(AuraApplication const* aurApp, uint Unit* target = aurApp->GetTarget(); - target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, GetMiscValue(), apply); + target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, GetMiscValue(), apply); // when removing flag aura, handle flag drop - if (!apply && target->GetTypeId() == TYPEID_PLAYER - && (GetSpellInfo()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION)) + Player* player = target->ToPlayer(); + if (!apply && player && (GetSpellInfo()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION)) { - if (target->GetTypeId() == TYPEID_PLAYER) + if (player->InBattleground()) { - if (target->ToPlayer()->InBattleground()) - { - if (Battleground* bg = target->ToPlayer()->GetBattleground()) - bg->EventPlayerDroppedFlag(target->ToPlayer()); - } - else - sOutdoorPvPMgr->HandleDropFlag((Player*)target, GetSpellInfo()->Id); + if (Battleground* bg = player->GetBattleground()) + bg->EventPlayerDroppedFlag(player); } + else + sOutdoorPvPMgr->HandleDropFlag(player, GetSpellInfo()->Id); } } @@ -5058,10 +5061,6 @@ void AuraEffect::HandleAuraEmpathy(AuraApplication const* aurApp, uint8 mode, bo return; Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() != TYPEID_UNIT) - return; - if (!apply) { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit @@ -5069,8 +5068,7 @@ void AuraEffect::HandleAuraEmpathy(AuraApplication const* aurApp, uint8 mode, bo return; } - CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(target->GetEntry()); - if (ci && ci->type == CREATURE_TYPE_BEAST) + if (target->GetCreatureType() == CREATURE_TYPE_BEAST) target->ApplyModUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_SPECIALINFO, apply); } diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index ba7c87ba10a..8b440b665ad 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -3212,24 +3212,6 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) switch (m_spellInfo->SpellFamilyName) { - case SPELLFAMILY_GENERIC: - { - switch (m_spellInfo->Id) - { - case 69055: // Saber Lash - case 70814: // Saber Lash - { - uint32 count = 0; - for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) - if (ihit->effectMask & (1 << effIndex)) - ++count; - - totalDamagePercentMod /= count; - break; - } - } - break; - } case SPELLFAMILY_WARRIOR: { // Devastate (player ones) diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 0c298efd83e..91bff331160 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -849,7 +849,7 @@ bool SpellInfo::IsLootCrafting() const return (Effects[0].Effect == SPELL_EFFECT_CREATE_RANDOM_ITEM || // different random cards from Inscription (121==Virtuoso Inking Set category) r without explicit item (Effects[0].Effect == SPELL_EFFECT_CREATE_ITEM_2 && - (TotemCategory[0] != 0 || Effects[0].ItemType == 0))); + ((TotemCategory[0] != 0 || (Totem[0] != 0 && SpellIconID == 1)) || Effects[0].ItemType == 0))); } bool SpellInfo::IsQuestTame() const @@ -1922,6 +1922,9 @@ SpellSpecificType SpellInfo::GetSpellSpecific() const case SPELL_AURA_AOE_CHARM: return SPELL_SPECIFIC_CHARM; case SPELL_AURA_TRACK_CREATURES: + /// @workaround For non-stacking tracking spells (We need generic solution) + if (Id == 30645) // Gas Cloud Tracking + return SPELL_SPECIFIC_NORMAL; case SPELL_AURA_TRACK_RESOURCES: case SPELL_AURA_TRACK_STEALTHED: return SPELL_SPECIFIC_TRACKER; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index b258f01ccd5..dbd4e3904ea 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3397,9 +3397,9 @@ void SpellMgr::LoadDbcDataCorrections() case 70861: // Sindragosa's Lair Teleport spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DB; break; - case 69055: // Saber Lash (Lord Marrowgar) - case 70814: // Saber Lash (Lord Marrowgar) - spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_5_YARDS; // 5yd + case 69055: // Bone Slice (Lord Marrowgar) + case 70814: // Bone Slice (Lord Marrowgar) + spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_8_YARDS; // 5yd break; case 69075: // Bone Storm (Lord Marrowgar) case 70834: // Bone Storm (Lord Marrowgar) diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index 89ed223545f..6229a30a5f0 100644 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -612,7 +612,7 @@ SpellValue const* SpellScript::GetSpellValue() bool AuraScript::_Validate(SpellInfo const* entry) { for (std::list<CheckAreaTargetHandler>::iterator itr = DoCheckAreaTarget.begin(); itr != DoCheckAreaTarget.end(); ++itr) - if (!entry->HasAreaAuraEffect()) + if (!entry->HasAreaAuraEffect() && !entry->HasEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA)) sLog->outError(LOG_FILTER_TSCR, "Spell `%u` of script `%s` does not have area aura effect - handler bound to hook `DoCheckAreaTarget` of AuraScript won't be executed", entry->Id, m_scriptName->c_str()); for (std::list<AuraDispelHandler>::iterator itr = OnDispel.begin(); itr != OnDispel.end(); ++itr) diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index c43cbbd417e..d02ba402c53 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -267,7 +267,7 @@ void World::AddSession_(WorldSession* s) if (decrease_session) --Sessions; - if (pLimit > 0 && Sessions >= pLimit && AccountMgr::IsPlayerAccount(s->GetSecurity()) && !HasRecentlyDisconnected(s)) + if (pLimit > 0 && Sessions >= pLimit && !s->HasPermission(RBAC_PERM_SKIP_QUEUE) && !HasRecentlyDisconnected(s)) { AddQueuedPlayer(s); UpdateMaxSessionCounters(); @@ -585,7 +585,6 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_TICKET_LEVEL_REQ] = ConfigMgr::GetIntDefault("LevelReq.Ticket", 1); m_int_configs[CONFIG_AUCTION_LEVEL_REQ] = ConfigMgr::GetIntDefault("LevelReq.Auction", 1); m_int_configs[CONFIG_MAIL_LEVEL_REQ] = ConfigMgr::GetIntDefault("LevelReq.Mail", 1); - m_bool_configs[CONFIG_ALLOW_PLAYER_COMMANDS] = ConfigMgr::GetBoolDefault("AllowPlayerCommands", 1); m_bool_configs[CONFIG_PRESERVE_CUSTOM_CHANNELS] = ConfigMgr::GetBoolDefault("PreserveCustomChannels", false); m_int_configs[CONFIG_PRESERVE_CUSTOM_CHANNEL_DURATION] = ConfigMgr::GetIntDefault("PreserveCustomChannelDuration", 14); m_bool_configs[CONFIG_GRID_UNLOAD] = ConfigMgr::GetBoolDefault("GridUnload", true); @@ -1059,8 +1058,6 @@ void World::LoadConfigSettings(bool reload) sLog->outError(LOG_FILTER_SERVER_LOADING, "ClientCacheVersion can't be negative %d, ignored.", clientCacheId); } - m_int_configs[CONFIG_INSTANT_LOGOUT] = ConfigMgr::GetIntDefault("InstantLogout", SEC_MODERATOR); - m_int_configs[CONFIG_GUILD_EVENT_LOG_COUNT] = ConfigMgr::GetIntDefault("Guild.EventLogRecordsCount", GUILD_EVENTLOG_MAX_RECORDS); if (m_int_configs[CONFIG_GUILD_EVENT_LOG_COUNT] > GUILD_EVENTLOG_MAX_RECORDS) m_int_configs[CONFIG_GUILD_EVENT_LOG_COUNT] = GUILD_EVENTLOG_MAX_RECORDS; @@ -1348,6 +1345,8 @@ void World::SetInitialWorldSettings() sObjectMgr->SetDBCLocaleIndex(GetDefaultDbcLocale()); // Get once for all the locale index of DBC language (console/broadcasts) sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Localization strings loaded in %u ms", GetMSTimeDiffToNow(oldMSTime)); + sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Account Roles and Permissions..."); + sAccountMgr->LoadRBAC(); sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Page Texts..."); sObjectMgr->LoadPageTexts(); @@ -2858,8 +2857,6 @@ void World::ResetMonthlyQuests() if (itr->second->GetPlayer()) itr->second->GetPlayer()->ResetMonthlyQuestStatus(); - time_t mostRecentQuestTime = 0; - // generate time time_t curTime = time(NULL); tm localTm = *localtime(&curTime); @@ -2886,14 +2883,8 @@ void World::ResetMonthlyQuests() time_t nextMonthResetTime = mktime(&localTm); - // last reset time before current moment - time_t resetTime = (curTime < nextMonthResetTime) ? nextMonthResetTime - MONTH : nextMonthResetTime; - - // need reset (if we have quest time before last reset time (not processed by some reason) - if (mostRecentQuestTime && mostRecentQuestTime <= resetTime) - m_NextMonthlyQuestReset = mostRecentQuestTime; - else // plan next reset time - m_NextMonthlyQuestReset = (curTime >= nextMonthResetTime) ? nextMonthResetTime + MONTH : nextMonthResetTime; + // plan next reset time + m_NextMonthlyQuestReset = (curTime >= nextMonthResetTime) ? nextMonthResetTime + MONTH : nextMonthResetTime; sWorld->setWorldState(WS_MONTHLY_QUEST_RESET_TIME, uint64(m_NextMonthlyQuestReset)); } diff --git a/src/server/scripts/Commands/CMakeLists.txt b/src/server/scripts/Commands/CMakeLists.txt index 7b9e2444952..83e97b2c80d 100644 --- a/src/server/scripts/Commands/CMakeLists.txt +++ b/src/server/scripts/Commands/CMakeLists.txt @@ -35,6 +35,7 @@ set(scripts_STAT_SRCS Commands/cs_modify.cpp Commands/cs_npc.cpp Commands/cs_quest.cpp + Commands/cs_rbac.cpp Commands/cs_reload.cpp Commands/cs_reset.cpp Commands/cs_tele.cpp diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp index 3a20a03bb4a..4dc44bbfc58 100644 --- a/src/server/scripts/Commands/cs_account.cpp +++ b/src/server/scripts/Commands/cs_account.cpp @@ -106,7 +106,7 @@ public: if (!accountName || !password) return false; - AccountOpResult result = AccountMgr::CreateAccount(std::string(accountName), std::string(password)); + AccountOpResult result = sAccountMgr->CreateAccount(std::string(accountName), std::string(password)); switch (result) { case AOR_OK: @@ -503,36 +503,8 @@ public: return false; } - // If gmRealmID is -1, delete all values for the account id, else, insert values for the specific realmID - PreparedStatement* stmt; - - if (gmRealmID == -1) - { - stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS); - - stmt->setUInt32(0, targetAccountId); - } - else - { - stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS_BY_REALM); - - stmt->setUInt32(0, targetAccountId); - stmt->setUInt32(1, realmID); - } - - LoginDatabase.Execute(stmt); - - if (gm != 0) - { - stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_ACCESS); - - stmt->setUInt32(0, targetAccountId); - stmt->setUInt8(1, uint8(gm)); - stmt->setInt32(2, gmRealmID); - - LoginDatabase.Execute(stmt); - } - + RBACData* rbac = isAccountNameGiven ? NULL : handler->getSelectedPlayer()->GetSession()->GetRBACData(); + sAccountMgr->UpdateAccountAccess(rbac, targetAccountId, uint8(gm), gmRealmID); handler->PSendSysMessage(LANG_YOU_CHANGE_SECURITY, targetAccountName.c_str(), gm); return true; diff --git a/src/server/scripts/Commands/cs_lfg.cpp b/src/server/scripts/Commands/cs_lfg.cpp index 7f39a8fc024..aa9d9308bcd 100644 --- a/src/server/scripts/Commands/cs_lfg.cpp +++ b/src/server/scripts/Commands/cs_lfg.cpp @@ -28,12 +28,12 @@ void GetPlayerInfo(ChatHandler* handler, Player* player) return; uint64 guid = player->GetGUID(); - LfgDungeonSet dungeons = sLFGMgr->GetSelectedDungeons(guid); + lfg::LfgDungeonSet dungeons = sLFGMgr->GetSelectedDungeons(guid); - std::string const& state = sLFGMgr->GetStateString(sLFGMgr->GetState(guid)); + std::string const& state = lfg::GetStateString(sLFGMgr->GetState(guid)); handler->PSendSysMessage(LANG_LFG_PLAYER_INFO, player->GetName().c_str(), - state.c_str(), uint8(dungeons.size()), sLFGMgr->ConcatenateDungeons(dungeons).c_str(), - sLFGMgr->GetRolesString(sLFGMgr->GetRoles(guid)).c_str(), sLFGMgr->GetComment(guid).c_str()); + state.c_str(), uint8(dungeons.size()), lfg::ConcatenateDungeons(dungeons).c_str(), + lfg::GetRolesString(sLFGMgr->GetRoles(guid)).c_str(), sLFGMgr->GetComment(guid).c_str()); } class lfg_commandscript : public CommandScript @@ -87,7 +87,7 @@ public: } uint64 guid = grp->GetGUID(); - std::string const& state = sLFGMgr->GetStateString(sLFGMgr->GetState(guid)); + std::string const& state = lfg::GetStateString(sLFGMgr->GetState(guid)); handler->PSendSysMessage(LANG_LFG_GROUP_INFO, grp->isLFGGroup(), state.c_str(), sLFGMgr->GetDungeon(guid)); diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 973d466bab5..cacefea7b85 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -1744,19 +1744,13 @@ public: result = CharacterDatabase.Query(stmt); if (result) { - uint32 guildId = 0; - std::string guildName = ""; - std::string guildRank = ""; - std::string note = ""; - std::string officeNote = ""; - - Field* fields = result->Fetch(); - guildId = fields[0].GetUInt32(); - guildName = fields[1].GetString(); - //rankId = fields[2].GetUInt8(); - guildRank = fields[3].GetString(); - note = fields[4].GetString(); - officeNote = fields[5].GetString(); + Field* fields = result->Fetch(); + + uint32 guildId = fields[0].GetUInt32(); + std::string guildName = fields[1].GetString(); + std::string guildRank = fields[2].GetString(); + std::string note = fields[3].GetString(); + std::string officeNote = fields[4].GetString(); handler->PSendSysMessage(LANG_PINFO_GUILD_INFO, guildName.c_str(), guildId, guildRank.c_str(), note.c_str(), officeNote.c_str()); } @@ -2853,41 +2847,40 @@ public: { handler->PSendSysMessage(LANG_GROUP_TYPE, (groupTarget->isRaidGroup() ? "raid" : "party")); Group::MemberSlotList const& members = groupTarget->GetMemberSlots(); - Group::MemberSlotList::const_iterator itr; - for (itr = members.begin(); itr != members.end(); ++itr) + for (Group::MemberSlotList::const_iterator itr = members.begin(); itr != members.end(); ++itr) { - std::ostringstream flags, roles; - if ((*itr).flags & MEMBER_FLAG_ASSISTANT) - flags << "Assistant "; - if ((*itr).flags & MEMBER_FLAG_MAINTANK) - flags << "MainTank "; - if ((*itr).flags & MEMBER_FLAG_MAINASSIST) - flags << "MainAssist "; - - if ((*itr).roles & PLAYER_ROLE_LEADER) - roles << "Leader "; - if ((*itr).roles & PLAYER_ROLE_TANK) - roles << "Tank "; - if ((*itr).roles & PLAYER_ROLE_HEALER) - roles << "Healer "; - if ((*itr).roles & PLAYER_ROLE_DAMAGE) - roles << "Damage "; + Group::MemberSlot const& slot = *itr; + + std::string flags; + if (slot.flags & MEMBER_FLAG_ASSISTANT) + flags = "Assistant"; + + if (slot.flags & MEMBER_FLAG_MAINTANK) + { + if (!flags.empty()) + flags.append(", "); + flags.append("MainTank"); + } + + if (slot.flags & MEMBER_FLAG_MAINASSIST) + { + if (!flags.empty()) + flags.append(", "); + flags.append("MainAssist"); + } + + if (flags.empty()) + flags = "None"; Player* p = ObjectAccessor::FindPlayer((*itr).guid); const char* onlineState = (p && p->IsInWorld()) ? "online" : "offline"; - std::string flagsStr = (flags.str().empty()) ? "None" : flags.str(); - std::string rolesStr = (roles.str().empty()) ? "None" : roles.str(); - - handler->PSendSysMessage(LANG_GROUP_PLAYER_NAME_GUID, (*itr).name.c_str(), onlineState, GUID_LOPART((*itr).guid), flagsStr.c_str(), rolesStr.c_str()); + handler->PSendSysMessage(LANG_GROUP_PLAYER_NAME_GUID, slot.name.c_str(), onlineState, + GUID_LOPART(slot.guid), flags.c_str(), lfg::GetRolesString(slot.roles).c_str()); } - return true; } else - { handler->PSendSysMessage(LANG_GROUP_NOT_IN_GROUP, nameTarget.c_str()); - return true; - } return true; } diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index 01648f25cff..eaed64db579 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -1046,9 +1046,12 @@ public: ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_MONEY_GIVEN, handler->GetNameLink().c_str(), moneyToAdd); if (moneyToAdd >= MAX_MONEY_AMOUNT) - target->SetMoney(MAX_MONEY_AMOUNT); - else - target->ModifyMoney(moneyToAdd); + moneyToAdd = MAX_MONEY_AMOUNT; + + if (targetMoney >= uint32(MAX_MONEY_AMOUNT) - moneyToAdd) + moneyToAdd -= targetMoney; + + target->ModifyMoney(moneyToAdd); } sLog->outDebug(LOG_FILTER_GENERAL, handler->GetTrinityString(LANG_NEW_MONEY), targetMoney, moneyToAdd, target->GetMoney()); diff --git a/src/server/scripts/Commands/cs_rbac.cpp b/src/server/scripts/Commands/cs_rbac.cpp new file mode 100644 index 00000000000..fb21def4c02 --- /dev/null +++ b/src/server/scripts/Commands/cs_rbac.cpp @@ -0,0 +1,780 @@ +/*
+ * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* ScriptData
+Name: rbac_commandscript
+%Complete: 100
+Comment: All role based access control related commands (including account related)
+Category: commandscripts
+EndScriptData */
+
+#include "RBAC.h"
+#include "Config.h"
+#include "Chat.h"
+#include "Language.h"
+#include "Player.h"
+#include "ScriptMgr.h"
+
+struct RBACCommandData
+{
+ RBACCommandData(): id(0), realmId(0), rbac(NULL), needDelete(false) { }
+ uint32 id;
+ int32 realmId;
+ RBACData* rbac;
+ bool needDelete;
+};
+
+class rbac_commandscript : public CommandScript
+{
+public:
+ rbac_commandscript() : CommandScript("rbac_commandscript") { }
+
+ ChatCommand* GetCommands() const
+ {
+ static ChatCommand rbacGroupsCommandTable[] =
+ {
+ { "add", SEC_ADMINISTRATOR, true, &HandleRBACGroupAddCommand, "", NULL },
+ { "remove", SEC_ADMINISTRATOR, true, &HandleRBACGroupRemoveCommand, "", NULL },
+ { "", SEC_ADMINISTRATOR, true, &HandleRBACGroupListCommand, "", NULL },
+ { NULL, SEC_ADMINISTRATOR, false, NULL, "", NULL }
+ };
+
+ static ChatCommand rbacRolesCommandTable[] =
+ {
+ { "grant", SEC_ADMINISTRATOR, true, &HandleRBACRoleGrantCommand, "", NULL },
+ { "deny", SEC_ADMINISTRATOR, true, &HandleRBACRoleDenyCommand, "", NULL },
+ { "revoke", SEC_ADMINISTRATOR, true, &HandleRBACRoleRevokeCommand, "", NULL },
+ { "", SEC_ADMINISTRATOR, true, &HandleRBACRoleListCommand, "", NULL },
+ { NULL, SEC_ADMINISTRATOR, false, NULL, "", NULL }
+ };
+
+ static ChatCommand rbacPermsCommandTable[] =
+ {
+ { "grant", SEC_ADMINISTRATOR, true, &HandleRBACPermGrantCommand, "", NULL },
+ { "deny", SEC_ADMINISTRATOR, true, &HandleRBACPermDenyCommand, "", NULL },
+ { "revoke", SEC_ADMINISTRATOR, true, &HandleRBACPermRevokeCommand, "", NULL },
+ { "", SEC_ADMINISTRATOR, true, &HandleRBACPermListCommand, "", NULL },
+ { NULL, SEC_ADMINISTRATOR, false, NULL, "", NULL }
+ };
+
+ static ChatCommand rbacListCommandTable[] =
+ {
+ { "groups", SEC_ADMINISTRATOR, true, &HandleRBACListGroupsCommand, "", NULL },
+ { "roles", SEC_ADMINISTRATOR, true, &HandleRBACListRolesCommand, "", NULL },
+ { "permissions", SEC_ADMINISTRATOR, true, &HandleRBACListPermissionsCommand, "", NULL },
+ { NULL, SEC_ADMINISTRATOR, false, NULL, "", NULL }
+ };
+
+ static ChatCommand rbacAccountCommandTable[] =
+ {
+ { "group", SEC_ADMINISTRATOR, true, NULL, "", rbacGroupsCommandTable },
+ { "role", SEC_ADMINISTRATOR, true, NULL, "", rbacRolesCommandTable },
+ { "permission", SEC_ADMINISTRATOR, true, NULL, "", rbacPermsCommandTable },
+ { "", SEC_ADMINISTRATOR, true, &HandleRBACAccountPermissionCommand, "", NULL },
+ { NULL, SEC_ADMINISTRATOR, false, NULL, "", NULL }
+ };
+
+ static ChatCommand rbacCommandTable[] =
+ {
+ { "account", SEC_ADMINISTRATOR, true, NULL, "", rbacAccountCommandTable },
+ { "list", SEC_ADMINISTRATOR, true, NULL, "", rbacListCommandTable },
+ { NULL, SEC_ADMINISTRATOR, false, NULL, "", NULL }
+ };
+
+ static ChatCommand commandTable[] =
+ {
+ { "rbac", SEC_ADMINISTRATOR, true, NULL, "", rbacCommandTable },
+ { NULL, SEC_ADMINISTRATOR, false, NULL, "", NULL }
+ };
+
+ return commandTable;
+ }
+
+ static RBACCommandData* ReadParams(ChatHandler* handler, char const* args, bool checkParams = true)
+ {
+ if (!args)
+ return NULL;
+
+ char* param1 = strtok((char*)args, " ");
+ char* param2 = strtok(NULL, " ");
+ char* param3 = strtok(NULL, " ");
+
+ int32 realmId = -1;
+ uint32 accountId = 0;
+ std::string accountName;
+ uint32 id = 0;
+ RBACCommandData* data = NULL;
+ RBACData* rdata = NULL;
+ bool useSelectedPlayer = false;
+
+ if (checkParams)
+ {
+ if (!param3)
+ {
+ if (param2)
+ realmId = atoi(param2);
+
+ if (param1)
+ id = atoi(param1);
+
+ useSelectedPlayer = true;
+ }
+ else
+ {
+ id = atoi(param2);
+ realmId = atoi(param3);
+ }
+
+ if (!id)
+ {
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, id);
+ handler->SetSentErrorMessage(true);
+ return NULL;
+ }
+
+ if (realmId < -1 || !realmId)
+ {
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_REALM, realmId);
+ handler->SetSentErrorMessage(true);
+ return NULL;
+ }
+ }
+ else if (!param1)
+ useSelectedPlayer = true;
+
+ if (useSelectedPlayer)
+ {
+ Player* player = handler->getSelectedPlayer();
+ if (!player)
+ return NULL;
+
+ rdata = player->GetSession()->GetRBACData();
+ accountId = rdata->GetId();
+ AccountMgr::GetName(accountId, accountName);
+ }
+ else
+ {
+ accountName = param1;
+
+ if (AccountMgr::normalizeString(accountName))
+ accountId = AccountMgr::GetId(accountName);
+
+ if (!accountId)
+ {
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return NULL;
+ }
+ }
+
+ if (checkParams && handler->HasLowerSecurityAccount(NULL, accountId, true))
+ return NULL;
+
+ data = new RBACCommandData();
+
+ if (!rdata)
+ {
+ data->rbac = new RBACData(accountId, accountName, ConfigMgr::GetIntDefault("RealmID", 0));
+ data->rbac->LoadFromDB();
+ data->needDelete = true;
+ }
+ else
+ data->rbac = rdata;
+
+ data->id = id;
+ data->realmId = realmId;
+ return data;
+ }
+
+ static bool HandleRBACGroupAddCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ RBACCommandResult result = command->rbac->AddGroup(command->id, command->realmId);
+ RBACGroup const* group = sAccountMgr->GetRBACGroup(command->id);
+
+ switch (result)
+ {
+ case RBAC_CANT_ADD_ALREADY_ADDED:
+ handler->PSendSysMessage(LANG_RBAC_GROUP_IN_LIST, command->id, group->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_OK:
+ handler->PSendSysMessage(LANG_RBAC_GROUP_ADDED, command->id, group->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_ID_DOES_NOT_EXISTS:
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, command->id);
+ break;
+ default:
+ break;
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACGroupRemoveCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ RBACCommandResult result = command->rbac->RemoveGroup(command->id, command->realmId);
+ RBACGroup const* group = sAccountMgr->GetRBACGroup(command->id);
+
+ switch (result)
+ {
+ case RBAC_CANT_REVOKE_NOT_IN_LIST:
+ handler->PSendSysMessage(LANG_RBAC_GROUP_NOT_IN_LIST, command->id, group->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_OK:
+ handler->PSendSysMessage(LANG_RBAC_GROUP_REMOVED, command->id, group->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_ID_DOES_NOT_EXISTS:
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, command->id);
+ break;
+ default:
+ break;
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACGroupListCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args, false);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ handler->PSendSysMessage(LANG_RBAC_GROUP_LIST_HEADER, command->rbac->GetId(), command->rbac->GetName().c_str());
+ RBACGroupContainer const& groups = command->rbac->GetGroups();
+ if (groups.empty())
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_EMPTY));
+ else
+ {
+ for (RBACGroupContainer::const_iterator it = groups.begin(); it != groups.end(); ++it)
+ {
+ RBACGroup const* group = sAccountMgr->GetRBACGroup(*it);
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, group->GetId(), group->GetName().c_str());
+ }
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACRoleGrantCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ RBACCommandResult result = command->rbac->GrantRole(command->id, command->realmId);
+ RBACRole const* role = sAccountMgr->GetRBACRole(command->id);
+
+ switch (result)
+ {
+ case RBAC_CANT_ADD_ALREADY_ADDED:
+ handler->PSendSysMessage(LANG_RBAC_ROLE_GRANTED_IN_LIST, command->id, role->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_IN_DENIED_LIST:
+ handler->PSendSysMessage(LANG_RBAC_ROLE_GRANTED_IN_DENIED_LIST, command->id, role->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_OK:
+ handler->PSendSysMessage(LANG_RBAC_ROLE_GRANTED, command->id, role->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_ID_DOES_NOT_EXISTS:
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, command->id);
+ break;
+ default:
+ break;
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACRoleDenyCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ RBACCommandResult result = command->rbac->DenyRole(command->id, command->realmId);
+ RBACRole const* role = sAccountMgr->GetRBACRole(command->id);
+
+ switch (result)
+ {
+ case RBAC_CANT_ADD_ALREADY_ADDED:
+ handler->PSendSysMessage(LANG_RBAC_ROLE_DENIED_IN_LIST, command->id, role->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_IN_GRANTED_LIST:
+ handler->PSendSysMessage(LANG_RBAC_ROLE_DENIED_IN_GRANTED_LIST, command->id, role->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_OK:
+ handler->PSendSysMessage(LANG_RBAC_ROLE_DENIED, command->id, role->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_ID_DOES_NOT_EXISTS:
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, command->id);
+ break;
+ default:
+ break;
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACRoleRevokeCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ RBACCommandResult result = command->rbac->RevokeRole(command->id, command->realmId);
+ RBACRole const* role = sAccountMgr->GetRBACRole(command->id);
+
+ switch (result)
+ {
+ case RBAC_CANT_REVOKE_NOT_IN_LIST:
+ handler->PSendSysMessage(LANG_RBAC_ROLE_REVOKED_NOT_IN_LIST, command->id, role->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_OK:
+ handler->PSendSysMessage(LANG_RBAC_ROLE_REVOKED, command->id, role->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_ID_DOES_NOT_EXISTS:
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, command->id);
+ break;
+ default:
+ break;
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACRoleListCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args, false);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ handler->PSendSysMessage(LANG_RBAC_ROLE_LIST_HEADER_GRANTED, command->rbac->GetId(), command->rbac->GetName().c_str());
+ RBACGroupContainer const& granted = command->rbac->GetGrantedRoles();
+ if (granted.empty())
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_EMPTY));
+ else
+ {
+ for (RBACRoleContainer::const_iterator it = granted.begin(); it != granted.end(); ++it)
+ {
+ RBACRole const* role = sAccountMgr->GetRBACRole(*it);
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, role->GetId(), role->GetName().c_str());
+ }
+ }
+
+ handler->PSendSysMessage(LANG_RBAC_ROLE_LIST_HEADER_DENIED, command->rbac->GetId(), command->rbac->GetName().c_str());
+ RBACGroupContainer const& denied = command->rbac->GetDeniedRoles();
+ if (denied.empty())
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_EMPTY));
+ else
+ {
+ for (RBACRoleContainer::const_iterator it = denied.begin(); it != denied.end(); ++it)
+ {
+ RBACRole const* role = sAccountMgr->GetRBACRole(*it);
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, role->GetId(), role->GetName().c_str());
+ }
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACPermGrantCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ RBACCommandResult result = command->rbac->GrantPermission(command->id, command->realmId);
+ RBACPermission const* permission = sAccountMgr->GetRBACPermission(command->id);
+
+ switch (result)
+ {
+ case RBAC_CANT_ADD_ALREADY_ADDED:
+ handler->PSendSysMessage(LANG_RBAC_PERM_GRANTED_IN_LIST, command->id, permission->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_IN_DENIED_LIST:
+ handler->PSendSysMessage(LANG_RBAC_PERM_GRANTED_IN_DENIED_LIST, command->id, permission->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_OK:
+ handler->PSendSysMessage(LANG_RBAC_PERM_GRANTED, command->id, permission->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_ID_DOES_NOT_EXISTS:
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, command->id);
+ break;
+ default:
+ break;
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACPermDenyCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ RBACCommandResult result = command->rbac->DenyPermission(command->id, command->realmId);
+ RBACPermission const* permission = sAccountMgr->GetRBACPermission(command->id);
+
+ switch (result)
+ {
+ case RBAC_CANT_ADD_ALREADY_ADDED:
+ handler->PSendSysMessage(LANG_RBAC_PERM_DENIED_IN_LIST, command->id, permission->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_IN_GRANTED_LIST:
+ handler->PSendSysMessage(LANG_RBAC_PERM_DENIED_IN_GRANTED_LIST, command->id, permission->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_OK:
+ handler->PSendSysMessage(LANG_RBAC_PERM_DENIED, command->id, permission->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_ID_DOES_NOT_EXISTS:
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, command->id);
+ break;
+ default:
+ break;
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACPermRevokeCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ RBACCommandResult result = command->rbac->RevokePermission(command->id, command->realmId);
+ RBACPermission const* permission = sAccountMgr->GetRBACPermission(command->id);
+
+ switch (result)
+ {
+ case RBAC_CANT_REVOKE_NOT_IN_LIST:
+ handler->PSendSysMessage(LANG_RBAC_PERM_REVOKED_NOT_IN_LIST, command->id, permission->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_OK:
+ handler->PSendSysMessage(LANG_RBAC_PERM_REVOKED, command->id, permission->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_ID_DOES_NOT_EXISTS:
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, command->id);
+ break;
+ default:
+ break;
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACPermListCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args, false);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ handler->PSendSysMessage(LANG_RBAC_PERM_LIST_HEADER_GRANTED, command->rbac->GetId(), command->rbac->GetName().c_str());
+ RBACPermissionContainer const& granted = command->rbac->GetGrantedPermissions();
+ if (!granted.any())
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_EMPTY));
+ else
+ {
+ for (uint32 i = 0; i < RBAC_PERM_MAX; ++i)
+ if (granted.test(i))
+ {
+ RBACPermission const* permission = sAccountMgr->GetRBACPermission(i);
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, permission->GetId(), permission->GetName().c_str());
+ }
+ }
+
+ handler->PSendSysMessage(LANG_RBAC_PERM_LIST_HEADER_DENIED, command->rbac->GetId(), command->rbac->GetName().c_str());
+ RBACPermissionContainer const& denied = command->rbac->GetDeniedPermissions();
+ if (!denied.any())
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_EMPTY));
+ else
+ {
+ for (uint32 i = 0; i < RBAC_PERM_MAX; ++i)
+ if (denied.test(i))
+ {
+ RBACPermission const* permission = sAccountMgr->GetRBACPermission(i);
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, permission->GetId(), permission->GetName().c_str());
+ }
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACAccountPermissionCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args, false);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ handler->PSendSysMessage(LANG_RBAC_PERM_LIST_GLOBAL, command->rbac->GetId(), command->rbac->GetName().c_str());
+ RBACPermissionContainer const& permissions = command->rbac->GetPermissions();
+ if (!permissions.any())
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_EMPTY));
+ else
+ {
+ for (uint32 i = 0; i < RBAC_PERM_MAX; ++i)
+ if (permissions.test(i))
+ {
+ RBACPermission const* permission = sAccountMgr->GetRBACPermission(i);
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, permission->GetId(), permission->GetName().c_str());
+ }
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACListGroupsCommand(ChatHandler* handler, char const* args)
+ {
+ uint32 id = 0;
+ if (char* param1 = strtok((char*)args, " "))
+ id = atoi(param1);
+
+ if (!id)
+ {
+ RBACGroupsContainer const& groups = sAccountMgr->GetRBACGroupList();
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_GROUPS_HEADER));
+ for (RBACGroupsContainer::const_iterator it = groups.begin(); it != groups.end(); ++it)
+ {
+ RBACGroup const* group = it->second;
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, group->GetId(), group->GetName().c_str());
+ }
+ }
+ else
+ {
+ RBACGroup const* group = sAccountMgr->GetRBACGroup(id);
+ if (!group)
+ {
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, id);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_GROUPS_HEADER));
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, group->GetId(), group->GetName().c_str());
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_ROLES_HEADER));
+ RBACRoleContainer const& roles = group->GetRoles();
+ if (roles.empty())
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_EMPTY));
+ else
+ {
+ for (RBACRoleContainer::const_iterator it = roles.begin(); it != roles.end(); ++it)
+ {
+ RBACRole const* role = sAccountMgr->GetRBACRole(*it);
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, role->GetId(), role->GetName().c_str());
+ }
+ }
+ }
+
+ return true;
+ }
+
+ static bool HandleRBACListRolesCommand(ChatHandler* handler, char const* args)
+ {
+ uint32 id = 0;
+ if (char* param1 = strtok((char*)args, " "))
+ id = atoi(param1);
+
+ if (!id)
+ {
+ RBACRolesContainer const& roles = sAccountMgr->GetRBACRoleList();
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_ROLES_HEADER));
+ for (RBACRolesContainer::const_iterator it = roles.begin(); it != roles.end(); ++it)
+ {
+ RBACRole const* role = it->second;
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, role->GetId(), role->GetName().c_str());
+ }
+ }
+ else
+ {
+ RBACRole const* role = sAccountMgr->GetRBACRole(id);
+ if (!role)
+ {
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, id);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_ROLES_HEADER));
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, role->GetId(), role->GetName().c_str());
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_PERMISSIONS_HEADER));
+ RBACPermissionContainer const& permissions = role->GetPermissions();
+ if (!permissions.any())
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_EMPTY));
+ else
+ {
+ for (uint32 i = 0; i < RBAC_PERM_MAX; ++i)
+ if (permissions.test(i))
+ {
+ RBACPermission const* permission = sAccountMgr->GetRBACPermission(i);
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, permission->GetId(), permission->GetName().c_str());
+ }
+ }
+ }
+
+ return true;
+ }
+
+ static bool HandleRBACListPermissionsCommand(ChatHandler* handler, char const* args)
+ {
+ uint32 id = 0;
+ if (char* param1 = strtok((char*)args, " "))
+ id = atoi(param1);
+
+ if (!id)
+ {
+ RBACPermissionsContainer const& permissions = sAccountMgr->GetRBACPermissionList();
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_PERMISSIONS_HEADER));
+ for (RBACPermissionsContainer::const_iterator it = permissions.begin(); it != permissions.end(); ++it)
+ {
+ RBACPermission const* permission = it->second;
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, permission->GetId(), permission->GetName().c_str());
+ }
+ }
+ else
+ {
+ RBACPermission const* permission = sAccountMgr->GetRBACPermission(id);
+ if (!permission)
+ {
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, id);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_PERMISSIONS_HEADER));
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, permission->GetId(), permission->GetName().c_str());
+ }
+
+ return true;
+ }
+};
+
+void AddSC_rbac_commandscript()
+{
+ new rbac_commandscript();
+}
diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp index 0aeba151385..fa1ab5528ca 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp @@ -101,10 +101,13 @@ public: if (KnockBack_Timer <= diff) { - DoCast(me->getVictim(), SPELL_KNOCKBACK); - //Drop 50% aggro - if (DoGetThreat(me->getVictim())) - DoModifyThreatPercent(me->getVictim(), -50); + if (Unit* target = me->getVictim()) + { + DoCast(target, SPELL_KNOCKBACK); + // Drop 50% aggro + if (DoGetThreat(target)) + DoModifyThreatPercent(target, -50); + } KnockBack_Timer = urand(15000, 30000); } else KnockBack_Timer -= diff; diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp index 7ca74f4ed4f..4c36d78667b 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp @@ -68,24 +68,26 @@ public: //ShadowFlame_Timer if (ShadowFlame_Timer <= diff) { - DoCast(me->getVictim(), SPELL_SHADOWFLAME); + DoCastVictim(SPELL_SHADOWFLAME); ShadowFlame_Timer = urand(15000, 18000); } else ShadowFlame_Timer -= diff; //WingBuffet_Timer if (WingBuffet_Timer <= diff) { - DoCast(me->getVictim(), SPELL_WINGBUFFET); - if (DoGetThreat(me->getVictim())) - DoModifyThreatPercent(me->getVictim(), -75); - + if (Unit* target = me->getVictim()) + { + DoCast(target, SPELL_WINGBUFFET); + if (DoGetThreat(target)) + DoModifyThreatPercent(target, -75); + } WingBuffet_Timer = 25000; } else WingBuffet_Timer -= diff; //FlameBuffet_Timer if (FlameBuffet_Timer <= diff) { - DoCast(me->getVictim(), SPELL_FLAMEBUFFET); + DoCastVictim(SPELL_FLAMEBUFFET); FlameBuffet_Timer = 5000; } else FlameBuffet_Timer -= diff; diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp index a1659330a6f..57215e3f43d 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp @@ -76,17 +76,19 @@ public: //ShadowFlame_Timer if (ShadowFlame_Timer <= diff) { - DoCast(me->getVictim(), SPELL_SHADOWFLAME); + DoCastVictim(SPELL_SHADOWFLAME); ShadowFlame_Timer = urand(15000, 22000); } else ShadowFlame_Timer -= diff; //WingBuffet_Timer if (WingBuffet_Timer <= diff) { - DoCast(me->getVictim(), SPELL_WINGBUFFET); - if (DoGetThreat(me->getVictim())) - DoModifyThreatPercent(me->getVictim(), -75); - + if (Unit* target = me->getVictim()) + { + DoCast(target, SPELL_WINGBUFFET); + if (DoGetThreat(target)) + DoModifyThreatPercent(target, -75); + } WingBuffet_Timer = 25000; } else WingBuffet_Timer -= diff; diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp index a4c11209e52..f508266434b 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp @@ -339,14 +339,14 @@ public: waveTimer -= uiDiff; } } - + private: uint8 wave; uint32 waveTimer; uint64 valrothGUID; }; - + CreatureAI* GetAI(Creature* creature) const { return new npc_koltira_deathweaverAI(creature); diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp index a8755c16418..742c80bea39 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp @@ -780,8 +780,9 @@ public: if (AgonyCurseTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (!target) target = me->getVictim(); + Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1); + if (!target) + target = me->getVictim(); DoCast(target, SPELL_AGONY_CURSE); AgonyCurseTimer = 20000; } else AgonyCurseTimer -= diff; diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp index 1b2512ccf63..f1cb7b4116a 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp @@ -201,8 +201,11 @@ class boss_akilzon : public CreatureScript //dealdamege for (std::list<Unit*>::const_iterator i = tempUnitMap.begin(); i != tempUnitMap.end(); ++i) { - if (!Cloud->IsWithinDist(*i, 6, false)) - Cloud->CastCustomSpell(*i, 43137, &bp0, NULL, NULL, true, 0, 0, me->GetGUID()); + if (Unit* target = (*i)) + { + if (!Cloud->IsWithinDist(target, 6, false)) + Cloud->CastCustomSpell(target, 43137, &bp0, NULL, NULL, true, 0, 0, me->GetGUID()); + } } // visual float x, y, z; diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_grilek.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_grilek.cpp index f06500694a5..77f6127c76c 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_grilek.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_grilek.cpp @@ -80,8 +80,12 @@ class boss_grilek : public CreatureScript // grilek { case EVENT_AVATAR: DoCast(me, SPELL_AVATAR); - if (DoGetThreat(me->getVictim())) - DoModifyThreatPercent(me->getVictim(), -50); + if (Unit* victim = me->getVictim()) + { + if (DoGetThreat(victim)) + DoModifyThreatPercent(victim, -50); + } + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1)) AttackStart(target); events.ScheduleEvent(EVENT_AVATAR, urand(25000, 35000)); diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_jeklik.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_jeklik.cpp index dc02c895327..e686881a672 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_jeklik.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_jeklik.cpp @@ -158,7 +158,7 @@ class boss_jeklik : public CreatureScript //jeklik { if (PhaseTwo) { - if (PhaseTwo && ShadowWordPain_Timer <= diff) + if (ShadowWordPain_Timer <= diff) { if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) { @@ -189,13 +189,11 @@ class boss_jeklik : public CreatureScript //jeklik if (SpawnFlyingBats_Timer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (!target) - return; - - Creature* FlyingBat = me->SummonCreature(14965, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()+15, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (FlyingBat) - FlyingBat->AI()->AttackStart(target); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + { + if (Creature* FlyingBat = me->SummonCreature(14965, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()+15, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) + FlyingBat->AI()->AttackStart(target); + } SpawnFlyingBats_Timer = urand(10000, 15000); } else SpawnFlyingBats_Timer -=diff; diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_jindo.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_jindo.cpp index 005609e88db..3c2b0f54225 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_jindo.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_jindo.cpp @@ -110,9 +110,12 @@ class boss_jindo : public CreatureScript events.ScheduleEvent(EVENT_POWERFULLHEALINGWARD, urand(14000, 20000)); break; case EVENT_HEX: - DoCastVictim(SPELL_HEX, true); - if (DoGetThreat(me->getVictim())) - DoModifyThreatPercent(me->getVictim(), -80); + if (Unit* target = me->getVictim()) + { + DoCast(target, SPELL_HEX, true); + if (DoGetThreat(target)) + DoModifyThreatPercent(target, -80); + } events.ScheduleEvent(EVENT_HEX, urand(12000, 20000)); break; case EVENT_DELUSIONSOFJINDO: // HACK @@ -161,7 +164,7 @@ class boss_jindo : public CreatureScript SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, target->GetPositionX()+3, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); if (SacrificedTroll) SacrificedTroll->AI()->AttackStart(target); - } + } events.ScheduleEvent(EVENT_TELEPORT, urand(15000, 23000)); break; default: diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_thekal.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_thekal.cpp index 61eb695719a..26322be76ca 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_thekal.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_thekal.cpp @@ -232,7 +232,7 @@ class boss_thekal : public CreatureScript if (me->IsFullHealth() && WasDead) WasDead = false; - if ((events.GetPhaseMask() == PHASE_ONE) && !WasDead && !HealthAbovePct(5)) + if ((events.IsInPhase(PHASE_ONE)) && !WasDead && !HealthAbovePct(5)) { me->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT); me->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE); diff --git a/src/server/scripts/Kalimdor/CMakeLists.txt b/src/server/scripts/Kalimdor/CMakeLists.txt index 5c44cd7ef27..536824e7a63 100644 --- a/src/server/scripts/Kalimdor/CMakeLists.txt +++ b/src/server/scripts/Kalimdor/CMakeLists.txt @@ -38,11 +38,11 @@ set(scripts_STAT_SRCS Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.h Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_azgalor.cpp Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp - Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite.cpp - Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm.cpp + Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite_corruptor.cpp + Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm_the_fleshcrafter.cpp Kalimdor/CavernsOfTime/CullingOfStratholme/boss_meathook.cpp Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp - Kalimdor/CavernsOfTime/CullingOfStratholme/boss_epoch.cpp + Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.h diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp index 36f6f94b324..2eb1b65fefd 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp @@ -1369,8 +1369,7 @@ public: forcemove = false; if (forcemove) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) me->Attack(target, false); } if (MoveTimer <= diff) diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_epoch.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp index fad5736e18f..fad5736e18f 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_epoch.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite_corruptor.cpp index 8c2861db299..8c2861db299 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite_corruptor.cpp diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm_the_fleshcrafter.cpp index d7d9beaedd4..d7d9beaedd4 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm_the_fleshcrafter.cpp diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_chrono_lord_deja.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_chrono_lord_deja.cpp index ea372621026..7ac8d4e783b 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_chrono_lord_deja.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_chrono_lord_deja.cpp @@ -124,8 +124,8 @@ public: //Arcane Discharge if (ArcaneDischarge_Timer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - DoCast(target, SPELL_ARCANE_DISCHARGE); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_ARCANE_DISCHARGE); ArcaneDischarge_Timer = 20000+rand()%10000; } else ArcaneDischarge_Timer -= diff; diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp index 2a9ea4ba4fc..a16e9cfa89d 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp @@ -274,10 +274,11 @@ public: for (uint8 i = 0; i < 10; ++i) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - Creature* Summoned = me->SummonCreature(15621, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000); - if (Summoned && target) - Summoned->AI()->AttackStart(target); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + { + if (Creature* Summoned = me->SummonCreature(15621, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000)) + Summoned->AI()->AttackStart(target); + } } } diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp index 80fdc111911..52d59efd0df 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp @@ -137,9 +137,7 @@ public: { if (SpawnHatchlings_Timer <= diff) { - Unit* target = NULL; - target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target && target->GetTypeId() == TYPEID_PLAYER) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) { DoCast(target, SPELL_ROOT); diff --git a/src/server/scripts/Kalimdor/zone_thunder_bluff.cpp b/src/server/scripts/Kalimdor/zone_thunder_bluff.cpp index 0d915dc7c44..2787d72ddde 100644 --- a/src/server/scripts/Kalimdor/zone_thunder_bluff.cpp +++ b/src/server/scripts/Kalimdor/zone_thunder_bluff.cpp @@ -105,8 +105,7 @@ public: if (BerserkerChargeTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) DoCast(target, SPELL_BERSERKER_CHARGE); BerserkerChargeTimer = 25000; } else BerserkerChargeTimer -= diff; diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp index 205a0b10d69..70c1141b6e6 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp @@ -61,9 +61,7 @@ enum Phases { PHASE_ALL = 0, PHASE_INTRO = 1, - PHASE_COMBAT = 2, - - PHASE_INTRO_MASK = 1 << PHASE_INTRO, + PHASE_COMBAT = 2 }; class boss_baltharus_the_warborn : public CreatureScript @@ -166,15 +164,16 @@ class boss_baltharus_the_warborn : public CreatureScript void UpdateAI(uint32 const diff) { - if (!UpdateVictim() && !(events.GetPhaseMask() & PHASE_INTRO_MASK)) + bool introPhase = events.IsInPhase(PHASE_INTRO); + if (!UpdateVictim() && !introPhase) return; - if (!(events.GetPhaseMask() & PHASE_INTRO_MASK)) + if (!introPhase) me->SetHealth(instance->GetData(DATA_BALTHARUS_SHARED_HEALTH)); events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING) && !(events.GetPhaseMask() & PHASE_INTRO_MASK)) + if (me->HasUnitState(UNIT_STATE_CASTING) && !introPhase) return; while (uint32 eventId = events.ExecuteEvent()) diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp index 6039e01b901..d31c2ead82d 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp @@ -165,12 +165,7 @@ enum Phases PHASE_INTRO = 1, PHASE_ONE = 2, PHASE_TWO = 3, - PHASE_THREE = 4, - - PHASE_INTRO_MASK = 1 << PHASE_INTRO, - PHASE_ONE_MASK = 1 << PHASE_ONE, - PHASE_TWO_MASK = 1 << PHASE_TWO, - PHASE_THREE_MASK = 1 << PHASE_THREE + PHASE_THREE = 4 }; enum Misc @@ -325,7 +320,7 @@ class boss_halion : public CreatureScript void EnterEvadeMode() { // Phase 1: We always can evade. Phase 2 & 3: We can evade if and only if the controller tells us to. - if ((events.GetPhaseMask() & PHASE_ONE_MASK) || _canEvade) + if (events.IsInPhase(PHASE_ONE) || _canEvade) generic_halionAI::EnterEvadeMode(); } @@ -369,7 +364,7 @@ class boss_halion : public CreatureScript void DamageTaken(Unit* attacker, uint32& damage) { - if (me->HealthBelowPctDamaged(75, damage) && (events.GetPhaseMask() & PHASE_ONE_MASK)) + if (me->HealthBelowPctDamaged(75, damage) && events.IsInPhase(PHASE_ONE)) { events.SetPhase(PHASE_TWO); Talk(SAY_PHASE_TWO); @@ -383,7 +378,7 @@ class boss_halion : public CreatureScript return; } - if (events.GetPhaseMask() & PHASE_THREE_MASK) + if (events.IsInPhase(PHASE_THREE)) { // Don't consider copied damage. if (!me->InSamePhase(attacker)) @@ -396,7 +391,7 @@ class boss_halion : public CreatureScript void UpdateAI(uint32 const diff) { - if (events.GetPhaseMask() & PHASE_TWO_MASK) + if (events.IsInPhase(PHASE_TWO)) return; generic_halionAI::UpdateAI(diff); @@ -528,7 +523,7 @@ class boss_twilight_halion : public CreatureScript void DamageTaken(Unit* attacker, uint32& damage) { - if (me->HealthBelowPctDamaged(50, damage) && (events.GetPhaseMask() & PHASE_TWO_MASK)) + if (me->HealthBelowPctDamaged(50, damage) && events.IsInPhase(PHASE_TWO)) { events.SetPhase(PHASE_THREE); me->CastStop(); @@ -537,7 +532,7 @@ class boss_twilight_halion : public CreatureScript return; } - if (events.GetPhaseMask() & PHASE_THREE_MASK) + if (events.IsInPhase(PHASE_THREE)) { // Don't consider copied damage. if (!me->InSamePhase(attacker)) @@ -693,7 +688,7 @@ class npc_halion_controller : public CreatureScript // The isInCombat() check is needed because that check should be false when Halion is // not engaged, while it would return true without as UpdateVictim() checks for // combat state. - if (!(_events.GetPhaseMask() & PHASE_INTRO_MASK) && me->isInCombat() && !UpdateVictim()) + if (!(_events.IsInPhase(PHASE_INTRO)) && me->isInCombat() && !UpdateVictim()) { EnterEvadeMode(); return; diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp index e44f5fba1b8..17b804ca31e 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp @@ -154,9 +154,7 @@ enum Phases { // Anub'arak PHASE_MELEE = 1, - PHASE_SUBMERGED = 2, - - PHASE_MASK_MELEE = 1 << PHASE_MELEE + PHASE_SUBMERGED = 2 }; class boss_anubarak_trial : public CreatureScript @@ -403,7 +401,7 @@ class boss_anubarak_trial : public CreatureScript } - if (HealthBelowPct(30) && events.GetPhaseMask() & PHASE_MASK_MELEE && !_reachedPhase3) + if (HealthBelowPct(30) && events.IsInPhase(PHASE_MELEE) && !_reachedPhase3) { _reachedPhase3 = true; DoCastAOE(SPELL_LEECHING_SWARM); @@ -411,7 +409,7 @@ class boss_anubarak_trial : public CreatureScript Talk(SAY_LEECHING_SWARM); } - if (events.GetPhaseMask() & PHASE_MASK_MELEE) + if (events.IsInPhase(PHASE_MELEE)) DoMeleeAttackIfReady(); } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp index 82cff5ff01f..073ebb0a35f 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp @@ -18,8 +18,9 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" -#include "trial_of_the_crusader.h" #include "SpellScript.h" +#include "Player.h" +#include "trial_of_the_crusader.h" enum Yells { @@ -69,7 +70,6 @@ enum BossSpells SPELL_FEL_INFERNO = 67047, SPELL_FEL_STREAK = 66494, SPELL_LORD_HITTIN = 66326, // special effect preventing more specific spells be cast on the same player within 10 seconds - SPELL_MISTRESS_KISS_DEBUFF = 66334, SPELL_MISTRESS_KISS_DAMAGE_SILENCE = 66359 }; @@ -533,6 +533,21 @@ class spell_mistress_kiss : public SpellScriptLoader } }; +class MistressKissTargetSelector +{ + public: + MistressKissTargetSelector() { } + + bool operator()(WorldObject* unit) const + { + if (unit->GetTypeId() == TYPEID_PLAYER) + if (unit->ToPlayer()->getPowerType() == POWER_MANA) + return false; + + return true; + } +}; + class spell_mistress_kiss_area : public SpellScriptLoader { public: @@ -542,44 +557,27 @@ class spell_mistress_kiss_area : public SpellScriptLoader { PrepareSpellScript(spell_mistress_kiss_area_SpellScript) - bool Load() + void FilterTargets(std::list<WorldObject*>& targets) { - if (GetCaster()) - if (sSpellMgr->GetSpellIdForDifficulty(SPELL_MISTRESS_KISS_DEBUFF, GetCaster())) - return true; - return false; - } + // get a list of players with mana + targets.remove_if(MistressKissTargetSelector()); + if (targets.empty()) + return; - void HandleScript(SpellEffIndex /*effIndex*/) - { - Unit* caster = GetCaster(); - Unit* target = GetHitUnit(); - if (caster && target) - caster->CastSpell(target, SPELL_MISTRESS_KISS_DEBUFF, true); + WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets); + targets.clear(); + targets.push_back(target); } - void FilterTargets(std::list<WorldObject*>& targets) + void HandleScript(SpellEffIndex /*effIndex*/) { - // get a list of players with mana - std::list<WorldObject*> _targets; - for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) - if ((*itr)->ToUnit()->getPowerType() == POWER_MANA) - _targets.push_back(*itr); - - // pick a random target and kiss him - if (WorldObject* _target = Trinity::Containers::SelectRandomContainerElement(_targets)) - { - // correctly fill "targets" for the visual effect - targets.clear(); - targets.push_back(_target); - if (Unit* caster = GetCaster()) - caster->CastSpell(_target->ToUnit(), SPELL_MISTRESS_KISS_DEBUFF, true); - } + GetCaster()->CastSpell(GetHitUnit(), uint32(GetEffectValue()), true); } void Register() { OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mistress_kiss_area_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_mistress_kiss_area_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp index 03a305356c4..95f59903141 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp @@ -146,10 +146,7 @@ enum Phases { PHASE_MOBILE = 1, PHASE_STATIONARY = 2, - PHASE_SUBMERGED = 3, - - PHASE_MASK_MOBILE = 1 << PHASE_MOBILE, - PHASE_MASK_STATIONARY = 1 << PHASE_STATIONARY + PHASE_SUBMERGED = 3 }; class boss_gormok : public CreatureScript @@ -624,9 +621,9 @@ struct boss_jormungarAI : public BossAI return; } } - if (events.GetPhaseMask() & PHASE_MASK_MOBILE) + if (events.IsInPhase(PHASE_MOBILE)) DoMeleeAttackIfReady(); - if (events.GetPhaseMask() & PHASE_MASK_STATIONARY) + if (events.IsInPhase(PHASE_STATIONARY)) DoSpellAttackIfReady(SpitSpell); } diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp index 261eb854aa3..5d261fd3804 100644 --- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp @@ -118,7 +118,7 @@ class boss_bronjahm : public CreatureScript void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) { - if (events.GetPhaseMask() & (1 << PHASE_1) && !HealthAbovePct(30)) + if (events.IsInPhase(PHASE_1) && !HealthAbovePct(30)) { events.SetPhase(PHASE_2); DoCast(me, SPELL_TELEPORT); diff --git a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_forgemaster_garfrost.cpp b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_forgemaster_garfrost.cpp index 160d45f5140..cc25e450340 100644 --- a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_forgemaster_garfrost.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_forgemaster_garfrost.cpp @@ -52,11 +52,7 @@ enum Phases { PHASE_ONE = 1, PHASE_TWO = 2, - PHASE_THREE = 3, - - PHASE_ONE_MASK = 1 << PHASE_ONE, - PHASE_TWO_MASK = 1 << PHASE_TWO, - PHASE_THREE_MASK = 1 << PHASE_THREE, + PHASE_THREE = 3 }; enum MiscData @@ -136,7 +132,7 @@ enum Events void DamageTaken(Unit* /*attacker*/, uint32& /*uiDamage*/) { - if (events.GetPhaseMask() & PHASE_ONE_MASK && !HealthAbovePct(66)) + if (events.IsInPhase(PHASE_ONE) && !HealthAbovePct(66)) { events.SetPhase(PHASE_TWO); Talk(SAY_PHASE2); @@ -146,7 +142,7 @@ enum Events return; } - if (events.GetPhaseMask() & PHASE_TWO_MASK && !HealthAbovePct(33)) + if (events.IsInPhase(PHASE_TWO) && !HealthAbovePct(33)) { events.SetPhase(PHASE_THREE); Talk(SAY_PHASE3); @@ -162,12 +158,12 @@ enum Events if (type != EFFECT_MOTION_TYPE || id != POINT_FORGE) return; - if (events.GetPhaseMask() & PHASE_TWO_MASK) + if (events.IsInPhase(PHASE_TWO)) { DoCast(me, SPELL_FORGE_BLADE); SetEquipmentSlots(false, EQUIP_ID_SWORD); } - if (events.GetPhaseMask() & PHASE_THREE_MASK) + if (events.IsInPhase(PHASE_THREE)) { me->RemoveAurasDueToSpell(SPELL_FORGE_BLADE_HELPER); DoCast(me, SPELL_FORGE_MACE); @@ -226,15 +222,15 @@ enum Events break; case EVENT_JUMP: me->AttackStop(); - if (events.GetPhaseMask() & PHASE_TWO_MASK) + if (events.IsInPhase(PHASE_TWO)) me->GetMotionMaster()->MoveJump(northForgePos.GetPositionX(), northForgePos.GetPositionY(), northForgePos.GetPositionZ(), 25.0f, 15.0f); - else if (events.GetPhaseMask() & PHASE_THREE_MASK) + else if (events.IsInPhase(PHASE_THREE)) me->GetMotionMaster()->MoveJump(southForgePos.GetPositionX(), southForgePos.GetPositionY(), southForgePos.GetPositionZ(), 25.0f, 15.0f); break; case EVENT_RESUME_ATTACK: - if (events.GetPhaseMask() & PHASE_TWO_MASK) + if (events.IsInPhase(PHASE_THREE)) events.ScheduleEvent(EVENT_CHILLING_WAVE, 5000, 0, PHASE_TWO); - else if (events.GetPhaseMask() & PHASE_THREE_MASK) + else if (events.IsInPhase(PHASE_THREE)) events.ScheduleEvent(EVENT_DEEP_FREEZE, 10000, 0, PHASE_THREE); AttackStart(me->getVictim()); break; diff --git a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp index 783cc266509..165cd8d647a 100644 --- a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp @@ -94,7 +94,7 @@ enum Phases PHASE_NONE = 0, PHASE_INTRO = 1, PHASE_COMBAT = 2, - PHASE_OUTRO = 3, + PHASE_OUTRO = 3 }; enum Actions @@ -168,7 +168,7 @@ class boss_tyrannus : public CreatureScript if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) return; - if (victim && me->Attack(victim, true) && !(events.GetPhaseMask() & (1 << PHASE_INTRO))) + if (victim && me->Attack(victim, true) && !events.IsInPhase(PHASE_INTRO)) me->GetMotionMaster()->MoveChase(victim); } @@ -217,7 +217,7 @@ class boss_tyrannus : public CreatureScript void UpdateAI(const uint32 diff) { - if (!UpdateVictim() && !(events.GetPhaseMask() & (1 << PHASE_INTRO))) + if (!UpdateVictim() && !events.IsInPhase(PHASE_INTRO)) return; events.Update(diff); @@ -337,7 +337,7 @@ class boss_rimefang : public CreatureScript void UpdateAI(const uint32 diff) { - if (!UpdateVictim() && !(_events.GetPhaseMask() & (1 << PHASE_COMBAT))) + if (!UpdateVictim() && !_events.IsInPhase(PHASE_COMBAT)) return; _events.Update(diff); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp index af727348719..c92f10e8b95 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp @@ -185,9 +185,7 @@ enum Phases { PHASE_INTRO_A = 1, PHASE_INTRO_H = 2, - PHASE_COMBAT = 3, - - PHASE_INTRO_MASK = (1 << PHASE_INTRO_A) | (1 << PHASE_INTRO_H), + PHASE_COMBAT = 3 }; enum Actions @@ -424,7 +422,7 @@ class boss_deathbringer_saurfang : public CreatureScript void UpdateAI(uint32 const diff) { - if (!UpdateVictim() && !(events.GetPhaseMask() & PHASE_INTRO_MASK)) + if (!UpdateVictim() && !(events.IsInPhase(PHASE_INTRO_A) || events.IsInPhase(PHASE_INTRO_H))) return; events.Update(diff); @@ -612,7 +610,7 @@ class npc_high_overlord_saurfang_icc : public CreatureScript case ACTION_START_EVENT: { // Prevent crashes - if (_events.GetPhaseMask() & PHASE_INTRO_MASK) + if (_events.IsInPhase(PHASE_INTRO_A) || _events.IsInPhase(PHASE_INTRO_H)) return; GetCreatureListWithEntryInGrid(_guardList, me, NPC_SE_KOR_KRON_REAVER, 20.0f); @@ -821,7 +819,7 @@ class npc_muradin_bronzebeard_icc : public CreatureScript case ACTION_START_EVENT: { // Prevent crashes - if (_events.GetPhaseMask() & PHASE_INTRO_MASK) + if (_events.IsInPhase(PHASE_INTRO_A) || _events.IsInPhase(PHASE_INTRO_H)) return; _events.SetPhase(PHASE_INTRO_A); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp index 4e677bf5b0e..f8d00f01713 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp @@ -160,10 +160,7 @@ enum Phases PHASE_ALL = 0, PHASE_INTRO = 1, PHASE_ONE = 2, - PHASE_TWO = 3, - - PHASE_INTRO_MASK = 1 << PHASE_INTRO, - PHASE_ONE_MASK = 1 << PHASE_ONE, + PHASE_TWO = 3 }; enum DeprogrammingData @@ -259,7 +256,7 @@ class boss_lady_deathwhisper : public CreatureScript if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) return; - if (victim && me->Attack(victim, true) && !(events.GetPhaseMask() & PHASE_ONE_MASK)) + if (victim && me->Attack(victim, true) && !events.IsInPhase(PHASE_ONE)) me->GetMotionMaster()->MoveChase(victim); } @@ -358,7 +355,7 @@ class boss_lady_deathwhisper : public CreatureScript void DamageTaken(Unit* /*damageDealer*/, uint32& damage) { // phase transition - if (events.GetPhaseMask() & PHASE_ONE_MASK && damage > me->GetPower(POWER_MANA)) + if (events.IsInPhase(PHASE_ONE) && damage > me->GetPower(POWER_MANA)) { Talk(SAY_PHASE_2); Talk(EMOTE_PHASE_2); @@ -406,12 +403,12 @@ class boss_lady_deathwhisper : public CreatureScript void UpdateAI(uint32 const diff) { - if ((!UpdateVictim() && !(events.GetPhaseMask() & PHASE_INTRO_MASK)) || !CheckInRoom()) + if ((!UpdateVictim() && !events.IsInPhase(PHASE_INTRO)) || !CheckInRoom()) return; events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING) && !(events.GetPhaseMask() & PHASE_INTRO_MASK)) + if (me->HasUnitState(UNIT_STATE_CASTING) && !events.IsInPhase(PHASE_INTRO)) return; while (uint32 eventId = events.ExecuteEvent()) diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp index 4763896cf72..1d340e61b61 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp @@ -20,8 +20,9 @@ #include "ScriptedCreature.h" #include "SpellAuras.h" #include "MapManager.h" -#include "icecrown_citadel.h" +#include "MoveSplineInit.h" #include "Player.h" +#include "icecrown_citadel.h" enum ScriptTexts { @@ -78,7 +79,46 @@ enum MovementPoints POINT_TARGET_COLDFLAME = 36672631, }; -#define DATA_COLDFLAME_GUID 0 +enum MiscInfo +{ + DATA_COLDFLAME_GUID = 0, + + // Manual marking for targets hit by Bone Slice as no aura exists for this purpose + // These units are the tanks in this encounter + // and should be immune to Bone Spike Graveyard + DATA_SPIKE_IMMUNE = 1, + //DATA_SPIKE_IMMUNE_1, = 2, // Reserved & used + //DATA_SPIKE_IMMUNE_2, = 3, // Reserved & used + + ACTION_CLEAR_SPIKE_IMMUNITIES = 1, + + MAX_BONE_SPIKE_IMMUNE = 3, +}; + +class BoneSpikeTargetSelector : public std::unary_function<Unit*, bool> +{ + public: + BoneSpikeTargetSelector(UnitAI* ai) : _ai(ai) { } + + bool operator()(Unit* unit) const + { + if (unit->GetTypeId() != TYPEID_PLAYER) + return false; + + if (unit->HasAura(SPELL_IMPALED)) + return false; + + // Check if it is one of the tanks soaking Bone Slice + for (uint32 i = 0; i < MAX_BONE_SPIKE_IMMUNE; ++i) + if (unit->GetGUID() == _ai->GetGUID(DATA_SPIKE_IMMUNE + i)) + return false; + + return true; + } + + private: + UnitAI* _ai; +}; class boss_lord_marrowgar : public CreatureScript { @@ -103,11 +143,12 @@ class boss_lord_marrowgar : public CreatureScript me->RemoveAurasDueToSpell(SPELL_BONE_STORM); me->RemoveAurasDueToSpell(SPELL_BERSERK); events.ScheduleEvent(EVENT_ENABLE_BONE_SLICE, 10000); - events.ScheduleEvent(EVENT_BONE_SPIKE_GRAVEYARD, urand(10000, 15000), EVENT_GROUP_SPECIAL); + events.ScheduleEvent(EVENT_BONE_SPIKE_GRAVEYARD, 15000, EVENT_GROUP_SPECIAL); events.ScheduleEvent(EVENT_COLDFLAME, 5000, EVENT_GROUP_SPECIAL); events.ScheduleEvent(EVENT_WARN_BONE_STORM, urand(45000, 50000)); events.ScheduleEvent(EVENT_ENRAGE, 600000); _boneSlice = false; + _boneSpikeImmune.clear(); } void EnterCombat(Unit* /*who*/) @@ -199,18 +240,18 @@ class boss_lord_marrowgar : public CreatureScript if (!unit) unit = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true); if (unit) - me->GetMotionMaster()->MovePoint(POINT_TARGET_BONESTORM_PLAYER, unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ()); + me->GetMotionMaster()->MovePoint(POINT_TARGET_BONESTORM_PLAYER, *unit); break; } case EVENT_BONE_STORM_END: if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE) me->GetMotionMaster()->MovementExpired(); - DoStartMovement(me->getVictim()); + me->GetMotionMaster()->MoveChase(me->getVictim()); me->SetSpeed(MOVE_RUN, _baseSpeed, true); events.CancelEvent(EVENT_BONE_STORM_MOVE); events.ScheduleEvent(EVENT_ENABLE_BONE_SLICE, 10000); if (!IsHeroic()) - events.RescheduleEvent(EVENT_BONE_SPIKE_GRAVEYARD, urand(15000, 20000), EVENT_GROUP_SPECIAL); + events.RescheduleEvent(EVENT_BONE_SPIKE_GRAVEYARD, 15000, EVENT_GROUP_SPECIAL); break; case EVENT_ENABLE_BONE_SLICE: _boneSlice = true; @@ -239,7 +280,7 @@ class boss_lord_marrowgar : public CreatureScript return; // lock movement - DoStartNoMovement(me->getVictim()); + me->GetMotionMaster()->MoveIdle(); } Position const* GetLastColdflamePosition() const @@ -247,23 +288,51 @@ class boss_lord_marrowgar : public CreatureScript return &_coldflameLastPos; } - uint64 GetGUID(int32 type/* = 0 */) const + uint64 GetGUID(int32 type /*= 0 */) const { - if (type == DATA_COLDFLAME_GUID) - return _coldflameTarget; + switch (type) + { + case DATA_COLDFLAME_GUID: + return _coldflameTarget; + case DATA_SPIKE_IMMUNE + 0: + case DATA_SPIKE_IMMUNE + 1: + case DATA_SPIKE_IMMUNE + 2: + { + uint32 index = uint32(type - DATA_SPIKE_IMMUNE); + if (index < _boneSpikeImmune.size()) + return _boneSpikeImmune[index]; + + break; + } + } + return 0LL; } - void SetGUID(uint64 guid, int32 type/* = 0 */) + void SetGUID(uint64 guid, int32 type /*= 0 */) + { + switch (type) + { + case DATA_COLDFLAME_GUID: + _coldflameTarget = guid; + break; + case DATA_SPIKE_IMMUNE: + _boneSpikeImmune.push_back(guid); + break; + } + } + + void DoAction(int32 const action) { - if (type != DATA_COLDFLAME_GUID) + if (action != ACTION_CLEAR_SPIKE_IMMUNITIES) return; - _coldflameTarget = guid; + _boneSpikeImmune.clear(); } private: Position _coldflameLastPos; + std::vector<uint64> _boneSpikeImmune; uint64 _coldflameTarget; uint32 _boneStormDuration; float _baseSpeed; @@ -295,19 +364,17 @@ class npc_coldflame : public CreatureScript if (owner->GetTypeId() != TYPEID_UNIT) return; - Creature* creOwner = owner->ToCreature(); Position pos; - // random target case + if (MarrowgarAI* marrowgarAI = CAST_AI(MarrowgarAI, owner->GetAI())) + pos.Relocate(marrowgarAI->GetLastColdflamePosition()); + else + pos.Relocate(owner); + if (owner->HasAura(SPELL_BONE_STORM)) { - if (MarrowgarAI* marrowgarAI = CAST_AI(MarrowgarAI, creOwner->AI())) - { - Position const* ownerPos = marrowgarAI->GetLastColdflamePosition(); - float ang = me->GetAngle(ownerPos) - static_cast<float>(M_PI); - MapManager::NormalizeOrientation(ang); - me->SetOrientation(ang); - owner->GetNearPosition(pos, 2.5f, 0.0f); - } + float ang = MapManager::NormalizeOrientation(pos.GetAngle(me)); + me->SetOrientation(ang); + owner->GetNearPoint2D(pos.m_positionX, pos.m_positionY, 5.0f - owner->GetObjectSize(), ang); } else { @@ -318,12 +385,14 @@ class npc_coldflame : public CreatureScript return; } - me->SetOrientation(owner->GetAngle(target)); - owner->GetNearPosition(pos, owner->GetObjectSize() / 2.0f, 0.0f); + float ang = MapManager::NormalizeOrientation(pos.GetAngle(target)); + me->SetOrientation(ang); + owner->GetNearPoint2D(pos.m_positionX, pos.m_positionY, 15.0f - owner->GetObjectSize(), ang); } me->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), me->GetPositionZ(), me->GetOrientation()); - _events.ScheduleEvent(EVENT_COLDFLAME_TRIGGER, 450); + DoCast(SPELL_COLDFLAME_SUMMON); + _events.ScheduleEvent(EVENT_COLDFLAME_TRIGGER, 500); } void UpdateAI(uint32 const diff) @@ -333,10 +402,10 @@ class npc_coldflame : public CreatureScript if (_events.ExecuteEvent() == EVENT_COLDFLAME_TRIGGER) { Position newPos; - me->GetNearPosition(newPos, 5.5f, 0.0f); + me->GetNearPosition(newPos, 5.0f, 0.0f); me->NearTeleportTo(newPos.GetPositionX(), newPos.GetPositionY(), me->GetPositionZ(), me->GetOrientation()); DoCast(SPELL_COLDFLAME_SUMMON); - _events.ScheduleEvent(EVENT_COLDFLAME_TRIGGER, 450); + _events.ScheduleEvent(EVENT_COLDFLAME_TRIGGER, 500); } } @@ -385,6 +454,24 @@ class npc_bone_spike : public CreatureScript _hasTrappedUnit = true; } + void PassengerBoarded(Unit* passenger, int8 /*seat*/, bool apply) + { + if (!apply) + return; + + /// @HACK - Change passenger offset to the one taken directly from sniffs + /// Remove this when proper calculations are implemented. + /// This fixes healing spiked people + Movement::MoveSplineInit init(passenger); + init.DisableTransportPathTransformations(); + init.MoveTo(-0.02206125f, -0.02132235f, 5.514783f, false); + init.Launch(); + + /// @WORKAROUND - Clear ON VEHICLE state to allow healing (Invalid target errors) + /// Current rule for applying this state is questionable (seatFlags & VEHICLE_SEAT_FLAG_ALLOW_TURNING ???) + passenger->ClearUnitState(UNIT_STATE_ONVEHICLE); + } + void UpdateAI(uint32 const diff) { if (!_hasTrappedUnit) @@ -487,16 +574,24 @@ class spell_marrowgar_coldflame_damage : public SpellScriptLoader { PrepareAuraScript(spell_marrowgar_coldflame_damage_AuraScript); - void OnPeriodic(AuraEffect const* /*aurEff*/) + bool CanBeAppliedOn(Unit* target) { - if (DynamicObject* owner = GetDynobjOwner()) - if (GetTarget()->GetExactDist2d(owner) >= owner->GetRadius() || GetTarget()->HasAura(SPELL_IMPALED)) - PreventDefaultAction(); + if (target->HasAura(SPELL_IMPALED)) + return false; + + if (target->GetExactDist2d(GetOwner()) > GetSpellInfo()->Effects[EFFECT_0].CalcRadius()) + return false; + + if (Aura* aur = target->GetAura(GetId())) + if (aur->GetOwner() != GetOwner()) + return false; + + return true; } void Register() { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_marrowgar_coldflame_damage_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); + DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_marrowgar_coldflame_damage_AuraScript::CanBeAppliedOn); } }; @@ -531,7 +626,7 @@ class spell_marrowgar_bone_spike_graveyard : public SpellScriptLoader SpellCastResult CheckCast() { - return GetCaster()->GetAI()->SelectTarget(SELECT_TARGET_TOPAGGRO, 1, 0.0f, true, -SPELL_IMPALED) ? SPELL_CAST_OK : SPELL_FAILED_NO_VALID_TARGETS; + return GetCaster()->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0, BoneSpikeTargetSelector(GetCaster()->GetAI())) ? SPELL_CAST_OK : SPELL_FAILED_NO_VALID_TARGETS; } void HandleSpikes(SpellEffIndex effIndex) @@ -539,22 +634,22 @@ class spell_marrowgar_bone_spike_graveyard : public SpellScriptLoader PreventHitDefaultEffect(effIndex); if (Creature* marrowgar = GetCaster()->ToCreature()) { - bool didHit = false; CreatureAI* marrowgarAI = marrowgar->AI(); uint8 boneSpikeCount = uint8(GetCaster()->GetMap()->GetSpawnMode() & 1 ? 3 : 1); - for (uint8 i = 0; i < boneSpikeCount; ++i) - { - // select any unit but not the tank - Unit* target = marrowgarAI->SelectTarget(SELECT_TARGET_RANDOM, 1, 150.0f, true, -SPELL_IMPALED); - if (!target) - break; - didHit = true; + std::list<Unit*> targets; + marrowgarAI->SelectTargetList(targets, BoneSpikeTargetSelector(marrowgarAI), boneSpikeCount, SELECT_TARGET_RANDOM); + if (targets.empty()) + return; + + uint32 i = 0; + for (std::list<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr, ++i) + { + Unit* target = *itr; target->CastCustomSpell(BoneSpikeSummonId[i], SPELLVALUE_BASE_POINT0, 0, target, true); } - if (didHit) - marrowgarAI->Talk(SAY_BONESPIKE); + marrowgarAI->Talk(SAY_BONESPIKE); } } @@ -597,6 +692,58 @@ class spell_marrowgar_bone_storm : public SpellScriptLoader } }; +class spell_marrowgar_bone_slice : public SpellScriptLoader +{ + public: + spell_marrowgar_bone_slice() : SpellScriptLoader("spell_marrowgar_bone_slice") { } + + class spell_marrowgar_bone_slice_SpellScript : public SpellScript + { + PrepareSpellScript(spell_marrowgar_bone_slice_SpellScript); + + bool Load() + { + _targetCount = 0; + return true; + } + + void ClearSpikeImmunities() + { + GetCaster()->GetAI()->DoAction(ACTION_CLEAR_SPIKE_IMMUNITIES); + } + + void CountTargets(std::list<WorldObject*>& targets) + { + _targetCount = std::min<uint32>(targets.size(), GetSpellInfo()->MaxAffectedTargets); + } + + void SplitDamage() + { + // Mark the unit as hit, even if the spell missed or was dodged/parried + GetCaster()->GetAI()->SetGUID(GetHitUnit()->GetGUID(), DATA_SPIKE_IMMUNE); + + if (!_targetCount) + return; // This spell can miss all targets + + SetHitDamage(GetHitDamage() / _targetCount); + } + + void Register() + { + BeforeCast += SpellCastFn(spell_marrowgar_bone_slice_SpellScript::ClearSpikeImmunities); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_marrowgar_bone_slice_SpellScript::CountTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY); + OnHit += SpellHitFn(spell_marrowgar_bone_slice_SpellScript::SplitDamage); + } + + uint32 _targetCount; + }; + + SpellScript* GetSpellScript() const + { + return new spell_marrowgar_bone_slice_SpellScript(); + } +}; + void AddSC_boss_lord_marrowgar() { new boss_lord_marrowgar(); @@ -607,4 +754,5 @@ void AddSC_boss_lord_marrowgar() new spell_marrowgar_coldflame_damage(); new spell_marrowgar_bone_spike_graveyard(); new spell_marrowgar_bone_storm(); + new spell_marrowgar_bone_slice(); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index 05bf7b9794a..103c72e947d 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -145,10 +145,7 @@ enum Phases PHASE_ROTFACE = 2, PHASE_COMBAT_1 = 4, PHASE_COMBAT_2 = 5, - PHASE_COMBAT_3 = 6, - - PHASE_MASK_COMBAT = (1 << PHASE_COMBAT_1) | (1 << PHASE_COMBAT_2) | (1 << PHASE_COMBAT_3), - PHASE_MASK_NOT_SELF = (1 << PHASE_FESTERGUT) | (1 << PHASE_ROTFACE) + PHASE_COMBAT_3 = 6 }; enum Points @@ -233,7 +230,7 @@ class boss_professor_putricide : public CreatureScript void Reset() { - if (!(events.GetPhaseMask() & PHASE_MASK_NOT_SELF)) + if (!(events.IsInPhase(PHASE_ROTFACE) || events.IsInPhase(PHASE_FESTERGUT))) instance->SetBossState(DATA_PROFESSOR_PUTRICIDE, NOT_STARTED); instance->SetData(DATA_NAUSEA_ACHIEVEMENT, uint32(true)); @@ -252,7 +249,7 @@ class boss_professor_putricide : public CreatureScript void EnterCombat(Unit* who) { - if (events.GetPhaseMask() & PHASE_MASK_NOT_SELF) + if (events.IsInPhase(PHASE_ROTFACE) || events.IsInPhase(PHASE_FESTERGUT)) return; if (!instance->CheckRequiredBosses(DATA_PROFESSOR_PUTRICIDE, who->ToPlayer())) @@ -282,7 +279,7 @@ class boss_professor_putricide : public CreatureScript { _JustReachedHome(); me->SetWalk(false); - if (events.GetPhaseMask() & PHASE_MASK_COMBAT) + if (events.IsInPhase(PHASE_COMBAT_1) || events.IsInPhase(PHASE_COMBAT_2) || events.IsInPhase(PHASE_COMBAT_3)) instance->SetBossState(DATA_PROFESSOR_PUTRICIDE, FAIL); } @@ -568,7 +565,7 @@ class boss_professor_putricide : public CreatureScript void UpdateAI(uint32 const diff) { - if ((!(events.GetPhaseMask() & PHASE_MASK_NOT_SELF) && !UpdateVictim()) || !CheckInRoom()) + if ((!(events.IsInPhase(PHASE_ROTFACE) || events.IsInPhase(PHASE_FESTERGUT)) && !UpdateVictim()) || !CheckInRoom()) return; events.Update(diff); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp index 3bd313fa148..fb1415aa60b 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -279,20 +279,10 @@ enum Phases PHASE_THREE = 4, PHASE_TRANSITION = 5, PHASE_FROSTMOURNE = 6, // only set on heroic mode when all players are sent into frostmourne - PHASE_OUTRO = 7, - - PHASE_MASK_INTRO = 1 << PHASE_INTRO, - PHASE_MASK_ONE = 1 << PHASE_ONE, - PHASE_MASK_TWO = 1 << PHASE_TWO, - PHASE_MASK_THREE = 1 << PHASE_THREE, - PHASE_MASK_TRANSITION = 1 << PHASE_TRANSITION, - PHASE_MASK_NO_CAST_CHECK = (1 << PHASE_TRANSITION) | (1 << PHASE_FROSTMOURNE) | (1 << PHASE_OUTRO), - PHASE_MASK_FROSTMOURNE = 1 << PHASE_FROSTMOURNE, - PHASE_MASK_OUTRO = 1 << PHASE_OUTRO, - PHASE_MASK_NO_VICTIM = (1 << PHASE_INTRO) | (1 << PHASE_OUTRO) | (1 << PHASE_FROSTMOURNE), + PHASE_OUTRO = 7 }; -#define PHASE_TWO_THREE (events.GetPhaseMask() & PHASE_MASK_TWO ? PHASE_TWO : PHASE_THREE) +#define PHASE_TWO_THREE (events.IsInPhase(PHASE_TWO) ? PHASE_TWO : PHASE_THREE) Position const CenterPosition = {503.6282f, -2124.655f, 840.8569f, 0.0f}; Position const TirionIntro = {489.2970f, -2124.840f, 840.8569f, 0.0f}; @@ -589,7 +579,7 @@ class boss_the_lich_king : public CreatureScript void KilledUnit(Unit* victim) { - if (victim->GetTypeId() == TYPEID_PLAYER && !me->IsInEvadeMode() && !(events.GetPhaseMask() & PHASE_MASK_OUTRO)) + if (victim->GetTypeId() == TYPEID_PLAYER && !me->IsInEvadeMode() && !events.IsInPhase(PHASE_OUTRO)) Talk(SAY_LK_KILL); } @@ -669,7 +659,7 @@ class boss_the_lich_king : public CreatureScript void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) { - if (events.GetPhaseMask() & PHASE_MASK_ONE && !HealthAbovePct(70)) + if (events.IsInPhase(PHASE_ONE) && !HealthAbovePct(70)) { events.SetPhase(PHASE_TRANSITION); me->SetReactState(REACT_PASSIVE); @@ -678,7 +668,7 @@ class boss_the_lich_king : public CreatureScript return; } - if (events.GetPhaseMask() & PHASE_MASK_TWO && !HealthAbovePct(40)) + if (events.IsInPhase(PHASE_TWO) && !HealthAbovePct(40)) { events.SetPhase(PHASE_TRANSITION); me->SetReactState(REACT_PASSIVE); @@ -687,7 +677,7 @@ class boss_the_lich_king : public CreatureScript return; } - if (events.GetPhaseMask() & PHASE_MASK_THREE && !HealthAbovePct(10)) + if (events.IsInPhase(PHASE_THREE) && !HealthAbovePct(10)) { me->SetReactState(REACT_PASSIVE); me->AttackStop(); @@ -758,7 +748,7 @@ class boss_the_lich_king : public CreatureScript summon->SetReactState(REACT_PASSIVE); summon->SetSpeed(MOVE_FLIGHT, 0.5f); summon->GetMotionMaster()->MoveRandom(10.0f); - if (!(events.GetPhaseMask() & PHASE_MASK_FROSTMOURNE)) + if (!events.IsInPhase(PHASE_FROSTMOURNE)) summon->m_Events.AddEvent(new VileSpiritActivateEvent(summon), summon->m_Events.CalculateTime(15000)); return; } @@ -873,14 +863,14 @@ class boss_the_lich_king : public CreatureScript void UpdateAI(uint32 const diff) { // check phase first to prevent updating victim and entering evade mode when not wanted - if (!(events.GetPhaseMask() & PHASE_MASK_NO_VICTIM)) + if (!(events.IsInPhase(PHASE_OUTRO) || events.IsInPhase(PHASE_INTRO) || events.IsInPhase(PHASE_FROSTMOURNE))) if (!UpdateVictim()) return; events.Update(diff); // during Remorseless Winter phases The Lich King is channeling a spell, but we must continue casting other spells - if (me->HasUnitState(UNIT_STATE_CASTING) && !(events.GetPhaseMask() & PHASE_MASK_NO_CAST_CHECK)) + if (me->HasUnitState(UNIT_STATE_CASTING) && !(events.IsInPhase(PHASE_TRANSITION) || events.IsInPhase(PHASE_OUTRO) || events.IsInPhase(PHASE_FROSTMOURNE))) return; while (uint32 eventId = events.ExecuteEvent()) @@ -936,7 +926,7 @@ class boss_the_lich_king : public CreatureScript break; case EVENT_INFEST: DoCast(me, SPELL_INFEST); - events.ScheduleEvent(EVENT_INFEST, urand(21000, 24000), 0, (events.GetPhaseMask() & PHASE_MASK_ONE) ? PHASE_ONE : PHASE_TWO); + events.ScheduleEvent(EVENT_INFEST, urand(21000, 24000), 0, events.IsInPhase(PHASE_ONE) ? PHASE_ONE : PHASE_TWO); break; case EVENT_NECROTIC_PLAGUE: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, NecroticPlagueTargetCheck(me, NECROTIC_PLAGUE_LK, NECROTIC_PLAGUE_PLR))) @@ -1005,7 +995,7 @@ class boss_the_lich_king : public CreatureScript break; case EVENT_START_ATTACK: me->SetReactState(REACT_AGGRESSIVE); - if (events.GetPhaseMask() & PHASE_MASK_FROSTMOURNE) + if (events.IsInPhase(PHASE_FROSTMOURNE)) events.SetPhase(PHASE_THREE); break; case EVENT_VILE_SPIRITS: @@ -1253,7 +1243,7 @@ class npc_tirion_fordring_tft : public CreatureScript void UpdateAI(uint32 const diff) { - if (!UpdateVictim() && !(_events.GetPhaseMask() & (PHASE_MASK_INTRO | PHASE_MASK_OUTRO))) + if (!UpdateVictim() && !(_events.IsInPhase(PHASE_OUTRO) || _events.IsInPhase(PHASE_INTRO))) return; _events.Update(diff); @@ -2847,8 +2837,6 @@ class spell_the_lich_king_vile_spirit_damage_target_search : public SpellScriptL { OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_vile_spirit_damage_target_search_SpellScript::CheckTargetCount, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); } - - Unit* _target; }; SpellScript* GetSpellScript() const diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp index 6f017884063..dc0ffcd2c63 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp @@ -198,8 +198,7 @@ public: summoned->CastSpell(summoned, DUNGEON_MODE(SPELL_SPARK_VISUAL_TRIGGER, H_SPELL_SPARK_VISUAL_TRIGGER), true); - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) { summoned->SetInCombatWith(target); summoned->GetMotionMaster()->Clear(); diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp index 7fbf5f3ee79..8accb3182ce 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp @@ -117,9 +117,7 @@ public: { if (PartingSorrowTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) DoCast(target, SPELL_PARTING_SORROW); PartingSorrowTimer = urand(30000, 40000); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index 13a4fe23690..e5ab119e3dc 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -176,10 +176,7 @@ enum EncounterPhases { PHASE_NORMAL = 0, PHASE_ROLE_PLAY = 1, - PHASE_BIG_BANG = 2, - - PHASE_MASK_NO_UPDATE = (1 << PHASE_ROLE_PLAY) | (1 << PHASE_BIG_BANG), - PHASE_MASK_NO_CAST_CHECK = 1 << PHASE_ROLE_PLAY, + PHASE_BIG_BANG = 2 }; enum AchievmentInfo @@ -542,12 +539,12 @@ class boss_algalon_the_observer : public CreatureScript void UpdateAI(uint32 const diff) { - if ((!(events.GetPhaseMask() & PHASE_MASK_NO_UPDATE) && !UpdateVictim()) || !CheckInRoom()) + if ((!(events.IsInPhase(PHASE_ROLE_PLAY) || events.IsInPhase(PHASE_BIG_BANG)) && !UpdateVictim()) || !CheckInRoom()) return; events.Update(diff); - if (!(events.GetPhaseMask() & PHASE_MASK_NO_CAST_CHECK)) + if (!events.IsInPhase(PHASE_ROLE_PLAY)) if (me->HasUnitState(UNIT_STATE_CASTING)) return; @@ -772,7 +769,7 @@ class npc_living_constellation : public CreatureScript void UpdateAI(uint32 const diff) { - if (!(_events.GetPhaseMask() & PHASE_MASK_NO_UPDATE) && !UpdateVictim()) + if (!(_events.IsInPhase(PHASE_ROLE_PLAY) || _events.IsInPhase(PHASE_BIG_BANG)) && !UpdateVictim()) return; _events.Update(diff); diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp index f579fb2b93c..dbf2058546f 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp @@ -154,7 +154,7 @@ public: Talk(YELL_DEAD_1); } - if (events.GetPhaseMask() & (1 << PHASE_EVENT)) + if (events.IsInPhase(PHASE_EVENT)) damage = 0; } @@ -206,7 +206,7 @@ public: void UpdateAI(const uint32 diff) { - if (!UpdateVictim() && !(events.GetPhaseMask() & (1 << PHASE_EVENT))) + if (!UpdateVictim() && !events.IsInPhase(PHASE_EVENT)) return; events.Update(diff); diff --git a/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp b/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp index 3a56a0bfed2..53d51e1fd6c 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp @@ -187,9 +187,7 @@ public: void RevertThreatOnTarget(uint64 guid) { - Unit* unit = NULL; - unit = Unit::GetUnit(*me, guid); - if (unit) + if (Unit* unit = Unit::GetUnit(*me, guid)) { if (DoGetThreat(unit)) DoModifyThreatPercent(unit, -100); @@ -279,8 +277,7 @@ public: { if (Phase1) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target && target->isAlive()) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) { Phase1 = false; @@ -308,7 +305,8 @@ public: AcidGeyserTimer = 1000; PhaseChangeTimer = 30000; } - } else // Encounter is a loop pretty much. Phase 1 -> Phase 2 -> Phase 1 -> Phase 2 till death or enrage + } + else // Encounter is a loop pretty much. Phase 1 -> Phase 2 -> Phase 1 -> Phase 2 till death or enrage { if (TargetGUID) RevertThreatOnTarget(TargetGUID); diff --git a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp index b8003761cc7..a91d25fa984 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp @@ -422,8 +422,7 @@ public: Glaive->InterruptNonMeleeSpells(true); DoCast(me, SPELL_FLAME_ENRAGE, true); DoResetThreat(); - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target && target->isAlive()) + if (SelectTarget(SELECT_TARGET_RANDOM, 0)) { me->AddThreat(me->getVictim(), 5000000.0f); AttackStart(me->getVictim()); diff --git a/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp b/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp index 6c28b058cf7..2dc0517dc49 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp @@ -468,8 +468,7 @@ public: if (CrushingShadowsTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target && target->isAlive()) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) DoCast(target, SPELL_CRUSHING_SHADOWS); CrushingShadowsTimer = urand(10, 26) * 1000; } else CrushingShadowsTimer -= diff; diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp index d9ad35f9552..5037f1c4964 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp @@ -227,9 +227,7 @@ public: //Only if not incombat check if the event is started if (!me->isInCombat() && instance && instance->GetData(DATA_KARATHRESSEVENT)) { - Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER)); - - if (target) + if (Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER))) { AttackStart(target); GetAdvisors(); @@ -360,12 +358,8 @@ public: { if (instance) { - Creature* Karathress = NULL; - Karathress = (Unit::GetCreature((*me), instance->GetData64(DATA_KARATHRESS))); - - if (Karathress) - if (!me->isAlive() && Karathress) - CAST_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventSharkkisDeath(); + if (Creature* Karathress = (Unit::GetCreature((*me), instance->GetData64(DATA_KARATHRESS)))) + CAST_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventSharkkisDeath(); } } @@ -383,12 +377,8 @@ public: //Only if not incombat check if the event is started if (!me->isInCombat() && instance && instance->GetData(DATA_KARATHRESSEVENT)) { - Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER)); - - if (target) - { + if (Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER))) AttackStart(target); - } } //Return since we have no target @@ -445,12 +435,13 @@ public: pet_id = CREATURE_FATHOM_SPOREBAT; } //DoCast(me, spell_id, true); - Creature* Pet = DoSpawnCreature(pet_id, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (Pet && target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) { - Pet->AI()->AttackStart(target); - SummonedPet = Pet->GetGUID(); + if (Creature* Pet = DoSpawnCreature(pet_id, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) + { + Pet->AI()->AttackStart(target); + SummonedPet = Pet->GetGUID(); + } } } else Pet_Timer -= diff; @@ -500,12 +491,8 @@ public: { if (instance) { - Creature* Karathress = NULL; - Karathress = (Unit::GetCreature((*me), instance->GetData64(DATA_KARATHRESS))); - - if (Karathress) - if (!me->isAlive() && Karathress) - CAST_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventTidalvessDeath(); + if (Creature* Karathress = Unit::GetCreature((*me), instance->GetData64(DATA_KARATHRESS))) + CAST_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventTidalvessDeath(); } } @@ -524,12 +511,8 @@ public: //Only if not incombat check if the event is started if (!me->isInCombat() && instance && instance->GetData(DATA_KARATHRESSEVENT)) { - Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER)); - - if (target) - { + if (Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER))) AttackStart(target); - } } //Return since we have no target @@ -627,12 +610,8 @@ public: { if (instance) { - Creature* Karathress = NULL; - Karathress = (Unit::GetCreature((*me), instance->GetData64(DATA_KARATHRESS))); - - if (Karathress) - if (!me->isAlive() && Karathress) - CAST_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventCaribdisDeath(); + if (Creature* Karathress = Unit::GetCreature((*me), instance->GetData64(DATA_KARATHRESS))) + CAST_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventCaribdisDeath(); } } @@ -650,12 +629,8 @@ public: //Only if not incombat check if the event is started if (!me->isInCombat() && instance && instance->GetData(DATA_KARATHRESSEVENT)) { - Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER)); - - if (target) - { + if (Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER))) AttackStart(target); - } } //Return since we have no target @@ -697,11 +672,8 @@ public: Cyclone->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); Cyclone->setFaction(me->getFaction()); Cyclone->CastSpell(Cyclone, SPELL_CYCLONE_CYCLONE, true); - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) - { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) Cyclone->AI()->AttackStart(target); - } } } else Cyclone_Timer -= diff; diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_hydross_the_unstable.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_hydross_the_unstable.cpp index b31292c4b00..ec85fe7293d 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_hydross_the_unstable.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_hydross_the_unstable.cpp @@ -272,8 +272,7 @@ public: //VileSludge_Timer if (VileSludge_Timer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) DoCast(target, SPELL_VILE_SLUDGE); VileSludge_Timer = 15000; diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp index 9476bb28f8e..06ea83881c8 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp @@ -184,10 +184,9 @@ public: for (uint8 i = 0; i < 10; ++i) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - Creature* Murloc = me->SummonCreature(NPC_TIDEWALKER_LURKER, MurlocCords[i][0], MurlocCords[i][1], MurlocCords[i][2], MurlocCords[i][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (target && Murloc) - Murloc->AI()->AttackStart(target); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + if (Creature* Murloc = me->SummonCreature(NPC_TIDEWALKER_LURKER, MurlocCords[i][0], MurlocCords[i][1], MurlocCords[i][2], MurlocCords[i][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000)) + Murloc->AI()->AttackStart(target); } Talk(EMOTE_EARTHQUAKE); Earthquake = false; diff --git a/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp b/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp index 83596c46936..e2b2425dcfc 100644 --- a/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp +++ b/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp @@ -519,8 +519,7 @@ public: //GreaterPolymorph_Timer if (GreaterPolymorph_Timer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) DoCast(target, SPELL_GREATER_POLYMORPH); GreaterPolymorph_Timer = urand(15000, 20000); diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp index 01ca1636c6b..9ec6691839b 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp @@ -245,11 +245,13 @@ class boss_high_astromancer_solarian : public CreatureScript } else { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (!me->HasInArc(2.5f, target)) - target = me->getVictim(); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + { + if (!me->HasInArc(2.5f, target)) + target = me->getVictim(); + DoCast(target, SPELL_ARCANE_MISSILES); + } } ArcaneMissiles_Timer = 3000; } diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 05fad623114..39992e94c21 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -1715,10 +1715,29 @@ class spell_gen_luck_of_the_draw : public SpellScriptLoader class spell_gen_luck_of_the_draw_AuraScript : public AuraScript { PrepareAuraScript(spell_gen_luck_of_the_draw_AuraScript); + Map const* map; + Difficulty difficulty; bool Load() { - return GetUnitOwner()->GetTypeId() == TYPEID_PLAYER; + Player* owner = GetUnitOwner()->ToPlayer(); + if (!owner) + return false; + + Group* group = owner->GetGroup(); + if (!group || !group->isLFGGroup()) + return false; + + if (!sLFGMgr->selectedRandomLfgDungeon(owner->GetGUID())) + return false; + + map = owner->GetMap(); + difficulty = owner->GetMap()->GetDifficulty(); + + if (!sLFGMgr->inLfgDungeonMap(owner->GetGUID(), map->GetId(), difficulty)) + return false; + + return true; } // cheap hax to make it have update calls @@ -1730,30 +1749,9 @@ class spell_gen_luck_of_the_draw : public SpellScriptLoader void Update(AuraEffect* /*effect*/) { - if (Player* owner = GetUnitOwner()->ToPlayer()) - { - const LfgDungeonSet dungeons = sLFGMgr->GetSelectedDungeons(owner->GetGUID()); - LfgDungeonSet::const_iterator itr = dungeons.begin(); - - if (itr == dungeons.end()) - { - Remove(AURA_REMOVE_BY_DEFAULT); - return; - } - - - LFGDungeonData const* randomDungeon = sLFGMgr->GetLFGDungeon(*itr); - if (Group* group = owner->GetGroup()) - if (Map const* map = owner->GetMap()) - if (group->isLFGGroup()) - if (uint32 dungeonId = sLFGMgr->GetDungeon(group->GetGUID(), true)) - if (LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(dungeonId)) - if (uint32(dungeon->map) == map->GetId() && dungeon->difficulty == map->GetDifficulty()) - if (randomDungeon && randomDungeon->type == LFG_TYPE_RANDOM) - return; // in correct dungeon - + Map const* currentMap = GetUnitOwner()->ToPlayer()->GetMap(); + if (currentMap != map || currentMap->GetDifficulty() != difficulty) Remove(AURA_REMOVE_BY_DEFAULT); - } } void Register() @@ -3518,6 +3516,63 @@ class spell_gen_replenishment : public SpellScriptLoader } }; +enum ServiceUniform +{ + SPELL_SERVICE_UNIFORM = 71450, + + MODEL_GOBLIN_MALE = 31002, + MODEL_GOBLIN_FEMALE = 31003, +}; + +class spell_gen_aura_service_uniform : public SpellScriptLoader +{ + public: + spell_gen_aura_service_uniform() : SpellScriptLoader("spell_gen_aura_service_uniform") { } + + class spell_gen_aura_service_uniform_AuraScript : public AuraScript + { + PrepareAuraScript(spell_gen_aura_service_uniform_AuraScript); + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_SERVICE_UNIFORM)) + return false; + return true; + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + // Apply model goblin + Unit* target = GetTarget(); + if (target->GetTypeId() == TYPEID_PLAYER) + { + if (target->getGender() == GENDER_MALE) + target->SetDisplayId(MODEL_GOBLIN_MALE); + else + target->SetDisplayId(MODEL_GOBLIN_FEMALE); + } + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* target = GetTarget(); + if (target->GetTypeId() == TYPEID_PLAYER) + target->RestoreDisplayId(); + } + + void Register() + { + AfterEffectApply += AuraEffectRemoveFn(spell_gen_aura_service_uniform_AuraScript::OnApply, EFFECT_0, SPELL_AURA_TRANSFORM, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_gen_aura_service_uniform_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_TRANSFORM, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_gen_aura_service_uniform_AuraScript(); + } +}; + void AddSC_generic_spell_scripts() { new spell_gen_absorb0_hitlimit1(); @@ -3597,4 +3652,5 @@ void AddSC_generic_spell_scripts() new spell_gen_bonked(); new spell_gen_gift_of_naaru(); new spell_gen_replenishment(); + new spell_gen_aura_service_uniform(); } diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index b3d818c7565..52845231490 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -101,7 +101,9 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS, "SELECT spell, item, time FROM character_spell_cooldown WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_DECLINEDNAMES, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_declinedname WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_GUILD_MEMBER, "SELECT guildid, rank FROM guild_member WHERE guid = ?", CONNECTION_BOTH); - PrepareStatement(CHAR_SEL_GUILD_MEMBER_EXTENDED, "SELECT g.guildid, g.name, gm.rank, gr.rname, gm.pnote, gm.offnote FROM guild g JOIN guild_member gm ON g.guildid = gm.guildid JOIN guild_rank gr ON g.guildid = gr.guildid WHERE gm.guid = ?", CONNECTION_BOTH); + PrepareStatement(CHAR_SEL_GUILD_MEMBER_EXTENDED, "SELECT g.guildid, g.name, gr.rname, gm.pnote, gm.offnote " + "FROM guild g JOIN guild_member gm ON g.guildid = gm.guildid " + "JOIN guild_rank gr ON g.guildid = gr.guildid AND gm.rank = gr.rid WHERE gm.guid = ?", CONNECTION_BOTH); PrepareStatement(CHAR_SEL_CHARACTER_ACHIEVEMENTS, "SELECT achievement, date FROM character_achievement WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_CRITERIAPROGRESS, "SELECT criteria, counter, date FROM character_achievement_progress WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_EQUIPMENTSETS, "SELECT setguid, setindex, name, iconname, ignore_mask, item0, item1, item2, item3, item4, item5, item6, item7, item8, " diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index 4e1d448a21f..bbb51cfbde6 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -55,7 +55,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_DEL_REALM_CHARACTERS, "DELETE FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_REALM_CHARACTERS, "INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_SUM_REALM_CHARACTERS, "SELECT SUM(numchars) FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC); - PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, sha_pass_hash, joindate) VALUES(?, ?, NOW())", CONNECTION_ASYNC); + PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, sha_pass_hash, joindate) VALUES(?, ?, NOW())", CONNECTION_SYNCH); PrepareStatement(LOGIN_INS_REALM_CHARACTERS_INIT, "INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist, account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_EXPANSION, "UPDATE account SET expansion = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_ACCOUNT_LOCK, "UPDATE account SET locked = ? WHERE id = ?", CONNECTION_ASYNC); @@ -88,4 +88,18 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_ACCOUNT_WHOIS, "SELECT username, email, last_ip FROM account WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_REALMLIST_SECURITY_LEVEL, "SELECT allowedSecurityLevel from realmlist WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_DEL_ACCOUNT, "DELETE FROM account WHERE id = ?", CONNECTION_ASYNC); + + PrepareStatement(LOGIN_SEL_ACCOUNT_ACCESS_BY_ID, "SELECT gmlevel, RealmID FROM account_access WHERE id = ? and (RealmID = ? OR RealmID = -1) ORDER BY gmlevel desc", CONNECTION_SYNCH); + + PrepareStatement(LOGIN_SEL_RBAC_ACCOUNT_GROUPS, "SELECT groupId FROM rbac_account_groups WHERE accountId = ? AND (realmId = ? OR realmId = -1) GROUP BY groupId", CONNECTION_SYNCH); + PrepareStatement(LOGIN_INS_RBAC_ACCOUNT_GROUP, "INSERT INTO rbac_account_groups (accountId, groupId, realmId) VALUES (?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(LOGIN_DEL_RBAC_ACCOUNT_GROUP, "DELETE FROM rbac_account_groups WHERE accountId = ? AND groupId = ? AND (realmId = ? OR realmId = -1)", CONNECTION_ASYNC); + + PrepareStatement(LOGIN_SEL_RBAC_ACCOUNT_ROLES, "SELECT roleId, granted FROM rbac_account_roles WHERE accountId = ? AND (realmId = ? OR realmId = -1) ORDER BY roleId, realmId", CONNECTION_SYNCH); + PrepareStatement(LOGIN_INS_RBAC_ACCOUNT_ROLE, "INSERT INTO rbac_account_roles (accountId, roleId, granted, realmId) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE granted = VALUES(granted)", CONNECTION_ASYNC); + PrepareStatement(LOGIN_DEL_RBAC_ACCOUNT_ROLE, "DELETE FROM rbac_account_roles WHERE accountId = ? AND roleId = ? AND (realmId = ? OR realmId = -1)", CONNECTION_ASYNC); + + PrepareStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, "SELECT permissionId, granted FROM rbac_account_permissions WHERE accountId = ? AND (realmId = ? OR realmId = -1) ORDER BY permissionId, realmId", CONNECTION_SYNCH); + PrepareStatement(LOGIN_INS_RBAC_ACCOUNT_PERMISSION, "INSERT INTO rbac_account_permissions (accountId, permissionId, granted, realmId) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE granted = VALUES(granted)", CONNECTION_ASYNC); + PrepareStatement(LOGIN_DEL_RBAC_ACCOUNT_PERMISSION, "DELETE FROM rbac_account_permissions WHERE accountId = ? AND permissionId = ? AND (realmId = ? OR realmId = -1)", CONNECTION_ASYNC); } diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index 4199bd5556a..939cc4b4790 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -109,6 +109,16 @@ enum LoginDatabaseStatements LOGIN_SEL_REALMLIST_SECURITY_LEVEL, LOGIN_DEL_ACCOUNT, + LOGIN_SEL_ACCOUNT_ACCESS_BY_ID, + LOGIN_SEL_RBAC_ACCOUNT_GROUPS, + LOGIN_INS_RBAC_ACCOUNT_GROUP, + LOGIN_DEL_RBAC_ACCOUNT_GROUP, + LOGIN_SEL_RBAC_ACCOUNT_ROLES, + LOGIN_INS_RBAC_ACCOUNT_ROLE, + LOGIN_DEL_RBAC_ACCOUNT_ROLE, + LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, + LOGIN_INS_RBAC_ACCOUNT_PERMISSION, + LOGIN_DEL_RBAC_ACCOUNT_PERMISSION, MAX_LOGINDATABASE_STATEMENTS }; diff --git a/src/server/shared/Debugging/WheatyExceptionReport.cpp b/src/server/shared/Debugging/WheatyExceptionReport.cpp index 96a115f8057..ea9ab096dcd 100644 --- a/src/server/shared/Debugging/WheatyExceptionReport.cpp +++ b/src/server/shared/Debugging/WheatyExceptionReport.cpp @@ -193,154 +193,125 @@ BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax) { // Windows NT product family. case VER_PLATFORM_WIN32_NT: + { + #if WINVER < 0x0500 + BYTE suiteMask = osvi.wReserved[0]; + BYTE productType = osvi.wReserved[1]; + #else + WORD suiteMask = osvi.wSuiteMask; + BYTE productType = osvi.wProductType; + #endif // WINVER < 0x0500 + // Test for the specific product family. if (osvi.dwMajorVersion == 6) { - #if WINVER < 0x0500 - if (osvi.wReserved[1] == VER_NT_WORKSTATION) - #else - if (osvi.wProductType == VER_NT_WORKSTATION) - #endif // WINVER < 0x0500 + if (productType == VER_NT_WORKSTATION) { - if (osvi.dwMinorVersion == 1) + if (osvi.dwMinorVersion == 2) + _tcsncat(szVersion, _T("Windows 8 "), cntMax); + else if (osvi.dwMinorVersion == 1) _tcsncat(szVersion, _T("Windows 7 "), cntMax); else _tcsncat(szVersion, _T("Windows Vista "), cntMax); } + else if (osvi.dwMinorVersion == 2) + _tcsncat(szVersion, _T("Windows Server 2012 "), cntMax); else if (osvi.dwMinorVersion == 1) _tcsncat(szVersion, _T("Windows Server 2008 R2 "), cntMax); else _tcsncat(szVersion, _T("Windows Server 2008 "), cntMax); } - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) + else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) _tcsncat(szVersion, _T("Microsoft Windows Server 2003 "), cntMax); - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) + else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) _tcsncat(szVersion, _T("Microsoft Windows XP "), cntMax); - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) + else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) _tcsncat(szVersion, _T("Microsoft Windows 2000 "), cntMax); - if (osvi.dwMajorVersion <= 4) + else if (osvi.dwMajorVersion <= 4) _tcsncat(szVersion, _T("Microsoft Windows NT "), cntMax); // Test for specific product on Windows NT 4.0 SP6 and later. if (bOsVersionInfoEx) { // Test for the workstation type. - #if WINVER < 0x0500 - if (osvi.wReserved[1] == VER_NT_WORKSTATION) - #else - if (osvi.wProductType == VER_NT_WORKSTATION) - #endif // WINVER < 0x0500 - { - if (osvi.dwMajorVersion == 4) - _tcsncat(szVersion, _T("Workstation 4.0 "), cntMax); - #if WINVER < 0x0500 - else if (osvi.wReserved[0] & VER_SUITE_PERSONAL) - #else - else if (osvi.wSuiteMask & VER_SUITE_PERSONAL) - #endif // WINVER < 0x0500 + if (productType == VER_NT_WORKSTATION) + { + if (osvi.dwMajorVersion == 4) + _tcsncat(szVersion, _T("Workstation 4.0 "), cntMax); + else if (suiteMask & VER_SUITE_PERSONAL) _tcsncat(szVersion, _T("Home Edition "), cntMax); - #if WINVER < 0x0500 - else if (osvi.wReserved[0] & VER_SUITE_EMBEDDEDNT) - #else - else if (osvi.wSuiteMask & VER_SUITE_EMBEDDEDNT) - #endif // WINVER < 0x0500 + else if (suiteMask & VER_SUITE_EMBEDDEDNT) _tcsncat(szVersion, _T("Embedded "), cntMax); - else - _tcsncat(szVersion, _T("Professional "), cntMax); - } - // Test for the server type. - #if WINVER < 0x0500 - else if (osvi.wReserved[1] == VER_NT_SERVER) - #else - else if (osvi.wProductType == VER_NT_SERVER) - #endif // WINVER < 0x0500 - { - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) + else + _tcsncat(szVersion, _T("Professional "), cntMax); + } + // Test for the server type. + else if (productType == VER_NT_SERVER) { - #if WINVER < 0x0500 - if (osvi.wReserved[0] & VER_SUITE_DATACENTER) - #else - if (osvi.wSuiteMask & VER_SUITE_DATACENTER) - #endif // WINVER < 0x0500 + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) + { + if (suiteMask & VER_SUITE_DATACENTER) _tcsncat(szVersion, _T("Datacenter Edition "), cntMax); - #if WINVER < 0x0500 - else if (osvi.wReserved[0] & VER_SUITE_ENTERPRISE) - #else - else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) - #endif // WINVER < 0x0500 + else if (suiteMask & VER_SUITE_ENTERPRISE) _tcsncat(szVersion, _T("Enterprise Edition "), cntMax); - #if WINVER < 0x0500 - else if (osvi.wReserved[0] == VER_SUITE_BLADE) - #else - else if (osvi.wSuiteMask == VER_SUITE_BLADE) - #endif // WINVER < 0x0500 + else if (suiteMask == VER_SUITE_BLADE) _tcsncat(szVersion, _T("Web Edition "), cntMax); - else - _tcsncat(szVersion, _T("Standard Edition "), cntMax); - } - else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) - { - #if WINVER < 0x0500 - if (osvi.wReserved[0] & VER_SUITE_DATACENTER) - #else - if (osvi.wSuiteMask & VER_SUITE_DATACENTER) - #endif // WINVER < 0x0500 + else + _tcsncat(szVersion, _T("Standard Edition "), cntMax); + } + else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) + { + if (suiteMask & VER_SUITE_DATACENTER) _tcsncat(szVersion, _T("Datacenter Server "), cntMax); - #if WINVER < 0x0500 - else if (osvi.wReserved[0] & VER_SUITE_ENTERPRISE) - #else - else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) - #endif // WINVER < 0x0500 + else if (suiteMask & VER_SUITE_ENTERPRISE) _tcsncat(szVersion, _T("Advanced Server "), cntMax); - else - _tcsncat(szVersion, _T("Server "), cntMax); - } - else // Windows NT 4.0 - { - #if WINVER < 0x0500 - if (osvi.wReserved[0] & VER_SUITE_ENTERPRISE) - #else - if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) - #endif // WINVER < 0x0500 + else + _tcsncat(szVersion, _T("Server "), cntMax); + } + else // Windows NT 4.0 + { + if (suiteMask & VER_SUITE_ENTERPRISE) _tcsncat(szVersion, _T("Server 4.0, Enterprise Edition "), cntMax); - else - _tcsncat(szVersion, _T("Server 4.0 "), cntMax); + else + _tcsncat(szVersion, _T("Server 4.0 "), cntMax); + } } } - } - // Display service pack (if any) and build number. - if (osvi.dwMajorVersion == 4 && _tcsicmp(osvi.szCSDVersion, _T("Service Pack 6")) == 0) - { - HKEY hKey; - LONG lRet; - // Test for SP6 versus SP6a. - lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009"), 0, KEY_QUERY_VALUE, &hKey); - if (lRet == ERROR_SUCCESS) + // Display service pack (if any) and build number. + if (osvi.dwMajorVersion == 4 && _tcsicmp(osvi.szCSDVersion, _T("Service Pack 6")) == 0) { - _stprintf(wszTmp, _T("Service Pack 6a (Version %d.%d, Build %d)"), - osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); - _tcsncat(szVersion, wszTmp, cntMax); + HKEY hKey; + LONG lRet; + + // Test for SP6 versus SP6a. + lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009"), 0, KEY_QUERY_VALUE, &hKey); + if (lRet == ERROR_SUCCESS) + { + _stprintf(wszTmp, _T("Service Pack 6a (Version %d.%d, Build %d)"), + osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); + _tcsncat(szVersion, wszTmp, cntMax); + } + else // Windows NT 4.0 prior to SP6a + { + _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"), + osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); + _tcsncat(szVersion, wszTmp, cntMax); + } + ::RegCloseKey(hKey); } - else // Windows NT 4.0 prior to SP6a + else // Windows NT 3.51 and earlier or Windows 2000 and later { - _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"), - osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); + if (!_tcslen(osvi.szCSDVersion)) + _stprintf(wszTmp, _T("(Version %d.%d, Build %d)"), + osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); + else + _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"), + osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); _tcsncat(szVersion, wszTmp, cntMax); } - ::RegCloseKey(hKey); - } - else // Windows NT 3.51 and earlier or Windows 2000 and later - { - if (!_tcslen(osvi.szCSDVersion)) - _stprintf(wszTmp, _T("(Version %d.%d, Build %d)"), - osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); - else - _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"), - osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); - _tcsncat(szVersion, wszTmp, cntMax); + break; } - break; default: _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"), osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 641fe1ebb62..f6a09667dda 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -814,18 +814,6 @@ RecruitAFriend.MaxLevel = 60 RecruitAFriend.MaxDifference = 4 # -# InstantLogout -# Description: Required security level for instantly logging out everywhere. -# Does not work while in combat, dueling or falling. -# Default: 1 - (Enabled, Mods/GMs/Admins) -# 0 - (Enabled, Everyone) -# 2 - (Enabled, GMs/Admins) -# 3 - (Enabled, Admins) -# 4 - (Disabled) - -InstantLogout = 1 - -# # DisableWaterBreath # Description: Required security level for water breathing. # Default: 4 - (Disabled) @@ -1568,14 +1556,6 @@ ChatLevelReq.Whisper = 1 ChatLevelReq.Say = 1 # -# AllowPlayerCommands -# Description: Allow players to use commands. -# Default: 1 - (Enabled) -# 0 - (Disabled) - -AllowPlayerCommands = 1 - -# # PreserveCustomChannels # Description: Store custom chat channel settings like password, automatic ownership handout # or ban list in the database. Needs to be enabled to save custom diff --git a/src/tools/mmaps_generator/MapBuilder.cpp b/src/tools/mmaps_generator/MapBuilder.cpp index 4a016f267b4..cd85d926125 100644 --- a/src/tools/mmaps_generator/MapBuilder.cpp +++ b/src/tools/mmaps_generator/MapBuilder.cpp @@ -957,7 +957,7 @@ namespace MMAP if (count != 1) return false; - if (header.mmapMagic != MMAP_MAGIC || header.dtVersion != DT_NAVMESH_VERSION) + if (header.mmapMagic != MMAP_MAGIC || header.dtVersion != uint32(DT_NAVMESH_VERSION)) return false; if (header.mmapVersion != MMAP_VERSION) |