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;