[11878] Add group looting rules for gameobjects (chests)

Patch based on original work by Wowka321

Signed-off-by: Schmoozerd <schmoozerd@scriptdev2.com>
This commit is contained in:
darkstalker 2011-06-17 01:18:27 +03:00 committed by Schmoozerd
parent 16b244373a
commit 461be74c3a
7 changed files with 209 additions and 26 deletions

View file

@ -59,6 +59,9 @@ GameObject::GameObject() : WorldObject(),
m_cooldownTime = 0;
m_packedRotation = 0;
m_groupLootTimer = 0;
m_groupLootId = 0;
m_lootGroupRecipientId = 0;
}
GameObject::~GameObject()
@ -352,6 +355,15 @@ void GameObject::Update(uint32 update_diff, uint32 /*p_time*/)
if (GetGOInfo()->GetAutoCloseTime() && (m_cooldownTime < time(NULL)))
ResetDoorOrButton();
break;
case GAMEOBJECT_TYPE_CHEST:
if (m_groupLootTimer)
{
if (m_groupLootTimer <= update_diff)
StopGroupLoot();
else
m_groupLootTimer -= update_diff;
}
break;
case GAMEOBJECT_TYPE_GOOBER:
if (m_cooldownTime < time(NULL))
{
@ -415,6 +427,7 @@ void GameObject::Update(uint32 update_diff, uint32 /*p_time*/)
}
loot.clear();
SetLootRecipient(NULL);
SetLootState(GO_READY);
if (!m_respawnDelayTime)
@ -1804,6 +1817,86 @@ void GameObject::SetDisplayId(uint32 modelId)
m_displayInfo = sGameObjectDisplayInfoStore.LookupEntry(modelId);
}
void GameObject::StartGroupLoot(Group* group, uint32 timer)
{
m_groupLootId = group->GetId();
m_groupLootTimer = timer;
}
void GameObject::StopGroupLoot()
{
if (!m_groupLootId)
return;
if (Group* group = sObjectMgr.GetGroupById(m_groupLootId))
group->EndRoll();
m_groupLootTimer = 0;
m_groupLootId = 0;
}
Player* GameObject::GetOriginalLootRecipient() const
{
return m_lootRecipientGuid ? ObjectAccessor::FindPlayer(m_lootRecipientGuid) : NULL;
}
Group* GameObject::GetGroupLootRecipient() const
{
// original recipient group if set and not disbanded
return m_lootGroupRecipientId ? sObjectMgr.GetGroupById(m_lootGroupRecipientId) : NULL;
}
Player* GameObject::GetLootRecipient() const
{
// original recipient group if set and not disbanded
Group* group = GetGroupLootRecipient();
// original recipient player if online
Player* player = GetOriginalLootRecipient();
// if group not set or disbanded return original recipient player if any
if (!group)
return player;
// group case
// return player if it still be in original recipient group
if (player && player->GetGroup() == group)
return player;
// find any in group
for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
if (Player* newPlayer = itr->getSource())
return newPlayer;
return NULL;
}
void GameObject::SetLootRecipient(Unit* pUnit)
{
// set the player whose group should receive the right
// to loot the gameobject after its used
// should be set to NULL after the loot disappears
if (!pUnit)
{
m_lootRecipientGuid.Clear();
m_lootGroupRecipientId = 0;
return;
}
Player* player = pUnit->GetCharmerOrOwnerPlayerOrPlayerItself();
if (!player) // normal creature, no player involved
return;
// set player for non group case or if group will disbanded
m_lootRecipientGuid = player->GetObjectGuid();
// set group for group existed case including if player will leave group at loot time
if (Group* group = player->GetGroup())
m_lootGroupRecipientId = group->GetId();
}
float GameObject::GetObjectBoundingRadius() const
{
//FIXME:

View file

@ -681,7 +681,6 @@ class MANGOS_DLL_SPEC GameObject : public WorldObject
static void AddToRemoveListInMaps(uint32 db_guid, GameObjectData const* data);
static void SpawnInMaps(uint32 db_guid, GameObjectData const* data);
void getFishLoot(Loot *loot, Player* loot_owner);
GameobjectTypes GetGoType() const { return GameobjectTypes(GetByteValue(GAMEOBJECT_BYTES_1, 1)); }
void SetGoType(GameobjectTypes type) { SetByteValue(GAMEOBJECT_BYTES_1, 1, type); }
GOState GetGoState() const { return GOState(GetByteValue(GAMEOBJECT_BYTES_1, 0)); }
@ -719,7 +718,19 @@ class MANGOS_DLL_SPEC GameObject : public WorldObject
void SaveRespawnTime();
// Loot System
Loot loot;
void getFishLoot(Loot* loot, Player* loot_owner);
void StartGroupLoot(Group* group, uint32 timer);
ObjectGuid GetLootRecipientGuid() const { return m_lootRecipientGuid; }
uint32 GetLootGroupRecipientId() const { return m_lootGroupRecipientId; }
Player* GetLootRecipient() const; // use group cases as prefered
Group* GetGroupLootRecipient() const;
bool HasLootRecipient() const { return m_lootGroupRecipientId || !m_lootRecipientGuid.IsEmpty(); }
bool IsGroupLootRecipient() const { return m_lootGroupRecipientId; }
void SetLootRecipient(Unit* pUnit);
Player* GetOriginalLootRecipient() const; // ignore group changes/etc, not for looting
bool HasQuest(uint32 quest_id) const;
bool HasInvolvedQuest(uint32 quest_id) const;
@ -763,6 +774,14 @@ class MANGOS_DLL_SPEC GameObject : public WorldObject
GameObjectDisplayInfoEntry const* m_displayInfo;
int64 m_packedRotation;
QuaternionData m_worldRotation;
// Loot System
uint32 m_groupLootTimer; // (msecs)timer used for group loot
uint32 m_groupLootId; // used to find group which is looting
void StopGroupLoot();
ObjectGuid m_lootRecipientGuid; // player who will have rights for looting if m_lootGroupRecipient==0 or group disbanded
uint32 m_lootGroupRecipientId; // group who will have rights for looting if set and exist
private:
void SwitchDoorOrButton(bool activate, bool alternative = false);

View file

@ -585,7 +585,7 @@ void Group::SendLootAllPassed(Roll const& r)
}
}
void Group::GroupLoot(Creature *creature, Loot *loot)
void Group::GroupLoot(WorldObject* pSource, Loot* loot)
{
uint32 maxEnchantingSkill = GetMaxSkillValueForGroup(SKILL_ENCHANTING);
@ -601,13 +601,13 @@ void Group::GroupLoot(Creature *creature, Loot *loot)
//roll for over-threshold item if it's one-player loot
if (itemProto->Quality >= uint32(m_lootThreshold) && !lootItem.freeforall)
StartLootRool(creature, GROUP_LOOT, loot, itemSlot, maxEnchantingSkill);
StartLootRool(pSource, GROUP_LOOT, loot, itemSlot, maxEnchantingSkill);
else
lootItem.is_underthreshold = 1;
}
}
void Group::NeedBeforeGreed(Creature *creature, Loot *loot)
void Group::NeedBeforeGreed(WorldObject* pSource, Loot* loot)
{
uint32 maxEnchantingSkill = GetMaxSkillValueForGroup(SKILL_ENCHANTING);
@ -623,13 +623,13 @@ void Group::NeedBeforeGreed(Creature *creature, Loot *loot)
//only roll for one-player items, not for ones everyone can get
if (itemProto->Quality >= uint32(m_lootThreshold) && !lootItem.freeforall)
StartLootRool(creature, NEED_BEFORE_GREED, loot, itemSlot, maxEnchantingSkill);
StartLootRool(pSource, NEED_BEFORE_GREED, loot, itemSlot, maxEnchantingSkill);
else
lootItem.is_underthreshold = 1;
}
}
void Group::MasterLoot(Creature *creature, Loot* loot)
void Group::MasterLoot(WorldObject* pSource, Loot* loot)
{
for (LootItemList::iterator i=loot->items.begin(); i != loot->items.end(); ++i)
{
@ -651,7 +651,7 @@ void Group::MasterLoot(Creature *creature, Loot* loot)
if (!looter->IsInWorld())
continue;
if (looter->IsWithinDist(creature, sWorld.getConfig(CONFIG_FLOAT_GROUP_XP_DISTANCE), false))
if (looter->IsWithinDist(pSource, sWorld.getConfig(CONFIG_FLOAT_GROUP_XP_DISTANCE), false))
{
data << looter->GetObjectGuid();
++real_count;
@ -663,7 +663,7 @@ void Group::MasterLoot(Creature *creature, Loot* loot)
for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
{
Player *looter = itr->getSource();
if (looter->IsWithinDist(creature, sWorld.getConfig(CONFIG_FLOAT_GROUP_XP_DISTANCE), false))
if (looter->IsWithinDist(pSource, sWorld.getConfig(CONFIG_FLOAT_GROUP_XP_DISTANCE), false))
looter->GetSession()->SendPacket(&data);
}
}
@ -743,7 +743,7 @@ bool Group::CountRollVote(ObjectGuid const& playerGUID, Rolls::iterator& rollI,
return false;
}
void Group::StartLootRool(Creature* lootTarget, LootMethod method, Loot* loot, uint8 itemSlot, uint32 maxEnchantingSkill)
void Group::StartLootRool(WorldObject* lootTarget, LootMethod method, Loot* loot, uint8 itemSlot, uint32 maxEnchantingSkill)
{
if (itemSlot >= loot->items.size())
return;
@ -778,10 +778,14 @@ void Group::StartLootRool(Creature* lootTarget, LootMethod method, Loot* loot, u
r->playerVote.begin()->second = ROLL_NEED;
else
{
// Only GO-group looting and NPC-group looting possible
MANGOS_ASSERT(lootTarget->isType(TYPEMASK_CREATURE_OR_GAMEOBJECT));
r->CalculateCommonVoteMask(maxEnchantingSkill); // dependent from item and possible skill
SendLootStartRoll(LOOT_ROLL_TIMEOUT, lootTarget->GetMapId(), *r);
loot->items[itemSlot].is_blocked = true;
lootTarget->StartGroupLoot(this, LOOT_ROLL_TIMEOUT);
}
@ -1488,7 +1492,7 @@ uint32 Group::GetMaxSkillValueForGroup( SkillType skill )
return maxvalue;
}
void Group::UpdateLooterGuid( Creature* creature, bool ifneed )
void Group::UpdateLooterGuid(WorldObject* pSource, bool ifneed)
{
switch (GetLootMethod())
{
@ -1508,7 +1512,7 @@ void Group::UpdateLooterGuid( Creature* creature, bool ifneed )
{
// not update if only update if need and ok
Player* looter = ObjectAccessor::FindPlayer(guid_itr->guid);
if (looter && looter->IsWithinDist(creature, sWorld.getConfig(CONFIG_FLOAT_GROUP_XP_DISTANCE), false))
if (looter && looter->IsWithinDist(pSource, sWorld.getConfig(CONFIG_FLOAT_GROUP_XP_DISTANCE), false))
return;
}
++guid_itr;
@ -1521,16 +1525,16 @@ void Group::UpdateLooterGuid( Creature* creature, bool ifneed )
{
if (Player* pl = ObjectAccessor::FindPlayer(itr->guid))
{
if (pl->IsWithinDist(creature, sWorld.getConfig(CONFIG_FLOAT_GROUP_XP_DISTANCE), false))
if (pl->IsWithinDist(pSource, sWorld.getConfig(CONFIG_FLOAT_GROUP_XP_DISTANCE), false))
{
bool refresh = pl->GetLootGuid() == creature->GetObjectGuid();
bool refresh = pl->GetLootGuid() == pSource->GetObjectGuid();
//if(refresh) // update loot for new looter
// pl->GetSession()->DoLootRelease(pl->GetLootGUID());
SetLooterGuid(pl->GetObjectGuid());
SendUpdate();
if (refresh) // update loot for new looter
pl->SendLoot(creature->GetObjectGuid(), LOOT_CORPSE);
pl->SendLoot(pSource->GetObjectGuid(), LOOT_CORPSE);
return;
}
}
@ -1542,16 +1546,16 @@ void Group::UpdateLooterGuid( Creature* creature, bool ifneed )
{
if (Player* pl = ObjectAccessor::FindPlayer(itr->guid))
{
if (pl->IsWithinDist(creature, sWorld.getConfig(CONFIG_FLOAT_GROUP_XP_DISTANCE), false))
if (pl->IsWithinDist(pSource, sWorld.getConfig(CONFIG_FLOAT_GROUP_XP_DISTANCE), false))
{
bool refresh = pl->GetLootGuid() == creature->GetObjectGuid();
bool refresh = pl->GetLootGuid() == pSource->GetObjectGuid();
//if(refresh) // update loot for new looter
// pl->GetSession()->DoLootRelease(pl->GetLootGUID());
SetLooterGuid(pl->GetObjectGuid());
SendUpdate();
if (refresh) // update loot for new looter
pl->SendLoot(creature->GetObjectGuid(), LOOT_CORPSE);
pl->SendLoot(pSource->GetObjectGuid(), LOOT_CORPSE);
return;
}
}

View file

@ -223,7 +223,7 @@ class MANGOS_DLL_SPEC Group
void ChangeLeader(ObjectGuid guid);
void SetLootMethod(LootMethod method) { m_lootMethod = method; }
void SetLooterGuid(ObjectGuid guid) { m_looterGuid = guid; }
void UpdateLooterGuid( Creature* creature, bool ifneed = false );
void UpdateLooterGuid(WorldObject* pSource, bool ifneed = false);
void SetLootThreshold(ItemQualities threshold) { m_lootThreshold = threshold; }
void Disband(bool hideDestroy=false);
@ -347,11 +347,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(Creature *creature, Loot *loot);
void NeedBeforeGreed(Creature *creature, Loot *loot);
void MasterLoot(Creature *creature, Loot *loot);
void GroupLoot(WorldObject* pSource, Loot* loot);
void NeedBeforeGreed(WorldObject* pSource, Loot* loot);
void MasterLoot(WorldObject* pSource, Loot* loot);
bool CountRollVote(Player* player, ObjectGuid const& lootedTarget, uint32 itemSlot, RollVote vote);
void StartLootRool(Creature* lootTarget, LootMethod method, Loot* loot, uint8 itemSlot, uint32 maxEnchantingSkill);
void StartLootRool(WorldObject* lootTarget, LootMethod method, Loot* loot, uint8 itemSlot, uint32 maxEnchantingSkill);
void EndRoll();
void LinkMember(GroupReference *pRef) { m_memberMgr.insertFirst(pRef); }

View file

@ -66,6 +66,7 @@ class WorldSession;
class Creature;
class Player;
class Unit;
class Group;
class Map;
class UpdateMask;
class InstanceData;
@ -356,6 +357,7 @@ class MANGOS_DLL_SPEC Object
virtual bool HasQuest(uint32 /* quest_id */) const { return false; }
virtual bool HasInvolvedQuest(uint32 /* quest_id */) const { return false; }
protected:
Object ( );
@ -586,6 +588,9 @@ class MANGOS_DLL_SPEC WorldObject : public Object
// ASSERT print helper
bool PrintCoordinatesError(float x, float y, float z, char const* descr) const;
virtual void StartGroupLoot(Group* group, uint32 timer) {}
protected:
explicit WorldObject();
@ -595,6 +600,8 @@ class MANGOS_DLL_SPEC WorldObject : public Object
void SetLocationMapId(uint32 _mapId) { m_mapId = _mapId; }
void SetLocationInstanceId(uint32 _instanceId) { m_InstanceId = _instanceId; }
virtual void StopGroupLoot() {}
std::string m_name;
private:

View file

@ -7976,7 +7976,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
if (ObjectGuid lootGuid = GetLootGuid())
m_session->DoLootRelease(lootGuid);
Loot *loot = 0;
Loot* loot = NULL;
PermissionTypes permission = ALL_PERMISSION;
DEBUG_LOG("Player::SendLoot");
@ -7997,6 +7997,13 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
loot = &go->loot;
Player* recipient = go->GetLootRecipient();
if (!recipient)
{
go->SetLootRecipient(this);
recipient = this;
}
// generate loot only if ready for open and spawned in world
if (go->getLootState() == GO_READY && go->isSpawned())
{
@ -8020,12 +8027,65 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
loot->clear();
loot->FillLoot(lootid, LootTemplates_Gameobject, this, false);
loot->generateMoneyLoot(go->GetGOInfo()->MinMoneyLoot, go->GetGOInfo()->MaxMoneyLoot);
if (go->GetGoType() == GAMEOBJECT_TYPE_CHEST && go->GetGOInfo()->chest.groupLootRules)
{
if (Group* group = go->GetGroupLootRecipient())
{
group->UpdateLooterGuid(go, true);
switch (group->GetLootMethod())
{
case GROUP_LOOT:
// GroupLoot delete items over threshold (threshold even not implemented), and roll them. Items with quality<threshold, round robin
group->GroupLoot(go, loot);
permission = GROUP_PERMISSION;
break;
case NEED_BEFORE_GREED:
group->NeedBeforeGreed(go, loot);
permission = GROUP_PERMISSION;
break;
case MASTER_LOOT:
group->MasterLoot(go, loot);
permission = MASTER_PERMISSION;
break;
default:
break;
}
}
}
}
else if (loot_type == LOOT_FISHING)
go->getFishLoot(loot,this);
go->SetLootState(GO_ACTIVATED);
}
if (go->getLootState() == GO_ACTIVATED && go->GetGoType() == GAMEOBJECT_TYPE_CHEST && go->GetGOInfo()->chest.groupLootRules)
{
if (Group* group = go->GetGroupLootRecipient())
{
if (group == GetGroup())
{
if (group->GetLootMethod() == FREE_FOR_ALL)
permission = ALL_PERMISSION;
else if (group->GetLooterGuid() == GetObjectGuid())
{
if (group->GetLootMethod() == MASTER_LOOT)
permission = MASTER_PERMISSION;
else
permission = ALL_PERMISSION;
}
else
permission = GROUP_PERMISSION;
}
else
permission = NONE_PERMISSION;
}
else if (recipient == this)
permission = ALL_PERMISSION;
else
permission = NONE_PERMISSION;
}
break;
}
case HIGHGUID_ITEM:

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "11877"
#define REVISION_NR "11878"
#endif // __REVISION_NR_H__