From 070bf64d6abd73c635c6af9e3ce0f1be8f04c721 Mon Sep 17 00:00:00 2001 From: hg <4683435+hgtw@users.noreply.github.com> Date: Sat, 5 Nov 2022 11:13:02 -0400 Subject: [PATCH] [Tasks] Only update loot tasks for NPC corpses (#2513) This fixes a bug that allowed looting items from a player's corpse to increment a task if it didn't have an npc target defined. It looks like this bug existed before the changes in 7482cfc0. This also now passes count for task loot updates to handle item stacks. Also fixes incorrectly casting Corpse to NPC on loot update --- zone/client.h | 15 ++++++++------- zone/corpse.cpp | 8 ++++++-- zone/forage.cpp | 4 ++-- zone/task_client_state.cpp | 37 ++++++++++++++++++++++++------------- zone/task_client_state.h | 5 +++-- zone/tradeskills.cpp | 2 +- 6 files changed, 44 insertions(+), 27 deletions(-) diff --git a/zone/client.h b/zone/client.h index f42951536..7f670138b 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1138,15 +1138,16 @@ public: ); } } - inline void UpdateTasksForItem( - TaskActivityType activity_type, - NPC* npc, - int item_id, - int count = 1 - ) + inline void UpdateTasksForItem(TaskActivityType type, int item_id, int count = 1) { if (task_state) { - task_state->UpdateTasksForItem(this, activity_type, npc, item_id, count); + task_state->UpdateTasksForItem(this, type, item_id, count); + } + } + inline void UpdateTasksOnLoot(Corpse* corpse, int item_id, int count = 1) + { + if (task_state) { + task_state->UpdateTasksOnLoot(this, corpse, item_id, count); } } inline void UpdateTasksOnExplore(const glm::vec4& pos) diff --git a/zone/corpse.cpp b/zone/corpse.cpp index 0e7faea95..88cef3690 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -1370,6 +1370,9 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app) } } + // get count for task update before it's mutated by AutoPutLootInInventory + int count = inst->IsStackable() ? inst->GetCharges() : 1; + /* First add it to the looter - this will do the bag contents too */ if (lootitem->auto_loot > 0) { if (!client->AutoPutLootInInventory(*inst, true, true, bag_item_data)) @@ -1380,8 +1383,9 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app) } /* Update any tasks that have an activity to loot this item */ - if (RuleB(TaskSystem, EnableTaskSystem)) - client->UpdateTasksForItem(TaskActivityType::Loot, IsNPCCorpse() ? CastToNPC() : nullptr, item->ID); + if (RuleB(TaskSystem, EnableTaskSystem) && IsNPCCorpse()) { + client->UpdateTasksOnLoot(this, item->ID, count); + } /* Remove it from Corpse */ if (item_data) { diff --git a/zone/forage.cpp b/zone/forage.cpp index 626732c68..21074b4a4 100644 --- a/zone/forage.cpp +++ b/zone/forage.cpp @@ -367,7 +367,7 @@ void Client::GoFish() PushItemOnCursor(*inst); SendItemPacket(EQ::invslot::slotCursor, inst, ItemPacketLimbo); if (RuleB(TaskSystem, EnableTaskSystem)) - UpdateTasksForItem(TaskActivityType::Fish, nullptr, food_id); + UpdateTasksForItem(TaskActivityType::Fish, food_id); safe_delete(inst); inst = m_inv.GetItem(EQ::invslot::slotCursor); @@ -486,7 +486,7 @@ void Client::ForageItem(bool guarantee) { PushItemOnCursor(*inst); SendItemPacket(EQ::invslot::slotCursor, inst, ItemPacketLimbo); if(RuleB(TaskSystem, EnableTaskSystem)) { - UpdateTasksForItem(TaskActivityType::Forage, nullptr, foragedfood); + UpdateTasksForItem(TaskActivityType::Forage, foragedfood); } safe_delete(inst); diff --git a/zone/task_client_state.cpp b/zone/task_client_state.cpp index 7923af74b..fde9a5bc1 100644 --- a/zone/task_client_state.cpp +++ b/zone/task_client_state.cpp @@ -522,10 +522,10 @@ bool ClientTaskState::CanUpdate(Client* client, const TaskUpdateFilter& filter, } // npc filter supports both npc names and ids in match lists - if (!activity.npc_match_list.empty() && (!filter.npc || - (!Tasks::IsInMatchListPartial(activity.npc_match_list, filter.npc->GetName()) && - !Tasks::IsInMatchListPartial(activity.npc_match_list, filter.npc->GetCleanName()) && - !Tasks::IsInMatchList(activity.npc_match_list, std::to_string(filter.npc->GetNPCTypeID()))))) + if (!activity.npc_match_list.empty() && (!filter.mob || + (!Tasks::IsInMatchListPartial(activity.npc_match_list, filter.mob->GetName()) && + !Tasks::IsInMatchListPartial(activity.npc_match_list, filter.mob->GetCleanName()) && + !Tasks::IsInMatchList(activity.npc_match_list, std::to_string(filter.mob->GetNPCTypeID()))))) { LogTasks("[CanUpdate] client [{}] task [{}]-[{}] failed npc match filter", client->GetName(), task_id, client_activity.activity_id); return false; @@ -640,7 +640,7 @@ bool ClientTaskState::UpdateTasksByNPC(Client* client, TaskActivityType type, NP { TaskUpdateFilter filter{}; filter.type = type; - filter.npc = npc; + filter.mob = npc; return UpdateTasks(client, filter) > 0; } @@ -651,7 +651,7 @@ int ClientTaskState::ActiveSpeakTask(Client* client, NPC* npc) // active task found which has an active SpeakWith activity_information for this NPC. TaskUpdateFilter filter{}; filter.type = TaskActivityType::SpeakWith; - filter.npc = npc; + filter.mob = npc; filter.method = METHODQUEST; auto result = FindTask(client, filter); @@ -670,7 +670,7 @@ int ClientTaskState::ActiveSpeakActivity(Client* client, NPC* npc, int task_id) TaskUpdateFilter filter{}; filter.type = TaskActivityType::SpeakWith; - filter.npc = npc; + filter.mob = npc; filter.method = METHODQUEST; filter.task_id = task_id; @@ -678,19 +678,30 @@ int ClientTaskState::ActiveSpeakActivity(Client* client, NPC* npc, int task_id) return result.first != 0 ? result.second : -1; // activity id } -void ClientTaskState::UpdateTasksForItem(Client* client, TaskActivityType type, NPC* npc, int item_id, int count) +void ClientTaskState::UpdateTasksForItem(Client* client, TaskActivityType type, int item_id, int count) { // This method updates the client's task activities of the specified type which relate // to the specified item. // - // Type should be one of ActivityLoot, ActivityTradeSkill, ActivityFish or ActivityForage + // Type should be one of ActivityTradeSkill, ActivityFish or ActivityForage - LogTasks("[UpdateTasksForItem] activity_type [{}] item_id [{}]", static_cast(type), item_id); + LogTasks("[UpdateTasksForItem] activity_type [{}] item_id [{}] count [{}]", static_cast(type), item_id, count); TaskUpdateFilter filter{}; filter.type = type; - filter.npc = npc; // looting may filter on npc id or name + filter.item_id = item_id; + + UpdateTasks(client, filter, count); +} + +void ClientTaskState::UpdateTasksOnLoot(Client* client, Corpse* corpse, int item_id, int count) +{ + LogTasks("[UpdateTasksOnLoot] corpse [{}] item_id [{}] count [{}]", corpse->GetName(), item_id, count); + + TaskUpdateFilter filter{}; + filter.type = TaskActivityType::Loot; + filter.mob = corpse; filter.item_id = item_id; UpdateTasks(client, filter, count); @@ -715,7 +726,7 @@ bool ClientTaskState::UpdateTasksOnDeliver(Client* client, std::vectorGetPosition(); // or should areas be filtered by client position? filter.use_pos = true; filter.exp_client = exp_client; diff --git a/zone/task_client_state.h b/zone/task_client_state.h index 561b8f9cf..f7b5aa60a 100644 --- a/zone/task_client_state.h +++ b/zone/task_client_state.h @@ -24,7 +24,7 @@ struct TaskUpdateFilter glm::vec4 pos; bool use_pos = false; // if true uses pos instead of client position for area filters bool ignore_area = false; // if true, area check is disabled - NPC* npc = nullptr; + Mob* mob = nullptr; Client* exp_client = nullptr; // used by Kill tasks to filter shared task updates TaskActivityType type = TaskActivityType::None; TaskMethodType method = TaskMethodType::METHODSINGLEID; @@ -56,7 +56,8 @@ public: void RemoveTask(Client *client, int sequence_number, TaskType task_type); void RemoveTaskByTaskID(Client *client, uint32 task_id); bool UpdateTasksByNPC(Client* client, TaskActivityType type, NPC* npc); - void UpdateTasksForItem(Client* client, TaskActivityType type, NPC* npc, int item_id, int count = 1); + void UpdateTasksForItem(Client* client, TaskActivityType type, int item_id, int count = 1); + void UpdateTasksOnLoot(Client* client, Corpse* corpse, int item_id, int count = 1); void UpdateTasksOnExplore(Client* client, const glm::vec4& loc); bool UpdateTasksOnSpeakWith(Client* client, NPC* npc); bool UpdateTasksOnDeliver(Client* client, std::vector& items, Trade& trade, NPC* npc); diff --git a/zone/tradeskills.cpp b/zone/tradeskills.cpp index 5dd09b571..1d3f95be0 100644 --- a/zone/tradeskills.cpp +++ b/zone/tradeskills.cpp @@ -1096,7 +1096,7 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) { } if (RuleB(TaskSystem, EnableTaskSystem)) { - UpdateTasksForItem(TaskActivityType::TradeSkill, nullptr, itr->first, itr->second); + UpdateTasksForItem(TaskActivityType::TradeSkill, itr->first, itr->second); } ++itr;