aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/updates/6096_world_loot_template.sql15
-rw-r--r--src/bindings/scripts/scripts/northrend/obsidian_sanctum/boss_sartharion.cpp17
-rw-r--r--src/game/Creature.cpp2
-rw-r--r--src/game/Creature.h8
-rw-r--r--src/game/GameObject.cpp2
-rw-r--r--src/game/GameObject.h9
-rw-r--r--src/game/LootMgr.cpp48
-rw-r--r--src/game/LootMgr.h11
-rw-r--r--src/game/Player.cpp4
-rw-r--r--src/game/SharedDefines.h3
10 files changed, 90 insertions, 29 deletions
diff --git a/sql/updates/6096_world_loot_template.sql b/sql/updates/6096_world_loot_template.sql
new file mode 100644
index 00000000000..17c88df4d25
--- /dev/null
+++ b/sql/updates/6096_world_loot_template.sql
@@ -0,0 +1,15 @@
+
+-- Currently utilized in the following tables (1 = default, 0 = disabled)
+ALTER TABLE `creature_loot_template` ADD COLUMN `lootmode` SMALLINT UNSIGNED NOT NULL DEFAULT 1 BEFORE `groupid`;
+ALTER TABLE `gameobject_loot_template` ADD COLUMN `lootmode` SMALLINT UNSIGNED NOT NULL DEFAULT 1 BEFORE `groupid`;
+ALTER TABLE `reference_loot_template` ADD COLUMN `lootmode` SMALLINT UNSIGNED NOT NULL DEFAULT 1 BEFORE `groupid`;
+
+-- Currently not utilized in the following tables (1 = enabled, any other value = disabled)
+ALTER TABLE `fishing_loot_template` ADD COLUMN `lootmode` SMALLINT UNSIGNED NOT NULL DEFAULT 1 BEFORE `groupid`;
+ALTER TABLE `disenchant_loot_template` ADD COLUMN `lootmode` SMALLINT UNSIGNED NOT NULL DEFAULT 1 BEFORE `groupid`;
+ALTER TABLE `item_loot_template` ADD COLUMN `lootmode` SMALLINT UNSIGNED NOT NULL DEFAULT 1 BEFORE `groupid`;
+ALTER TABLE `milling_loot_template` ADD COLUMN `lootmode` SMALLINT UNSIGNED NOT NULL DEFAULT 1 BEFORE `groupid`;
+ALTER TABLE `pickpocketing_loot_template` ADD COLUMN `lootmode` SMALLINT UNSIGNED NOT NULL DEFAULT 1 BEFORE `groupid`;
+ALTER TABLE `prospecting_loot_template` ADD COLUMN `lootmode` SMALLINT UNSIGNED NOT NULL DEFAULT 1 BEFORE `groupid`;
+ALTER TABLE `skinning_loot_template` ADD COLUMN `lootmode` SMALLINT UNSIGNED NOT NULL DEFAULT 1 BEFORE `groupid`;
+ALTER TABLE `quest_mail_loot_template` ADD COLUMN `lootmode` SMALLINT UNSIGNED NOT NULL DEFAULT 1 BEFORE `groupid`;
diff --git a/src/bindings/scripts/scripts/northrend/obsidian_sanctum/boss_sartharion.cpp b/src/bindings/scripts/scripts/northrend/obsidian_sanctum/boss_sartharion.cpp
index d40ed2dc2e7..d7557370174 100644
--- a/src/bindings/scripts/scripts/northrend/obsidian_sanctum/boss_sartharion.cpp
+++ b/src/bindings/scripts/scripts/northrend/obsidian_sanctum/boss_sartharion.cpp
@@ -214,6 +214,8 @@ struct TRINITY_DLL_DECL boss_sartharionAI : public ScriptedAI
if (m_creature->HasAura(SPELL_TWILIGHT_REVENGE))
m_creature->RemoveAurasDueToSpell(SPELL_TWILIGHT_REVENGE);
+
+ m_creature->ResetLootMode();
}
void JustReachedHome()
@@ -247,6 +249,18 @@ struct TRINITY_DLL_DECL boss_sartharionAI : public ScriptedAI
DoScriptText(RAND(SAY_SARTHARION_SLAY_1,SAY_SARTHARION_SLAY_2,SAY_SARTHARION_SLAY_3), m_creature);
}
+ // m_creature->ResetLootMode() is called from Reset()
+ // AddDrakeLootMode() should only ever be called from FetchDragons(), which is called from Aggro()
+ void AddDrakeLootMode()
+ {
+ if (m_creature->HasLootMode(4)) // Has two Drake loot modes
+ m_creature->AddLootMode(8); // Add 3rd Drake loot mode
+ else if (m_creature->HasLootMode(2)) // Has one Drake loot mode
+ m_creature->AddLootMode(4); // Add 2nd Drake loot mode
+ else // Has no Drake loot modes
+ m_creature->AddLootMode(2); // Add 1st Drake loot mode
+ }
+
void FetchDragons()
{
Unit* pTene = Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_TENEBRON));
@@ -258,6 +272,7 @@ struct TRINITY_DLL_DECL boss_sartharionAI : public ScriptedAI
if (pTene && pTene->isAlive() && !pTene->getVictim())
{
+ AddDrakeLootMode();
bCanUseWill = true;
pTene->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aTene[0].m_fX, m_aTene[0].m_fY, m_aTene[0].m_fZ);
@@ -267,6 +282,7 @@ struct TRINITY_DLL_DECL boss_sartharionAI : public ScriptedAI
if (pShad && pShad->isAlive() && !pShad->getVictim())
{
+ AddDrakeLootMode();
bCanUseWill = true;
pShad->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aShad[0].m_fX, m_aShad[0].m_fY, m_aShad[0].m_fZ);
@@ -276,6 +292,7 @@ struct TRINITY_DLL_DECL boss_sartharionAI : public ScriptedAI
if (pVesp && pVesp->isAlive() && !pVesp->getVictim())
{
+ AddDrakeLootMode();
bCanUseWill = true;
pVesp->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aVesp[0].m_fX, m_aVesp[0].m_fY, m_aVesp[0].m_fZ);
diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp
index 82afa402ff7..6b85cdfd887 100644
--- a/src/game/Creature.cpp
+++ b/src/game/Creature.cpp
@@ -157,6 +157,8 @@ m_creatureInfo(NULL), m_reactState(REACT_AGGRESSIVE), m_formation(NULL)
m_SightDistance = sWorld.getConfig(CONFIG_SIGHT_MONSTER);
m_CombatDistance = 0;//MELEE_RANGE;
+
+ ResetLootMode(); // restore default loot mode
}
Creature::~Creature()
diff --git a/src/game/Creature.h b/src/game/Creature.h
index 5fbe4a07a28..2ee2a3997d7 100644
--- a/src/game/Creature.h
+++ b/src/game/Creature.h
@@ -621,6 +621,13 @@ class TRINITY_DLL_SPEC Creature : public Unit
void SetLootRecipient (Unit* unit);
void AllLootRemovedFromCorpse();
+ uint16 GetLootMode() { return m_LootMode; }
+ bool HasLootMode(uint16 lootMode) { return m_LootMode & lootMode; }
+ void SetLootMode(uint16 lootMode) { m_LootMode = lootMode; }
+ void AddLootMode(uint16 lootMode) { m_LootMode |= lootMode; }
+ void RemoveLootMode(uint16 lootMode) { m_LootMode &= ~lootMode; }
+ void ResetLootMode() { m_LootMode = DEFAULT_LOOT_MODE; }
+
SpellEntry const *reachWithSpellAttack(Unit *pVictim);
SpellEntry const *reachWithSpellCure(Unit *pVictim);
@@ -778,6 +785,7 @@ class TRINITY_DLL_SPEC Creature : public Unit
CreatureInfo const* m_creatureInfo; // in heroic mode can different from ObjMgr::GetCreatureTemplate(GetEntry())
CreatureData const* m_creatureData;
+ uint16 m_LootMode; // bitmask, default DEFAULT_LOOT_MODE, determines what loot will be lootable
private:
//WaypointMovementGenerator vars
uint32 m_waypointID;
diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp
index 1d1b56f0bef..f95fb9643d8 100644
--- a/src/game/GameObject.cpp
+++ b/src/game/GameObject.cpp
@@ -60,6 +60,8 @@ GameObject::GameObject() : WorldObject(), m_goValue(new GameObjectValue)
m_DBTableGuid = 0;
m_rotation = 0;
+
+ ResetLootMode(); // restore default loot mode
}
GameObject::~GameObject()
diff --git a/src/game/GameObject.h b/src/game/GameObject.h
index 1386e220317..232b711bcf9 100644
--- a/src/game/GameObject.h
+++ b/src/game/GameObject.h
@@ -672,6 +672,13 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject
LootState getLootState() const { return m_lootState; }
void SetLootState(LootState s) { m_lootState = s; }
+ uint16 GetLootMode() { return m_LootMode; }
+ bool HasLootMode(uint16 lootMode) { return m_LootMode & lootMode; }
+ void SetLootMode(uint16 lootMode) { m_LootMode = lootMode; }
+ void AddLootMode(uint16 lootMode) { m_LootMode |= lootMode; }
+ void RemoveLootMode(uint16 lootMode) { m_LootMode &= ~lootMode; }
+ void ResetLootMode() { m_LootMode = DEFAULT_LOOT_MODE; }
+
void AddToSkillupList(uint32 PlayerGuidLow) { m_SkillupList.push_back(PlayerGuidLow); }
bool IsInSkillupList(uint32 PlayerGuidLow) const
{
@@ -738,6 +745,8 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject
GameObjectValue * const m_goValue;
uint64 m_rotation;
+
+ uint16 m_LootMode; // bitmask, default DEFAULT_LOOT_MODE, determines what loot will be lootable
private:
void SwitchDoorOrButton(bool activate, bool alternative = false);
diff --git a/src/game/LootMgr.cpp b/src/game/LootMgr.cpp
index 29c19a4eecf..e7337b78333 100644
--- a/src/game/LootMgr.cpp
+++ b/src/game/LootMgr.cpp
@@ -57,11 +57,11 @@ class LootTemplate::LootGroup // A set of loot def
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
- void Process(Loot& loot) const; // Rolls an item from the group (if any) and adds the item to the loot
+ void Process(Loot& loot, uint16 lootMode) const; // Rolls an item from the group (if any) and adds the item to the loot
float RawTotalChance() const; // Overall chance for the group (without equal chanced items)
float TotalChance() const; // Overall chance for the group
- void Verify(LootStore const& lootstore, uint32 id, uint32 group_id) const;
+ void Verify(LootStore const& lootstore, uint32 id, uint8 group_id) const;
void CollectLootIds(LootIdSet& set) const;
void CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_set) const;
private:
@@ -99,8 +99,8 @@ void LootStore::LoadLootTable()
sLog.outString( "%s :", GetName());
- // 0 1 2 3 4 5 6 7 8
- QueryResult *result = WorldDatabase.PQuery("SELECT entry, item, ChanceOrQuestChance, groupid, mincountOrRef, maxcount, lootcondition, condition_value1, condition_value2 FROM %s",GetName());
+ // 0 1 2 3 4 5 6 7 8 9
+ QueryResult *result = WorldDatabase.PQuery("SELECT entry, item, ChanceOrQuestChance, lootmode, groupid, mincountOrRef, maxcount, lootcondition, condition_value1, condition_value2 FROM %s",GetName());
if (result)
{
@@ -114,12 +114,13 @@ void LootStore::LoadLootTable()
uint32 entry = fields[0].GetUInt32();
uint32 item = fields[1].GetUInt32();
float chanceOrQuestChance = fields[2].GetFloat();
- uint8 group = fields[3].GetUInt8();
- int32 mincountOrRef = fields[4].GetInt32();
- uint32 maxcount = fields[5].GetUInt32();
- ConditionType condition = (ConditionType)fields[6].GetUInt8();
- uint32 cond_value1 = fields[7].GetUInt32();
- uint32 cond_value2 = fields[8].GetUInt32();
+ uint16 lootmode = fields[3].GetUInt16();
+ uint8 group = fields[4].GetUInt8();
+ int32 mincountOrRef = fields[5].GetInt32();
+ uint32 maxcount = fields[6].GetUInt32();
+ ConditionType condition = (ConditionType)fields[7].GetUInt8();
+ uint32 cond_value1 = fields[8].GetUInt32();
+ uint32 cond_value2 = fields[9].GetUInt32();
if(maxcount > std::numeric_limits<uint8>::max())
{
@@ -136,7 +137,7 @@ void LootStore::LoadLootTable()
// (condition + cond_value1/2) are converted into single conditionId
uint16 conditionId = objmgr.GetConditionId(condition, cond_value1, cond_value2);
- LootStoreItem storeitem = LootStoreItem(item, chanceOrQuestChance, group, conditionId, mincountOrRef, maxcount);
+ LootStoreItem storeitem = LootStoreItem(item, chanceOrQuestChance, lootmode, group, conditionId, mincountOrRef, maxcount);
if (!storeitem.IsValid(*this,entry)) // Validity checks
continue;
@@ -387,7 +388,7 @@ void Loot::AddItem(LootStoreItem const & item)
}
// Calls processor of corresponding LootTemplate (which handles everything including references)
-void Loot::FillLoot(uint32 loot_id, LootStore const& store, Player* loot_owner, bool personal)
+void Loot::FillLoot(uint32 loot_id, LootStore const& store, Player* loot_owner, bool personal, uint16 lootMode /*= DEFAULT_LOOT_MODE*/)
{
// Must be provided
if(!loot_owner)
@@ -404,7 +405,7 @@ void Loot::FillLoot(uint32 loot_id, LootStore const& store, Player* loot_owner,
items.reserve(MAX_NR_LOOT_ITEMS);
quest_items.reserve(MAX_NR_QUEST_ITEMS);
- tab->Process(*this, store,store.IsRatesAllowed ()); // Processing is done there, callback via Loot::AddItem()
+ tab->Process(*this, store, store.IsRatesAllowed(), lootMode); // Processing is done there, callback via Loot::AddItem()
// Setting access rights for group loot case
Group * pGroup=loot_owner->GetGroup();
@@ -857,10 +858,10 @@ bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player const * player) const
}
// Rolls an item from the group (if any takes its chance) and adds the item to the loot
-void LootTemplate::LootGroup::Process(Loot& loot) const
+void LootTemplate::LootGroup::Process(Loot& loot, uint16 lootMode) const
{
LootStoreItem const * item = Roll();
- if (item != NULL)
+ if (item != NULL && item->lootmode & lootMode) // only add this item if roll succeeds and the mode matches
loot.AddItem(*item);
}
@@ -887,7 +888,7 @@ float LootTemplate::LootGroup::TotalChance() const
return result;
}
-void LootTemplate::LootGroup::Verify(LootStore const& lootstore, uint32 id, uint32 group_id) const
+void LootTemplate::LootGroup::Verify(LootStore const& lootstore, uint32 id, uint8 group_id) const
{
float chance = RawTotalChance();
if (chance > 101.0f) // TODO: replace with 100% when DBs will be ready
@@ -944,20 +945,23 @@ void LootTemplate::AddEntry(LootStoreItem& item)
}
// Rolls for every item in the template and adds the rolled items the the loot
-void LootTemplate::Process(Loot& loot, LootStore const& store, bool rate, uint8 groupId) const
+void LootTemplate::Process(Loot& loot, LootStore const& store, bool rate, uint16 lootMode, uint8 groupId) const
{
if (groupId) // Group reference uses own processing of the group
{
if (groupId > Groups.size())
return; // Error message already printed at loading stage
- Groups[groupId-1].Process(loot);
+ 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
+ continue;
+
if (!i->Roll(rate))
continue; // Bad luck for the entry
@@ -968,16 +972,16 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, bool rate, uint8
if(!Referenced)
continue; // Error message already printed at loading stage
- for (uint32 loop=0; loop < i->maxcount; ++loop )// Ref multiplicator
- Referenced->Process(loot, store, rate, i->group);
+ for (uint32 loop=0; loop < i->maxcount; ++loop) // Ref multiplicator
+ Referenced->Process(loot, store, rate, lootMode, i->group);
}
else // Plain entries (not a reference, not grouped)
loot.AddItem(*i); // Chance is already checked, just add
}
// Now processing groups
- for (LootGroups::const_iterator i = Groups.begin( ) ; i != Groups.end( ) ; ++i )
- i->Process(loot);
+ for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
+ i->Process(loot, lootMode);
}
// True if template includes at least 1 quest drop entry
diff --git a/src/game/LootMgr.h b/src/game/LootMgr.h
index c629977ea67..be20c57ec9a 100644
--- a/src/game/LootMgr.h
+++ b/src/game/LootMgr.h
@@ -81,14 +81,15 @@ struct LootStoreItem
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)
uint8 group :7;
+ uint16 lootmode;
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, uint8 _conditionId, int32 _mincountOrRef, uint8 _maxcount)
- : itemid(_itemid), chance(fabs(_chanceOrQuestChance)), mincountOrRef(_mincountOrRef),
+ LootStoreItem(uint32 _itemid, float _chanceOrQuestChance, uint8 _group, uint16 _lootmode, uint8 _conditionId, int32 _mincountOrRef, uint8 _maxcount)
+ : itemid(_itemid), chance(fabs(_chanceOrQuestChance)), mincountOrRef(_mincountOrRef), lootmode(_lootmode),
group(_group), needs_quest(_chanceOrQuestChance < 0), maxcount(_maxcount), conditionId(_conditionId)
{}
@@ -183,12 +184,12 @@ class LootTemplate
// Adds an entry to the group (at loading stage)
void AddEntry(LootStoreItem& item);
// Rolls for every item in the template and adds the rolled items the the loot
- void Process(Loot& loot, LootStore const& store, bool rate, uint8 GroupId = 0) const;
+ void Process(Loot& loot, LootStore const& store, bool rate, uint16 lootMode, uint8 groupId = 0) const;
// True if template includes at least 1 quest drop entry
bool HasQuestDrop(LootTemplateMap const& store, uint8 GroupId = 0) const;
// True if template includes at least 1 quest drop for an active quest of the player
- bool HasQuestDropForPlayer(LootTemplateMap const& store, Player const * player, uint8 GroupId = 0) const;
+ bool HasQuestDropForPlayer(LootTemplateMap const& store, Player const * player, uint8 groupId = 0) const;
// Checks integrity of the template
void Verify(LootStore const& store, uint32 Id) const;
@@ -285,7 +286,7 @@ struct Loot
void RemoveLooter(uint64 GUID) { PlayersLooting.erase(GUID); }
void generateMoneyLoot(uint32 minAmount, uint32 maxAmount);
- void FillLoot(uint32 loot_id, LootStore const& store, Player* loot_owner, bool personal);
+ void FillLoot(uint32 loot_id, LootStore const& store, Player* loot_owner, bool personal, uint16 lootMode = DEFAULT_LOOT_MODE);
// Inserts the item into the loot (called by LootTemplate processors)
void AddItem(LootStoreItem const & item);
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index 09f6226e400..292cde60ea9 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -7856,7 +7856,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
{
sLog.outDebug(" if(lootid)");
loot->clear();
- loot->FillLoot(lootid, LootTemplates_Gameobject, this, false);
+ loot->FillLoot(lootid, LootTemplates_Gameobject, this, false, go->GetLootMode());
}
if (loot_type == LOOT_FISHING)
@@ -7985,7 +7985,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
loot->clear();
if (uint32 lootid = creature->GetCreatureInfo()->lootid)
- loot->FillLoot(lootid, LootTemplates_Creature, recipient, false);
+ loot->FillLoot(lootid, LootTemplates_Creature, recipient, false, creature->GetLootMode());
loot->generateMoneyLoot(creature->GetCreatureInfo()->mingold,creature->GetCreatureInfo()->maxgold);
diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h
index 8fbd95403c3..eaeb583d0e9 100644
--- a/src/game/SharedDefines.h
+++ b/src/game/SharedDefines.h
@@ -24,6 +24,9 @@
#include "Platform/Define.h"
#include <cassert>
+// default loot mode for creatures and gameobjects
+#define DEFAULT_LOOT_MODE 1
+
enum Gender
{
GENDER_MALE = 0,