[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; m_deathTimer = 0;
setDeathState(DEAD); setDeathState(DEAD);
UpdateObjectVisibility(); UpdateObjectVisibility();
// stop loot rolling before loot clear and for close client dialogs
StopGroupLoot();
loot.clear(); loot.clear();
uint32 respawnDelay = m_respawnDelay; uint32 respawnDelay = m_respawnDelay;
if (AI()) if (AI())
@ -413,19 +417,12 @@ void Creature::Update(uint32 diff)
else else
{ {
m_deathTimer -= diff; m_deathTimer -= diff;
if (m_groupLootTimer && m_groupLootId) if (m_groupLootId)
{
if(diff <= m_groupLootTimer)
{ {
if(diff < m_groupLootTimer)
m_groupLootTimer -= diff; m_groupLootTimer -= diff;
}
else else
{ StopGroupLoot();
if (Group* group = sObjectMgr.GetGroupById(m_groupLootId))
group->EndRoll();
m_groupLootTimer = 0;
m_groupLootId = 0;
}
} }
} }
@ -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() void Creature::RegenerateMana()
{ {
uint32 curValue = GetPower(POWER_MANA); uint32 curValue = GetPower(POWER_MANA);

View file

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

View file

@ -34,6 +34,8 @@
#include "Util.h" #include "Util.h"
#include "LootMgr.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), 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_dungeonDifficulty(REGULAR_DIFFICULTY), m_raidDifficulty(REGULAR_DIFFICULTY),
m_bgGroup(NULL), m_lootMethod(FREE_FOR_ALL), m_looterGuid(0), m_lootThreshold(ITEM_QUALITY_UNCOMMON), 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; for(uint8 itemSlot = 0; itemSlot < loot->items.size(); ++itemSlot)
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)
{ {
item = ObjectMgr::GetItemPrototype(i->itemid); LootItem& lootItem = loot->items[itemSlot];
if (!item) 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; continue;
} }
//roll for over-threshold item if it's one-player loot //roll for over-threshold item if it's one-player loot
if (item->Quality >= uint32(m_lootThreshold) && !i->freeforall) if (itemProto->Quality >= uint32(m_lootThreshold) && !lootItem.freeforall)
{ StartLootRool(creature,loot,itemSlot,false);
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;
else else
{ lootItem.is_underthreshold = 1;
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;
} }
} }
void Group::NeedBeforeGreed(ObjectGuid const& playerGUID, Loot *loot, Creature *creature) void Group::NeedBeforeGreed(Creature *creature, Loot *loot)
{ {
ItemPrototype const *item; for(uint8 itemSlot = 0; itemSlot < loot->items.size(); ++itemSlot)
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)
{ {
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 //only roll for one-player items, not for ones everyone can get
if (item->Quality >= uint32(m_lootThreshold) && !i->freeforall) if (itemProto->Quality >= uint32(m_lootThreshold) && !lootItem.freeforall)
{ StartLootRool(creature, loot, itemSlot, true);
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;
else else
{ lootItem.is_underthreshold = 1;
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;
} }
} }
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; uint32 real_count = 0;
WorldPacket data(SMSG_LOOT_MASTER_LIST, 330); WorldPacket data(SMSG_LOOT_MASTER_LIST, 330);
@ -763,6 +679,54 @@ bool Group::CountRollVote(ObjectGuid const& playerGUID, Rolls::iterator& rollI,
return false; 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 // called when roll timer expires
void Group::EndRoll() 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 SendLootRoll(ObjectGuid const& targetGuid, uint8 rollNumber, uint8 rollType, const Roll &r);
void SendLootRollWon(ObjectGuid const& targetGuid, uint8 rollNumber, RollVote rollType, const Roll &r); void SendLootRollWon(ObjectGuid const& targetGuid, uint8 rollNumber, RollVote rollType, const Roll &r);
void SendLootAllPassed(const Roll &r); void SendLootAllPassed(const Roll &r);
void GroupLoot(ObjectGuid const& playerGUID, Loot *loot, Creature *creature); void GroupLoot(Creature *creature, Loot *loot);
void NeedBeforeGreed(ObjectGuid const& playerGUID, Loot *loot, Creature *creature); void NeedBeforeGreed(Creature *creature, Loot *loot);
void MasterLoot(ObjectGuid const& playerGUID, Loot *loot, Creature *creature); void MasterLoot(Creature *creature, Loot *loot);
void CountRollVote(ObjectGuid const& playerGUID, ObjectGuid const& lootedTarget, uint32 itemSlot, RollVote choise); 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 EndRoll();
void LinkMember(GroupReference *pRef) { m_memberMgr.insertFirst(pRef); } 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: case GROUP_LOOT:
// GroupLoot delete items over threshold (threshold even not implemented), and roll them. Items with quality<threshold, round robin // 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; break;
case NEED_BEFORE_GREED: case NEED_BEFORE_GREED:
group->NeedBeforeGreed(recipient->GetObjectGuid(), loot, creature); group->NeedBeforeGreed(creature, loot);
break; break;
case MASTER_LOOT: case MASTER_LOOT:
group->MasterLoot(recipient->GetObjectGuid(), loot, creature); group->MasterLoot(creature, loot);
break; break;
default: default:
break; break;

View file

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