diff --git a/data/sql/updates/pending_db_world/rev_1636980654557070200.sql b/data/sql/updates/pending_db_world/rev_1636980654557070200.sql new file mode 100644 index 000000000..c68a17ac5 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1636980654557070200.sql @@ -0,0 +1,50 @@ +INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1636980654557070200'); + +DROP TABLE IF EXISTS `player_loot_template`; +CREATE TABLE IF NOT EXISTS `player_loot_template` ( + `Entry` MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, + `Item` MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, + `Reference` MEDIUMINT NOT NULL DEFAULT 0, + `Chance` FLOAT NOT NULL DEFAULT 100, + `QuestRequired` TINYINT NOT NULL DEFAULT 0, + `LootMode` SMALLINT UNSIGNED NOT NULL DEFAULT 1, + `GroupId` TINYINT UNSIGNED NOT NULL DEFAULT 0, + `MinCount` TINYINT UNSIGNED NOT NULL DEFAULT 1, + `MaxCount` TINYINT UNSIGNED NOT NULL DEFAULT 1, + `Comment` TEXT DEFAULT NULL, + PRIMARY KEY (`Entry`,`Item`) +) ENGINE=MYISAM DEFAULT CHARSET=utf8mb4 COMMENT='Loot System'; + +DELETE FROM `player_loot_template` WHERE `Entry` IN (1, 0); +INSERT INTO `player_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES +(1, 17306, 0, 50, 0, 1, 0, 2, 5, 'Alterac Valley - Alliance - Stormpike Soldier\s Blood'), +(1, 17326, 0, 30, 0, 1, 0, 1, 1, 'Alterac Valley - Alliance - Stormpike Soldier\s Flesh'), +(1, 17327, 0, 20, 0, 1, 0, 1, 1, 'Alterac Valley - Alliance - Stormpike Lieutenant\s Flesh'), +(1, 17328, 0, 10, 0, 1, 0, 1, 1, 'Alterac Valley - Alliance - Stormpike Commander\'s Flesh'), +(1, 17422, 0, 85, 0, 1, 0, 15, 22, 'Alterac Valley - Alliance - Armor Scrapts'), +(1, 18228, 0, 1, 0, 1, 0, 1, 1, 'Alterac Valley - Alliance - Autographed Picture of Foror & Tigule'), +(0, 17423, 0, 50, 0, 1, 0, 2, 5, 'Alterac Valley - Horde - Storm Crystal'), -- Horde +(0, 17502, 0, 30, 0, 1, 0, 1, 1, 'Alterac Valley - Horde - Frostwolf Soldier\s Medal'), +(0, 17503, 0, 20, 0, 1, 0, 1, 1, 'Alterac Valley - Horde - Frostwolf Lieutenant\s Medal'), +(0, 17504, 0, 10, 0, 1, 0, 1, 1, 'Alterac Valley - Horde - Frostwolf Commander\'s Medal'), +(0, 17422, 0, 85, 0, 1, 0, 15, 22, 'Alterac Valley - Horde - Armor Scraps'), +(0, 18228, 0, 1, 0, 1, 0, 1, 1, 'Alterac Valley - Horde - Autographed Picture of Foror & Tigule'); + +DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 28) AND (`SourceGroup` IN (0, 1)) AND (`SourceEntry` IN (17306, 17326, 17327, 17328, 17422, 18228, 17423, 17502, 17503, 17504)); +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(28, 1, 17306, 0, 0, 22, 0, 30, 0, 0, 0, 0, 0, '', 'Stormpike Soldier Blood Hat only drops inside Alterac Valley Battleground'), +(28, 1, 17326, 0, 0, 22, 0, 30, 0, 0, 0, 0, 0, '', 'Stormpike Soldier Flesh only drops inside Alterac Valley Battleground'), +(28, 1, 17327, 0, 0, 22, 0, 30, 0, 0, 0, 0, 0, '', 'Stormpike Lieutenant Flesh only drops inside Alterac Valley Battleground'), +(28, 1, 17328, 0, 0, 22, 0, 30, 0, 0, 0, 0, 0, '', 'Stormpike Commander Flesh only drops inside Alterac Valley Battleground'), +(28, 1, 17422, 0, 0, 22, 0, 30, 0, 0, 0, 0, 0, '', 'Armor Scrap only drops inside Alterac Valley Battleground'), +(28, 1, 18228, 0, 0, 22, 0, 30, 0, 0, 0, 0, 0, '', 'Autographed Picture of Foror & Tigule only drops inside Alterac Valley Battleground'), +(28, 0, 17423, 0, 0, 22, 0, 30, 0, 0, 0, 0, 0, '', 'Storm Crystal only drops inside Alterac Valley Battleground'), +(28, 0, 17502, 0, 0, 22, 0, 30, 0, 0, 0, 0, 0, '', 'Frostwolf Soldier\s Medal only drops inside Alterac Valley Battleground'), +(28, 0, 17503, 0, 0, 22, 0, 30, 0, 0, 0, 0, 0, '', 'Frostwolf Lieutenant\s Medal only drops inside Alterac Valley Battleground'), +(28, 0, 17504, 0, 0, 22, 0, 30, 0, 0, 0, 0, 0, '', 'Frostwolf Commander\'s Medal only drops inside Alterac Valley Battleground'), +(28, 0, 17422, 0, 0, 22, 0, 30, 0, 0, 0, 0, 0, '', 'Armor Scrap only drops inside Alterac Valley Battleground'), +(28, 0, 18228, 0, 0, 22, 0, 30, 0, 0, 0, 0, 0, '', 'Autographed Picture of Foror & Tigule only drops inside Alterac Valley Battleground'); + +DELETE FROM `command` WHERE `name` IN ('reload player_loot_template'); +INSERT INTO `command` (`name`, `security`, `help`) VALUES +('reload player_loot_template', 3, 'Syntax: .reload player_loot_template\nReload player_loot_template table.'); diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 15e87a9cc..3945a0eae 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -763,7 +763,7 @@ bool ConditionMgr::CanHaveSourceGroupSet(ConditionSourceType sourceType) const { return (sourceType == CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU || sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION || sourceType == CONDITION_SOURCE_TYPE_VEHICLE_SPELL || - sourceType == CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET || sourceType == CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT || sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT || sourceType == CONDITION_SOURCE_TYPE_NPC_VENDOR); + sourceType == CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET || sourceType == CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT || sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT || sourceType == CONDITION_SOURCE_TYPE_NPC_VENDOR || sourceType == CONDITION_SOURCE_TYPE_PLAYER_LOOT_TEMPLATE); } bool ConditionMgr::CanHaveSourceIdSet(ConditionSourceType sourceType) const @@ -876,6 +876,7 @@ void ConditionMgr::LoadConditions(bool isReload) LootTemplates_Disenchant.ResetConditions(); LootTemplates_Prospecting.ResetConditions(); LootTemplates_Spell.ResetConditions(); + LootTemplates_Player.ResetConditions(); LOG_INFO("server.loading", "Re-Loading `gossip_menu` Table for Conditions!"); sObjectMgr->LoadGossipMenu(); @@ -1003,7 +1004,7 @@ void ConditionMgr::LoadConditions(bool isReload) cond->ErrorTextId = 0; } - if (cond->SourceGroup) + if (cond->SourceGroup || cond->SourceType == CONDITION_SOURCE_TYPE_PLAYER_LOOT_TEMPLATE) { bool valid = false; // handle grouped conditions @@ -1084,6 +1085,11 @@ void ConditionMgr::LoadConditions(bool isReload) ++count; continue; } + case CONDITION_SOURCE_TYPE_PLAYER_LOOT_TEMPLATE: + { + valid = addToLootTemplate(cond, LootTemplates_Player.GetLootForConditionFill(cond->SourceGroup)); + break; + } default: break; } @@ -1615,6 +1621,23 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) } break; } + case CONDITION_SOURCE_TYPE_PLAYER_LOOT_TEMPLATE: + { + if (!LootTemplates_Player.HaveLootFor(cond->SourceGroup)) + { + LOG_ERROR("sql.sql", "SourceGroup %u in `condition` table, does not exist in `player_loot_template`, ignoring.", cond->SourceGroup); + return false; + } + + LootTemplate* loot = LootTemplates_Player.GetLootForConditionFill(cond->SourceGroup); + ItemTemplate const* pItemProto = sObjectMgr->GetItemTemplate(cond->SourceEntry); + if (!pItemProto && !loot->isReference(cond->SourceEntry)) + { + LOG_ERROR("sql.sql", "SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->SourceType, cond->SourceEntry); + return false; + } + break; + } case CONDITION_SOURCE_TYPE_GOSSIP_MENU: case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION: case CONDITION_SOURCE_TYPE_SMART_EVENT: diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index 9d935b257..d3989dfeb 100644 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -147,7 +147,8 @@ enum ConditionSourceType CONDITION_SOURCE_TYPE_TERRAIN_SWAP = 25, // don't use on 3.3.5a CONDITION_SOURCE_TYPE_PHASE = 26, // don't use on 3.3.5a CONDITION_SOURCE_TYPE_GRAVEYARD = 27, // don't use on 3.3.5a - CONDITION_SOURCE_TYPE_MAX = 28 // placeholder + CONDITION_SOURCE_TYPE_PLAYER_LOOT_TEMPLATE = 28, + CONDITION_SOURCE_TYPE_MAX = 29 // placeholder }; enum RelationType diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 330ae61ad..92f881095 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -7706,15 +7706,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type) uint32 pLevel = bones->loot.gold; bones->loot.clear(); - // Xinef: For AV Achievement - if (Battleground* bg = GetBattleground()) - { - if (bg->GetBgTypeID(true) == BATTLEGROUND_AV) - loot->FillLoot(1, LootTemplates_Creature, this, true); - } - // Xinef: For wintergrasp Quests - else if (GetZoneId() == AREA_WINTERGRASP) - loot->FillLoot(1, LootTemplates_Creature, this, true); + loot->FillLoot(GetTeamId(), LootTemplates_Player, this, true); // It may need a better formula // Now it works like this: lvl10: ~6copper, lvl70: ~9silver diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index 215cb674f..a8bcabfec 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -51,6 +51,7 @@ LootStore LootTemplates_Prospecting("prospecting_loot_template", "item entry LootStore LootTemplates_Reference("reference_loot_template", "reference id", false); LootStore LootTemplates_Skinning("skinning_loot_template", "creature skinning id", true); LootStore LootTemplates_Spell("spell_loot_template", "spell id (random item creating)", false); +LootStore LootTemplates_Player("player_loot_template", "team id", true); // Selects invalid loot items to be removed from group possible entries (before rolling) struct LootGroupInvalidSelector : public Acore::unary_function @@ -2252,6 +2253,27 @@ void LoadLootTemplates_Spell() LOG_INFO("server.loading", " "); } +void LoadLootTemplates_Player() +{ + LOG_INFO("server.loading", "Loading player loot templates..."); + + uint32 oldMSTime = getMSTime(); + + LootIdSet lootIdSet; + uint32 count = LootTemplates_Player.LoadAndCollectLootIds(lootIdSet); + + if (count) + { + LOG_INFO("server.loading", ">> Loaded %u player loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + } + else + { + LOG_ERROR("sql.sql", ">> Loaded 0 player loot templates. DB table `player_loot_template` is empty"); + } + + LOG_INFO("server.loading", " "); +} + void LoadLootTemplates_Reference() { LOG_INFO("server.loading", "Loading reference loot templates..."); diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h index 67f6523d4..32b1021f1 100644 --- a/src/server/game/Loot/LootMgr.h +++ b/src/server/game/Loot/LootMgr.h @@ -421,6 +421,7 @@ extern LootStore LootTemplates_Skinning; extern LootStore LootTemplates_Disenchant; extern LootStore LootTemplates_Prospecting; extern LootStore LootTemplates_Spell; +extern LootStore LootTemplates_Player; void LoadLootTemplates_Creature(); void LoadLootTemplates_Fishing(); @@ -436,6 +437,8 @@ void LoadLootTemplates_Prospecting(); void LoadLootTemplates_Spell(); void LoadLootTemplates_Reference(); +void LoadLootTemplates_Player(); + inline void LoadLootTables() { LoadLootTemplates_Creature(); @@ -451,6 +454,8 @@ inline void LoadLootTables() LoadLootTemplates_Spell(); LoadLootTemplates_Reference(); + + LoadLootTemplates_Player(); } #endif diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index 3ac998e1a..d5a3c6920 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -156,6 +156,7 @@ public: { "spell_target_position", HandleReloadSpellTargetPositionCommand, SEC_ADMINISTRATOR, Console::Yes }, { "spell_threats", HandleReloadSpellThreatsCommand, SEC_ADMINISTRATOR, Console::Yes }, { "spell_group_stack_rules", HandleReloadSpellGroupStackRulesCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "player_loot_template", HandleReloadLootTemplatesPlayerCommand, SEC_ADMINISTRATOR, Console::Yes }, { "acore_string", HandleReloadAcoreStringCommand, SEC_ADMINISTRATOR, Console::Yes }, { "warden_action", HandleReloadWardenactionCommand, SEC_ADMINISTRATOR, Console::Yes }, { "waypoint_scripts", HandleReloadWpScriptsCommand, SEC_ADMINISTRATOR, Console::Yes }, @@ -658,6 +659,16 @@ public: return true; } + static bool HandleReloadLootTemplatesPlayerCommand(ChatHandler* handler) + { + LOG_INFO("server.loading", "Re-Loading Loot Tables... (`player_loot_template`)"); + LoadLootTemplates_Player(); + LootTemplates_Player.CheckLootRefs(); + handler->SendGlobalGMSysMessage("DB table `player_loot_template` reloaded."); + sConditionMgr->LoadConditions(true); + return true; + } + static bool HandleReloadAcoreStringCommand(ChatHandler* handler) { LOG_INFO("server.loading", "Re-Loading acore_string Table!");