*Implement new LootMode system, and add some basic support in boss_sartharion.cpp. Requires database support.
--HG-- branch : trunk
This commit is contained in:
@@ -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`;
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -60,6 +60,8 @@ GameObject::GameObject() : WorldObject(), m_goValue(new GameObjectValue)
|
||||
|
||||
m_DBTableGuid = 0;
|
||||
m_rotation = 0;
|
||||
|
||||
ResetLootMode(); // restore default loot mode
|
||||
}
|
||||
|
||||
GameObject::~GameObject()
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
+26
-22
@@ -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
|
||||
|
||||
+6
-5
@@ -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);
|
||||
|
||||
+2
-2
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user