From ef0f63e05bde39d8862a2419a264449397a7f115 Mon Sep 17 00:00:00 2001 From: Yaki Khadafi Date: Thu, 13 Sep 2012 17:33:27 +0300 Subject: [PATCH] [12216] Implement currency loot and update loot opcodes. Now negative item value in loot tables represent currency id. Signed-off-by: Yaki Khadafi --- sql/mangos.sql | 50 ++-- ...12216_01_mangos_creature_loot_template.sql | 4 + ...216_02_mangos_disenchant_loot_template.sql | 4 + .../12216_03_mangos_fishing_loot_template.sql | 4 + ...216_04_mangos_gameobject_loot_template.sql | 4 + .../12216_05_mangos_item_loot_template.sql | 4 + .../12216_06_mangos_mail_loot_template.sql | 4 + .../12216_07_mangos_milling_loot_template.sql | 4 + ..._08_mangos_pickpocketing_loot_template.sql | 4 + ...16_09_mangos_prospecting_loot_template.sql | 4 + ...2216_10_mangos_reference_loot_template.sql | 4 + ...12216_11_mangos_skinning_loot_template.sql | 4 + .../12216_12_mangos_spell_loot_template.sql | 4 + src/game/DBCEnums.h | 5 + src/game/DBCStructure.h | 2 +- src/game/DBCfmt.h | 2 +- src/game/Group.cpp | 34 ++- src/game/Group.h | 4 +- src/game/Item.cpp | 33 ++- src/game/LootHandler.cpp | 26 +- src/game/LootMgr.cpp | 269 +++++++++++++----- src/game/LootMgr.h | 38 ++- src/game/Opcodes.cpp | 20 +- src/game/Opcodes.h | 20 +- src/game/Player.cpp | 4 +- src/game/Player.h | 2 +- src/game/World.cpp | 2 + src/game/World.h | 2 + src/mangosd/mangosd.conf.dist.in | 13 +- src/shared/revision_nr.h | 2 +- src/shared/revision_sql.h | 2 +- 31 files changed, 418 insertions(+), 160 deletions(-) create mode 100644 sql/updates/12216_01_mangos_creature_loot_template.sql create mode 100644 sql/updates/12216_02_mangos_disenchant_loot_template.sql create mode 100644 sql/updates/12216_03_mangos_fishing_loot_template.sql create mode 100644 sql/updates/12216_04_mangos_gameobject_loot_template.sql create mode 100644 sql/updates/12216_05_mangos_item_loot_template.sql create mode 100644 sql/updates/12216_06_mangos_mail_loot_template.sql create mode 100644 sql/updates/12216_07_mangos_milling_loot_template.sql create mode 100644 sql/updates/12216_08_mangos_pickpocketing_loot_template.sql create mode 100644 sql/updates/12216_09_mangos_prospecting_loot_template.sql create mode 100644 sql/updates/12216_10_mangos_reference_loot_template.sql create mode 100644 sql/updates/12216_11_mangos_skinning_loot_template.sql create mode 100644 sql/updates/12216_12_mangos_spell_loot_template.sql diff --git a/sql/mangos.sql b/sql/mangos.sql index 97fe190fb..e81d4c4d5 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -24,7 +24,7 @@ CREATE TABLE `db_version` ( `version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL, `cache_id` int(10) default '0', - `required_12195_02_mangos_mangos_string"` bit(1) default NULL + `required_12216_12_mangos_spell_loot_template"` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -1020,11 +1020,11 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `creature_loot_template`; CREATE TABLE `creature_loot_template` ( `entry` mediumint(8) unsigned NOT NULL default '0' COMMENT 'entry 0 used for player insignia loot', - `item` mediumint(8) unsigned NOT NULL default '0', + `item` mediumint(8) NOT NULL default '0', `ChanceOrQuestChance` float NOT NULL default '100', `groupid` tinyint(3) unsigned NOT NULL default '0', `mincountOrRef` mediumint(9) NOT NULL default '1', - `maxcount` tinyint(3) unsigned NOT NULL default '1', + `maxcount` smallint(5) unsigned NOT NULL default '1', `lootcondition` tinyint(3) unsigned NOT NULL default '0', `condition_value1` mediumint(8) unsigned NOT NULL default '0', `condition_value2` mediumint(8) unsigned NOT NULL default '0', @@ -1429,11 +1429,11 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `disenchant_loot_template`; CREATE TABLE `disenchant_loot_template` ( `entry` mediumint(8) unsigned NOT NULL default '0' COMMENT 'Recommended id selection: item_level*100 + item_quality', - `item` mediumint(8) unsigned NOT NULL default '0', + `item` mediumint(8) NOT NULL default '0', `ChanceOrQuestChance` float NOT NULL default '100', `groupid` tinyint(3) unsigned NOT NULL default '0', `mincountOrRef` mediumint(9) NOT NULL default '1', - `maxcount` tinyint(3) unsigned NOT NULL default '1', + `maxcount` smallint(5) unsigned NOT NULL default '1', `lootcondition` tinyint(3) unsigned NOT NULL default '0', `condition_value1` mediumint(8) unsigned NOT NULL default '0', `condition_value2` mediumint(8) unsigned NOT NULL default '0', @@ -1684,11 +1684,11 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `fishing_loot_template`; CREATE TABLE `fishing_loot_template` ( `entry` mediumint(8) unsigned NOT NULL default '0' COMMENT 'entry 0 used for junk loot at fishing fail (if allowed by config option)', - `item` mediumint(8) unsigned NOT NULL default '0', + `item` mediumint(8) NOT NULL default '0', `ChanceOrQuestChance` float NOT NULL default '100', `groupid` tinyint(3) unsigned NOT NULL default '0', `mincountOrRef` mediumint(9) NOT NULL default '1', - `maxcount` tinyint(3) unsigned NOT NULL default '1', + `maxcount` smallint(5) unsigned NOT NULL default '1', `lootcondition` tinyint(3) unsigned NOT NULL default '0', `condition_value1` mediumint(8) unsigned NOT NULL default '0', `condition_value2` mediumint(8) unsigned NOT NULL default '0', @@ -2022,11 +2022,11 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `gameobject_loot_template`; CREATE TABLE `gameobject_loot_template` ( `entry` mediumint(8) unsigned NOT NULL default '0', - `item` mediumint(8) unsigned NOT NULL default '0', + `item` mediumint(8) NOT NULL default '0', `ChanceOrQuestChance` float NOT NULL default '100', `groupid` tinyint(3) unsigned NOT NULL default '0', `mincountOrRef` mediumint(9) NOT NULL default '1', - `maxcount` tinyint(3) unsigned NOT NULL default '1', + `maxcount` smallint(5) unsigned NOT NULL default '1', `lootcondition` tinyint(3) unsigned NOT NULL default '0', `condition_value1` mediumint(8) unsigned NOT NULL default '0', `condition_value2` mediumint(8) unsigned NOT NULL default '0', @@ -2411,11 +2411,11 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `item_loot_template`; CREATE TABLE `item_loot_template` ( `entry` mediumint(8) unsigned NOT NULL default '0', - `item` mediumint(8) unsigned NOT NULL default '0', + `item` mediumint(8) NOT NULL default '0', `ChanceOrQuestChance` float NOT NULL default '100', `groupid` tinyint(3) unsigned NOT NULL default '0', `mincountOrRef` mediumint(9) NOT NULL default '1', - `maxcount` tinyint(3) unsigned NOT NULL default '1', + `maxcount` smallint(5) unsigned NOT NULL default '1', `lootcondition` tinyint(3) unsigned NOT NULL default '0', `condition_value1` mediumint(8) unsigned NOT NULL default '0', `condition_value2` mediumint(8) unsigned NOT NULL default '0', @@ -3309,11 +3309,11 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `mail_loot_template`; CREATE TABLE `mail_loot_template` ( `entry` mediumint(8) unsigned NOT NULL default '0', - `item` mediumint(8) unsigned NOT NULL default '0', + `item` mediumint(8) NOT NULL default '0', `ChanceOrQuestChance` float NOT NULL default '100', `groupid` tinyint(3) unsigned NOT NULL default '0', `mincountOrRef` mediumint(9) NOT NULL default '1', - `maxcount` tinyint(3) unsigned NOT NULL default '1', + `maxcount` smallint(5) unsigned NOT NULL default '1', `lootcondition` tinyint(3) unsigned NOT NULL default '0', `condition_value1` mediumint(8) unsigned NOT NULL default '0', `condition_value2` mediumint(8) unsigned NOT NULL default '0', @@ -4227,11 +4227,11 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `milling_loot_template`; CREATE TABLE `milling_loot_template` ( `entry` mediumint(8) unsigned NOT NULL default '0', - `item` mediumint(8) unsigned NOT NULL default '0', + `item` mediumint(8) NOT NULL default '0', `ChanceOrQuestChance` float NOT NULL default '100', `groupid` tinyint(3) unsigned NOT NULL default '0', `mincountOrRef` mediumint(9) NOT NULL default '1', - `maxcount` tinyint(3) unsigned NOT NULL default '1', + `maxcount` smallint(5) unsigned NOT NULL default '1', `lootcondition` tinyint(3) unsigned NOT NULL default '0', `condition_value1` mediumint(8) unsigned NOT NULL default '0', `condition_value2` mediumint(8) unsigned NOT NULL default '0', @@ -4824,11 +4824,11 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `pickpocketing_loot_template`; CREATE TABLE `pickpocketing_loot_template` ( `entry` mediumint(8) unsigned NOT NULL default '0', - `item` mediumint(8) unsigned NOT NULL default '0', + `item` mediumint(8) NOT NULL default '0', `ChanceOrQuestChance` float NOT NULL default '100', `groupid` tinyint(3) unsigned NOT NULL default '0', `mincountOrRef` mediumint(9) NOT NULL default '1', - `maxcount` tinyint(3) unsigned NOT NULL default '1', + `maxcount` smallint(5) unsigned NOT NULL default '1', `lootcondition` tinyint(3) unsigned NOT NULL default '0', `condition_value1` mediumint(8) unsigned NOT NULL default '0', `condition_value2` mediumint(8) unsigned NOT NULL default '0', @@ -20409,11 +20409,11 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `prospecting_loot_template`; CREATE TABLE `prospecting_loot_template` ( `entry` mediumint(8) unsigned NOT NULL default '0', - `item` mediumint(8) unsigned NOT NULL default '0', + `item` mediumint(8) NOT NULL default '0', `ChanceOrQuestChance` float NOT NULL default '100', `groupid` tinyint(3) unsigned NOT NULL default '0', `mincountOrRef` mediumint(9) NOT NULL default '1', - `maxcount` tinyint(3) unsigned NOT NULL default '1', + `maxcount` smallint(5) unsigned NOT NULL default '1', `lootcondition` tinyint(3) unsigned NOT NULL default '0', `condition_value1` mediumint(8) unsigned NOT NULL default '0', `condition_value2` mediumint(8) unsigned NOT NULL default '0', @@ -20761,11 +20761,11 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `reference_loot_template`; CREATE TABLE `reference_loot_template` ( `entry` mediumint(8) unsigned NOT NULL default '0', - `item` mediumint(8) unsigned NOT NULL default '0', + `item` mediumint(8) NOT NULL default '0', `ChanceOrQuestChance` float NOT NULL default '100', `groupid` tinyint(3) unsigned NOT NULL default '0', `mincountOrRef` mediumint(9) NOT NULL default '1', - `maxcount` tinyint(3) unsigned NOT NULL default '1', + `maxcount` smallint(5) unsigned NOT NULL default '1', `lootcondition` tinyint(3) unsigned NOT NULL default '0', `condition_value1` mediumint(8) unsigned NOT NULL default '0', `condition_value2` mediumint(8) unsigned NOT NULL default '0', @@ -20965,11 +20965,11 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `skinning_loot_template`; CREATE TABLE `skinning_loot_template` ( `entry` mediumint(8) unsigned NOT NULL default '0', - `item` mediumint(8) unsigned NOT NULL default '0', + `item` mediumint(8) NOT NULL default '0', `ChanceOrQuestChance` float NOT NULL default '100', `groupid` tinyint(3) unsigned NOT NULL default '0', `mincountOrRef` mediumint(9) NOT NULL default '1', - `maxcount` tinyint(3) unsigned NOT NULL default '1', + `maxcount` smallint(5) unsigned NOT NULL default '1', `lootcondition` tinyint(3) unsigned NOT NULL default '0', `condition_value1` mediumint(8) unsigned NOT NULL default '0', `condition_value2` mediumint(8) unsigned NOT NULL default '0', @@ -23411,11 +23411,11 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `spell_loot_template`; CREATE TABLE `spell_loot_template` ( `entry` mediumint(8) unsigned NOT NULL default '0', - `item` mediumint(8) unsigned NOT NULL default '0', + `item` mediumint(8) NOT NULL default '0', `ChanceOrQuestChance` float NOT NULL default '100', `groupid` tinyint(3) unsigned NOT NULL default '0', `mincountOrRef` mediumint(9) NOT NULL default '1', - `maxcount` tinyint(3) unsigned NOT NULL default '1', + `maxcount` smallint(5) unsigned NOT NULL default '1', `lootcondition` tinyint(3) unsigned NOT NULL default '0', `condition_value1` mediumint(8) unsigned NOT NULL default '0', `condition_value2` mediumint(8) unsigned NOT NULL default '0', diff --git a/sql/updates/12216_01_mangos_creature_loot_template.sql b/sql/updates/12216_01_mangos_creature_loot_template.sql new file mode 100644 index 000000000..6728e1f14 --- /dev/null +++ b/sql/updates/12216_01_mangos_creature_loot_template.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_12195_02_mangos_mangos_string required_12216_01_mangos_creature_loot_template bit; + +ALTER TABLE `creature_loot_template` MODIFY COLUMN `item` mediumint(8) NOT NULL DEFAULT '0'; +ALTER TABLE `creature_loot_template` MODIFY COLUMN `maxcount` smallint(5) unsigned NOT NULL DEFAULT '1'; diff --git a/sql/updates/12216_02_mangos_disenchant_loot_template.sql b/sql/updates/12216_02_mangos_disenchant_loot_template.sql new file mode 100644 index 000000000..4e54fff0b --- /dev/null +++ b/sql/updates/12216_02_mangos_disenchant_loot_template.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_12216_01_mangos_creature_loot_template required_12216_02_mangos_disenchant_loot_template bit; + +ALTER TABLE `disenchant_loot_template` MODIFY COLUMN `item` mediumint(8) NOT NULL DEFAULT '0'; +ALTER TABLE `disenchant_loot_template` MODIFY COLUMN `maxcount` smallint(5) unsigned NOT NULL DEFAULT '1'; diff --git a/sql/updates/12216_03_mangos_fishing_loot_template.sql b/sql/updates/12216_03_mangos_fishing_loot_template.sql new file mode 100644 index 000000000..d135579ee --- /dev/null +++ b/sql/updates/12216_03_mangos_fishing_loot_template.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_12216_02_mangos_disenchant_loot_template required_12216_03_mangos_fishing_loot_template bit; + +ALTER TABLE `fishing_loot_template` MODIFY COLUMN `item` mediumint(8) NOT NULL DEFAULT '0'; +ALTER TABLE `fishing_loot_template` MODIFY COLUMN `maxcount` smallint(5) unsigned NOT NULL DEFAULT '1'; diff --git a/sql/updates/12216_04_mangos_gameobject_loot_template.sql b/sql/updates/12216_04_mangos_gameobject_loot_template.sql new file mode 100644 index 000000000..8a7d8bc6c --- /dev/null +++ b/sql/updates/12216_04_mangos_gameobject_loot_template.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_12216_03_mangos_fishing_loot_template required_12216_04_mangos_gameobject_loot_template bit; + +ALTER TABLE `gameobject_loot_template` MODIFY COLUMN `item` mediumint(8) NOT NULL DEFAULT '0'; +ALTER TABLE `gameobject_loot_template` MODIFY COLUMN `maxcount` smallint(5) unsigned NOT NULL DEFAULT '1'; diff --git a/sql/updates/12216_05_mangos_item_loot_template.sql b/sql/updates/12216_05_mangos_item_loot_template.sql new file mode 100644 index 000000000..c8ecd5662 --- /dev/null +++ b/sql/updates/12216_05_mangos_item_loot_template.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_12216_04_mangos_gameobject_loot_template required_12216_05_mangos_item_loot_template bit; + +ALTER TABLE `item_loot_template` MODIFY COLUMN `item` mediumint(8) NOT NULL DEFAULT '0'; +ALTER TABLE `item_loot_template` MODIFY COLUMN `maxcount` smallint(5) unsigned NOT NULL DEFAULT '1'; diff --git a/sql/updates/12216_06_mangos_mail_loot_template.sql b/sql/updates/12216_06_mangos_mail_loot_template.sql new file mode 100644 index 000000000..0814a23de --- /dev/null +++ b/sql/updates/12216_06_mangos_mail_loot_template.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_12216_05_mangos_item_loot_template required_12216_06_mangos_mail_loot_template bit; + +ALTER TABLE `mail_loot_template` MODIFY COLUMN `item` mediumint(8) NOT NULL DEFAULT '0'; +ALTER TABLE `mail_loot_template` MODIFY COLUMN `maxcount` smallint(5) unsigned NOT NULL DEFAULT '1'; diff --git a/sql/updates/12216_07_mangos_milling_loot_template.sql b/sql/updates/12216_07_mangos_milling_loot_template.sql new file mode 100644 index 000000000..319ae4665 --- /dev/null +++ b/sql/updates/12216_07_mangos_milling_loot_template.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_12216_06_mangos_mail_loot_template required_12216_07_mangos_milling_loot_template bit; + +ALTER TABLE `milling_loot_template` MODIFY COLUMN `item` mediumint(8) NOT NULL DEFAULT '0'; +ALTER TABLE `milling_loot_template` MODIFY COLUMN `maxcount` smallint(5) unsigned NOT NULL DEFAULT '1'; diff --git a/sql/updates/12216_08_mangos_pickpocketing_loot_template.sql b/sql/updates/12216_08_mangos_pickpocketing_loot_template.sql new file mode 100644 index 000000000..7ef00a811 --- /dev/null +++ b/sql/updates/12216_08_mangos_pickpocketing_loot_template.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_12216_07_mangos_milling_loot_template required_12216_08_mangos_pickpocketing_loot_template bit; + +ALTER TABLE `pickpocketing_loot_template` MODIFY COLUMN `item` mediumint(8) NOT NULL DEFAULT '0'; +ALTER TABLE `pickpocketing_loot_template` MODIFY COLUMN `maxcount` smallint(5) unsigned NOT NULL DEFAULT '1'; diff --git a/sql/updates/12216_09_mangos_prospecting_loot_template.sql b/sql/updates/12216_09_mangos_prospecting_loot_template.sql new file mode 100644 index 000000000..0e44aea6f --- /dev/null +++ b/sql/updates/12216_09_mangos_prospecting_loot_template.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_12216_08_mangos_pickpocketing_loot_template required_12216_09_mangos_prospecting_loot_template bit; + +ALTER TABLE `prospecting_loot_template` MODIFY COLUMN `item` mediumint(8) NOT NULL DEFAULT '0'; +ALTER TABLE `prospecting_loot_template` MODIFY COLUMN `maxcount` smallint(5) unsigned NOT NULL DEFAULT '1'; diff --git a/sql/updates/12216_10_mangos_reference_loot_template.sql b/sql/updates/12216_10_mangos_reference_loot_template.sql new file mode 100644 index 000000000..7368040af --- /dev/null +++ b/sql/updates/12216_10_mangos_reference_loot_template.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_12216_09_mangos_prospecting_loot_template required_12216_10_mangos_reference_loot_template bit; + +ALTER TABLE `reference_loot_template` MODIFY COLUMN `item` mediumint(8) NOT NULL DEFAULT '0'; +ALTER TABLE `reference_loot_template` MODIFY COLUMN `maxcount` smallint(5) unsigned NOT NULL DEFAULT '1'; diff --git a/sql/updates/12216_11_mangos_skinning_loot_template.sql b/sql/updates/12216_11_mangos_skinning_loot_template.sql new file mode 100644 index 000000000..8f451741b --- /dev/null +++ b/sql/updates/12216_11_mangos_skinning_loot_template.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_12216_10_mangos_reference_loot_template required_12216_11_mangos_skinning_loot_template bit; + +ALTER TABLE `skinning_loot_template` MODIFY COLUMN `item` mediumint(8) NOT NULL DEFAULT '0'; +ALTER TABLE `skinning_loot_template` MODIFY COLUMN `maxcount` smallint(5) unsigned NOT NULL DEFAULT '1'; diff --git a/sql/updates/12216_12_mangos_spell_loot_template.sql b/sql/updates/12216_12_mangos_spell_loot_template.sql new file mode 100644 index 000000000..a72626909 --- /dev/null +++ b/sql/updates/12216_12_mangos_spell_loot_template.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_12216_11_mangos_skinning_loot_template required_12216_12_mangos_spell_loot_template bit; + +ALTER TABLE `spell_loot_template` MODIFY COLUMN `item` mediumint(8) NOT NULL DEFAULT '0'; +ALTER TABLE `spell_loot_template` MODIFY COLUMN `maxcount` smallint(5) unsigned NOT NULL DEFAULT '1'; diff --git a/src/game/DBCEnums.h b/src/game/DBCEnums.h index 0d1023a59..413e296f7 100644 --- a/src/game/DBCEnums.h +++ b/src/game/DBCEnums.h @@ -380,6 +380,11 @@ enum AbilitySkillFlags #define CURRENCY_PRECISION 100.0f +enum CurrencyCategory +{ + CURRENCY_CATEGORY_ARCHAEOLOGY = 82, +}; + enum CurrencyFlags { CURRENCY_FLAG_HAS_PRECISION = 0x08, diff --git a/src/game/DBCStructure.h b/src/game/DBCStructure.h index 36700ff48..bb8de8389 100644 --- a/src/game/DBCStructure.h +++ b/src/game/DBCStructure.h @@ -817,7 +817,7 @@ struct CreatureTypeEntry struct CurrencyTypesEntry { uint32 ID; // 0 - //uint32 Category; // 1 + uint32 Category; // 1 DBCString name; // 2 //char* iconName; // 3 //char* iconName2; // 4 diff --git a/src/game/DBCfmt.h b/src/game/DBCfmt.h index 3332c5d63..68b21c4af 100644 --- a/src/game/DBCfmt.h +++ b/src/game/DBCfmt.h @@ -43,7 +43,7 @@ const char CreatureFamilyfmt[]="nfifiiiiixsx"; const char CreatureSpellDatafmt[]="niiiixxxx"; const char DungeonEncounterfmt[]="niiiisxx"; const char CreatureTypefmt[]="nxx"; -const char CurrencyTypesfmt[]="nxsxxxxiiix"; +const char CurrencyTypesfmt[]="nisxxxxiiix"; const char DurabilityCostsfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiii"; const char DurabilityQualityfmt[]="nf"; const char EmotesEntryfmt[]="nxxiiixx"; diff --git a/src/game/Group.cpp b/src/game/Group.cpp index 7303c90b3..6a3a6a073 100644 --- a/src/game/Group.cpp +++ b/src/game/Group.cpp @@ -500,6 +500,7 @@ void Group::SendLootStartRoll(uint32 CountDown, uint32 mapid, const Roll& r) size_t voteMaskPos = data.wpos(); data << uint8(0); // roll type mask, allowed choices (placeholder) + data << uint8(r.totalPlayersRolling); for (Roll::PlayerVote::const_iterator itr = r.playerVote.begin(); itr != r.playerVote.end(); ++itr) { @@ -518,7 +519,7 @@ void Group::SendLootStartRoll(uint32 CountDown, uint32 mapid, const Roll& r) } } -void Group::SendLootRoll(ObjectGuid const& targetGuid, uint8 rollNumber, uint8 rollType, const Roll& r) +void Group::SendLootRoll(ObjectGuid const& targetGuid, uint32 rollNumber, uint8 rollType, const Roll& r) { WorldPacket data(SMSG_LOOT_ROLL, (8 + 4 + 8 + 4 + 4 + 4 + 1 + 1 + 1)); data << r.lootedTargetGUID; // creature guid what we're looting @@ -527,7 +528,7 @@ void Group::SendLootRoll(ObjectGuid const& targetGuid, uint8 rollNumber, uint8 r data << uint32(r.itemid); // the itemEntryId for the item that shall be rolled for data << uint32(r.itemRandomSuffix); // randomSuffix data << uint32(r.itemRandomPropId); // Item random property ID - data << uint8(rollNumber); // 0: "Need for: [item name]" > 127: "you passed on: [item name]" Roll number + data << uint32(rollNumber); // 0: "Need for: [item name]", -1: "you passed on: [item name]" Roll number data << uint8(rollType); // 0: "Need for: [item name]" 0: "You have selected need for [item name] 1: need roll 2: greed roll data << uint8(0); // auto pass on loot @@ -542,7 +543,7 @@ void Group::SendLootRoll(ObjectGuid const& targetGuid, uint8 rollNumber, uint8 r } } -void Group::SendLootRollWon(ObjectGuid const& targetGuid, uint8 rollNumber, RollVote rollType, const Roll& r) +void Group::SendLootRollWon(ObjectGuid const& targetGuid, uint32 rollNumber, RollVote rollType, const Roll& r) { WorldPacket data(SMSG_LOOT_ROLL_WON, (8 + 4 + 4 + 4 + 4 + 8 + 1 + 1)); data << r.lootedTargetGUID; // creature guid what we're looting @@ -551,7 +552,7 @@ void Group::SendLootRollWon(ObjectGuid const& targetGuid, uint8 rollNumber, Roll data << uint32(r.itemRandomSuffix); // randomSuffix data << uint32(r.itemRandomPropId); // Item random property data << targetGuid; // guid of the player who won. - data << uint8(rollNumber); // rollnumber related to SMSG_LOOT_ROLL + data << uint32(rollNumber); // rollnumber related to SMSG_LOOT_ROLL data << uint8(rollType); // Rolltype related to SMSG_LOOT_ROLL for (Roll::PlayerVote::const_iterator itr = r.playerVote.begin(); itr != r.playerVote.end(); ++itr) @@ -592,6 +593,9 @@ void Group::GroupLoot(WorldObject* pSource, Loot* loot) for (uint8 itemSlot = 0; itemSlot < loot->items.size(); ++itemSlot) { LootItem& lootItem = loot->items[itemSlot]; + if (lootItem.currency) + continue; + ItemPrototype const* itemProto = ObjectMgr::GetItemPrototype(lootItem.itemid); if (!itemProto) { @@ -614,6 +618,9 @@ void Group::NeedBeforeGreed(WorldObject* pSource, Loot* loot) for (uint8 itemSlot = 0; itemSlot < loot->items.size(); ++itemSlot) { LootItem& lootItem = loot->items[itemSlot]; + if (lootItem.currency) + continue; + ItemPrototype const* itemProto = ObjectMgr::GetItemPrototype(lootItem.itemid); if (!itemProto) { @@ -633,6 +640,9 @@ void Group::MasterLoot(WorldObject* pSource, Loot* loot) { for (LootItemList::iterator i = loot->items.begin(); i != loot->items.end(); ++i) { + if (i->currency) + continue; + ItemPrototype const* item = ObjectMgr::GetItemPrototype(i->itemid); if (!item) continue; @@ -704,7 +714,7 @@ bool Group::CountRollVote(ObjectGuid const& playerGUID, Rolls::iterator& rollI, { case ROLL_PASS: // Player choose pass { - SendLootRoll(playerGUID, 128, 128, *roll); + SendLootRoll(playerGUID, uint32(-1), ROLL_PASS, *roll); ++roll->totalPass; itr->second = ROLL_PASS; break; @@ -718,14 +728,14 @@ bool Group::CountRollVote(ObjectGuid const& playerGUID, Rolls::iterator& rollI, } case ROLL_GREED: // player choose Greed { - SendLootRoll(playerGUID, 128, ROLL_GREED, *roll); + SendLootRoll(playerGUID, uint32(-1), ROLL_GREED, *roll); ++roll->totalGreed; itr->second = ROLL_GREED; break; } case ROLL_DISENCHANT: // player choose Disenchant { - SendLootRoll(playerGUID, 128, ROLL_DISENCHANT, *roll); + SendLootRoll(playerGUID, uint32(-1), ROLL_DISENCHANT, *roll); ++roll->totalGreed; itr->second = ROLL_DISENCHANT; break; @@ -749,6 +759,8 @@ void Group::StartLootRoll(WorldObject* lootTarget, LootMethod method, Loot* loot return; LootItem const& lootItem = loot->items[itemSlot]; + if (lootItem.currency) + return; Roll* r = new Roll(lootTarget->GetObjectGuid(), method, lootItem); @@ -821,7 +833,7 @@ void Group::CountTheRoll(Rolls::iterator& rollI) { if (!roll->playerVote.empty()) { - uint8 maxresul = 0; + uint32 maxresul = 0; ObjectGuid maxguid = (*roll->playerVote.begin()).first; Player* player; @@ -830,7 +842,7 @@ void Group::CountTheRoll(Rolls::iterator& rollI) if (itr->second != ROLL_NEED) continue; - uint8 randomN = urand(1, 100); + uint32 randomN = urand(1, 100); SendLootRoll(itr->first, randomN, ROLL_NEED, *roll); if (maxresul < randomN) { @@ -870,7 +882,7 @@ void Group::CountTheRoll(Rolls::iterator& rollI) { if (!roll->playerVote.empty()) { - uint8 maxresul = 0; + uint32 maxresul = 0; ObjectGuid maxguid = (*roll->playerVote.begin()).first; Player* player; RollVote rollvote = ROLL_PASS; // Fixed: Using uninitialized memory 'rollvote' @@ -881,7 +893,7 @@ void Group::CountTheRoll(Rolls::iterator& rollI) if (itr->second != ROLL_GREED && itr->second != ROLL_DISENCHANT) continue; - uint8 randomN = urand(1, 100); + uint32 randomN = urand(1, 100); SendLootRoll(itr->first, randomN, itr->second, *roll); if (maxresul < randomN) { diff --git a/src/game/Group.h b/src/game/Group.h index 2338ccbc5..df6b7dba6 100644 --- a/src/game/Group.h +++ b/src/game/Group.h @@ -369,8 +369,8 @@ class MANGOS_DLL_SPEC Group /*********************************************************/ void SendLootStartRoll(uint32 CountDown, uint32 mapid, const Roll& r); - void SendLootRoll(ObjectGuid const& targetGuid, uint8 rollNumber, uint8 rollType, const Roll& r); - void SendLootRollWon(ObjectGuid const& targetGuid, uint8 rollNumber, RollVote rollType, const Roll& r); + void SendLootRoll(ObjectGuid const& targetGuid, uint32 rollNumber, uint8 rollType, const Roll& r); + void SendLootRollWon(ObjectGuid const& targetGuid, uint32 rollNumber, RollVote rollType, const Roll& r); void SendLootAllPassed(const Roll& r); void GroupLoot(WorldObject* pSource, Loot* loot); void NeedBeforeGreed(WorldObject* pSource, Loot* loot); diff --git a/src/game/Item.cpp b/src/game/Item.cpp index 8c6cd58b0..a1f34b24f 100644 --- a/src/game/Item.cpp +++ b/src/game/Item.cpp @@ -648,7 +648,8 @@ bool Item::LoadFromDB(uint32 guidLow, Field* fields, ObjectGuid ownerGuid) void Item::LoadLootFromDB(Field* fields) { - uint32 item_id = fields[1].GetUInt32(); + uint32 item_id = abs(fields[1].GetInt32()); + uint8 type = fields[1].GetInt32() > 0 ? LOOT_ITEM_TYPE_ITEM : LOOT_ITEM_TYPE_CURRENCY; uint32 item_amount = fields[2].GetUInt32(); uint32 item_suffix = fields[3].GetUInt32(); int32 item_propid = fields[4].GetInt32(); @@ -662,16 +663,32 @@ void Item::LoadLootFromDB(Field* fields) } // normal item case - ItemPrototype const* proto = ObjectMgr::GetItemPrototype(item_id); - - if (!proto) + if (type == LOOT_ITEM_TYPE_ITEM) { - CharacterDatabase.PExecute("DELETE FROM item_loot WHERE guid = '%u' AND itemid = '%u'", GetGUIDLow(), item_id); - sLog.outError("Item::LoadLootFromDB: %s has an unknown item (id: #%u) in item_loot, deleted.", GetOwnerGuid().GetString().c_str(), item_id); - return; + ItemPrototype const* proto = ObjectMgr::GetItemPrototype(item_id); + if (!proto) + { + CharacterDatabase.PExecute("DELETE FROM item_loot WHERE guid = '%u' AND itemid = '%u'", GetGUIDLow(), item_id); + sLog.outError("Item::LoadLootFromDB: %s has an unknown item (id: #%u) in item_loot, deleted.", GetOwnerGuid().GetString().c_str(), item_id); + return; + } + + loot.items.push_back(LootItem(item_id, type, item_amount, item_suffix, item_propid)); + } + // currency case + else //if (type == LOOT_ITEM_TYPE_CURRENCY) + { + CurrencyTypesEntry const* currencyEntry = sCurrencyTypesStore.LookupEntry(item_id); + if (!currencyEntry) + { + CharacterDatabase.PExecute("DELETE FROM item_loot WHERE guid = '%u' AND itemid = '%i'", GetGUIDLow(), -int32(item_id)); + sLog.outError("Item::LoadLootFromDB: %s has an unknown currency (id: #%u) in item_loot, deleted.", GetOwnerGuid().GetString().c_str(), item_id); + return; + } + + loot.items.push_back(LootItem(item_id, type, item_amount)); } - loot.items.push_back(LootItem(item_id, item_amount, item_suffix, item_propid)); ++loot.unlootedCount; SetLootState(ITEM_LOOT_UNCHANGED); diff --git a/src/game/LootHandler.cpp b/src/game/LootHandler.cpp index 2c146bde5..5d4276350 100644 --- a/src/game/LootHandler.cpp +++ b/src/game/LootHandler.cpp @@ -34,7 +34,7 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recv_data) { - DEBUG_LOG("WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); + DEBUG_LOG("WORLD: %s", LookupOpcodeName(recv_data.GetOpcode())); Player* player = GetPlayer(); ObjectGuid lguid = player->GetLootGuid(); Loot* loot; @@ -109,8 +109,9 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recv_data) QuestItem* qitem = NULL; QuestItem* ffaitem = NULL; QuestItem* conditem = NULL; + QuestItem* currency = NULL; - LootItem* item = loot->LootItemInSlot(lootSlot, player, &qitem, &ffaitem, &conditem); + LootItem* item = loot->LootItemInSlot(lootSlot, player, &qitem, &ffaitem, &conditem, ¤cy); if (!item) { @@ -128,6 +129,17 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recv_data) if (pItem) pItem->SetLootState(ITEM_LOOT_CHANGED); + if (currency) + { + if (CurrencyTypesEntry const * currencyEntry = sCurrencyTypesStore.LookupEntry(item->itemid)) + player->ModifyCurrencyCount(item->itemid, int32(item->count * currencyEntry->GetPrecision())); + + player->SendNotifyLootItemRemoved(lootSlot, true); + currency->is_looted = true; + --loot->unlootedCount; + return; + } + ItemPosCountVec dest; InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item->itemid, item->count); if (msg == EQUIP_ERR_OK) @@ -261,8 +273,6 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recv_data*/) WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4 + 1); data << uint32(money_per_player); data << uint8(playersNear.size() > 1 ? 0 : 1); // 0 is "you share of loot..." - data << uint32(0); // guild share - (*i)->GetSession()->SendPacket(&data); } } @@ -274,7 +284,6 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recv_data*/) WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4 + 1); data << uint32(pLoot->gold); data << uint8(1); // 1 is "you loot..." - data << uint32(0); // guild share player->GetSession()->SendPacket(&data); } @@ -555,11 +564,16 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recv_data) if (slotid > pLoot->items.size()) { - DEBUG_LOG("AutoLootItem: Player %s might be using a hack! (slot %d, size " SIZEFMTD ")", GetPlayer()->GetName(), slotid, pLoot->items.size()); + DEBUG_LOG("WorldSession::HandleLootMasterGiveOpcode: Player %s might be using a hack! (slot %d, size " SIZEFMTD ")", GetPlayer()->GetName(), slotid, pLoot->items.size()); return; } LootItem& item = pLoot->items[slotid]; + if (item.currency) + { + sLog.outError("WorldSession::HandleLootMasterGiveOpcode: player %s tried to give currency via master loot! Hack alert! Slot %u, currency id %u", GetPlayer()->GetName(), slotid, item.itemid); + return; + } ItemPosCountVec dest; InventoryResult msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count); diff --git a/src/game/LootMgr.cpp b/src/game/LootMgr.cpp index 6c33279d3..98e1e9201 100644 --- a/src/game/LootMgr.cpp +++ b/src/game/LootMgr.cpp @@ -113,16 +113,17 @@ void LootStore::LoadLootTable() bar.step(); uint32 entry = fields[0].GetUInt32(); - uint32 item = fields[1].GetUInt32(); + uint32 item = abs(fields[1].GetInt32()); + uint8 type = fields[1].GetInt32() > 0 ? LOOT_ITEM_TYPE_ITEM : LOOT_ITEM_TYPE_CURRENCY; float chanceOrQuestChance = fields[2].GetFloat(); uint8 group = fields[3].GetUInt8(); int32 mincountOrRef = fields[4].GetInt32(); uint32 maxcount = fields[5].GetUInt32(); uint16 conditionId = fields[6].GetUInt16(); - if (maxcount > std::numeric_limits::max()) + if (type == LOOT_ITEM_TYPE_ITEM && maxcount > std::numeric_limits::max()) { - sLog.outErrorDb("Table '%s' entry %d item %d: maxcount value (%u) to large. must be less %u - skipped", GetName(), entry, item, maxcount, std::numeric_limits::max()); + sLog.outErrorDb("Table '%s' entry %d item %d: maxcount value (%u) too large. must be less than %u - skipped", GetName(), entry, item, maxcount, std::numeric_limits::max()); continue; // error already printed to log/console. } @@ -142,7 +143,7 @@ void LootStore::LoadLootTable() } } - LootStoreItem storeitem = LootStoreItem(item, chanceOrQuestChance, group, conditionId, mincountOrRef, maxcount); + LootStoreItem storeitem = LootStoreItem(item, type, chanceOrQuestChance, group, conditionId, mincountOrRef, maxcount); if (!storeitem.IsValid(*this, entry)) // Validity checks continue; @@ -253,11 +254,18 @@ bool LootStoreItem::Roll(bool rate) const if (mincountOrRef < 0) // reference case return roll_chance_f(chance * (rate ? sWorld.getConfig(CONFIG_FLOAT_RATE_DROP_ITEM_REFERENCED) : 1.0f)); - ItemPrototype const* pProto = ObjectMgr::GetItemPrototype(itemid); + if (type == LOOT_ITEM_TYPE_ITEM) + { + ItemPrototype const* pProto = ObjectMgr::GetItemPrototype(itemid); - float qualityModifier = pProto && rate ? sWorld.getConfig(qualityToRate[pProto->Quality]) : 1.0f; + float qualityModifier = pProto && rate ? sWorld.getConfig(qualityToRate[pProto->Quality]) : 1.0f; - return roll_chance_f(chance * qualityModifier); + return roll_chance_f(chance * qualityModifier); + } + else if (type == LOOT_ITEM_TYPE_CURRENCY) + return roll_chance_f(chance * (rate ? sWorld.getConfig(CONFIG_FLOAT_RATE_DROP_CURRENCY) : 1.0f)); + + return false; } // Checks correctness of values @@ -269,6 +277,12 @@ bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const return false; } + if (group && type == LOOT_ITEM_TYPE_CURRENCY) + { + sLog.outErrorDb("Table '%s' entry %d currency %d: group is set, but currencies must not have group - skipped", store.GetName(), entry, itemid, group, 1 << 7); + return false; + } + if (mincountOrRef == 0) { sLog.outErrorDb("Table '%s' entry %d item %d: wrong mincountOrRef (%d) - skipped", store.GetName(), entry, itemid, mincountOrRef); @@ -277,10 +291,27 @@ bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const if (mincountOrRef > 0) // item (quest or non-quest) entry, maybe grouped { - ItemPrototype const* proto = ObjectMgr::GetItemPrototype(itemid); - if (!proto) + if (type == LOOT_ITEM_TYPE_ITEM) { - sLog.outErrorDb("Table '%s' entry %d item %d: item entry not listed in `item_template` - skipped", store.GetName(), entry, itemid); + ItemPrototype const* proto = ObjectMgr::GetItemPrototype(itemid); + if (!proto) + { + sLog.outErrorDb("Table '%s' entry %d item %d: item entry not listed in `item_template` - skipped", store.GetName(), entry, itemid); + return false; + } + } + else if (type == LOOT_ITEM_TYPE_CURRENCY) + { + CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(itemid); + if (!currency) + { + sLog.outErrorDb("Table '%s' entry %d: currency entry %u not exists - skipped", store.GetName(), entry, itemid); + return false; + } + } + else + { + sLog.outErrorDb("Table '%s' entry %d: has unknown item %u with type %u - skipped", store.GetName(), entry, itemid, type); return false; } @@ -301,7 +332,6 @@ bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const sLog.outErrorDb("Table '%s' entry %d item %d: max count (%u) less that min count (%i) - skipped", store.GetName(), entry, itemid, uint32(maxcount), mincountOrRef); return false; } - } else // mincountOrRef < 0 { @@ -327,32 +357,39 @@ bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const LootItem::LootItem(LootStoreItem const& li) { itemid = li.itemid; + type = li.type; conditionId = li.conditionId; - - ItemPrototype const* proto = ObjectMgr::GetItemPrototype(itemid); - freeforall = proto && (proto->Flags & ITEM_FLAG_PARTY_LOOT); - - needs_quest = li.needs_quest; - + currency = type == LOOT_ITEM_TYPE_CURRENCY; count = urand(li.mincountOrRef, li.maxcount); // constructor called for mincountOrRef > 0 only - randomSuffix = GenerateEnchSuffixFactor(itemid); - randomPropertyId = Item::GenerateItemRandomPropertyId(itemid); + is_looted = 0; is_blocked = 0; is_underthreshold = 0; is_counted = 0; + + if (currency) + { + freeforall = false; + needs_quest = false; + randomSuffix = 0; + randomPropertyId = 0; + count = uint32(count * sWorld.getConfig(CONFIG_FLOAT_RATE_DROP_CURRENCY_AMOUNT)); + } + else + { + ItemPrototype const* proto = ObjectMgr::GetItemPrototype(itemid); + freeforall = proto && (proto->Flags & ITEM_FLAG_PARTY_LOOT); + needs_quest = li.needs_quest; + randomSuffix = GenerateEnchSuffixFactor(itemid); + randomPropertyId = Item::GenerateItemRandomPropertyId(itemid); + } } -LootItem::LootItem(uint32 itemid_, uint32 count_, uint32 randomSuffix_, int32 randomPropertyId_) +LootItem::LootItem(uint32 itemid_, uint8 type_, uint32 count_, uint32 randomSuffix_, int32 randomPropertyId_) { itemid = itemid_; + type = type_; conditionId = 0; - - ItemPrototype const* proto = ObjectMgr::GetItemPrototype(itemid); - freeforall = proto && (proto->Flags & ITEM_FLAG_PARTY_LOOT); - - needs_quest = false; - count = count_; randomSuffix = randomSuffix_; randomPropertyId = randomPropertyId_; @@ -360,6 +397,16 @@ LootItem::LootItem(uint32 itemid_, uint32 count_, uint32 randomSuffix_, int32 ra is_blocked = 0; is_underthreshold = 0; is_counted = 0; + currency = type == LOOT_ITEM_TYPE_CURRENCY; + needs_quest = false; + + if (currency) + freeforall = false; + else + { + ItemPrototype const* proto = ObjectMgr::GetItemPrototype(itemid); + freeforall = proto && (proto->Flags & ITEM_FLAG_PARTY_LOOT); + } } // Basic checks for player/item compatibility - if false no chance to see the item in the loot @@ -369,28 +416,46 @@ bool LootItem::AllowedForPlayer(Player const* player) const if (conditionId && !sObjectMgr.IsPlayerMeetToNEWCondition(player, conditionId)) return false; - ItemPrototype const* pProto = ObjectMgr::GetItemPrototype(itemid); - if (!pProto) - return false; - - // not show loot for not own team - if ((pProto->Flags2 & ITEM_FLAG2_HORDE_ONLY) && player->GetTeam() != HORDE) - return false; - - if ((pProto->Flags2 & ITEM_FLAG2_ALLIANCE_ONLY) && player->GetTeam() != ALLIANCE) - return false; - - if (needs_quest) + if (type == LOOT_ITEM_TYPE_ITEM) { - // Checking quests for quest-only drop (check only quests requirements in this case) - if (!player->HasQuestForItem(itemid)) + ItemPrototype const* pProto = ObjectMgr::GetItemPrototype(itemid); + if (!pProto) return false; + + // not show loot for not own team + if ((pProto->Flags2 & ITEM_FLAG2_HORDE_ONLY) && player->GetTeam() != HORDE) + return false; + + if ((pProto->Flags2 & ITEM_FLAG2_ALLIANCE_ONLY) && player->GetTeam() != ALLIANCE) + return false; + + if (needs_quest) + { + // Checking quests for quest-only drop (check only quests requirements in this case) + if (!player->HasQuestForItem(itemid)) + return false; + } + else + { + // Not quest only drop (check quest starting items for already accepted non-repeatable quests) + if (pProto->StartQuest && player->GetQuestStatus(pProto->StartQuest) != QUEST_STATUS_NONE && !player->HasQuestForItem(itemid)) + return false; + } } - else + else if (type == LOOT_ITEM_TYPE_CURRENCY) { - // Not quest only drop (check quest starting items for already accepted non-repeatable quests) - if (pProto->StartQuest && player->GetQuestStatus(pProto->StartQuest) != QUEST_STATUS_NONE && !player->HasQuestForItem(itemid)) + CurrencyTypesEntry const * currency = sCurrencyTypesStore.LookupEntry(itemid); + if (!itemid) return false; + + if (!player->isGameMaster()) + { + if (currency->ID == CURRENCY_CONQUEST_ARENA_META || currency->ID == CURRENCY_CONQUEST_BG_META) + return false; + + if (currency->Category == CURRENCY_CATEGORY_ARCHAEOLOGY && !player->HasSkill(SKILL_ARCHAEOLOGY)) + return false; + } } return true; @@ -398,8 +463,8 @@ bool LootItem::AllowedForPlayer(Player const* player) const LootSlotType LootItem::GetSlotTypeForSharedLoot(PermissionTypes permission, Player* viewer, bool condition_ok /*= false*/) const { - // ignore looted, FFA (each player get own copy) and not allowed items - if (is_looted || freeforall || (conditionId && !condition_ok) || !AllowedForPlayer(viewer)) + // ignore currencies, looted items, FFA (each player get own copy) and not allowed items + if (currency || is_looted || freeforall || (conditionId && !condition_ok) || !AllowedForPlayer(viewer)) return MAX_LOOT_SLOT_TYPE; switch (permission) @@ -434,9 +499,10 @@ void Loot::AddItem(LootStoreItem const& item) items.push_back(LootItem(item)); // non-conditional one-player only items are counted here, + // currencies are counter in FillCurrencyLoot, // free for all items are counted in FillFFALoot(), - // non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot() - if (!item.conditionId) + // non-ffa conditionals are counted in FillNonQuestNonFFANonCurrencyConditionalLoot() + if (!item.conditionId && item.type == LOOT_ITEM_TYPE_ITEM) { ItemPrototype const* proto = ObjectMgr::GetItemPrototype(item.itemid); if (!proto || !(proto->Flags & ITEM_FLAG_PARTY_LOOT)) @@ -485,7 +551,11 @@ void Loot::FillNotNormalLootFor(Player* pl) { uint32 plguid = pl->GetGUIDLow(); - QuestItemMap::const_iterator qmapitr = m_playerQuestItems.find(plguid); + QuestItemMap::const_iterator qmapitr = m_playerCurrencies.find(plguid); + if (qmapitr == m_playerCurrencies.end()) + FillCurrencyLoot(pl); + + qmapitr = m_playerQuestItems.find(plguid); if (qmapitr == m_playerQuestItems.end()) FillQuestLoot(pl); @@ -493,9 +563,32 @@ void Loot::FillNotNormalLootFor(Player* pl) if (qmapitr == m_playerFFAItems.end()) FillFFALoot(pl); - qmapitr = m_playerNonQuestNonFFAConditionalItems.find(plguid); - if (qmapitr == m_playerNonQuestNonFFAConditionalItems.end()) - FillNonQuestNonFFAConditionalLoot(pl); + qmapitr = m_playerNonQuestNonFFANonCurrencyConditionalItems.find(plguid); + if (qmapitr == m_playerNonQuestNonFFANonCurrencyConditionalItems.end()) + FillNonQuestNonFFANonCurrencyConditionalLoot(pl); +} + +QuestItemList* Loot::FillCurrencyLoot(Player* player) +{ + QuestItemList* ql = new QuestItemList(); + + for (uint8 i = 0; i < items.size(); ++i) + { + LootItem& item = items[i]; + if (!item.is_looted && item.currency && item.AllowedForPlayer(player)) + { + ql->push_back(QuestItem(i)); + ++unlootedCount; + } + } + if (ql->empty()) + { + delete ql; + return NULL; + } + + m_playerCurrencies[player->GetGUIDLow()] = ql; + return ql; } QuestItemList* Loot::FillFFALoot(Player* player) @@ -556,14 +649,14 @@ QuestItemList* Loot::FillQuestLoot(Player* player) return ql; } -QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player) +QuestItemList* Loot::FillNonQuestNonFFANonCurrencyConditionalLoot(Player* player) { QuestItemList* ql = new QuestItemList(); for (uint8 i = 0; i < items.size(); ++i) { LootItem& item = items[i]; - if (!item.is_looted && !item.freeforall && item.conditionId && item.AllowedForPlayer(player)) + if (!item.is_looted && !item.freeforall && !item.currency && item.conditionId && item.AllowedForPlayer(player)) { ql->push_back(QuestItem(i)); if (!item.is_counted) @@ -579,7 +672,7 @@ QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player) return NULL; } - m_playerNonQuestNonFFAConditionalItems[player->GetGUIDLow()] = ql; + m_playerNonQuestNonFFANonCurrencyConditionalItems[player->GetGUIDLow()] = ql; return ql; } @@ -663,7 +756,7 @@ void Loot::generateMoneyLoot(uint32 minAmount, uint32 maxAmount) } } -LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem** qitem, QuestItem** ffaitem, QuestItem** conditem) +LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem** qitem, QuestItem** ffaitem, QuestItem** conditem, QuestItem** currency) { LootItem* item = NULL; bool is_looted = true; @@ -684,7 +777,25 @@ LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem** qite { item = &items[lootSlot]; is_looted = item->is_looted; - if (item->freeforall) + if (item->currency) + { + QuestItemMap::const_iterator itr = m_playerCurrencies.find(player->GetGUIDLow()); + if (itr != m_playerCurrencies.end()) + { + for (QuestItemList::const_iterator iter = itr->second->begin(); iter != itr->second->end(); ++iter) + { + if (iter->index == lootSlot) + { + QuestItem* currency2 = (QuestItem*) & (*iter); + if (currency) + *currency = currency2; + is_looted = currency2->is_looted; + break; + } + } + } + } + else if (item->freeforall) { QuestItemMap::const_iterator itr = m_playerFFAItems.find(player->GetGUIDLow()); if (itr != m_playerFFAItems.end()) @@ -702,8 +813,8 @@ LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem** qite } else if (item->conditionId) { - QuestItemMap::const_iterator itr = m_playerNonQuestNonFFAConditionalItems.find(player->GetGUIDLow()); - if (itr != m_playerNonQuestNonFFAConditionalItems.end()) + QuestItemMap::const_iterator itr = m_playerNonQuestNonFFANonCurrencyConditionalItems.find(player->GetGUIDLow()); + if (itr != m_playerNonQuestNonFFANonCurrencyConditionalItems.end()) { for (QuestItemList::const_iterator iter = itr->second->begin(); iter != itr->second->end(); ++iter) { @@ -734,11 +845,19 @@ uint32 Loot::GetMaxSlotInLootFor(Player* player) const ByteBuffer& operator<<(ByteBuffer& b, LootItem const& li) { - b << uint32(li.itemid); - b << uint32(li.count); // nr of items of this type - b << uint32(ObjectMgr::GetItemPrototype(li.itemid)->DisplayInfoID); - b << uint32(li.randomSuffix); - b << uint32(li.randomPropertyId); + if (li.type == LOOT_ITEM_TYPE_ITEM) + { + b << uint32(li.itemid); + b << uint32(li.count); // nr of items of this type + b << uint32(ObjectMgr::GetItemPrototype(li.itemid)->DisplayInfoID); + b << uint32(li.randomSuffix); + b << uint32(li.randomPropertyId); + } + else if (li.type == LOOT_ITEM_TYPE_CURRENCY) + { + b << uint32(li.itemid); + b << uint32(li.count); + } // b << uint8(0); // slot type - will send after this function call return b; } @@ -765,10 +884,6 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) size_t currency_count_pos = b.wpos(); // pos of currency count byte b << uint8(0); // currency count placeholder - if (lv.permission == NONE_PERMISSION) - return b; - - for (uint8 i = 0; i < l.items.size(); ++i) { LootSlotType slot_type = l.items[i].GetSlotTypeForSharedLoot(lv.permission, lv.viewer); @@ -780,7 +895,7 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) ++itemsShown; } - QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = l.GetPlayerNonQuestNonFFAConditionalItems(); + QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = l.GetPlayerNonQuestNonFFANonCurrencyConditionalItems(); QuestItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(lv.viewer->GetGUIDLow()); if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end()) { @@ -837,6 +952,22 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) } } + QuestItemMap const& lootPlayerCurrencies = l.GetPlayerCurrencies(); + QuestItemMap::const_iterator currency_itr = lootPlayerCurrencies.find(lv.viewer->GetGUIDLow()); + if (currency_itr != lootPlayerCurrencies.end()) + { + QuestItemList* currency_list = currency_itr->second; + for (QuestItemList::const_iterator ci = currency_list->begin() ; ci != currency_list->end(); ++ci) + { + LootItem& item = l.items[ci->index]; + if (!ci->is_looted && !item.is_looted) + { + b << uint8(ci->index) << item; + ++currenciesShown; + } + } + } + // update number of items and currencies shown b.put(count_pos, itemsShown); b.put(currency_count_pos, currenciesShown); @@ -1009,7 +1140,7 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, bool rate, uint8 if (!i->Roll(rate)) continue; // Bad luck for the entry - if (i->mincountOrRef < 0) // References processing + if (i->mincountOrRef < 0 && i->type == LOOT_ITEM_TYPE_ITEM) // References processing { LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(-i->mincountOrRef); diff --git a/src/game/LootMgr.h b/src/game/LootMgr.h index effecf108..b93734b6c 100644 --- a/src/game/LootMgr.h +++ b/src/game/LootMgr.h @@ -41,6 +41,12 @@ enum PermissionTypes NONE_PERMISSION = 4 }; +enum LootItemType +{ + LOOT_ITEM_TYPE_ITEM = 0, + LOOT_ITEM_TYPE_CURRENCY = 1, +}; + enum LootType { LOOT_CORPSE = 1, @@ -75,17 +81,18 @@ class LootStore; struct LootStoreItem { uint32 itemid; // id of the item + uint8 type; // 0 = item, 1 = currency float chance; // always positive, chance to drop for both quest and non-quest items, chance to be used for refs int32 mincountOrRef; // mincount for drop items (positive) or minus referenced TemplateleId (negative) + uint32 maxcount; // max drop count for the item (mincountOrRef positive) or Ref multiplicator (mincountOrRef negative) uint8 group : 7; bool needs_quest : 1; // quest drop (negative ChanceOrQuestChance in DB) - uint8 maxcount : 8; // max drop count for the item (mincountOrRef positive) or Ref multiplicator (mincountOrRef negative) uint16 conditionId : 16; // additional loot condition Id // Constructor, converting ChanceOrQuestChance -> (chance, needs_quest) // displayid is filled in IsValid() which must be called after - LootStoreItem(uint32 _itemid, float _chanceOrQuestChance, int8 _group, uint16 _conditionId, int32 _mincountOrRef, uint8 _maxcount) - : itemid(_itemid), chance(fabs(_chanceOrQuestChance)), mincountOrRef(_mincountOrRef), + LootStoreItem(uint32 _itemid, uint8 _type, float _chanceOrQuestChance, int8 _group, uint16 _conditionId, int32 _mincountOrRef, uint32 _maxcount) + : itemid(_itemid), type(_type), chance(fabs(_chanceOrQuestChance)), mincountOrRef(_mincountOrRef), group(_group), needs_quest(_chanceOrQuestChance < 0), maxcount(_maxcount), conditionId(_conditionId) {} @@ -97,10 +104,12 @@ struct LootStoreItem struct LootItem { uint32 itemid; + uint8 type; // 0 = item, 1 = currency uint32 randomSuffix; int32 randomPropertyId; + uint32 count; uint16 conditionId : 16; // allow compiler pack structure - uint8 count : 8; + bool currency : 1; bool is_looted : 1; bool is_blocked : 1; bool freeforall : 1; // free for all @@ -112,7 +121,7 @@ struct LootItem // Should be called for non-reference LootStoreItem entries only (mincountOrRef > 0) explicit LootItem(LootStoreItem const& li); - LootItem(uint32 itemid_, uint32 count_, uint32 randomSuffix_ = 0, int32 randomPropertyId_ = 0); + LootItem(uint32 itemid_, uint8 type_, uint32 count_, uint32 randomSuffix_ = 0, int32 randomPropertyId_ = 0); // Basic checks for player/item compatibility - if false no chance to see the item in the loot bool AllowedForPlayer(Player const* player) const; @@ -236,9 +245,10 @@ struct Loot { friend ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv); + QuestItemMap const& GetPlayerCurrencies() const { return m_playerCurrencies; } QuestItemMap const& GetPlayerQuestItems() const { return m_playerQuestItems; } QuestItemMap const& GetPlayerFFAItems() const { return m_playerFFAItems; } - QuestItemMap const& GetPlayerNonQuestNonFFAConditionalItems() const { return m_playerNonQuestNonFFAConditionalItems; } + QuestItemMap const& GetPlayerNonQuestNonFFANonCurrencyConditionalItems() const { return m_playerNonQuestNonFFANonCurrencyConditionalItems; } LootItemList items; uint32 gold; @@ -257,6 +267,10 @@ struct Loot // void clear(); void clear() { + for (QuestItemMap::const_iterator itr = m_playerCurrencies.begin(); itr != m_playerCurrencies.end(); ++itr) + delete itr->second; + m_playerCurrencies.clear(); + for (QuestItemMap::const_iterator itr = m_playerQuestItems.begin(); itr != m_playerQuestItems.end(); ++itr) delete itr->second; m_playerQuestItems.clear(); @@ -265,9 +279,9 @@ struct Loot delete itr->second; m_playerFFAItems.clear(); - for (QuestItemMap::const_iterator itr = m_playerNonQuestNonFFAConditionalItems.begin(); itr != m_playerNonQuestNonFFAConditionalItems.end(); ++itr) + for (QuestItemMap::const_iterator itr = m_playerNonQuestNonFFANonCurrencyConditionalItems.begin(); itr != m_playerNonQuestNonFFANonCurrencyConditionalItems.end(); ++itr) delete itr->second; - m_playerNonQuestNonFFAConditionalItems.clear(); + m_playerNonQuestNonFFANonCurrencyConditionalItems.clear(); m_playersLooting.clear(); items.clear(); @@ -292,22 +306,24 @@ struct Loot // Inserts the item into the loot (called by LootTemplate processors) void AddItem(LootStoreItem const& item); - LootItem* LootItemInSlot(uint32 lootslot, Player* player, QuestItem** qitem = NULL, QuestItem** ffaitem = NULL, QuestItem** conditem = NULL); + LootItem* LootItemInSlot(uint32 lootslot, Player* player, QuestItem** qitem = NULL, QuestItem** ffaitem = NULL, QuestItem** conditem = NULL, QuestItem** currency = NULL); uint32 GetMaxSlotInLootFor(Player* player) const; private: void FillNotNormalLootFor(Player* player); + QuestItemList* FillCurrencyLoot(Player* player); QuestItemList* FillFFALoot(Player* player); QuestItemList* FillQuestLoot(Player* player); - QuestItemList* FillNonQuestNonFFAConditionalLoot(Player* player); + QuestItemList* FillNonQuestNonFFANonCurrencyConditionalLoot(Player* player); LootItemList m_questItems; GuidSet m_playersLooting; + QuestItemMap m_playerCurrencies; QuestItemMap m_playerQuestItems; QuestItemMap m_playerFFAItems; - QuestItemMap m_playerNonQuestNonFFAConditionalItems; + QuestItemMap m_playerNonQuestNonFFANonCurrencyConditionalItems; // All rolls are registered here. They need to know, when the loot is not valid anymore LootValidatorRefManager m_LootValidatorRefManager; diff --git a/src/game/Opcodes.cpp b/src/game/Opcodes.cpp index 4ab03b950..ab4db7e27 100644 --- a/src/game/Opcodes.cpp +++ b/src/game/Opcodes.cpp @@ -332,6 +332,7 @@ void InitializeOpcodes() //OPCODE(CMSG_AUTOEQUIP_GROUND_ITEM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); //OPCODE(CMSG_AUTOSTORE_GROUND_ITEM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); OPCODE(CMSG_AUTOSTORE_LOOT_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutostoreLootItemOpcode ); + OPCODE(CMSG_LOOT_CURRENCY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutostoreLootItemOpcode ); //OPCODE(CMSG_STORE_LOOT_IN_SLOT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); OPCODE(CMSG_AUTOEQUIP_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoEquipItemOpcode ); OPCODE(CMSG_AUTOSTORE_BAG_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoStoreBagItemOpcode ); @@ -422,6 +423,7 @@ void InitializeOpcodes() OPCODE(SMSG_LOOT_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_LOOT_RELEASE_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_LOOT_REMOVED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + OPCODE(SMSG_LOOT_CURRENCY_REMOVED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_LOOT_MONEY_NOTIFY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_LOOT_ITEM_NOTIFY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_LOOT_CLEAR_MONEY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); @@ -732,13 +734,13 @@ void InitializeOpcodes() //OPCODE(CMSG_CANCEL_GROWTH_AURA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelGrowthAuraOpcode ); OPCODE(SMSG_CANCEL_AUTO_REPEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_STANDSTATE_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); - //OPCODE(SMSG_LOOT_ALL_PASSED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); - //OPCODE(SMSG_LOOT_ROLL_WON, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); - //OPCODE(CMSG_LOOT_ROLL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLootRoll ); - //OPCODE(SMSG_LOOT_START_ROLL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); - //OPCODE(SMSG_LOOT_ROLL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); - //OPCODE(CMSG_LOOT_MASTER_GIVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLootMasterGiveOpcode ); - //OPCODE(SMSG_LOOT_MASTER_LIST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + OPCODE(SMSG_LOOT_ALL_PASSED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + OPCODE(SMSG_LOOT_ROLL_WON, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + OPCODE(CMSG_LOOT_ROLL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLootRoll ); + OPCODE(SMSG_LOOT_START_ROLL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + OPCODE(SMSG_LOOT_ROLL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + OPCODE(CMSG_LOOT_MASTER_GIVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLootMasterGiveOpcode ); + OPCODE(SMSG_LOOT_MASTER_LIST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); //OPCODE(SMSG_SET_FORCED_REACTIONS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(SMSG_SPELL_FAILED_OTHER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); //OPCODE(SMSG_GAMEOBJECT_RESET_STATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); @@ -1078,7 +1080,7 @@ void InitializeOpcodes() //OPCODE(SMSG_ECHO_PARTY_SQUELCH, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); //OPCODE(CMSG_SET_TITLE_SUFFIX, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); OPCODE(CMSG_SPELLCLICK, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSpellClick ); - //OPCODE(SMSG_LOOT_LIST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + OPCODE(SMSG_LOOT_LIST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); //OPCODE(CMSG_GM_CHARACTER_RESTORE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); //OPCODE(CMSG_GM_CHARACTER_SAVE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); //OPCODE(SMSG_VOICESESSION_FULL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); @@ -1094,7 +1096,7 @@ void InitializeOpcodes() //OPCODE(SMSG_IGNORE_DIMINISHING_RETURNS_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); OPCODE(CMSG_KEEP_ALIVE, STATUS_NEVER, PROCESS_THREADUNSAFE, &WorldSession::Handle_EarlyProccess ); //OPCODE(SMSG_RAID_READY_CHECK_ERROR, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); - //OPCODE(CMSG_OPT_OUT_OF_LOOT, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleOptOutOfLootOpcode ); + OPCODE(CMSG_OPT_OUT_OF_LOOT, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleOptOutOfLootOpcode ); //OPCODE(MSG_QUERY_GUILD_BANK_TEXT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQueryGuildBankTabText ); OPCODE(CMSG_SET_GUILD_BANK_TEXT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetGuildBankTabText ); //OPCODE(CMSG_SET_GRANTABLE_LEVELS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); diff --git a/src/game/Opcodes.h b/src/game/Opcodes.h index 695822889..c28a22140 100644 --- a/src/game/Opcodes.h +++ b/src/game/Opcodes.h @@ -402,11 +402,13 @@ enum Opcodes SMSG_RESURRECT_REQUEST = 0x2905, // 4.3.4 15595 CMSG_RESURRECT_RESPONSE = 0x6827, // 4.3.4 15595 CMSG_LOOT = 0x0127, // 4.3.4 15595 + CMSG_LOOT_CURRENCY = 0x781C, // 4.3.4 15595 CMSG_LOOT_MONEY = 0x6227, // 4.3.4 15595 CMSG_LOOT_RELEASE = 0x2007, // 4.3.4 15595 SMSG_LOOT_RESPONSE = 0x4C16, // 4.3.4 15595 SMSG_LOOT_RELEASE_RESPONSE = 0x6D25, // 4.3.4 15595 SMSG_LOOT_REMOVED = 0x6817, // 4.3.4 15595 + SMSG_LOOT_CURRENCY_REMOVED = 0x1DB4, // 4.3.4 15595 SMSG_LOOT_MONEY_NOTIFY = 0x2836, // 4.3.4 15595 SMSG_LOOT_ITEM_NOTIFY = 0x6D15, // 4.3.4 15595 SMSG_LOOT_CLEAR_MONEY = 0x2B37, // 4.3.4 15595 @@ -717,13 +719,13 @@ enum Opcodes CMSG_CANCEL_GROWTH_AURA = 0x129C, SMSG_CANCEL_AUTO_REPEAT = 0x6436, // 4.3.4 15595 SMSG_STANDSTATE_UPDATE = 0x6F04, // 4.3.4 15595 - SMSG_LOOT_ALL_PASSED = 0x129F, - SMSG_LOOT_ROLL_WON = 0x12A0, - CMSG_LOOT_ROLL = 0x12A1, - SMSG_LOOT_START_ROLL = 0x12A2, - SMSG_LOOT_ROLL = 0x12A3, - CMSG_LOOT_MASTER_GIVE = 0x12A4, - SMSG_LOOT_MASTER_LIST = 0x12A5, + SMSG_LOOT_ALL_PASSED = 0x6237, // 4.3.4 15595 + SMSG_LOOT_ROLL_WON = 0x6617, // 4.3.4 15595 + CMSG_LOOT_ROLL = 0x6934, // 4.3.4 15595 + SMSG_LOOT_START_ROLL = 0x2227, // 4.3.4 15595 + SMSG_LOOT_ROLL = 0x6507, // 4.3.4 15595 + CMSG_LOOT_MASTER_GIVE = 0x4F35, // 4.3.4 15595 + SMSG_LOOT_MASTER_LIST = 0x0325, // 4.3.4 15595 SMSG_SET_FORCED_REACTIONS = 0x12A6, SMSG_SPELL_FAILED_OTHER = 0x4535, // 4.3.4 15595 SMSG_GAMEOBJECT_RESET_STATE = 0x12A8, @@ -1063,7 +1065,7 @@ enum Opcodes SMSG_ECHO_PARTY_SQUELCH = 0x13F7, CMSG_SET_TITLE_SUFFIX = 0x13F8, CMSG_SPELLCLICK = 0x0805, // 4.3.4 15595 - SMSG_LOOT_LIST = 0x13FA, + SMSG_LOOT_LIST = 0x6807, // 4.3.4 15595 CMSG_GM_CHARACTER_RESTORE = 0x13FB, CMSG_GM_CHARACTER_SAVE = 0x13FC, SMSG_VOICESESSION_FULL = 0x13FD, @@ -1079,7 +1081,7 @@ enum Opcodes SMSG_IGNORE_DIMINISHING_RETURNS_CHEAT = 0x1407, CMSG_KEEP_ALIVE = 0x0015, // 4.3.4 15595 SMSG_RAID_READY_CHECK_ERROR = 0x1409, - CMSG_OPT_OUT_OF_LOOT = 0x140A, + CMSG_OPT_OUT_OF_LOOT = 0x6B16, // 4.3.4 15595 MSG_QUERY_GUILD_BANK_TEXT = 0x140B, CMSG_SET_GUILD_BANK_TEXT = 0x3023, // 4.3.4 15595 CMSG_SET_GRANTABLE_LEVELS = 0x140D, diff --git a/src/game/Player.cpp b/src/game/Player.cpp index a3bbe43ad..8f6426573 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -8318,9 +8318,9 @@ void Player::SendNotifyLootMoneyRemoved() GetSession()->SendPacket(&data); } -void Player::SendNotifyLootItemRemoved(uint8 lootSlot) +void Player::SendNotifyLootItemRemoved(uint8 lootSlot, bool currency) { - WorldPacket data(SMSG_LOOT_REMOVED, 1); + WorldPacket data(currency ? SMSG_LOOT_CURRENCY_REMOVED : SMSG_LOOT_REMOVED, 1); data << uint8(lootSlot); GetSession()->SendPacket(&data); } diff --git a/src/game/Player.h b/src/game/Player.h index ddd08efa6..aeaba0644 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -2063,7 +2063,7 @@ class MANGOS_DLL_SPEC Player : public Unit void SendLoot(ObjectGuid guid, LootType loot_type); void SendLootRelease(ObjectGuid guid); - void SendNotifyLootItemRemoved(uint8 lootSlot); + void SendNotifyLootItemRemoved(uint8 lootSlot, bool currency = false); void SendNotifyLootMoneyRemoved(); /*********************************************************/ diff --git a/src/game/World.cpp b/src/game/World.cpp index 2089e220a..15425714d 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -476,6 +476,8 @@ void World::LoadConfigSettings(bool reload) setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_ARTIFACT, "Rate.Drop.Item.Artifact", 1.0f); setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_REFERENCED, "Rate.Drop.Item.Referenced", 1.0f); setConfigPos(CONFIG_FLOAT_RATE_DROP_MONEY, "Rate.Drop.Money", 1.0f); + setConfigPos(CONFIG_FLOAT_RATE_DROP_CURRENCY, "Rate.Drop.Currency", 1.0f); + setConfigPos(CONFIG_FLOAT_RATE_DROP_CURRENCY_AMOUNT, "Rate.Drop.Currency.Amount", 1.0f); setConfig(CONFIG_FLOAT_RATE_XP_KILL, "Rate.XP.Kill", 1.0f); setConfig(CONFIG_FLOAT_RATE_XP_QUEST, "Rate.XP.Quest", 1.0f); setConfig(CONFIG_FLOAT_RATE_XP_EXPLORE, "Rate.XP.Explore", 1.0f); diff --git a/src/game/World.h b/src/game/World.h index 24db00f07..37c4f8183 100644 --- a/src/game/World.h +++ b/src/game/World.h @@ -224,6 +224,8 @@ enum eConfigFloatValues CONFIG_FLOAT_RATE_DROP_ITEM_ARTIFACT, CONFIG_FLOAT_RATE_DROP_ITEM_REFERENCED, CONFIG_FLOAT_RATE_DROP_MONEY, + CONFIG_FLOAT_RATE_DROP_CURRENCY, + CONFIG_FLOAT_RATE_DROP_CURRENCY_AMOUNT, CONFIG_FLOAT_RATE_XP_KILL, CONFIG_FLOAT_RATE_XP_QUEST, CONFIG_FLOAT_RATE_XP_EXPLORE, diff --git a/src/mangosd/mangosd.conf.dist.in b/src/mangosd/mangosd.conf.dist.in index b55c7d77f..cfa82c7e4 100644 --- a/src/mangosd/mangosd.conf.dist.in +++ b/src/mangosd/mangosd.conf.dist.in @@ -1215,7 +1215,12 @@ Visibility.AIRelocationNotifyDelay = 1000 # Rate.Drop.Item.Artifact # Rate.Drop.Item.Referenced # Rate.Drop.Money -# Drop rates (items by quality and money) +# Rate.Drop.Currency +# Drop rates (items by quality, money and currency drop chance) +# Default: 1 +# +# Rate.Drop.Currency.Amount +# Drop rate for currency amount # Default: 1 # # Rate.XP.Kill @@ -1361,8 +1366,10 @@ Rate.Drop.Item.Legendary = 1 Rate.Drop.Item.Artifact = 1 Rate.Drop.Item.Referenced = 1 Rate.Drop.Money = 1 -Rate.XP.Kill = 1 -Rate.XP.Quest = 1 +Rate.Drop.Currency = 1 +Rate.Drop.Currency.Amount = 1 +Rate.XP.Kill = 1 +Rate.XP.Quest = 1 Rate.XP.Explore = 1 Rate.Rest.InGame = 1 Rate.Rest.Offline.InTavernOrCity = 1 diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 5cf8a3726..86b3ddfba 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "12215" + #define REVISION_NR "12216" #endif // __REVISION_NR_H__ diff --git a/src/shared/revision_sql.h b/src/shared/revision_sql.h index c788b8df8..24ebfb7bd 100644 --- a/src/shared/revision_sql.h +++ b/src/shared/revision_sql.h @@ -1,6 +1,6 @@ #ifndef __REVISION_SQL_H__ #define __REVISION_SQL_H__ #define REVISION_DB_CHARACTERS "required_12161_01_characters_characters" - #define REVISION_DB_MANGOS "required_12195_02_mangos_mangos_string" + #define REVISION_DB_MANGOS "required_12216_12_mangos_spell_loot_template" #define REVISION_DB_REALMD "required_12112_01_realmd_account_access" #endif // __REVISION_SQL_H__