diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 90d99b622..938b076dd 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -159,6 +159,7 @@ #include "HousingNeighborhoodMirrorEntity.h" #include "HousingPlayerHouseEntity.h" #include "QueryPackets.h" +#include "WorldQuestMgr.h" //WowCommunity // corpse reclaim times #define DEATH_EXPIRE_STEP (5*MINUTE) @@ -6300,6 +6301,9 @@ bool Player::UpdatePosition(float x, float y, float z, float orientation, bool t if (!Unit::UpdatePosition(x, y, z, orientation, teleport)) return false; + //WowCommunity + UpdateWorldQuestPosition(x, y); + //WowCommunity //if (movementInfo.flags & MOVEMENTFLAG_MOVING) // mover->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Moving); //if (movementInfo.flags & MOVEMENTFLAG_TURNING) @@ -9306,7 +9310,9 @@ void Player::SendInitWorldStates(uint32 zoneId, uint32 areaId) packet.SubareaID = areaId; sWorldStateMgr->FillInitialWorldStates(packet, GetMap(), areaId); - + //WowCommunity + sWorldQuestMgr->FillInitWorldStates(packet); + //WowCommunity TC_LOG_INFO("housing", "Player::SendInitWorldStates: Map={} Zone={} Area={} WorldStateCount={}", mapId, zoneId, areaId, uint32(packet.Worldstates.size())); @@ -15190,6 +15196,13 @@ void Player::RewardQuest(Quest const* quest, LootItemType rewardType, uint32 rew else if (quest->IsSeasonal()) SetSeasonalQuestStatus(quest_id); + else if (!quest->IsWorldQuest() && !quest->IsEmissaryQuest()) + { + m_RewardedQuests.insert(quest_id); + // m_accountQuests.insert(quest_id); + m_RewardedQuestsSave[quest_id] = QUEST_DEFAULT_SAVE_TYPE; + } + RemoveTimedQuest(quest_id); RemoveActiveQuest(quest_id, false); if (quest->CanIncreaseRewardedQuestCounters()) @@ -15339,6 +15352,10 @@ void Player::RewardQuest(Quest const* quest, LootItemType rewardType, uint32 rew if (uint32 honor = quest->CalculateHonorGain(GetLevel())) RewardHonor(nullptr, 0, honor, HonorGainSource::Quest); + //wq reward + if (quest->IsWorldQuest()) + sWorldQuestMgr->RewardQuestForPlayer(this, quest->GetQuestId()); + // title reward if (quest->GetRewTitle()) { @@ -18658,7 +18675,10 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol _LoadSeasonalQuestStatus(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS)); _LoadMonthlyQuestStatus(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS)); _LoadRandomBGStatus(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_RANDOM_BG)); - + //WowCommunity +// _LoadWorldQuestStatus(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOADWORLDQUESTSTATUS)); todo thor + //WowCommunity + // after spell and quest load InitTalentForLevel(); LearnDefaultSkills(); @@ -19188,6 +19208,9 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol _restMgr->AddRestBonus(REST_TYPE_XP, time_diff * _restMgr->CalcExtraPerSec(REST_TYPE_XP, bubble)); } + // Add active emissary quests on player at login + sWorldQuestMgr->AddEmissaryQuestsOnPlayerIfNeeded(this); + // Unlock battle pet system if it's enabled in bnet account if (GetSession()->GetBattlePetMgr()->IsBattlePetSystemEnabled()) LearnSpell(BattlePets::SPELL_BATTLE_PET_TRAINING, false); @@ -21241,6 +21264,7 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba _SaveBGData(trans); _SaveInventory(trans); _SaveQuestStatus(trans); + // _SaveWorldQuestStatus(trans); todo thor _SaveDailyQuestStatus(trans); _SaveWeeklyQuestStatus(trans); _SaveSeasonalQuestStatus(trans); @@ -32594,4 +32618,92 @@ bool Player::HasQuest(uint32 questID) const return false; } + +void Player::UpdateWorldQuestPosition(float x, float y) +{ + // Throttle updates to avoid excessive processing + if (time(nullptr) < m_areaQuestTimer) + return; + + // Set next update time to 2 seconds from now + m_areaQuestTimer = time(nullptr) + 2; + + std::vector questsToRemove; + + // Process all bonus quests with area restrictions + //for (auto bonus_quest : sObjectMgr->BonusQuestsRects) + //{ + // uint32 questId = bonus_quest.first; + + // // Skip quests already completed + // if (IsQuestRewarded(questId)) + // continue; + + // // Get quest template + // Quest const* quest = sObjectMgr->GetQuestTemplate(questId); + // if (!quest) + // continue; + + // // Check if player is in any of the quest's valid areas + // bool isInQuestArea = false; + // for (uint32 i = 0; i < bonus_quest.second.size(); ++i) + // { + // if (bonus_quest.second[i].IsIn(GetMapId(), x, y)) + // { + // isInQuestArea = true; + // break; + // } + // } + + // uint32 slot = FindQuestSlot(questId); + // bool hasQuest = (slot < MAX_QUEST_LOG_SIZE); + + // // Player left quest area - remove quest + // if (!isInQuestArea && hasQuest) + // { + // questsToRemove.push_back(slot); + // RemoveActiveQuest(questId, true); + // } + // // Player entered quest area - add quest if eligible + // else if (isInQuestArea && !hasQuest) + // { + // // Check if player can take this quest + // if (!CanTakeQuest(quest, false)) + // continue; + + // // Additional checks for world quests + // if (quest->IsWorldQuest()) + // { + // // Check if player has unlocked world quests for this expansion + // if (!HasWorldQuestEnabled(quest->GetExpansion())) + // { + // // TC_LOG_DEBUG("entities.player.worldquests", "Player %s cannot take world quest %u - world quests not enabled for expansion %u", + // // GetGUID().ToString().c_str(), questId, quest->GetExpansion()); + // continue; + // } + + // // Check if the world quest is currently active + // if (!sWorldQuestMgr->IsQuestActive(quest->GetQuestId())) + // { + // // TC_LOG_DEBUG("entities.player.worldquests", "Player %s cannot take world quest %u - quest is not active", + // // GetGUID().ToString().c_str(), questId); + // continue; + // } + // } + + // // Add the quest to player's quest log + // AddQuest(quest, this); + // /* TC_LOG_DEBUG("entities.player.worldquests", "Player %s automatically added quest %u when entering quest area at [%.2f, %.2f]", + // GetGUID().ToString().c_str(), questId, x, y);*/ + // } + //} + + // Clear quest slots for removed quests + for (uint32 slot : questsToRemove) + { + SetQuestSlot(slot, 0); + TC_LOG_DEBUG("entities.player.worldquests", "Player %s removed quest in slot %u when leaving quest area", + GetGUID().ToString().c_str(), slot); + } +} //WowCommunity diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index e04b6b007..eb787918f 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -3425,6 +3425,10 @@ class TC_GAME_API Player final : public Unit, public GridObject //WowCommunity bool HasQuest(uint32 questID) const; + void UpdateWorldQuestPosition(float x, float y); + + protected: + uint32 m_areaQuestTimer; //WowCommunity private: std::unique_ptr _pendingSpellCastRequest; diff --git a/src/server/game/Quests/WorldQuestMgr.cpp b/src/server/game/Quests/WorldQuestMgr.cpp index 2a390f486..4c70f55e6 100644 --- a/src/server/game/Quests/WorldQuestMgr.cpp +++ b/src/server/game/Quests/WorldQuestMgr.cpp @@ -578,6 +578,50 @@ bool WorldQuestMgr::IsQuestActive(uint32 questId) return false; } +void WorldQuestMgr::RewardQuestForPlayer(Player* player, uint32 questId) +{ + ActiveWorldQuest const* activeWorldQuest = GetActiveWorldQuest(questId); + if (!activeWorldQuest) + return; + + player->TakeQuestSourceItem(questId, false); + + std::vector worldQuestRewards = GetRewardsForPlayerById(player, activeWorldQuest->RewardId); + for (WorldQuestReward const* worldQuestReward : worldQuestRewards) + { + switch (worldQuestReward->Type) + { + case WORLD_QUEST_REWARD_ITEM: + { + ItemPosCountVec dest; + if (player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, worldQuestReward->Id, worldQuestReward->Count) == EQUIP_ERR_OK) + { + std::vector bonusListIDs = ItemBonusMgr::GetAllBonusListsForTree(worldQuestReward->Id); + Item* item = player->StoreNewItem(dest, worldQuestReward->Id, true, GenerateItemRandomBonusListId(worldQuestReward->ItemBonusListID), GuidSet(), ItemContext::World_Quest_13, &bonusListIDs); + player->SendNewItem(item, worldQuestReward->Count, true, false); + } + break; + } + case WORLD_QUEST_REWARD_CURRENCY: + { + player->ModifyCurrency(worldQuestReward->Id, worldQuestReward->Count); + break; + } + case WORLD_QUEST_REWARD_GOLD: + { + uint64 moneyRew = worldQuestReward->Count * sWorld->getRate(RATE_MONEY_QUEST); + player->ModifyMoney(moneyRew); + + if (moneyRew > 0) + player->UpdateCriteria(CriteriaType::MoneyEarnedFromQuesting, uint32(moneyRew)); + break; + } + default: + break; + } + } +} + WorldQuestTemplate* WorldQuestMgr::GetWorldQuestTemplate(uint32 questId) { for (auto& expansionTemplates : _worldQuestTemplates) @@ -656,3 +700,12 @@ TeamId WorldQuestMgr::GetQuestTeamId(Quest const* quest) // For now, return neutral as default return TEAM_NEUTRAL; } + +void WorldQuestMgr::FillInitWorldStates(WorldPackets::WorldState::InitWorldStates& packet) const +{ + for (auto const& [_, expansionWorldQuests] : _activeWorldQuests) + for (auto const& [_, teamWorldQuests] : expansionWorldQuests) + for (auto const& [_, activeWorldQuest] : teamWorldQuests) + if (WorldQuestTemplate const* worldQuestTemplate = activeWorldQuest->GetTemplate()) + packet.Worldstates.emplace_back(worldQuestTemplate->Variable, worldQuestTemplate->Value); +} diff --git a/src/server/game/Quests/WorldQuestMgr.h b/src/server/game/Quests/WorldQuestMgr.h index b4f837b9a..018c64b31 100644 --- a/src/server/game/Quests/WorldQuestMgr.h +++ b/src/server/game/Quests/WorldQuestMgr.h @@ -21,6 +21,7 @@ #include "Common.h" #include "QuestDef.h" #include "GameTime.h" +#include "WorldStatePackets.h" #include #include #include @@ -101,7 +102,9 @@ struct ActiveWorldQuest uint32 StartTime; uint32 EndTime; bool IsCompleted; - + + WorldQuestTemplate const* GetTemplate() const; + uint32 GetRemainingTime() const { uint32 currentTime = GameTime::GetGameTime(); @@ -165,6 +168,9 @@ public: // Timer (public - used by external code) uint32 GetTimerForQuest(uint32 questId); + //packet + void FillInitWorldStates(WorldPackets::WorldState::InitWorldStates& packet) const; + // Team (public - used by external code) TeamId GetQuestTeamId(Quest const* quest); WorldQuestTemplate* GetWorldQuestTemplate(uint32 questId); @@ -191,4 +197,6 @@ private: #define sWorldQuestMgr WorldQuestMgr::instance() +inline WorldQuestTemplate const* ActiveWorldQuest::GetTemplate() const { return sWorldQuestMgr->GetWorldQuestTemplate(QuestId); } + #endif // TRINITYCORE_WORLD_QUEST_MGR_H diff --git a/src/server/game/Server/Packets/QuestPackets.h b/src/server/game/Server/Packets/QuestPackets.h index 8e32010dd..aabdba4c9 100644 --- a/src/server/game/Server/Packets/QuestPackets.h +++ b/src/server/game/Server/Packets/QuestPackets.h @@ -695,14 +695,6 @@ namespace WorldPackets int32 QuestID = 0; }; - class RequestWorldQuestUpdate final : public ClientPacket - { - public: - explicit RequestWorldQuestUpdate(WorldPacket&& packet) : ClientPacket(CMSG_REQUEST_WORLD_QUEST_UPDATE, std::move(packet)) { } - - void Read() override { } - }; - struct PlayerChoiceResponseRewardEntry { WorldPackets::Item::ItemInstance Item;