[9917] Fixes in loot roll timer work and related cleanups.

* Changes include (in fact as part cleanup) fix got NeedBeforeGreed locked item after expire roll timer
  suggested by somedruid@mangos.lighthouseapp.com.
* Added cancel rolling at creatuer corpse remove.
* For NeedBeforeGreed and GroupLoot sued common code for prepare item roll.
This commit is contained in:
VladimirMangos 2010-05-17 05:24:30 +04:00
parent 0b7f090a37
commit 96d50bf55a
6 changed files with 112 additions and 127 deletions

View file

@ -168,6 +168,10 @@ void Creature::RemoveCorpse()
m_deathTimer = 0;
setDeathState(DEAD);
UpdateObjectVisibility();
// stop loot rolling before loot clear and for close client dialogs
StopGroupLoot();
loot.clear();
uint32 respawnDelay = m_respawnDelay;
if (AI())
@ -413,19 +417,12 @@ void Creature::Update(uint32 diff)
else
{
m_deathTimer -= diff;
if (m_groupLootTimer && m_groupLootId)
{
if(diff <= m_groupLootTimer)
if (m_groupLootId)
{
if(diff < m_groupLootTimer)
m_groupLootTimer -= diff;
}
else
{
if (Group* group = sObjectMgr.GetGroupById(m_groupLootId))
group->EndRoll();
m_groupLootTimer = 0;
m_groupLootId = 0;
}
StopGroupLoot();
}
}
@ -504,6 +501,25 @@ void Creature::Update(uint32 diff)
}
}
void Creature::StartGroupLoot( Group* group, uint32 timer )
{
m_groupLootId = group->GetId();
m_groupLootTimer = timer;
}
void Creature::StopGroupLoot()
{
if (!m_groupLootId)
return;
if (Group* group = sObjectMgr.GetGroupById(m_groupLootId))
group->EndRoll();
m_groupLootTimer = 0;
m_groupLootId = 0;
}
void Creature::RegenerateMana()
{
uint32 curValue = GetPower(POWER_MANA);

View file

@ -33,6 +33,7 @@
struct SpellEntry;
class CreatureAI;
class Group;
class Quest;
class Player;
class WorldSession;
@ -583,8 +584,7 @@ class MANGOS_DLL_SPEC Creature : public Unit
float GetRespawnRadius() const { return m_respawnradius; }
void SetRespawnRadius(float dist) { m_respawnradius = dist; }
uint32 m_groupLootTimer; // (msecs)timer used for group loot
uint32 m_groupLootId; // used to find group which is looting corpse
void StartGroupLoot(Group* group, uint32 timer);
void SendZoneUnderAttackMessage(Player* attacker);
@ -628,6 +628,10 @@ class MANGOS_DLL_SPEC Creature : public Unit
bool InitEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL);
void RelocationNotify();
uint32 m_groupLootTimer; // (msecs)timer used for group loot
uint32 m_groupLootId; // used to find group which is looting corpse
void StopGroupLoot();
// vendor items
VendorItemCounts m_vendorItemCounts;

View file

@ -34,6 +34,8 @@
#include "Util.h"
#include "LootMgr.h"
#define LOOT_ROLL_TIMEOUT (1*MINUTE*IN_MILLISECONDS)
Group::Group() : m_Id(0), m_leaderGuid(0), m_mainTank(0), m_mainAssistant(0), m_groupType(GROUPTYPE_NORMAL),
m_dungeonDifficulty(REGULAR_DIFFICULTY), m_raidDifficulty(REGULAR_DIFFICULTY),
m_bgGroup(NULL), m_lootMethod(FREE_FOR_ALL), m_looterGuid(0), m_lootThreshold(ITEM_QUALITY_UNCOMMON),
@ -538,134 +540,48 @@ void Group::SendLootAllPassed(Roll const& r)
}
}
void Group::GroupLoot(ObjectGuid const& playerGUID, Loot *loot, Creature *creature)
void Group::GroupLoot(Creature *creature, Loot *loot)
{
std::vector<LootItem>::iterator i;
ItemPrototype const *item;
uint8 itemSlot = 0;
Player *player = sObjectMgr.GetPlayer(playerGUID);
Group *group = player->GetGroup();
for (i = loot->items.begin(); i != loot->items.end(); ++i, ++itemSlot)
for(uint8 itemSlot = 0; itemSlot < loot->items.size(); ++itemSlot)
{
item = ObjectMgr::GetItemPrototype(i->itemid);
if (!item)
LootItem& lootItem = loot->items[itemSlot];
ItemPrototype const *itemProto = ObjectMgr::GetItemPrototype(lootItem.itemid);
if (!itemProto)
{
//DEBUG_LOG("Group::GroupLoot: missing item prototype for item with id: %d", i->itemid);
DEBUG_LOG("Group::GroupLoot: missing item prototype for item with id: %d", lootItem.itemid);
continue;
}
//roll for over-threshold item if it's one-player loot
if (item->Quality >= uint32(m_lootThreshold) && !i->freeforall)
{
Roll* r = new Roll(creature->GetGUID(), *i);
//a vector is filled with only near party members
for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
{
Player *member = itr->getSource();
if(!member || !member->GetSession())
continue;
if ( i->AllowedForPlayer(member) )
{
if (member->IsWithinDist(creature, sWorld.getConfig(CONFIG_FLOAT_GROUP_XP_DISTANCE), false))
{
r->playerVote[member->GetGUID()] = ROLL_NOT_EMITED_YET;
++r->totalPlayersRolling;
}
}
}
if (r->totalPlayersRolling > 0) // has looters
{
r->setLoot(loot);
r->itemSlot = itemSlot;
if (r->totalPlayersRolling == 1) // single looter
r->playerVote.begin()->second = ROLL_NEED;
if (itemProto->Quality >= uint32(m_lootThreshold) && !lootItem.freeforall)
StartLootRool(creature,loot,itemSlot,false);
else
{
group->SendLootStartRoll(60000, creature->GetMapId(), *r);
loot->items[itemSlot].is_blocked = true;
creature->m_groupLootTimer = 60000;
creature->m_groupLootId = GetId();
}
RollId.push_back(r);
}
else // no looters??
delete r;
}
else
i->is_underthreshold = 1;
lootItem.is_underthreshold = 1;
}
}
void Group::NeedBeforeGreed(ObjectGuid const& playerGUID, Loot *loot, Creature *creature)
void Group::NeedBeforeGreed(Creature *creature, Loot *loot)
{
ItemPrototype const *item;
Player *player = sObjectMgr.GetPlayer(playerGUID);
Group *group = player->GetGroup();
uint8 itemSlot = 0;
for(std::vector<LootItem>::iterator i = loot->items.begin(); i != loot->items.end(); ++i, ++itemSlot)
for(uint8 itemSlot = 0; itemSlot < loot->items.size(); ++itemSlot)
{
item = ObjectMgr::GetItemPrototype(i->itemid);
LootItem& lootItem = loot->items[itemSlot];
ItemPrototype const *itemProto = ObjectMgr::GetItemPrototype(lootItem.itemid);
if (!itemProto)
{
DEBUG_LOG("Group::NeedBeforeGreed: missing item prototype for item with id: %d", lootItem.itemid);
continue;
}
//only roll for one-player items, not for ones everyone can get
if (item->Quality >= uint32(m_lootThreshold) && !i->freeforall)
{
Roll* r = new Roll(creature->GetGUID(), *i);
for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
{
Player *playerToRoll = itr->getSource();
if(!playerToRoll || !playerToRoll->GetSession())
continue;
if (playerToRoll->CanUseItem(item) && i->AllowedForPlayer(playerToRoll) )
{
if (playerToRoll->IsWithinDist(creature, sWorld.getConfig(CONFIG_FLOAT_GROUP_XP_DISTANCE), false))
{
r->playerVote[playerToRoll->GetGUID()] = ROLL_NOT_EMITED_YET;
++r->totalPlayersRolling;
}
}
}
if (r->totalPlayersRolling > 0) // has looters
{
r->setLoot(loot);
r->itemSlot = itemSlot;
if (r->totalPlayersRolling == 1) // single looter
r->playerVote.begin()->second = ROLL_NEED;
if (itemProto->Quality >= uint32(m_lootThreshold) && !lootItem.freeforall)
StartLootRool(creature, loot, itemSlot, true);
else
{
group->SendLootStartRoll(60000, creature->GetMapId(), *r);
loot->items[itemSlot].is_blocked = true;
}
RollId.push_back(r);
}
else // no looters??
delete r;
}
else
i->is_underthreshold = 1;
lootItem.is_underthreshold = 1;
}
}
void Group::MasterLoot(ObjectGuid const& playerGUID, Loot* /*loot*/, Creature *creature)
void Group::MasterLoot(Creature *creature, Loot* /*loot*/)
{
Player *player = sObjectMgr.GetPlayer(playerGUID);
if(!player)
return;
DEBUG_LOG("Group::MasterLoot (SMSG_LOOT_MASTER_LIST, 330) player = [%s].", player->GetName());
uint32 real_count = 0;
WorldPacket data(SMSG_LOOT_MASTER_LIST, 330);
@ -763,6 +679,54 @@ bool Group::CountRollVote(ObjectGuid const& playerGUID, Rolls::iterator& rollI,
return false;
}
void Group::StartLootRool(Creature* lootTarget, Loot* loot, uint8 itemSlot, bool skipIfCanNotUse)
{
if (itemSlot >= loot->items.size())
return;
LootItem const& lootItem = loot->items[itemSlot];
ItemPrototype const* item = ObjectMgr::GetItemPrototype(lootItem.itemid);
Roll* r = new Roll(lootTarget->GetGUID(), lootItem);
//a vector is filled with only near party members
for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
{
Player *playerToRoll = itr->getSource();
if(!playerToRoll || !playerToRoll->GetSession())
continue;
if ((!skipIfCanNotUse || playerToRoll->CanUseItem(item)) && lootItem.AllowedForPlayer(playerToRoll) )
{
if (playerToRoll->IsWithinDist(lootTarget, sWorld.getConfig(CONFIG_FLOAT_GROUP_XP_DISTANCE), false))
{
r->playerVote[playerToRoll->GetGUID()] = ROLL_NOT_EMITED_YET;
++r->totalPlayersRolling;
}
}
}
if (r->totalPlayersRolling > 0) // has looters
{
r->setLoot(loot);
r->itemSlot = itemSlot;
if (r->totalPlayersRolling == 1) // single looter
r->playerVote.begin()->second = ROLL_NEED;
else
{
SendLootStartRoll(LOOT_ROLL_TIMEOUT, lootTarget->GetMapId(), *r);
loot->items[itemSlot].is_blocked = true;
lootTarget->StartGroupLoot(this,LOOT_ROLL_TIMEOUT);
}
RollId.push_back(r);
}
else // no looters??
delete r;
}
// called when roll timer expires
void Group::EndRoll()
{

View file

@ -331,10 +331,11 @@ class MANGOS_DLL_SPEC Group
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 SendLootAllPassed(const Roll &r);
void GroupLoot(ObjectGuid const& playerGUID, Loot *loot, Creature *creature);
void NeedBeforeGreed(ObjectGuid const& playerGUID, Loot *loot, Creature *creature);
void MasterLoot(ObjectGuid const& playerGUID, Loot *loot, Creature *creature);
void GroupLoot(Creature *creature, Loot *loot);
void NeedBeforeGreed(Creature *creature, Loot *loot);
void MasterLoot(Creature *creature, Loot *loot);
void CountRollVote(ObjectGuid const& playerGUID, ObjectGuid const& lootedTarget, uint32 itemSlot, RollVote choise);
void StartLootRool(Creature* lootTarget, Loot* loot, uint8 itemSlot, bool skipIfCanNotUse);
void EndRoll();
void LinkMember(GroupReference *pRef) { m_memberMgr.insertFirst(pRef); }

View file

@ -7869,13 +7869,13 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
{
case GROUP_LOOT:
// GroupLoot delete items over threshold (threshold even not implemented), and roll them. Items with quality<threshold, round robin
group->GroupLoot(recipient->GetObjectGuid(), loot, creature);
group->GroupLoot(creature, loot);
break;
case NEED_BEFORE_GREED:
group->NeedBeforeGreed(recipient->GetObjectGuid(), loot, creature);
group->NeedBeforeGreed(creature, loot);
break;
case MASTER_LOOT:
group->MasterLoot(recipient->GetObjectGuid(), loot, creature);
group->MasterLoot(creature, loot);
break;
default:
break;

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "9916"
#define REVISION_NR "9917"
#endif // __REVISION_NR_H__