Added catches for quest and money loot
This commit is contained in:
parent
4886019ca0
commit
ff4d63ef39
@ -25,14 +25,20 @@ namespace
|
|||||||
uint32 sRequiredEquipId = 0;
|
uint32 sRequiredEquipId = 0;
|
||||||
std::vector<uint32> sBobberEntries;
|
std::vector<uint32> sBobberEntries;
|
||||||
|
|
||||||
struct GuidHash { std::size_t operator()(ObjectGuid const& g) const noexcept { return std::hash<uint64>()(g.GetRawValue()); } };
|
struct GuidHash
|
||||||
|
{
|
||||||
|
std::size_t operator()(ObjectGuid const &g) const noexcept { return std::hash<uint64>()(g.GetRawValue()); }
|
||||||
|
};
|
||||||
|
|
||||||
std::unordered_map<ObjectGuid, uint32, GuidHash> sRecastTimers;
|
std::unordered_map<ObjectGuid, uint32, GuidHash> sRecastTimers;
|
||||||
|
|
||||||
struct PendingLoot { uint32 timer; };
|
struct PendingLoot
|
||||||
|
{
|
||||||
|
uint32 timer;
|
||||||
|
};
|
||||||
std::unordered_map<ObjectGuid, PendingLoot, GuidHash> sLootTimers;
|
std::unordered_map<ObjectGuid, PendingLoot, GuidHash> sLootTimers;
|
||||||
|
|
||||||
std::vector<uint32> ParseEntryList(std::string const& csv)
|
std::vector<uint32> ParseEntryList(std::string const &csv)
|
||||||
{
|
{
|
||||||
std::vector<uint32> out;
|
std::vector<uint32> out;
|
||||||
std::stringstream ss(csv);
|
std::stringstream ss(csv);
|
||||||
@ -47,21 +53,23 @@ namespace
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasEquippedItem(Player* plr, uint32 entry)
|
bool HasEquippedItem(Player *plr, uint32 entry)
|
||||||
{
|
{
|
||||||
if (!entry) return true;
|
if (!entry)
|
||||||
|
return true;
|
||||||
for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
|
for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
|
||||||
{
|
{
|
||||||
if (Item* it = plr->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
if (Item *it = plr->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
||||||
if (it->GetEntry() == entry)
|
if (it->GetEntry() == entry)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RequirementMet(Player* plr)
|
bool RequirementMet(Player *plr)
|
||||||
{
|
{
|
||||||
if (!plr) return false;
|
if (!plr)
|
||||||
|
return false;
|
||||||
if (sRequiredItemId && !plr->HasItemCount(sRequiredItemId, 1, false))
|
if (sRequiredItemId && !plr->HasItemCount(sRequiredItemId, 1, false))
|
||||||
return false;
|
return false;
|
||||||
if (sRequiredEquipId && !HasEquippedItem(plr, sRequiredEquipId))
|
if (sRequiredEquipId && !HasEquippedItem(plr, sRequiredEquipId))
|
||||||
@ -69,18 +77,18 @@ namespace
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScheduleRecast(Player* plr)
|
void ScheduleRecast(Player *plr)
|
||||||
{
|
{
|
||||||
if (!sAutoRecast || !plr || !plr->IsInWorld())
|
if (!sAutoRecast || !plr || !plr->IsInWorld())
|
||||||
return;
|
return;
|
||||||
sRecastTimers[plr->GetGUID()] = sRecastDelayMs;
|
sRecastTimers[plr->GetGUID()] = sRecastDelayMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScheduleAutoLoot(Player* plr)
|
void ScheduleAutoLoot(Player *plr)
|
||||||
{
|
{
|
||||||
if (!sServerAutoLoot || !plr)
|
if (!sServerAutoLoot || !plr)
|
||||||
return;
|
return;
|
||||||
sLootTimers[plr->GetGUID()] = PendingLoot{ sAutoLootDelayMs };
|
sLootTimers[plr->GetGUID()] = PendingLoot{sAutoLootDelayMs};
|
||||||
}
|
}
|
||||||
|
|
||||||
void TickRecast(uint32 diff)
|
void TickRecast(uint32 diff)
|
||||||
@ -94,7 +102,7 @@ namespace
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Player* plr = ObjectAccessor::FindPlayer(it->first);
|
Player *plr = ObjectAccessor::FindPlayer(it->first);
|
||||||
if (plr && plr->IsInWorld() && plr->IsAlive() && !plr->IsInCombat() && RequirementMet(plr))
|
if (plr && plr->IsInWorld() && plr->IsAlive() && !plr->IsInCombat() && RequirementMet(plr))
|
||||||
plr->CastSpell(plr, sRecastSpell, true);
|
plr->CastSpell(plr, sRecastSpell, true);
|
||||||
it = sRecastTimers.erase(it);
|
it = sRecastTimers.erase(it);
|
||||||
@ -113,105 +121,131 @@ namespace
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player* plr = ObjectAccessor::FindPlayer(it->first);
|
Player *plr = ObjectAccessor::FindPlayer(it->first);
|
||||||
if (plr && plr->IsInWorld() && RequirementMet(plr))
|
if (plr && plr->IsInWorld() && RequirementMet(plr))
|
||||||
{
|
{
|
||||||
ObjectGuid lootGuid = plr->GetLootGUID();
|
ObjectGuid lootGuid = plr->GetLootGUID();
|
||||||
if (lootGuid.IsGameObject())
|
if (lootGuid.IsGameObject())
|
||||||
{
|
{
|
||||||
if (GameObject* lootGo = ObjectAccessor::GetGameObject(*plr, lootGuid))
|
if (GameObject *lootGo = ObjectAccessor::GetGameObject(*plr, lootGuid))
|
||||||
{
|
{
|
||||||
Loot* loot = &lootGo->loot;
|
Loot *loot = &lootGo->loot;
|
||||||
for (uint32 i = 0; i < loot->items.size(); ++i)
|
|
||||||
|
// 1) Normal items
|
||||||
|
for (uint32 slot = 0; slot < loot->items.size(); ++slot)
|
||||||
{
|
{
|
||||||
if (loot->items[i].is_looted)
|
LootItem &li = loot->items[slot];
|
||||||
|
if (li.is_looted)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
InventoryResult msg = EQUIP_ERR_OK;
|
InventoryResult msg = EQUIP_ERR_OK;
|
||||||
plr->StoreLootItem(uint8(i), loot, msg);
|
plr->StoreLootItem(uint8(slot), loot, msg);
|
||||||
|
|
||||||
|
if (!loot->quest_items.empty())
|
||||||
|
{
|
||||||
|
uint32 baseSlot = loot->items.size();
|
||||||
|
for (uint32 q = 0; q < loot->quest_items.size(); ++q)
|
||||||
|
{
|
||||||
|
QuestItem &qi = loot->quest_items[q];
|
||||||
|
if (qi.is_looted)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint8 slot = uint8(baseSlot + q);
|
||||||
|
InventoryResult msg = EQUIP_ERR_OK;
|
||||||
|
plr->StoreLootItem(slot, loot, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loot->gold > 0)
|
||||||
|
{
|
||||||
|
plr->ModifyMoney(loot->gold);
|
||||||
|
loot->gold = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
plr->SendLootRelease(lootGuid);
|
||||||
|
|
||||||
|
if (lootGo->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE)
|
||||||
|
lootGo->SetLootState(GO_JUST_DEACTIVATED);
|
||||||
}
|
}
|
||||||
plr->SendLootRelease(lootGuid);
|
|
||||||
if (lootGo->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE)
|
|
||||||
lootGo->SetLootState(GO_JUST_DEACTIVATED);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it = sLootTimers.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TryAutoFish(Player * plr)
|
||||||
|
{
|
||||||
|
if (!plr || !plr->IsInWorld() || !RequirementMet(plr))
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::list<GameObject *> nearList;
|
||||||
|
for (auto entry : sBobberEntries)
|
||||||
|
plr->GetGameObjectListWithEntryInGrid(nearList, entry, sScanRange);
|
||||||
|
|
||||||
|
for (GameObject *go : nearList)
|
||||||
|
{
|
||||||
|
if (!go || go->GetOwnerGUID() != plr->GetGUID())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (go->getLootState() == GO_READY && go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE)
|
||||||
|
{
|
||||||
|
go->Use(plr);
|
||||||
|
if (sServerAutoLoot)
|
||||||
|
ScheduleAutoLoot(plr);
|
||||||
|
ScheduleRecast(plr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AutoFish_WorldScript : public WorldScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AutoFish_WorldScript() : WorldScript("AutoFish_WorldScript") {}
|
||||||
|
|
||||||
|
void OnAfterConfigLoad(bool) override
|
||||||
|
{
|
||||||
|
sEnabled = sConfigMgr->GetOption<bool>("AutoFish.Enabled", true);
|
||||||
|
sServerAutoLoot = sConfigMgr->GetOption<bool>("AutoFish.ServerAutoLoot", true);
|
||||||
|
sAutoRecast = sConfigMgr->GetOption<bool>("AutoFish.AutoRecast", true);
|
||||||
|
sTickMs = sConfigMgr->GetOption<uint32>("AutoFish.TickMs", 200u);
|
||||||
|
sScanRange = sConfigMgr->GetOption<float>("AutoFish.ScanRange", 30.0f);
|
||||||
|
sRecastDelayMs = sConfigMgr->GetOption<uint32>("AutoFish.RecastDelayMs", 500u);
|
||||||
|
sRecastSpell = sConfigMgr->GetOption<uint32>("AutoFish.RecastSpell", 18248u);
|
||||||
|
sAutoLootDelayMs = sConfigMgr->GetOption<uint32>("AutoFish.AutoLootDelayMs", 120u);
|
||||||
|
sRequiredItemId = sConfigMgr->GetOption<uint32>("AutoFish.RequiredItemId", 0u);
|
||||||
|
sRequiredEquipId = sConfigMgr->GetOption<uint32>("AutoFish.RequiredEquipId", 0u);
|
||||||
|
sBobberEntries = ParseEntryList(sConfigMgr->GetOption<std::string>("AutoFish.BobberEntries", "35591"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnUpdate(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (!sEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
static uint32 acc = 0;
|
||||||
|
acc += diff;
|
||||||
|
if (acc >= sTickMs)
|
||||||
|
{
|
||||||
|
acc = 0;
|
||||||
|
auto const &players = ObjectAccessor::GetPlayers();
|
||||||
|
for (auto const &kv : players)
|
||||||
|
{
|
||||||
|
Player *plr = kv.second;
|
||||||
|
if (!plr || !plr->IsInWorld() || plr->IsGameMaster())
|
||||||
|
continue;
|
||||||
|
TryAutoFish(plr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
it = sLootTimers.erase(it);
|
TickAutoLoot(diff);
|
||||||
|
TickRecast(diff);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
void TryAutoFish(Player* plr)
|
void AddSC_autofish_world()
|
||||||
{
|
{
|
||||||
if (!plr || !plr->IsInWorld() || !RequirementMet(plr))
|
new AutoFish_WorldScript();
|
||||||
return;
|
|
||||||
|
|
||||||
std::list<GameObject*> nearList;
|
|
||||||
for (auto entry : sBobberEntries)
|
|
||||||
plr->GetGameObjectListWithEntryInGrid(nearList, entry, sScanRange);
|
|
||||||
|
|
||||||
for (GameObject* go : nearList)
|
|
||||||
{
|
|
||||||
if (!go || go->GetOwnerGUID() != plr->GetGUID())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (go->getLootState() == GO_READY && go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE)
|
|
||||||
{
|
|
||||||
go->Use(plr);
|
|
||||||
if (sServerAutoLoot)
|
|
||||||
ScheduleAutoLoot(plr);
|
|
||||||
ScheduleRecast(plr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
class AutoFish_WorldScript : public WorldScript
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AutoFish_WorldScript() : WorldScript("AutoFish_WorldScript") {}
|
|
||||||
|
|
||||||
void OnAfterConfigLoad(bool) override
|
|
||||||
{
|
|
||||||
sEnabled = sConfigMgr->GetOption<bool>("AutoFish.Enabled", true);
|
|
||||||
sServerAutoLoot = sConfigMgr->GetOption<bool>("AutoFish.ServerAutoLoot", true);
|
|
||||||
sAutoRecast = sConfigMgr->GetOption<bool>("AutoFish.AutoRecast", true);
|
|
||||||
sTickMs = sConfigMgr->GetOption<uint32>("AutoFish.TickMs", 200u);
|
|
||||||
sScanRange = sConfigMgr->GetOption<float>("AutoFish.ScanRange", 30.0f);
|
|
||||||
sRecastDelayMs = sConfigMgr->GetOption<uint32>("AutoFish.RecastDelayMs", 500u);
|
|
||||||
sRecastSpell = sConfigMgr->GetOption<uint32>("AutoFish.RecastSpell", 18248u);
|
|
||||||
sAutoLootDelayMs = sConfigMgr->GetOption<uint32>("AutoFish.AutoLootDelayMs", 120u);
|
|
||||||
sRequiredItemId = sConfigMgr->GetOption<uint32>("AutoFish.RequiredItemId", 0u);
|
|
||||||
sRequiredEquipId = sConfigMgr->GetOption<uint32>("AutoFish.RequiredEquipId", 0u);
|
|
||||||
sBobberEntries = ParseEntryList(sConfigMgr->GetOption<std::string>("AutoFish.BobberEntries", "35591"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnUpdate(uint32 diff) override
|
|
||||||
{
|
|
||||||
if (!sEnabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
static uint32 acc = 0;
|
|
||||||
acc += diff;
|
|
||||||
if (acc >= sTickMs)
|
|
||||||
{
|
|
||||||
acc = 0;
|
|
||||||
auto const& players = ObjectAccessor::GetPlayers();
|
|
||||||
for (auto const& kv : players)
|
|
||||||
{
|
|
||||||
Player* plr = kv.second;
|
|
||||||
if (!plr || !plr->IsInWorld() || plr->IsGameMaster())
|
|
||||||
continue;
|
|
||||||
TryAutoFish(plr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TickAutoLoot(diff);
|
|
||||||
TickRecast(diff);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void AddSC_autofish_world()
|
|
||||||
{
|
|
||||||
new AutoFish_WorldScript();
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user