mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-13 09:07:19 +00:00
Big update.
This commit is contained in:
247
src/LootObjectStack.cpp
Normal file
247
src/LootObjectStack.cpp
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "LootObjectStack.h"
|
||||
#include "LootMgr.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
#define MAX_LOOT_OBJECT_COUNT 10
|
||||
|
||||
LootTarget::LootTarget(ObjectGuid guid) : guid(guid), asOfTime(time(nullptr))
|
||||
{
|
||||
}
|
||||
|
||||
LootTarget::LootTarget(LootTarget const& other)
|
||||
{
|
||||
guid = other.guid;
|
||||
asOfTime = other.asOfTime;
|
||||
}
|
||||
|
||||
LootTarget& LootTarget::operator=(LootTarget const& other)
|
||||
{
|
||||
if ((void*)this == (void*)&other)
|
||||
return *this;
|
||||
|
||||
guid = other.guid;
|
||||
asOfTime = other.asOfTime;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool LootTarget::operator<(LootTarget const& other) const
|
||||
{
|
||||
return guid < other.guid;
|
||||
}
|
||||
|
||||
void LootTargetList::shrink(time_t fromTime)
|
||||
{
|
||||
for (std::set<LootTarget>::iterator i = begin(); i != end(); )
|
||||
{
|
||||
if (i->asOfTime <= fromTime)
|
||||
erase(i++);
|
||||
else
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
LootObject::LootObject(Player* bot, ObjectGuid guid) : guid(), skillId(SKILL_NONE), reqSkillValue(0), reqItem(0)
|
||||
{
|
||||
Refresh(bot, guid);
|
||||
}
|
||||
|
||||
void LootObject::Refresh(Player* bot, ObjectGuid lootGUID)
|
||||
{
|
||||
skillId = SKILL_NONE;
|
||||
reqSkillValue = 0;
|
||||
reqItem = 0;
|
||||
guid.Clear();
|
||||
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||
Creature* creature = botAI->GetCreature(lootGUID);
|
||||
if (creature && creature->getDeathState() == CORPSE)
|
||||
{
|
||||
if (creature->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE))
|
||||
guid = lootGUID;
|
||||
|
||||
if (creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE))
|
||||
{
|
||||
skillId = creature->GetCreatureTemplate()->GetRequiredLootSkill();
|
||||
uint32 targetLevel = creature->getLevel();
|
||||
reqSkillValue = targetLevel < 10 ? 1 : targetLevel < 20 ? (targetLevel - 10) * 10 : targetLevel * 5;
|
||||
if (botAI->HasSkill((SkillType) skillId) && bot->GetSkillValue(skillId) >= reqSkillValue)
|
||||
guid = lootGUID;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject* go = botAI->GetGameObject(lootGUID);
|
||||
if (go && go->isSpawned() && go->GetGoState() == GO_STATE_READY)
|
||||
{
|
||||
uint32 lockId = go->GetGOInfo()->GetLockId();
|
||||
LockEntry const* lockInfo = sLockStore.LookupEntry(lockId);
|
||||
if (!lockInfo)
|
||||
return;
|
||||
|
||||
for (uint8 i = 0; i < 8; ++i)
|
||||
{
|
||||
switch (lockInfo->Type[i])
|
||||
{
|
||||
case LOCK_KEY_ITEM:
|
||||
if (lockInfo->Index[i] > 0)
|
||||
{
|
||||
reqItem = lockInfo->Index[i];
|
||||
guid = lootGUID;
|
||||
}
|
||||
break;
|
||||
case LOCK_KEY_SKILL:
|
||||
if (SkillByLockType(LockType(lockInfo->Index[i])) > 0)
|
||||
{
|
||||
skillId = SkillByLockType(LockType(lockInfo->Index[i]));
|
||||
reqSkillValue = std::max((uint32)1, lockInfo->Skill[i]);
|
||||
guid = lootGUID;
|
||||
}
|
||||
break;
|
||||
case LOCK_KEY_NONE:
|
||||
guid = lootGUID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WorldObject* LootObject::GetWorldObject(Player* bot)
|
||||
{
|
||||
Refresh(bot, guid);
|
||||
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||
|
||||
Creature* creature = botAI->GetCreature(guid);
|
||||
if (creature && creature->getDeathState() == CORPSE)
|
||||
return creature;
|
||||
|
||||
GameObject* go = botAI->GetGameObject(guid);
|
||||
if (go && go->isSpawned())
|
||||
return go;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LootObject::LootObject(LootObject const& other)
|
||||
{
|
||||
guid = other.guid;
|
||||
skillId = other.skillId;
|
||||
reqSkillValue = other.reqSkillValue;
|
||||
reqItem = other.reqItem;
|
||||
}
|
||||
|
||||
bool LootObject::IsLootPossible(Player* bot)
|
||||
{
|
||||
if (IsEmpty() || !GetWorldObject(bot))
|
||||
return false;
|
||||
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||
|
||||
if (reqItem && !bot->HasItemCount(reqItem, 1))
|
||||
return false;
|
||||
|
||||
if (abs(GetWorldObject(bot)->GetPositionZ() - bot->GetPositionZ()) > INTERACTION_DISTANCE)
|
||||
return false;
|
||||
|
||||
Creature* creature = botAI->GetCreature(guid);
|
||||
if (creature && creature->getDeathState() == CORPSE)
|
||||
{
|
||||
if (!creature->loot.hasItemFor(bot) && skillId != SKILL_SKINNING)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (skillId == SKILL_NONE)
|
||||
return true;
|
||||
|
||||
if (skillId == SKILL_FISHING)
|
||||
return false;
|
||||
|
||||
if (!botAI->HasSkill((SkillType)skillId))
|
||||
return false;
|
||||
|
||||
if (!reqSkillValue)
|
||||
return true;
|
||||
|
||||
uint32 skillValue = uint32(bot->GetSkillValue(skillId));
|
||||
if (reqSkillValue > skillValue)
|
||||
return false;
|
||||
|
||||
if (skillId == SKILL_MINING && !bot->HasItemCount(2901, 1))
|
||||
return false;
|
||||
|
||||
if (skillId == SKILL_SKINNING && !bot->HasItemCount(7005, 1))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LootObjectStack::Add(ObjectGuid guid)
|
||||
{
|
||||
if (!availableLoot.insert(guid).second)
|
||||
return false;
|
||||
|
||||
if (availableLoot.size() < MAX_LOOT_OBJECT_COUNT)
|
||||
return true;
|
||||
|
||||
std::vector<LootObject> ordered = OrderByDistance();
|
||||
for (size_t i = MAX_LOOT_OBJECT_COUNT; i < ordered.size(); i++)
|
||||
Remove(ordered[i].guid);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LootObjectStack::Remove(ObjectGuid guid)
|
||||
{
|
||||
LootTargetList::iterator i = availableLoot.find(guid);
|
||||
if (i != availableLoot.end())
|
||||
availableLoot.erase(i);
|
||||
}
|
||||
|
||||
void LootObjectStack::Clear()
|
||||
{
|
||||
availableLoot.clear();
|
||||
}
|
||||
|
||||
bool LootObjectStack::CanLoot(float maxDistance)
|
||||
{
|
||||
std::vector<LootObject> ordered = OrderByDistance(maxDistance);
|
||||
return !ordered.empty();
|
||||
}
|
||||
|
||||
LootObject LootObjectStack::GetLoot(float maxDistance)
|
||||
{
|
||||
std::vector<LootObject> ordered = OrderByDistance(maxDistance);
|
||||
return ordered.empty() ? LootObject() : *ordered.begin();
|
||||
}
|
||||
|
||||
std::vector<LootObject> LootObjectStack::OrderByDistance(float maxDistance)
|
||||
{
|
||||
availableLoot.shrink(time(nullptr) - 30);
|
||||
|
||||
std::map<float, LootObject> sortedMap;
|
||||
LootTargetList safeCopy(availableLoot);
|
||||
for (LootTargetList::iterator i = safeCopy.begin(); i != safeCopy.end(); i++)
|
||||
{
|
||||
ObjectGuid guid = i->guid;
|
||||
LootObject lootObject(bot, guid);
|
||||
if (!lootObject.IsLootPossible(bot))
|
||||
continue;
|
||||
|
||||
float distance = bot->GetDistance(lootObject.GetWorldObject(bot));
|
||||
if (!maxDistance || distance <= maxDistance)
|
||||
sortedMap[distance] = lootObject;
|
||||
}
|
||||
|
||||
std::vector<LootObject> result;
|
||||
for (std::map<float, LootObject>::iterator i = sortedMap.begin(); i != sortedMap.end(); i++)
|
||||
result.push_back(i->second);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user